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,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Git extension: initialize-repo.sh
|
|
3
|
+
# Initialize a Git repository with an initial commit.
|
|
4
|
+
# Customizable — replace this script to add .gitignore templates,
|
|
5
|
+
# default branch config, git-flow, LFS, signing, etc.
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
+
|
|
11
|
+
# Find project root
|
|
12
|
+
_find_project_root() {
|
|
13
|
+
local dir="$1"
|
|
14
|
+
while [ "$dir" != "/" ]; do
|
|
15
|
+
if [ -d "$dir/.duaer" ] || [ -d "$dir/.git" ]; then
|
|
16
|
+
echo "$dir"
|
|
17
|
+
return 0
|
|
18
|
+
fi
|
|
19
|
+
dir="$(dirname "$dir")"
|
|
20
|
+
done
|
|
21
|
+
return 1
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
REPO_ROOT=$(_find_project_root "$SCRIPT_DIR") || REPO_ROOT="$(pwd)"
|
|
25
|
+
cd "$REPO_ROOT"
|
|
26
|
+
|
|
27
|
+
# Read commit message from extension config, fall back to default
|
|
28
|
+
COMMIT_MSG="[Duaer] Initial commit"
|
|
29
|
+
_config_file="$REPO_ROOT/.duaer/extensions/git/git-config.yml"
|
|
30
|
+
if [ -f "$_config_file" ]; then
|
|
31
|
+
_msg=$(grep '^init_commit_message:' "$_config_file" 2>/dev/null | sed 's/^init_commit_message:[[:space:]]*//' | sed 's/^["'\'']//' | sed 's/["'\'']*$//')
|
|
32
|
+
if [ -n "$_msg" ]; then
|
|
33
|
+
COMMIT_MSG="$_msg"
|
|
34
|
+
fi
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Check if git is available
|
|
38
|
+
if ! command -v git >/dev/null 2>&1; then
|
|
39
|
+
echo "[specify] Warning: Git not found; skipped repository initialization" >&2
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Check if already a git repo
|
|
44
|
+
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
45
|
+
echo "[specify] Git repository already initialized; skipping" >&2
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Initialize
|
|
50
|
+
_git_out=$(git init -q 2>&1) || { echo "[specify] Error: git init failed: $_git_out" >&2; exit 1; }
|
|
51
|
+
_git_out=$(git add . 2>&1) || { echo "[specify] Error: git add failed: $_git_out" >&2; exit 1; }
|
|
52
|
+
_git_out=$(git commit --allow-empty -q -m "$COMMIT_MSG" 2>&1) || { echo "[specify] Error: git commit failed: $_git_out" >&2; exit 1; }
|
|
53
|
+
|
|
54
|
+
echo "[OK] Git repository initialized" >&2
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
# Git extension: auto-commit.ps1
|
|
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.ps1 <event_name> [generated_message]
|
|
7
|
+
# auto-commit.ps1 <event_name> -MessageFile <path>
|
|
8
|
+
# e.g.: auto-commit.ps1 after_specify
|
|
9
|
+
# e.g.: auto-commit.ps1 after_specify -MessageFile C:\temp\commit-msg.txt (commit_style: conventional)
|
|
10
|
+
#
|
|
11
|
+
# -MessageFile 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
|
+
param(
|
|
16
|
+
[Parameter(Position = 0, Mandatory = $true)]
|
|
17
|
+
[string]$EventName,
|
|
18
|
+
|
|
19
|
+
# Optional agent-generated commit message (used when commit_style: conventional is configured).
|
|
20
|
+
# Prefer -MessageFile over passing the message directly as a shell argument.
|
|
21
|
+
[Parameter(Position = 1, Mandatory = $false)]
|
|
22
|
+
[string]$GeneratedMessage = "",
|
|
23
|
+
|
|
24
|
+
[Parameter(Mandatory = $false)]
|
|
25
|
+
[string]$MessageFile = ""
|
|
26
|
+
)
|
|
27
|
+
$ErrorActionPreference = 'Stop'
|
|
28
|
+
|
|
29
|
+
if ($MessageFile) {
|
|
30
|
+
if (-not (Test-Path $MessageFile -PathType Leaf)) {
|
|
31
|
+
Write-Warning "[specify] Error: message file '$MessageFile' not found"
|
|
32
|
+
exit 1
|
|
33
|
+
}
|
|
34
|
+
$GeneratedMessage = (Get-Content -Path $MessageFile -Raw)
|
|
35
|
+
if ($null -ne $GeneratedMessage) {
|
|
36
|
+
$GeneratedMessage = $GeneratedMessage.TrimEnd("`r", "`n")
|
|
37
|
+
}
|
|
38
|
+
# The message file is a transport-only artifact: its content is now
|
|
39
|
+
# captured above, so remove it immediately. Otherwise, if it was written
|
|
40
|
+
# inside the worktree, it would be picked up as an untracked change by
|
|
41
|
+
# both the "any changes?" check below and by `git add .`, polluting the
|
|
42
|
+
# commit or defeating the no-changes short-circuit even when nothing
|
|
43
|
+
# else changed.
|
|
44
|
+
Remove-Item -Path $MessageFile -Force -ErrorAction SilentlyContinue
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function Find-ProjectRoot {
|
|
48
|
+
param([string]$StartDir)
|
|
49
|
+
$current = Resolve-Path $StartDir
|
|
50
|
+
while ($true) {
|
|
51
|
+
foreach ($marker in @('.duaer', '.git')) {
|
|
52
|
+
if (Test-Path (Join-Path $current $marker)) {
|
|
53
|
+
return $current
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
$parent = Split-Path $current -Parent
|
|
57
|
+
if ($parent -eq $current) { return $null }
|
|
58
|
+
$current = $parent
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
$repoRoot = Find-ProjectRoot -StartDir $PSScriptRoot
|
|
63
|
+
if (-not $repoRoot) { $repoRoot = Get-Location }
|
|
64
|
+
Set-Location $repoRoot
|
|
65
|
+
|
|
66
|
+
# Check if git is available
|
|
67
|
+
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
|
68
|
+
Write-Warning "[specify] Warning: Git not found; skipped auto-commit"
|
|
69
|
+
exit 0
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Temporarily relax ErrorActionPreference so git stderr warnings
|
|
73
|
+
# (e.g. CRLF notices on Windows) do not become terminating errors.
|
|
74
|
+
$savedEAP = $ErrorActionPreference
|
|
75
|
+
$ErrorActionPreference = 'Continue'
|
|
76
|
+
try {
|
|
77
|
+
git rev-parse --is-inside-work-tree 2>$null | Out-Null
|
|
78
|
+
$isRepo = $LASTEXITCODE -eq 0
|
|
79
|
+
} finally {
|
|
80
|
+
$ErrorActionPreference = $savedEAP
|
|
81
|
+
}
|
|
82
|
+
if (-not $isRepo) {
|
|
83
|
+
Write-Warning "[specify] Warning: Not a Git repository; skipped auto-commit"
|
|
84
|
+
exit 0
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Read per-command config from git-config.yml
|
|
88
|
+
$configFile = Join-Path $repoRoot ".duaer/extensions/git/git-config.yml"
|
|
89
|
+
$enabled = $false
|
|
90
|
+
$commitMsg = ""
|
|
91
|
+
$commitStyle = "fixed"
|
|
92
|
+
|
|
93
|
+
if (Test-Path $configFile) {
|
|
94
|
+
# Top-level scalar key: commit_style (fixed | conventional)
|
|
95
|
+
foreach ($line in Get-Content $configFile) {
|
|
96
|
+
if ($line -match '^commit_style:\s*(.+)$') {
|
|
97
|
+
$styleVal = (($matches[1] -replace '\s+#.*$', '').Trim()) -replace '^["'']' -replace '["'']$'
|
|
98
|
+
if ($styleVal) {
|
|
99
|
+
$styleVal = $styleVal.ToLower()
|
|
100
|
+
if ($styleVal -eq 'fixed' -or $styleVal -eq 'conventional') {
|
|
101
|
+
$commitStyle = $styleVal
|
|
102
|
+
} else {
|
|
103
|
+
Write-Warning "[specify] Warning: unknown commit_style '$styleVal' in git-config.yml (expected 'fixed' or 'conventional'); defaulting to 'fixed'"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
break
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# Parse YAML to find auto_commit section
|
|
111
|
+
$inAutoCommit = $false
|
|
112
|
+
$inEvent = $false
|
|
113
|
+
$defaultEnabled = $false
|
|
114
|
+
|
|
115
|
+
foreach ($line in Get-Content $configFile) {
|
|
116
|
+
# Detect auto_commit: section
|
|
117
|
+
if ($line -match '^auto_commit:') {
|
|
118
|
+
$inAutoCommit = $true
|
|
119
|
+
$inEvent = $false
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Exit auto_commit section on next top-level key
|
|
124
|
+
if ($inAutoCommit -and $line -match '^[a-z]') {
|
|
125
|
+
break
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if ($inAutoCommit) {
|
|
129
|
+
# Check default key
|
|
130
|
+
if ($line -match '^\s+default:\s*(.+)$') {
|
|
131
|
+
$val = $matches[1].Trim().ToLower()
|
|
132
|
+
if ($val -eq 'true') { $defaultEnabled = $true }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Detect our event subsection
|
|
136
|
+
if ($line -match "^\s+${EventName}:") {
|
|
137
|
+
$inEvent = $true
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Inside our event subsection
|
|
142
|
+
if ($inEvent) {
|
|
143
|
+
# Exit on next sibling key (2-space indent, not 4+)
|
|
144
|
+
if ($line -match '^\s{2}[a-z]' -and $line -notmatch '^\s{4}') {
|
|
145
|
+
$inEvent = $false
|
|
146
|
+
continue
|
|
147
|
+
}
|
|
148
|
+
if ($line -match '\s+enabled:\s*(.+)$') {
|
|
149
|
+
$val = $matches[1].Trim().ToLower()
|
|
150
|
+
if ($val -eq 'true') { $enabled = $true }
|
|
151
|
+
if ($val -eq 'false') { $enabled = $false }
|
|
152
|
+
}
|
|
153
|
+
if ($line -match '\s+message:\s*(.+)$') {
|
|
154
|
+
$commitMsg = $matches[1].Trim() -replace '^["'']' -replace '["'']$'
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# If event-specific key not found, use default
|
|
161
|
+
if (-not $enabled -and $defaultEnabled) {
|
|
162
|
+
$hasEventKey = Select-String -Path $configFile -Pattern "^\s*${EventName}:" -Quiet
|
|
163
|
+
if (-not $hasEventKey) {
|
|
164
|
+
$enabled = $true
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
# No config file -- auto-commit disabled by default
|
|
169
|
+
exit 0
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (-not $enabled) {
|
|
173
|
+
exit 0
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
# Check if there are changes to commit
|
|
177
|
+
# Relax ErrorActionPreference so CRLF warnings on stderr do not terminate.
|
|
178
|
+
$savedEAP = $ErrorActionPreference
|
|
179
|
+
$ErrorActionPreference = 'Continue'
|
|
180
|
+
try {
|
|
181
|
+
git diff --quiet HEAD 2>$null; $d1 = $LASTEXITCODE
|
|
182
|
+
git diff --cached --quiet 2>$null; $d2 = $LASTEXITCODE
|
|
183
|
+
$untracked = git ls-files --others --exclude-standard 2>$null
|
|
184
|
+
} finally {
|
|
185
|
+
$ErrorActionPreference = $savedEAP
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if ($d1 -eq 0 -and $d2 -eq 0 -and -not $untracked) {
|
|
189
|
+
Write-Host "[specify] No changes to commit after $EventName" -ForegroundColor DarkGray
|
|
190
|
+
exit 0
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# In conventional mode, the commit message must be supplied by the agent
|
|
194
|
+
# (via the GeneratedMessage argument); never fall back to the fixed message.
|
|
195
|
+
if ($commitStyle -eq 'conventional') {
|
|
196
|
+
if ($GeneratedMessage) {
|
|
197
|
+
$commitMsg = $GeneratedMessage
|
|
198
|
+
} else {
|
|
199
|
+
Write-Warning "[specify] Error: commit_style is 'conventional' but no generated commit message was supplied; aborting auto-commit (pass -MessageFile <path>, or a raw message as arg 2, or set commit_style: fixed)"
|
|
200
|
+
exit 1
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
# Derive a human-readable command name from the event
|
|
205
|
+
$commandName = $EventName -replace '^after_', '' -replace '^before_', ''
|
|
206
|
+
$phase = if ($EventName -match '^before_') { 'before' } else { 'after' }
|
|
207
|
+
|
|
208
|
+
# Use custom message if configured, otherwise default
|
|
209
|
+
if (-not $commitMsg) {
|
|
210
|
+
$commitMsg = "[Duaer] Auto-commit $phase $commandName"
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# Stage and commit
|
|
214
|
+
# Relax ErrorActionPreference so CRLF warnings on stderr do not terminate,
|
|
215
|
+
# while still allowing redirected error output to be captured for diagnostics.
|
|
216
|
+
$savedEAP = $ErrorActionPreference
|
|
217
|
+
$ErrorActionPreference = 'Continue'
|
|
218
|
+
try {
|
|
219
|
+
$out = git add . 2>&1 | Out-String
|
|
220
|
+
if ($LASTEXITCODE -ne 0) { throw "git add failed: $out" }
|
|
221
|
+
$out = git commit -q -m $commitMsg 2>&1 | Out-String
|
|
222
|
+
if ($LASTEXITCODE -ne 0) { throw "git commit failed: $out" }
|
|
223
|
+
} catch {
|
|
224
|
+
Write-Warning "[specify] Error: $_"
|
|
225
|
+
exit 1
|
|
226
|
+
} finally {
|
|
227
|
+
$ErrorActionPreference = $savedEAP
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
Write-Host "[OK] Changes committed $phase $commandName"
|