duaer-spec 0.1.0
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/.cursor/rules/agents-workflow.mdc +50 -0
- package/.cursor/rules/ai-ui-copy.mdc +12 -0
- package/.cursor/rules/duaer-spec.mdc +33 -0
- package/.cursor/skills/duaer-analyze/SKILL.md +259 -0
- package/.cursor/skills/duaer-checklist/SKILL.md +383 -0
- package/.cursor/skills/duaer-clarify/SKILL.md +291 -0
- package/.cursor/skills/duaer-constitution/SKILL.md +177 -0
- package/.cursor/skills/duaer-converge/SKILL.md +277 -0
- package/.cursor/skills/duaer-git-commit/SKILL.md +68 -0
- package/.cursor/skills/duaer-git-feature/SKILL.md +94 -0
- package/.cursor/skills/duaer-git-initialize/SKILL.md +54 -0
- package/.cursor/skills/duaer-git-remote/SKILL.md +50 -0
- package/.cursor/skills/duaer-git-validate/SKILL.md +54 -0
- package/.cursor/skills/duaer-implement/SKILL.md +226 -0
- package/.cursor/skills/duaer-plan/SKILL.md +166 -0
- package/.cursor/skills/duaer-specify/SKILL.md +345 -0
- package/.cursor/skills/duaer-tasks/SKILL.md +214 -0
- package/.cursor/skills/duaer-taskstoissues/SKILL.md +109 -0
- package/.duaer/extensions/.registry +23 -0
- package/.duaer/extensions/git/README.md +119 -0
- package/.duaer/extensions/git/commands/duaer.git.commit.md +63 -0
- package/.duaer/extensions/git/commands/duaer.git.feature.md +82 -0
- package/.duaer/extensions/git/commands/duaer.git.initialize.md +49 -0
- package/.duaer/extensions/git/commands/duaer.git.remote.md +45 -0
- package/.duaer/extensions/git/commands/duaer.git.validate.md +49 -0
- package/.duaer/extensions/git/config-template.yml +79 -0
- package/.duaer/extensions/git/extension.yml +142 -0
- package/.duaer/extensions/git/git-config.yml +79 -0
- package/.duaer/extensions/git/scripts/bash/auto-commit.sh +211 -0
- package/.duaer/extensions/git/scripts/bash/create-new-feature-branch.sh +626 -0
- package/.duaer/extensions/git/scripts/bash/git-common.sh +56 -0
- package/.duaer/extensions/git/scripts/bash/initialize-repo.sh +54 -0
- package/.duaer/extensions/git/scripts/powershell/auto-commit.ps1 +230 -0
- package/.duaer/extensions/git/scripts/powershell/create-new-feature-branch.ps1 +592 -0
- package/.duaer/extensions/git/scripts/powershell/git-common.ps1 +52 -0
- package/.duaer/extensions/git/scripts/powershell/initialize-repo.ps1 +69 -0
- package/.duaer/extensions/git/scripts/python/auto_commit.py +195 -0
- package/.duaer/extensions/git/scripts/python/create_new_feature_branch.py +634 -0
- package/.duaer/extensions/git/scripts/python/git_common.py +81 -0
- package/.duaer/extensions/git/scripts/python/initialize_repo.py +89 -0
- package/.duaer/extensions.yml +167 -0
- package/.duaer/init-options.json +9 -0
- package/.duaer/integration.json +15 -0
- package/.duaer/integrations/cursor-agent.manifest.json +17 -0
- package/.duaer/integrations/duaer.manifest.json +19 -0
- package/.duaer/memory/.constitution-template.json +4 -0
- package/.duaer/memory/constitution.md +37 -0
- package/.duaer/memory/project-context.md +24 -0
- package/.duaer/memory/testing.md +14 -0
- package/.duaer/scripts/bash/check-prerequisites.sh +243 -0
- package/.duaer/scripts/bash/common.sh +926 -0
- package/.duaer/scripts/bash/create-new-feature.sh +407 -0
- package/.duaer/scripts/bash/resolve-template.sh +57 -0
- package/.duaer/scripts/bash/setup-plan.sh +85 -0
- package/.duaer/scripts/bash/setup-tasks.sh +94 -0
- package/.duaer/templates/checklist-template.md +45 -0
- package/.duaer/templates/constitution-template.md +50 -0
- package/.duaer/templates/plan-template.md +113 -0
- package/.duaer/templates/spec-template.md +131 -0
- package/.duaer/templates/tasks-template.md +252 -0
- package/.duaer/workflows/duaer/workflow.yml +78 -0
- package/.duaer/workflows/workflow-registry.json +13 -0
- package/ADOPT.md +75 -0
- package/AGENTS.md +290 -0
- package/CHANGELOG.md +28 -0
- package/DUADER.md +57 -0
- package/LICENSE +21 -0
- package/README.md +74 -0
- package/bin/duaer.mjs +298 -0
- package/docs/agent/README.md +12 -0
- package/docs/agent/change-checklist.md +130 -0
- package/docs/agent/e2e-test-plan.md +33 -0
- package/docs/agent/workflow.md +127 -0
- package/docs/baseline.md +10 -0
- package/package.json +49 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Git Branching Workflow Extension Configuration
|
|
2
|
+
# Copied to .duaer/extensions/git/git-config.yml on install
|
|
3
|
+
|
|
4
|
+
# Branch numbering strategy: "sequential" (001, 002, ...) or "timestamp" (YYYYMMDD-HHMMSS)
|
|
5
|
+
branch_numbering: sequential
|
|
6
|
+
|
|
7
|
+
# Optional branch name template. Leave empty for the default "{number}-{slug}".
|
|
8
|
+
# Supported tokens: {author}, {app}, {number}, {slug}
|
|
9
|
+
# {slug} must not appear before {number}; final path segment must start with {number}-.
|
|
10
|
+
# Example for monorepos: "{author}/{app}/{number}-{slug}"
|
|
11
|
+
branch_template: ""
|
|
12
|
+
|
|
13
|
+
# Optional shorthand namespace. Leave empty to use branch_template/default behavior.
|
|
14
|
+
# Example: "features/{app}" expands to "features/{app}/{number}-{slug}"
|
|
15
|
+
branch_prefix: "feat"
|
|
16
|
+
|
|
17
|
+
# Commit message used by `git commit` during repository initialization
|
|
18
|
+
init_commit_message: "[Duaer] Initial commit"
|
|
19
|
+
|
|
20
|
+
# Commit message style used by auto-commit hooks (duaer.git.commit):
|
|
21
|
+
# "fixed" - default; use the configured/static messages below.
|
|
22
|
+
# "conventional" - ask the agent to inspect the diff and generate a
|
|
23
|
+
# Conventional Commit message (e.g. "feat: add OAuth spec")
|
|
24
|
+
# instead of using the messages configured below.
|
|
25
|
+
commit_style: fixed
|
|
26
|
+
|
|
27
|
+
# Auto-commit before/after core commands.
|
|
28
|
+
# Set "default" to enable for all commands, then override per-command.
|
|
29
|
+
# Each key can be true/false. Message is customizable per-command.
|
|
30
|
+
auto_commit:
|
|
31
|
+
default: false
|
|
32
|
+
before_clarify:
|
|
33
|
+
enabled: false
|
|
34
|
+
message: "[Duaer] Save progress before clarification"
|
|
35
|
+
before_plan:
|
|
36
|
+
enabled: false
|
|
37
|
+
message: "[Duaer] Save progress before planning"
|
|
38
|
+
before_tasks:
|
|
39
|
+
enabled: false
|
|
40
|
+
message: "[Duaer] Save progress before task generation"
|
|
41
|
+
before_implement:
|
|
42
|
+
enabled: false
|
|
43
|
+
message: "[Duaer] Save progress before implementation"
|
|
44
|
+
before_checklist:
|
|
45
|
+
enabled: false
|
|
46
|
+
message: "[Duaer] Save progress before checklist"
|
|
47
|
+
before_analyze:
|
|
48
|
+
enabled: false
|
|
49
|
+
message: "[Duaer] Save progress before analysis"
|
|
50
|
+
before_taskstoissues:
|
|
51
|
+
enabled: false
|
|
52
|
+
message: "[Duaer] Save progress before issue sync"
|
|
53
|
+
after_constitution:
|
|
54
|
+
enabled: false
|
|
55
|
+
message: "[Duaer] Add project constitution"
|
|
56
|
+
after_specify:
|
|
57
|
+
enabled: false
|
|
58
|
+
message: "[Duaer] Add specification"
|
|
59
|
+
after_clarify:
|
|
60
|
+
enabled: false
|
|
61
|
+
message: "[Duaer] Clarify specification"
|
|
62
|
+
after_plan:
|
|
63
|
+
enabled: false
|
|
64
|
+
message: "[Duaer] Add implementation plan"
|
|
65
|
+
after_tasks:
|
|
66
|
+
enabled: false
|
|
67
|
+
message: "[Duaer] Add tasks"
|
|
68
|
+
after_implement:
|
|
69
|
+
enabled: false
|
|
70
|
+
message: "[Duaer] Implementation progress"
|
|
71
|
+
after_checklist:
|
|
72
|
+
enabled: false
|
|
73
|
+
message: "[Duaer] Add checklist"
|
|
74
|
+
after_analyze:
|
|
75
|
+
enabled: false
|
|
76
|
+
message: "[Duaer] Add analysis report"
|
|
77
|
+
after_taskstoissues:
|
|
78
|
+
enabled: false
|
|
79
|
+
message: "[Duaer] Sync tasks to issues"
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Git extension: auto-commit.sh
|
|
3
|
+
# Automatically commit changes after a Duaer command completes.
|
|
4
|
+
# Checks per-command config keys in git-config.yml before committing.
|
|
5
|
+
#
|
|
6
|
+
# Usage: auto-commit.sh <event_name> [generated_message]
|
|
7
|
+
# auto-commit.sh <event_name> --message-file <path>
|
|
8
|
+
# e.g.: auto-commit.sh after_specify
|
|
9
|
+
# e.g.: auto-commit.sh after_specify --message-file /tmp/commit-msg.txt (commit_style: conventional)
|
|
10
|
+
#
|
|
11
|
+
# --message-file is the preferred way to supply an agent-generated commit
|
|
12
|
+
# message: it reads the message from a file instead of a shell argument,
|
|
13
|
+
# so message content (which may contain quotes, `$(...)`, backticks, etc.)
|
|
14
|
+
# is never interpolated into a shell command line.
|
|
15
|
+
|
|
16
|
+
set -e
|
|
17
|
+
|
|
18
|
+
EVENT_NAME="${1:-}"
|
|
19
|
+
if [ -z "$EVENT_NAME" ]; then
|
|
20
|
+
echo "Usage: $0 <event_name> [generated_message | --message-file <path>]" >&2
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
23
|
+
shift || true
|
|
24
|
+
|
|
25
|
+
# Optional second argument: an agent-generated commit message (used when
|
|
26
|
+
# commit_style: conventional is configured). Prefer --message-file over
|
|
27
|
+
# passing the message directly as a shell argument.
|
|
28
|
+
GENERATED_MESSAGE=""
|
|
29
|
+
while [ $# -gt 0 ]; do
|
|
30
|
+
case "$1" in
|
|
31
|
+
--message-file)
|
|
32
|
+
_message_file="${2:-}"
|
|
33
|
+
if [ -z "$_message_file" ]; then
|
|
34
|
+
echo "[specify] Error: --message-file requires a path argument" >&2
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
if [ ! -f "$_message_file" ]; then
|
|
38
|
+
echo "[specify] Error: message file '$_message_file' not found" >&2
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
GENERATED_MESSAGE="$(cat "$_message_file")"
|
|
42
|
+
# The message file is a transport-only artifact: its content is
|
|
43
|
+
# now captured above, so remove it immediately. Otherwise, if it
|
|
44
|
+
# was written inside the worktree, it would be picked up as an
|
|
45
|
+
# untracked change by both the "any changes?" check below and by
|
|
46
|
+
# `git add .`, polluting the commit or defeating the no-changes
|
|
47
|
+
# short-circuit even when nothing else changed.
|
|
48
|
+
rm -f "$_message_file"
|
|
49
|
+
shift 2
|
|
50
|
+
;;
|
|
51
|
+
*)
|
|
52
|
+
GENERATED_MESSAGE="$1"
|
|
53
|
+
shift
|
|
54
|
+
;;
|
|
55
|
+
esac
|
|
56
|
+
done
|
|
57
|
+
|
|
58
|
+
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
59
|
+
|
|
60
|
+
_find_project_root() {
|
|
61
|
+
local dir="$1"
|
|
62
|
+
while [ "$dir" != "/" ]; do
|
|
63
|
+
if [ -d "$dir/.duaer" ] || [ -d "$dir/.git" ]; then
|
|
64
|
+
echo "$dir"
|
|
65
|
+
return 0
|
|
66
|
+
fi
|
|
67
|
+
dir="$(dirname "$dir")"
|
|
68
|
+
done
|
|
69
|
+
return 1
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
REPO_ROOT=$(_find_project_root "$SCRIPT_DIR") || REPO_ROOT="$(pwd)"
|
|
73
|
+
cd "$REPO_ROOT"
|
|
74
|
+
|
|
75
|
+
# Check if git is available
|
|
76
|
+
if ! command -v git >/dev/null 2>&1; then
|
|
77
|
+
echo "[specify] Warning: Git not found; skipped auto-commit" >&2
|
|
78
|
+
exit 0
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
82
|
+
echo "[specify] Warning: Not a Git repository; skipped auto-commit" >&2
|
|
83
|
+
exit 0
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Read per-command config from git-config.yml
|
|
87
|
+
_config_file="$REPO_ROOT/.duaer/extensions/git/git-config.yml"
|
|
88
|
+
_enabled=false
|
|
89
|
+
_commit_msg=""
|
|
90
|
+
_commit_style="fixed"
|
|
91
|
+
|
|
92
|
+
if [ -f "$_config_file" ]; then
|
|
93
|
+
# Top-level scalar key: commit_style (fixed | conventional)
|
|
94
|
+
_style_val=$(grep -m1 '^commit_style:' "$_config_file" 2>/dev/null | sed 's/^commit_style:[[:space:]]*//' | sed 's/[[:space:]]\{1,\}#.*$//' | sed 's/[[:space:]]*$//' | sed 's/^["'\'']//' | sed 's/["'\'']*$//' | tr '[:upper:]' '[:lower:]')
|
|
95
|
+
if [ -n "$_style_val" ]; then
|
|
96
|
+
case "$_style_val" in
|
|
97
|
+
fixed|conventional)
|
|
98
|
+
_commit_style="$_style_val"
|
|
99
|
+
;;
|
|
100
|
+
*)
|
|
101
|
+
echo "[specify] Warning: unknown commit_style '$_style_val' in git-config.yml (expected 'fixed' or 'conventional'); defaulting to 'fixed'" >&2
|
|
102
|
+
;;
|
|
103
|
+
esac
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# Parse the auto_commit section for this event.
|
|
107
|
+
# Look for auto_commit.<event_name>.enabled and .message
|
|
108
|
+
# Also check auto_commit.default as fallback.
|
|
109
|
+
_in_auto_commit=false
|
|
110
|
+
_in_event=false
|
|
111
|
+
_default_enabled=false
|
|
112
|
+
|
|
113
|
+
while IFS= read -r _line; do
|
|
114
|
+
# Detect auto_commit: section
|
|
115
|
+
if echo "$_line" | grep -q '^auto_commit:'; then
|
|
116
|
+
_in_auto_commit=true
|
|
117
|
+
_in_event=false
|
|
118
|
+
continue
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# Exit auto_commit section on next top-level key
|
|
122
|
+
if $_in_auto_commit && echo "$_line" | grep -Eq '^[a-z]'; then
|
|
123
|
+
break
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
if $_in_auto_commit; then
|
|
127
|
+
# Check default key
|
|
128
|
+
if echo "$_line" | grep -Eq "^[[:space:]]+default:[[:space:]]"; then
|
|
129
|
+
_val=$(echo "$_line" | sed 's/^[^:]*:[[:space:]]*//' | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
|
|
130
|
+
[ "$_val" = "true" ] && _default_enabled=true
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# Detect our event subsection
|
|
134
|
+
if echo "$_line" | grep -Eq "^[[:space:]]+${EVENT_NAME}:"; then
|
|
135
|
+
_in_event=true
|
|
136
|
+
continue
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# Inside our event subsection
|
|
140
|
+
if $_in_event; then
|
|
141
|
+
# Exit on next sibling key (same indent level as event name)
|
|
142
|
+
if echo "$_line" | grep -Eq '^[[:space:]]{2}[a-z]' && ! echo "$_line" | grep -Eq '^[[:space:]]{4}'; then
|
|
143
|
+
_in_event=false
|
|
144
|
+
continue
|
|
145
|
+
fi
|
|
146
|
+
if echo "$_line" | grep -Eq '[[:space:]]+enabled:'; then
|
|
147
|
+
_val=$(echo "$_line" | sed 's/^[^:]*:[[:space:]]*//' | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
|
|
148
|
+
[ "$_val" = "true" ] && _enabled=true
|
|
149
|
+
[ "$_val" = "false" ] && _enabled=false
|
|
150
|
+
fi
|
|
151
|
+
if echo "$_line" | grep -Eq '[[:space:]]+message:'; then
|
|
152
|
+
# Trim trailing whitespace before stripping the closing quote:
|
|
153
|
+
# a value like `message: "Done" ` (trailing spaces after the
|
|
154
|
+
# quote) would otherwise leave the quote dangling (`Done" `),
|
|
155
|
+
# since the closing-quote strip is anchored to end-of-string.
|
|
156
|
+
# The PowerShell twin .Trim()s first; match it for parity.
|
|
157
|
+
_commit_msg=$(echo "$_line" | sed 's/^[^:]*:[[:space:]]*//' | sed 's/[[:space:]]*$//' | sed 's/^["'\'']//' | sed 's/["'\'']*$//')
|
|
158
|
+
fi
|
|
159
|
+
fi
|
|
160
|
+
fi
|
|
161
|
+
done < "$_config_file"
|
|
162
|
+
|
|
163
|
+
# If event-specific key not found, use default
|
|
164
|
+
if [ "$_enabled" = "false" ] && [ "$_default_enabled" = "true" ]; then
|
|
165
|
+
# Only use default if the event wasn't explicitly set to false
|
|
166
|
+
# Check if event section existed at all
|
|
167
|
+
if ! grep -q "^[[:space:]]*${EVENT_NAME}:" "$_config_file" 2>/dev/null; then
|
|
168
|
+
_enabled=true
|
|
169
|
+
fi
|
|
170
|
+
fi
|
|
171
|
+
else
|
|
172
|
+
# No config file — auto-commit disabled by default
|
|
173
|
+
exit 0
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
if [ "$_enabled" != "true" ]; then
|
|
177
|
+
exit 0
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
# Check if there are changes to commit
|
|
181
|
+
if git diff --quiet HEAD 2>/dev/null && git diff --cached --quiet 2>/dev/null && [ -z "$(git ls-files --others --exclude-standard 2>/dev/null)" ]; then
|
|
182
|
+
echo "[specify] No changes to commit after $EVENT_NAME" >&2
|
|
183
|
+
exit 0
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# In conventional mode, the commit message must be supplied by the agent
|
|
187
|
+
# (via the generated_message argument); never fall back to the fixed message.
|
|
188
|
+
if [ "$_commit_style" = "conventional" ]; then
|
|
189
|
+
if [ -n "$GENERATED_MESSAGE" ]; then
|
|
190
|
+
_commit_msg="$GENERATED_MESSAGE"
|
|
191
|
+
else
|
|
192
|
+
echo "[specify] Error: commit_style is 'conventional' but no generated commit message was supplied; aborting auto-commit (pass --message-file <path>, or a raw message as arg 2, or set commit_style: fixed)" >&2
|
|
193
|
+
exit 1
|
|
194
|
+
fi
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
# Derive a human-readable command name from the event
|
|
198
|
+
# e.g., after_specify -> specify, before_plan -> plan
|
|
199
|
+
_command_name=$(echo "$EVENT_NAME" | sed 's/^after_//' | sed 's/^before_//')
|
|
200
|
+
_phase=$(echo "$EVENT_NAME" | grep -q '^before_' && echo 'before' || echo 'after')
|
|
201
|
+
|
|
202
|
+
# Use custom message if configured, otherwise default
|
|
203
|
+
if [ -z "$_commit_msg" ]; then
|
|
204
|
+
_commit_msg="[Duaer] Auto-commit ${_phase} ${_command_name}"
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
# Stage and commit
|
|
208
|
+
_git_out=$(git add . 2>&1) || { echo "[specify] Error: git add failed: $_git_out" >&2; exit 1; }
|
|
209
|
+
_git_out=$(git commit -q -m "$_commit_msg" 2>&1) || { echo "[specify] Error: git commit failed: $_git_out" >&2; exit 1; }
|
|
210
|
+
|
|
211
|
+
echo "[OK] Changes committed ${_phase} ${_command_name}" >&2
|