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.
Files changed (75) hide show
  1. package/.cursor/rules/agents-workflow.mdc +50 -0
  2. package/.cursor/rules/ai-ui-copy.mdc +12 -0
  3. package/.cursor/rules/duaer-spec.mdc +33 -0
  4. package/.cursor/skills/duaer-analyze/SKILL.md +259 -0
  5. package/.cursor/skills/duaer-checklist/SKILL.md +383 -0
  6. package/.cursor/skills/duaer-clarify/SKILL.md +291 -0
  7. package/.cursor/skills/duaer-constitution/SKILL.md +177 -0
  8. package/.cursor/skills/duaer-converge/SKILL.md +277 -0
  9. package/.cursor/skills/duaer-git-commit/SKILL.md +68 -0
  10. package/.cursor/skills/duaer-git-feature/SKILL.md +94 -0
  11. package/.cursor/skills/duaer-git-initialize/SKILL.md +54 -0
  12. package/.cursor/skills/duaer-git-remote/SKILL.md +50 -0
  13. package/.cursor/skills/duaer-git-validate/SKILL.md +54 -0
  14. package/.cursor/skills/duaer-implement/SKILL.md +226 -0
  15. package/.cursor/skills/duaer-plan/SKILL.md +166 -0
  16. package/.cursor/skills/duaer-specify/SKILL.md +345 -0
  17. package/.cursor/skills/duaer-tasks/SKILL.md +214 -0
  18. package/.cursor/skills/duaer-taskstoissues/SKILL.md +109 -0
  19. package/.duaer/extensions/.registry +23 -0
  20. package/.duaer/extensions/git/README.md +119 -0
  21. package/.duaer/extensions/git/commands/duaer.git.commit.md +63 -0
  22. package/.duaer/extensions/git/commands/duaer.git.feature.md +82 -0
  23. package/.duaer/extensions/git/commands/duaer.git.initialize.md +49 -0
  24. package/.duaer/extensions/git/commands/duaer.git.remote.md +45 -0
  25. package/.duaer/extensions/git/commands/duaer.git.validate.md +49 -0
  26. package/.duaer/extensions/git/config-template.yml +79 -0
  27. package/.duaer/extensions/git/extension.yml +142 -0
  28. package/.duaer/extensions/git/git-config.yml +79 -0
  29. package/.duaer/extensions/git/scripts/bash/auto-commit.sh +211 -0
  30. package/.duaer/extensions/git/scripts/bash/create-new-feature-branch.sh +626 -0
  31. package/.duaer/extensions/git/scripts/bash/git-common.sh +56 -0
  32. package/.duaer/extensions/git/scripts/bash/initialize-repo.sh +54 -0
  33. package/.duaer/extensions/git/scripts/powershell/auto-commit.ps1 +230 -0
  34. package/.duaer/extensions/git/scripts/powershell/create-new-feature-branch.ps1 +592 -0
  35. package/.duaer/extensions/git/scripts/powershell/git-common.ps1 +52 -0
  36. package/.duaer/extensions/git/scripts/powershell/initialize-repo.ps1 +69 -0
  37. package/.duaer/extensions/git/scripts/python/auto_commit.py +195 -0
  38. package/.duaer/extensions/git/scripts/python/create_new_feature_branch.py +634 -0
  39. package/.duaer/extensions/git/scripts/python/git_common.py +81 -0
  40. package/.duaer/extensions/git/scripts/python/initialize_repo.py +89 -0
  41. package/.duaer/extensions.yml +167 -0
  42. package/.duaer/init-options.json +9 -0
  43. package/.duaer/integration.json +15 -0
  44. package/.duaer/integrations/cursor-agent.manifest.json +17 -0
  45. package/.duaer/integrations/duaer.manifest.json +19 -0
  46. package/.duaer/memory/.constitution-template.json +4 -0
  47. package/.duaer/memory/constitution.md +37 -0
  48. package/.duaer/memory/project-context.md +24 -0
  49. package/.duaer/memory/testing.md +14 -0
  50. package/.duaer/scripts/bash/check-prerequisites.sh +243 -0
  51. package/.duaer/scripts/bash/common.sh +926 -0
  52. package/.duaer/scripts/bash/create-new-feature.sh +407 -0
  53. package/.duaer/scripts/bash/resolve-template.sh +57 -0
  54. package/.duaer/scripts/bash/setup-plan.sh +85 -0
  55. package/.duaer/scripts/bash/setup-tasks.sh +94 -0
  56. package/.duaer/templates/checklist-template.md +45 -0
  57. package/.duaer/templates/constitution-template.md +50 -0
  58. package/.duaer/templates/plan-template.md +113 -0
  59. package/.duaer/templates/spec-template.md +131 -0
  60. package/.duaer/templates/tasks-template.md +252 -0
  61. package/.duaer/workflows/duaer/workflow.yml +78 -0
  62. package/.duaer/workflows/workflow-registry.json +13 -0
  63. package/ADOPT.md +75 -0
  64. package/AGENTS.md +290 -0
  65. package/CHANGELOG.md +28 -0
  66. package/DUADER.md +57 -0
  67. package/LICENSE +21 -0
  68. package/README.md +74 -0
  69. package/bin/duaer.mjs +298 -0
  70. package/docs/agent/README.md +12 -0
  71. package/docs/agent/change-checklist.md +130 -0
  72. package/docs/agent/e2e-test-plan.md +33 -0
  73. package/docs/agent/workflow.md +127 -0
  74. package/docs/baseline.md +10 -0
  75. 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"