@draht/coding-agent 2026.3.2 → 2026.3.4
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/CHANGELOG.md +194 -13
- package/README.md +90 -106
- package/agents/architect.md +45 -0
- package/agents/debugger.md +57 -0
- package/agents/git-committer.md +46 -0
- package/agents/implementer.md +25 -0
- package/agents/reviewer.md +52 -0
- package/agents/security-auditor.md +61 -0
- package/agents/verifier.md +44 -0
- package/bin/draht-tools.cjs +20 -20
- package/dist/agents/architect.md +45 -0
- package/dist/agents/debugger.md +57 -0
- package/dist/agents/git-committer.md +46 -0
- package/dist/agents/implementer.md +25 -0
- package/dist/agents/reviewer.md +52 -0
- package/dist/agents/security-auditor.md +61 -0
- package/dist/agents/verifier.md +44 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +0 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -14
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +14 -4
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +167 -49
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +2 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/builtins/subagent.d.ts +14 -0
- package/dist/core/builtins/subagent.d.ts.map +1 -0
- package/dist/core/builtins/subagent.js +492 -0
- package/dist/core/builtins/subagent.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +4 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +6 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +19 -8
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +8 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +9 -6
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +35 -5
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +5 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts +4 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +34 -12
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +5 -5
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +3 -3
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +5 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +9 -1
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +1 -1
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +1 -1
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +1 -1
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +2 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +28 -3
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +1 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +11 -0
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +28 -27
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -1
- package/dist/modes/interactive/theme/light.json +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +5 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/prompts/commands/discuss-phase.md +3 -3
- package/dist/prompts/commands/execute-phase.md +9 -9
- package/dist/prompts/commands/fix.md +29 -0
- package/dist/prompts/commands/init-project.md +49 -0
- package/dist/prompts/commands/map-codebase.md +2 -2
- package/dist/prompts/commands/new-project.md +9 -9
- package/dist/prompts/commands/next-milestone.md +44 -0
- package/dist/prompts/commands/pause-work.md +2 -2
- package/dist/prompts/commands/plan-phase.md +5 -5
- package/dist/prompts/commands/progress.md +1 -1
- package/dist/prompts/commands/quick.md +4 -4
- package/dist/prompts/commands/resume-work.md +1 -1
- package/dist/prompts/commands/review.md +26 -0
- package/dist/prompts/commands/verify-work.md +4 -4
- package/docs/compaction.md +14 -14
- package/docs/custom-provider.md +19 -11
- package/docs/development.md +1 -1
- package/docs/extensions.md +52 -33
- package/docs/json.md +4 -4
- package/docs/packages.md +1 -1
- package/docs/providers.md +4 -2
- package/docs/rpc.md +1 -1
- package/docs/sdk.md +24 -24
- package/docs/session.md +6 -6
- package/docs/settings.md +1 -0
- package/docs/termux.md +1 -1
- package/docs/themes.md +2 -2
- package/docs/tui.md +20 -20
- package/examples/extensions/README.md +5 -4
- package/examples/extensions/antigravity-image-gen.ts +3 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/doom-overlay/README.md +1 -1
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/dynamic-tools.ts +74 -0
- package/examples/extensions/subagent/README.md +11 -11
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/README.md +3 -3
- package/package.json +11 -8
- package/prompts/commands/discuss-phase.md +3 -3
- package/prompts/commands/execute-phase.md +9 -9
- package/prompts/commands/fix.md +29 -0
- package/prompts/commands/init-project.md +49 -0
- package/prompts/commands/map-codebase.md +2 -2
- package/prompts/commands/new-project.md +9 -9
- package/prompts/commands/next-milestone.md +44 -0
- package/prompts/commands/pause-work.md +2 -2
- package/prompts/commands/plan-phase.md +5 -5
- package/prompts/commands/progress.md +1 -1
- package/prompts/commands/quick.md +4 -4
- package/prompts/commands/resume-work.md +1 -1
- package/prompts/commands/review.md +26 -0
- package/prompts/commands/verify-work.md +4 -4
- package/dist/extensions/gsd-commands.ts +0 -338
- package/dist/extensions/subagent.ts +0 -312
- package/extensions/gsd-commands.ts +0 -338
- package/extensions/subagent.ts +0 -312
|
@@ -8,11 +8,11 @@ Initialize a new GSD project: questioning → research → requirements → road
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
## Steps
|
|
11
|
-
1. Run `draht init` to check preconditions
|
|
12
|
-
2. If existing code detected, run `draht map-codebase` first
|
|
11
|
+
1. Run `draht-tools init` to check preconditions
|
|
12
|
+
2. If existing code detected, run `draht-tools map-codebase` first
|
|
13
13
|
3. Deep questioning phase (3-7 rounds, 1-2 questions at a time)
|
|
14
|
-
4. Run `draht create-project` with gathered info
|
|
15
|
-
5. Run `draht create-domain-model` to define bounded contexts, entities, and ubiquitous language
|
|
14
|
+
4. Run `draht-tools create-project` with gathered info
|
|
15
|
+
5. Run `draht-tools create-domain-model` to define bounded contexts, entities, and ubiquitous language
|
|
16
16
|
6. Create `.planning/DOMAIN.md` with:
|
|
17
17
|
- `## Bounded Contexts` — each context with name, responsibility, and brief description
|
|
18
18
|
- `## Ubiquitous Language` — glossary of domain terms agreed with the user (term → definition)
|
|
@@ -25,11 +25,11 @@ Initialize a new GSD project: questioning → research → requirements → road
|
|
|
25
25
|
- `## Coverage Goals` — target coverage percentage and which paths are critical
|
|
26
26
|
- `## Testing Levels` — what is tested at unit level vs integration vs e2e, with examples
|
|
27
27
|
- `## Excluded` — what is explicitly not tested and why (config files, generated code, etc.)
|
|
28
|
-
8. Optional research phase via `draht research`
|
|
29
|
-
9. Run `draht create-requirements` with v1/v2/out-of-scope (map requirements to bounded contexts)
|
|
30
|
-
10. Run `draht create-roadmap` with phases
|
|
31
|
-
11. Run `draht init-state`
|
|
32
|
-
12. Git commit via `draht commit-docs "initialize GSD project"`
|
|
28
|
+
8. Optional research phase via `draht-tools research`
|
|
29
|
+
9. Run `draht-tools create-requirements` with v1/v2/out-of-scope (map requirements to bounded contexts)
|
|
30
|
+
10. Run `draht-tools create-roadmap` with phases
|
|
31
|
+
11. Run `draht-tools init-state`
|
|
32
|
+
12. Git commit via `draht-tools commit-docs "initialize GSD project"`
|
|
33
33
|
|
|
34
34
|
## Rules
|
|
35
35
|
- Ask 1-2 questions at a time, never dump 10 at once
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# /next-milestone
|
|
2
|
+
|
|
3
|
+
Plan the next milestone after the current one is complete.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
```
|
|
7
|
+
/next-milestone
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
- `.planning/ROADMAP.md` must exist
|
|
12
|
+
- Current milestone should be complete or nearly complete
|
|
13
|
+
|
|
14
|
+
## Steps
|
|
15
|
+
1. Load project context:
|
|
16
|
+
- Read `.planning/ROADMAP.md` — identify the completed milestone and its phases
|
|
17
|
+
- Read `.planning/STATE.md` — understand current status
|
|
18
|
+
- Read `.planning/REQUIREMENTS.md` — check which requirements are satisfied
|
|
19
|
+
- Read `.planning/DOMAIN.md` (if exists) — review domain model for evolution needs
|
|
20
|
+
2. Review completed work:
|
|
21
|
+
- Scan `.planning/phases/` for all UAT reports (`*-UAT.md`) and summaries (`*-SUMMARY.md`)
|
|
22
|
+
- Note what was built, what worked well, what had issues
|
|
23
|
+
3. Assess requirements:
|
|
24
|
+
- Which v1 requirements are now satisfied?
|
|
25
|
+
- Which v1 requirements remain?
|
|
26
|
+
- Should any v2 requirements be promoted based on what we learned?
|
|
27
|
+
- Are there new requirements discovered during implementation?
|
|
28
|
+
4. Propose next milestone:
|
|
29
|
+
- Define 3-5 phases, each with a clear goal (outcome, not activity)
|
|
30
|
+
- Order phases by dependency
|
|
31
|
+
- Map each phase to specific requirements
|
|
32
|
+
- Estimate relative complexity
|
|
33
|
+
5. Present the proposed milestone for user approval before writing files
|
|
34
|
+
6. After approval:
|
|
35
|
+
- Update `ROADMAP.md` with the new milestone and phases
|
|
36
|
+
- Update `STATE.md` to reflect milestone transition
|
|
37
|
+
- Update `REQUIREMENTS.md` if requirements changed
|
|
38
|
+
- Update `DOMAIN.md` if domain model needs evolution
|
|
39
|
+
- Commit: `draht-tools commit-docs "plan next milestone"`
|
|
40
|
+
|
|
41
|
+
## Rules
|
|
42
|
+
- Always review what was actually built, not just what was planned
|
|
43
|
+
- Be honest about requirements that slipped or changed scope
|
|
44
|
+
- Each phase goal must be testable — "user can X" not "implement Y"
|
|
@@ -8,5 +8,5 @@ Create a handoff document for session continuity.
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
## Steps
|
|
11
|
-
1. Run `draht pause` — creates CONTINUE-HERE.md
|
|
12
|
-
2. Commit: `draht commit-docs "pause work"`
|
|
11
|
+
1. Run `draht-tools pause` — creates CONTINUE-HERE.md
|
|
12
|
+
2. Commit: `draht-tools commit-docs "pause work"`
|
|
@@ -8,17 +8,17 @@ Create atomic execution plans for a roadmap phase.
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
## Steps
|
|
11
|
-
1. Run `draht load-phase-context N` to gather all context
|
|
12
|
-
2. Optional: `draht research-phase N` for domain research
|
|
11
|
+
1. Run `draht-tools load-phase-context N` to gather all context
|
|
12
|
+
2. Optional: `draht-tools research-phase N` for domain research
|
|
13
13
|
3. Goal-backward planning:
|
|
14
14
|
a. State the goal (outcome, not activity)
|
|
15
15
|
b. Derive observable truths (3-7 from user perspective)
|
|
16
16
|
c. From each observable truth, derive the test scenarios that would prove it (specific inputs → expected outputs or state changes)
|
|
17
17
|
d. Map to required artifacts (files, endpoints, schemas)
|
|
18
18
|
e. Break into atomic tasks (2-5 per plan)
|
|
19
|
-
4. Write plans: `draht create-plan N P`
|
|
20
|
-
5. Validate: `draht validate-plans N`
|
|
21
|
-
6. Commit: `draht commit-docs "create phase N plans"`
|
|
19
|
+
4. Write plans: `draht-tools create-plan N P`
|
|
20
|
+
5. Validate: `draht-tools validate-plans N`
|
|
21
|
+
6. Commit: `draht-tools commit-docs "create phase N plans"`
|
|
22
22
|
|
|
23
23
|
## Plan Format
|
|
24
24
|
Plans use XML task format:
|
|
@@ -8,12 +8,12 @@ Execute a small ad-hoc task with GSD tracking.
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
## Steps
|
|
11
|
-
1. Run `draht next-quick-number` to get task number
|
|
12
|
-
2. Create quick plan: `draht create-quick-plan NNN "description"`
|
|
11
|
+
1. Run `draht-tools next-quick-number` to get task number
|
|
12
|
+
2. Create quick plan: `draht-tools create-quick-plan NNN "description"`
|
|
13
13
|
3. Execute tasks following the TDD cycle:
|
|
14
14
|
- **🔴 RED** — Write a failing test that describes the desired behaviour
|
|
15
15
|
- **🟢 GREEN** — Write the minimum implementation to make it pass
|
|
16
16
|
- **🔵 REFACTOR** — Clean up while keeping the test green
|
|
17
17
|
- *Exception: skip the TDD cycle only for pure config or documentation-only tasks that have no testable behaviour*
|
|
18
|
-
4. Write summary: `draht write-quick-summary NNN`
|
|
19
|
-
5. Update state: `draht update-state`
|
|
18
|
+
4. Write summary: `draht-tools write-quick-summary NNN`
|
|
19
|
+
5. Update state: `draht-tools update-state`
|
|
@@ -8,6 +8,6 @@ Resume from last session state.
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
## Steps
|
|
11
|
-
1. Run `draht resume` — loads CONTINUE-HERE.md or STATE.md
|
|
11
|
+
1. Run `draht-tools resume` — loads CONTINUE-HERE.md or STATE.md
|
|
12
12
|
2. Display context and ask to continue
|
|
13
13
|
3. Delete CONTINUE-HERE.md after confirmation
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# /review
|
|
2
|
+
|
|
3
|
+
Ad-hoc code review and security audit of recent changes or a specific scope.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
```
|
|
7
|
+
/review [scope]
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
If no scope given, reviews all recent uncommitted changes.
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
1. Identify the scope:
|
|
14
|
+
- If argument given: review those files/directories/description
|
|
15
|
+
- If no argument: run `git diff --stat` and `git diff --cached --stat` to find changes
|
|
16
|
+
2. For each changed file, examine:
|
|
17
|
+
- Correctness: logic errors, off-by-one, null handling, error paths
|
|
18
|
+
- Type safety: any `as` casts, `any` types, missing null checks
|
|
19
|
+
- Conventions: naming, file organization, import style
|
|
20
|
+
- Security: injection risks, auth bypasses, secrets in code, unsafe deserialization
|
|
21
|
+
- Performance: unnecessary allocations, missing indexes, N+1 queries
|
|
22
|
+
3. Produce a prioritized findings report:
|
|
23
|
+
- **Critical** — must fix before merge (security, data loss, crashes)
|
|
24
|
+
- **Important** — should fix (bugs, type issues, missing error handling)
|
|
25
|
+
- **Minor** — style, naming, or optional improvements
|
|
26
|
+
4. For each finding: cite the exact file and line, explain the issue, suggest the fix
|
|
@@ -15,13 +15,13 @@ Walk through acceptance testing of completed phase work.
|
|
|
15
15
|
- Load `.planning/DOMAIN.md` and extract all defined terms
|
|
16
16
|
- Scan source files for PascalCase identifiers not present in the glossary
|
|
17
17
|
- Flag any bounded context boundary violations (cross-context direct imports)
|
|
18
|
-
3. Run quality gate: `draht quality-gate --strict`
|
|
19
|
-
4. Run `draht extract-deliverables N` to get testable items
|
|
18
|
+
3. Run quality gate: `draht-tools quality-gate --strict`
|
|
19
|
+
4. Run `draht-tools extract-deliverables N` to get testable items
|
|
20
20
|
5. Walk user through each deliverable one at a time
|
|
21
21
|
6. Record results (pass/fail/partially/skip)
|
|
22
|
-
7. For failures: diagnose and create fix plans via `draht create-fix-plan N P`
|
|
22
|
+
7. For failures: diagnose and create fix plans via `draht-tools create-fix-plan N P`
|
|
23
23
|
- Fix plans MUST include a reproducing test that demonstrates the failure before any implementation
|
|
24
|
-
8. Write UAT report: `draht write-uat N`
|
|
24
|
+
8. Write UAT report: `draht-tools write-uat N`
|
|
25
25
|
- Report must include: test health summary (pass/fail/coverage), domain model status (any glossary violations), deliverable results
|
|
26
26
|
9. If all passed: mark phase complete
|
|
27
27
|
10. If failures: route to `execute-phase N --gaps-only`
|
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GSD — Get Shit Done
|
|
3
|
-
*
|
|
4
|
-
* Batteries-included phase commands for structured AI-assisted development.
|
|
5
|
-
*
|
|
6
|
-
* Full workflow:
|
|
7
|
-
* /discuss <feature> — clarify requirements before planning
|
|
8
|
-
* /plan <feature> — architect produces implementation plan
|
|
9
|
-
* /execute <task1, task2...> — parallel implement → review → commit
|
|
10
|
-
* /verify — parallel lint/typecheck/tests + security audit
|
|
11
|
-
*
|
|
12
|
-
* Utilities:
|
|
13
|
-
* /review <scope> — ad-hoc code review + security audit
|
|
14
|
-
* /fix <issue> — targeted fix plan for a failing task
|
|
15
|
-
* /quick <task> — one-shot implement + commit (skip full GSD)
|
|
16
|
-
* /resume — pick up interrupted work from CONTINUE-HERE.md
|
|
17
|
-
* /status — show .planning/STATE.md overview
|
|
18
|
-
* /new-project <name> [path] — create project dir, git init, scaffold .draht/
|
|
19
|
-
* /init-project — scaffold .draht/ in existing project
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import * as fs from "node:fs";
|
|
23
|
-
import * as path from "node:path";
|
|
24
|
-
import type { ExtensionAPI } from "@draht/coding-agent";
|
|
25
|
-
|
|
26
|
-
function isBusy(ctx: { isIdle: () => boolean }, ui: { notify: (msg: string, level: string) => void }): boolean {
|
|
27
|
-
if (!ctx.isIdle()) {
|
|
28
|
-
ui.notify("Agent is busy", "warning");
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export default function (pi: ExtensionAPI) {
|
|
35
|
-
// ── /discuss ─────────────────────────────────────────────────────────────
|
|
36
|
-
pi.registerCommand("discuss", {
|
|
37
|
-
description: "Clarify requirements before planning. Architect asks questions and defines scope. Usage: /discuss <feature>",
|
|
38
|
-
handler: async (args, ctx) => {
|
|
39
|
-
if (!args.trim()) {
|
|
40
|
-
ctx.ui.notify("Usage: /discuss <feature description>", "warning");
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
if (isBusy(ctx, ctx.ui)) return;
|
|
44
|
-
|
|
45
|
-
pi.sendUserMessage(
|
|
46
|
-
`Use the subagent tool to delegate to the architect agent with this task:
|
|
47
|
-
|
|
48
|
-
"We are in the DISCUSS phase for: ${args.trim()}
|
|
49
|
-
|
|
50
|
-
Your job is NOT to plan yet. First:
|
|
51
|
-
1. Read relevant existing code to understand the current state
|
|
52
|
-
2. Identify ambiguities, unknowns, and risks
|
|
53
|
-
3. List clarifying questions that need answers before planning can begin
|
|
54
|
-
4. Define a clear, bounded scope for what will and won't be built
|
|
55
|
-
5. Output a DISCUSS summary with: scope, assumptions, open questions, risks
|
|
56
|
-
|
|
57
|
-
Do not produce file lists or implementation details yet."
|
|
58
|
-
|
|
59
|
-
Set agentScope to "project".`,
|
|
60
|
-
);
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// ── /plan ────────────────────────────────────────────────────────────────
|
|
65
|
-
pi.registerCommand("plan", {
|
|
66
|
-
description: "Plan a feature — architect reads codebase and produces structured implementation plan. Usage: /plan <feature>",
|
|
67
|
-
handler: async (args, ctx) => {
|
|
68
|
-
if (!args.trim()) {
|
|
69
|
-
ctx.ui.notify("Usage: /plan <feature description>", "warning");
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (isBusy(ctx, ctx.ui)) return;
|
|
73
|
-
|
|
74
|
-
pi.sendUserMessage(
|
|
75
|
-
`Use the subagent tool to delegate to the architect agent with this task: "${args.trim()}"\n\nSet agentScope to "project".`,
|
|
76
|
-
);
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// ── /execute ─────────────────────────────────────────────────────────────
|
|
81
|
-
pi.registerCommand("execute", {
|
|
82
|
-
description: "Execute tasks in parallel, then chain reviewer + git-committer. Usage: /execute task1, task2, task3",
|
|
83
|
-
handler: async (args, ctx) => {
|
|
84
|
-
if (!args.trim()) {
|
|
85
|
-
ctx.ui.notify("Usage: /execute task1, task2, task3", "warning");
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
if (isBusy(ctx, ctx.ui)) return;
|
|
89
|
-
|
|
90
|
-
const tasks = args.split(",").map((t) => t.trim()).filter(Boolean);
|
|
91
|
-
|
|
92
|
-
if (tasks.length === 1) {
|
|
93
|
-
pi.sendUserMessage(
|
|
94
|
-
`Use the subagent tool in chain mode with agentScope "project":
|
|
95
|
-
1. agent: implementer — task: "${tasks[0]}"
|
|
96
|
-
2. agent: reviewer — task: "Review the changes just made: {previous}"
|
|
97
|
-
3. agent: git-committer — task: "Commit all changes. Review context: {previous}"`,
|
|
98
|
-
);
|
|
99
|
-
} else {
|
|
100
|
-
const parallelList = tasks.map((t, i) => `${i + 1}. agent: implementer — task: "${t}"`).join("\n");
|
|
101
|
-
pi.sendUserMessage(
|
|
102
|
-
`Use the subagent tool with agentScope "project":
|
|
103
|
-
|
|
104
|
-
Step 1 — PARALLEL mode (run all simultaneously):
|
|
105
|
-
${parallelList}
|
|
106
|
-
|
|
107
|
-
Step 2 — CHAIN mode (after all parallel tasks complete):
|
|
108
|
-
1. agent: reviewer — task: "Review all changes just implemented"
|
|
109
|
-
2. agent: git-committer — task: "Commit all changes. Review findings: {previous}"`,
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// ── /verify ──────────────────────────────────────────────────────────────
|
|
116
|
-
pi.registerCommand("verify", {
|
|
117
|
-
description: "Parallel verification: lint, typecheck, tests, and security audit",
|
|
118
|
-
handler: async (_args, ctx) => {
|
|
119
|
-
if (isBusy(ctx, ctx.ui)) return;
|
|
120
|
-
|
|
121
|
-
pi.sendUserMessage(
|
|
122
|
-
`Use the subagent tool in PARALLEL mode with agentScope "project":
|
|
123
|
-
1. agent: verifier — task: "Run all lint, typecheck, and test checks"
|
|
124
|
-
2. agent: security-auditor — task: "Audit all recent changes for security vulnerabilities"
|
|
125
|
-
|
|
126
|
-
After both complete, merge findings into a single prioritized report. List what must be fixed before this is production-ready.`,
|
|
127
|
-
);
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// ── /review ──────────────────────────────────────────────────────────────
|
|
132
|
-
pi.registerCommand("review", {
|
|
133
|
-
description: "Ad-hoc code review + security audit. Usage: /review <scope or files>",
|
|
134
|
-
handler: async (args, ctx) => {
|
|
135
|
-
if (isBusy(ctx, ctx.ui)) return;
|
|
136
|
-
|
|
137
|
-
const scope = args.trim() || "all recent changes";
|
|
138
|
-
pi.sendUserMessage(
|
|
139
|
-
`Use the subagent tool in PARALLEL mode with agentScope "project":
|
|
140
|
-
1. agent: reviewer — task: "Review ${scope} for correctness, type safety, and conventions"
|
|
141
|
-
2. agent: security-auditor — task: "Audit ${scope} for security vulnerabilities"
|
|
142
|
-
|
|
143
|
-
After both complete, merge into a single prioritized findings report.`,
|
|
144
|
-
);
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// ── /fix ─────────────────────────────────────────────────────────────────
|
|
149
|
-
pi.registerCommand("fix", {
|
|
150
|
-
description: "Create a targeted fix plan for a failing task or bug. Usage: /fix <description of what's broken>",
|
|
151
|
-
handler: async (args, ctx) => {
|
|
152
|
-
if (!args.trim()) {
|
|
153
|
-
ctx.ui.notify("Usage: /fix <description of what's broken>", "warning");
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
if (isBusy(ctx, ctx.ui)) return;
|
|
157
|
-
|
|
158
|
-
pi.sendUserMessage(
|
|
159
|
-
`Use the subagent tool in chain mode with agentScope "project":
|
|
160
|
-
1. agent: architect — task: "Diagnose this issue and produce a minimal fix plan: ${args.trim()}. Read the relevant code first. Output: root cause, exact files to change, fix steps."
|
|
161
|
-
2. agent: implementer — task: "Apply this fix plan exactly: {previous}"
|
|
162
|
-
3. agent: reviewer — task: "Verify the fix is correct and doesn't introduce regressions: {previous}"
|
|
163
|
-
4. agent: git-committer — task: "Commit the fix. Fix summary: {previous}"`,
|
|
164
|
-
);
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// ── /quick ───────────────────────────────────────────────────────────────
|
|
169
|
-
pi.registerCommand("quick", {
|
|
170
|
-
description: "One-shot task: implement + commit. Skips full GSD workflow. Usage: /quick <task>",
|
|
171
|
-
handler: async (args, ctx) => {
|
|
172
|
-
if (!args.trim()) {
|
|
173
|
-
ctx.ui.notify("Usage: /quick <task description>", "warning");
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
if (isBusy(ctx, ctx.ui)) return;
|
|
177
|
-
|
|
178
|
-
pi.sendUserMessage(
|
|
179
|
-
`Use the subagent tool in chain mode with agentScope "project":
|
|
180
|
-
1. agent: implementer — task: "${args.trim()}"
|
|
181
|
-
2. agent: git-committer — task: "Commit the changes just made: {previous}"`,
|
|
182
|
-
);
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
// ── /resume ──────────────────────────────────────────────────────────────
|
|
187
|
-
pi.registerCommand("resume", {
|
|
188
|
-
description: "Resume interrupted work — reads CONTINUE-HERE.md and picks up where we left off",
|
|
189
|
-
handler: async (_args, ctx) => {
|
|
190
|
-
if (isBusy(ctx, ctx.ui)) return;
|
|
191
|
-
|
|
192
|
-
const continueFile = path.join(ctx.cwd, ".planning", "CONTINUE-HERE.md");
|
|
193
|
-
const stateFile = path.join(ctx.cwd, ".planning", "STATE.md");
|
|
194
|
-
|
|
195
|
-
if (!fs.existsSync(continueFile) && !fs.existsSync(stateFile)) {
|
|
196
|
-
ctx.ui.notify("No .planning/CONTINUE-HERE.md or STATE.md found. Nothing to resume.", "warning");
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
let context = "";
|
|
201
|
-
if (fs.existsSync(continueFile)) {
|
|
202
|
-
context += `\nCONTINUE-HERE.md:\n${fs.readFileSync(continueFile, "utf-8")}`;
|
|
203
|
-
}
|
|
204
|
-
if (fs.existsSync(stateFile)) {
|
|
205
|
-
context += `\nSTATE.md:\n${fs.readFileSync(stateFile, "utf-8")}`;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
pi.sendUserMessage(
|
|
209
|
-
`Read the following project state and resume work from where it was interrupted. Identify the next incomplete task and proceed with it using the appropriate subagent.${context}`,
|
|
210
|
-
);
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// ── /status ──────────────────────────────────────────────────────────────
|
|
215
|
-
pi.registerCommand("status", {
|
|
216
|
-
description: "Show current GSD project state from .planning/STATE.md",
|
|
217
|
-
handler: async (_args, ctx) => {
|
|
218
|
-
const stateFile = path.join(ctx.cwd, ".planning", "STATE.md");
|
|
219
|
-
const logFile = path.join(ctx.cwd, ".planning", "execution-log.jsonl");
|
|
220
|
-
|
|
221
|
-
if (!fs.existsSync(stateFile)) {
|
|
222
|
-
ctx.ui.notify("No .planning/STATE.md found. Run /init-project or /new-project first.", "warning");
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
let output = fs.readFileSync(stateFile, "utf-8");
|
|
227
|
-
|
|
228
|
-
if (fs.existsSync(logFile)) {
|
|
229
|
-
const entries = fs.readFileSync(logFile, "utf-8")
|
|
230
|
-
.split("\n").filter(Boolean)
|
|
231
|
-
.map((l) => { try { return JSON.parse(l); } catch { return null; } })
|
|
232
|
-
.filter(Boolean);
|
|
233
|
-
|
|
234
|
-
const passed = entries.filter((e) => e.status === "pass").length;
|
|
235
|
-
const failed = entries.filter((e) => e.status === "fail").length;
|
|
236
|
-
const skipped = entries.filter((e) => e.status === "skip").length;
|
|
237
|
-
output += `\n\n---\n**Execution log:** ${passed} passed, ${failed} failed, ${skipped} skipped`;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
pi.sendUserMessage(`Here is the current project state:\n\n${output}`);
|
|
241
|
-
},
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
// ── /new-project ─────────────────────────────────────────────────────────
|
|
245
|
-
pi.registerCommand("new-project", {
|
|
246
|
-
description: "Create a new project: mkdir, git init, scaffold .draht/. Usage: /new-project <name> [/base/path]",
|
|
247
|
-
handler: async (args, ctx) => {
|
|
248
|
-
const parts = args.trim().split(/\s+/);
|
|
249
|
-
const name = parts[0];
|
|
250
|
-
if (!name) {
|
|
251
|
-
ctx.ui.notify("Usage: /new-project <name> [/optional/base/path]", "warning");
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const basePath = parts[1] ?? ctx.cwd;
|
|
256
|
-
const projectDir = path.join(basePath, name);
|
|
257
|
-
|
|
258
|
-
if (fs.existsSync(projectDir)) {
|
|
259
|
-
ctx.ui.notify(`Directory already exists: ${projectDir}`, "warning");
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
fs.mkdirSync(projectDir, { recursive: true });
|
|
264
|
-
|
|
265
|
-
const { execSync } = await import("node:child_process");
|
|
266
|
-
execSync("git init", { cwd: projectDir });
|
|
267
|
-
|
|
268
|
-
// Scaffold .draht/ from global agents
|
|
269
|
-
const agentSrc = path.join(process.env.HOME ?? "~", ".draht", "agent", "agents");
|
|
270
|
-
const agentDest = path.join(projectDir, ".draht", "agents");
|
|
271
|
-
const extDest = path.join(projectDir, ".draht", "extensions");
|
|
272
|
-
fs.mkdirSync(agentDest, { recursive: true });
|
|
273
|
-
fs.mkdirSync(extDest, { recursive: true });
|
|
274
|
-
|
|
275
|
-
let agentsCopied = 0;
|
|
276
|
-
if (fs.existsSync(agentSrc)) {
|
|
277
|
-
for (const file of fs.readdirSync(agentSrc)) {
|
|
278
|
-
if (!file.endsWith(".md")) continue;
|
|
279
|
-
fs.copyFileSync(path.join(agentSrc, file), path.join(agentDest, file));
|
|
280
|
-
agentsCopied++;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Copy shipped extensions into the new project
|
|
285
|
-
const extSrc = path.dirname(new URL(import.meta.url).pathname);
|
|
286
|
-
for (const file of ["subagent.ts", "gsd-commands.ts"]) {
|
|
287
|
-
const src = path.join(extSrc, file);
|
|
288
|
-
if (fs.existsSync(src)) {
|
|
289
|
-
fs.copyFileSync(src, path.join(extDest, file));
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
fs.writeFileSync(path.join(projectDir, ".gitignore"), "node_modules/\n.env\n.env.local\n");
|
|
294
|
-
|
|
295
|
-
ctx.ui.notify(
|
|
296
|
-
`✓ ${projectDir} created — ${agentsCopied} agents, git initialized. Customize .draht/agents/*.md for your stack.`,
|
|
297
|
-
"info",
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
pi.sendUserMessage(
|
|
301
|
-
`New project "${name}" created at ${projectDir} with ${agentsCopied} GSD agents scaffolded. What should we build first?`,
|
|
302
|
-
);
|
|
303
|
-
},
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
// ── /init-project ────────────────────────────────────────────────────────
|
|
307
|
-
pi.registerCommand("init-project", {
|
|
308
|
-
description: "Scaffold .draht/ config into an existing project from global agent defaults",
|
|
309
|
-
handler: async (_args, ctx) => {
|
|
310
|
-
const targetDir = path.join(ctx.cwd, ".draht");
|
|
311
|
-
|
|
312
|
-
if (fs.existsSync(targetDir)) {
|
|
313
|
-
ctx.ui.notify(".draht/ already exists in this project", "warning");
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const agentSrc = path.join(process.env.HOME ?? "~", ".draht", "agent", "agents");
|
|
318
|
-
const agentDest = path.join(targetDir, "agents");
|
|
319
|
-
const extDest = path.join(targetDir, "extensions");
|
|
320
|
-
fs.mkdirSync(agentDest, { recursive: true });
|
|
321
|
-
fs.mkdirSync(extDest, { recursive: true });
|
|
322
|
-
|
|
323
|
-
let copied = 0;
|
|
324
|
-
if (fs.existsSync(agentSrc)) {
|
|
325
|
-
for (const file of fs.readdirSync(agentSrc)) {
|
|
326
|
-
if (!file.endsWith(".md")) continue;
|
|
327
|
-
fs.copyFileSync(path.join(agentSrc, file), path.join(agentDest, file));
|
|
328
|
-
copied++;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
ctx.ui.notify(
|
|
333
|
-
`.draht/ scaffolded with ${copied} agents. Customize .draht/agents/*.md for this project's stack.`,
|
|
334
|
-
"info",
|
|
335
|
-
);
|
|
336
|
-
},
|
|
337
|
-
});
|
|
338
|
-
}
|