doit-toolkit-cli 0.1.9__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.
- doit_cli/__init__.py +1356 -0
- doit_cli/cli/__init__.py +26 -0
- doit_cli/cli/analytics_command.py +616 -0
- doit_cli/cli/context_command.py +213 -0
- doit_cli/cli/diagram_command.py +304 -0
- doit_cli/cli/fixit_command.py +641 -0
- doit_cli/cli/hooks_command.py +211 -0
- doit_cli/cli/init_command.py +613 -0
- doit_cli/cli/memory_command.py +293 -0
- doit_cli/cli/status_command.py +117 -0
- doit_cli/cli/sync_prompts_command.py +248 -0
- doit_cli/cli/validate_command.py +196 -0
- doit_cli/cli/verify_command.py +204 -0
- doit_cli/cli/workflow_mixin.py +224 -0
- doit_cli/cli/xref_command.py +555 -0
- doit_cli/formatters/__init__.py +8 -0
- doit_cli/formatters/base.py +38 -0
- doit_cli/formatters/json_formatter.py +126 -0
- doit_cli/formatters/markdown_formatter.py +97 -0
- doit_cli/formatters/rich_formatter.py +257 -0
- doit_cli/main.py +49 -0
- doit_cli/models/__init__.py +139 -0
- doit_cli/models/agent.py +74 -0
- doit_cli/models/analytics_models.py +384 -0
- doit_cli/models/context_config.py +464 -0
- doit_cli/models/crossref_models.py +182 -0
- doit_cli/models/diagram_models.py +363 -0
- doit_cli/models/fixit_models.py +355 -0
- doit_cli/models/hook_config.py +125 -0
- doit_cli/models/project.py +91 -0
- doit_cli/models/results.py +121 -0
- doit_cli/models/search_models.py +228 -0
- doit_cli/models/status_models.py +195 -0
- doit_cli/models/sync_models.py +146 -0
- doit_cli/models/template.py +77 -0
- doit_cli/models/validation_models.py +175 -0
- doit_cli/models/workflow_models.py +319 -0
- doit_cli/prompts/__init__.py +5 -0
- doit_cli/prompts/fixit_prompts.py +344 -0
- doit_cli/prompts/interactive.py +390 -0
- doit_cli/rules/__init__.py +5 -0
- doit_cli/rules/builtin_rules.py +160 -0
- doit_cli/services/__init__.py +79 -0
- doit_cli/services/agent_detector.py +168 -0
- doit_cli/services/analytics_service.py +218 -0
- doit_cli/services/architecture_generator.py +290 -0
- doit_cli/services/backup_service.py +204 -0
- doit_cli/services/config_loader.py +113 -0
- doit_cli/services/context_loader.py +1121 -0
- doit_cli/services/coverage_calculator.py +142 -0
- doit_cli/services/crossref_service.py +237 -0
- doit_cli/services/cycle_time_calculator.py +134 -0
- doit_cli/services/date_inferrer.py +349 -0
- doit_cli/services/diagram_service.py +337 -0
- doit_cli/services/drift_detector.py +109 -0
- doit_cli/services/entity_parser.py +301 -0
- doit_cli/services/er_diagram_generator.py +197 -0
- doit_cli/services/fixit_service.py +699 -0
- doit_cli/services/github_service.py +192 -0
- doit_cli/services/hook_manager.py +258 -0
- doit_cli/services/hook_validator.py +528 -0
- doit_cli/services/input_validator.py +322 -0
- doit_cli/services/memory_search.py +527 -0
- doit_cli/services/mermaid_validator.py +334 -0
- doit_cli/services/prompt_transformer.py +91 -0
- doit_cli/services/prompt_writer.py +133 -0
- doit_cli/services/query_interpreter.py +428 -0
- doit_cli/services/report_exporter.py +219 -0
- doit_cli/services/report_generator.py +256 -0
- doit_cli/services/requirement_parser.py +112 -0
- doit_cli/services/roadmap_summarizer.py +209 -0
- doit_cli/services/rule_engine.py +443 -0
- doit_cli/services/scaffolder.py +215 -0
- doit_cli/services/score_calculator.py +172 -0
- doit_cli/services/section_parser.py +204 -0
- doit_cli/services/spec_scanner.py +327 -0
- doit_cli/services/state_manager.py +355 -0
- doit_cli/services/status_reporter.py +143 -0
- doit_cli/services/task_parser.py +347 -0
- doit_cli/services/template_manager.py +710 -0
- doit_cli/services/template_reader.py +158 -0
- doit_cli/services/user_journey_generator.py +214 -0
- doit_cli/services/user_story_parser.py +232 -0
- doit_cli/services/validation_service.py +188 -0
- doit_cli/services/validator.py +232 -0
- doit_cli/services/velocity_tracker.py +173 -0
- doit_cli/services/workflow_engine.py +405 -0
- doit_cli/templates/agent-file-template.md +28 -0
- doit_cli/templates/checklist-template.md +39 -0
- doit_cli/templates/commands/doit.checkin.md +363 -0
- doit_cli/templates/commands/doit.constitution.md +187 -0
- doit_cli/templates/commands/doit.documentit.md +485 -0
- doit_cli/templates/commands/doit.fixit.md +181 -0
- doit_cli/templates/commands/doit.implementit.md +265 -0
- doit_cli/templates/commands/doit.planit.md +262 -0
- doit_cli/templates/commands/doit.reviewit.md +355 -0
- doit_cli/templates/commands/doit.roadmapit.md +368 -0
- doit_cli/templates/commands/doit.scaffoldit.md +458 -0
- doit_cli/templates/commands/doit.specit.md +521 -0
- doit_cli/templates/commands/doit.taskit.md +304 -0
- doit_cli/templates/commands/doit.testit.md +277 -0
- doit_cli/templates/config/context.yaml +134 -0
- doit_cli/templates/config/hooks.yaml +93 -0
- doit_cli/templates/config/validation-rules.yaml +64 -0
- doit_cli/templates/github-issue-templates/epic.yml +78 -0
- doit_cli/templates/github-issue-templates/feature.yml +116 -0
- doit_cli/templates/github-issue-templates/task.yml +129 -0
- doit_cli/templates/hooks/.gitkeep +0 -0
- doit_cli/templates/hooks/post-commit.sh +25 -0
- doit_cli/templates/hooks/post-merge.sh +75 -0
- doit_cli/templates/hooks/pre-commit.sh +17 -0
- doit_cli/templates/hooks/pre-push.sh +18 -0
- doit_cli/templates/memory/completed_roadmap.md +50 -0
- doit_cli/templates/memory/constitution.md +125 -0
- doit_cli/templates/memory/roadmap.md +61 -0
- doit_cli/templates/plan-template.md +146 -0
- doit_cli/templates/scripts/bash/check-prerequisites.sh +166 -0
- doit_cli/templates/scripts/bash/common.sh +156 -0
- doit_cli/templates/scripts/bash/create-new-feature.sh +297 -0
- doit_cli/templates/scripts/bash/setup-plan.sh +61 -0
- doit_cli/templates/scripts/bash/update-agent-context.sh +675 -0
- doit_cli/templates/scripts/powershell/check-prerequisites.ps1 +148 -0
- doit_cli/templates/scripts/powershell/common.ps1 +137 -0
- doit_cli/templates/scripts/powershell/create-new-feature.ps1 +283 -0
- doit_cli/templates/scripts/powershell/setup-plan.ps1 +61 -0
- doit_cli/templates/scripts/powershell/update-agent-context.ps1 +406 -0
- doit_cli/templates/spec-template.md +159 -0
- doit_cli/templates/tasks-template.md +313 -0
- doit_cli/templates/vscode-settings.json +14 -0
- doit_toolkit_cli-0.1.9.dist-info/METADATA +324 -0
- doit_toolkit_cli-0.1.9.dist-info/RECORD +134 -0
- doit_toolkit_cli-0.1.9.dist-info/WHEEL +4 -0
- doit_toolkit_cli-0.1.9.dist-info/entry_points.txt +2 -0
- doit_toolkit_cli-0.1.9.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
<#!
|
|
3
|
+
.SYNOPSIS
|
|
4
|
+
Update agent context files with information from plan.md (PowerShell version)
|
|
5
|
+
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
Mirrors the behavior of scripts/bash/update-agent-context.sh:
|
|
8
|
+
1. Environment Validation
|
|
9
|
+
2. Plan Data Extraction
|
|
10
|
+
3. Agent File Management (create from template or update existing)
|
|
11
|
+
4. Content Generation (technology stack, recent changes, timestamp)
|
|
12
|
+
5. Multi-Agent Support (claude, copilot)
|
|
13
|
+
|
|
14
|
+
.PARAMETER AgentType
|
|
15
|
+
Optional agent key to update a single agent. If omitted, updates all existing agent files (creating a default Claude file if none exist).
|
|
16
|
+
|
|
17
|
+
.EXAMPLE
|
|
18
|
+
./update-agent-context.ps1 -AgentType claude
|
|
19
|
+
|
|
20
|
+
.EXAMPLE
|
|
21
|
+
./update-agent-context.ps1 # Updates all existing agent files
|
|
22
|
+
|
|
23
|
+
.NOTES
|
|
24
|
+
Relies on common helper functions in common.ps1
|
|
25
|
+
#>
|
|
26
|
+
param(
|
|
27
|
+
[Parameter(Position=0)]
|
|
28
|
+
[ValidateSet('claude','copilot')]
|
|
29
|
+
[string]$AgentType
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
$ErrorActionPreference = 'Stop'
|
|
33
|
+
|
|
34
|
+
# Import common helpers
|
|
35
|
+
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
36
|
+
. (Join-Path $ScriptDir 'common.ps1')
|
|
37
|
+
|
|
38
|
+
# Acquire environment paths
|
|
39
|
+
$envData = Get-FeaturePathsEnv
|
|
40
|
+
$REPO_ROOT = $envData.REPO_ROOT
|
|
41
|
+
$CURRENT_BRANCH = $envData.CURRENT_BRANCH
|
|
42
|
+
$HAS_GIT = $envData.HAS_GIT
|
|
43
|
+
$IMPL_PLAN = $envData.IMPL_PLAN
|
|
44
|
+
$NEW_PLAN = $IMPL_PLAN
|
|
45
|
+
|
|
46
|
+
# Agent file paths
|
|
47
|
+
$CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md'
|
|
48
|
+
$COPILOT_FILE = Join-Path $REPO_ROOT '.github/agents/copilot-instructions.md'
|
|
49
|
+
|
|
50
|
+
$TEMPLATE_FILE = Join-Path $REPO_ROOT '.doit/templates/agent-file-template.md'
|
|
51
|
+
|
|
52
|
+
# Parsed plan data placeholders
|
|
53
|
+
$script:NEW_LANG = ''
|
|
54
|
+
$script:NEW_FRAMEWORK = ''
|
|
55
|
+
$script:NEW_DB = ''
|
|
56
|
+
$script:NEW_PROJECT_TYPE = ''
|
|
57
|
+
|
|
58
|
+
function Write-Info {
|
|
59
|
+
param(
|
|
60
|
+
[Parameter(Mandatory=$true)]
|
|
61
|
+
[string]$Message
|
|
62
|
+
)
|
|
63
|
+
Write-Host "INFO: $Message"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function Write-Success {
|
|
67
|
+
param(
|
|
68
|
+
[Parameter(Mandatory=$true)]
|
|
69
|
+
[string]$Message
|
|
70
|
+
)
|
|
71
|
+
Write-Host "$([char]0x2713) $Message"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function Write-WarningMsg {
|
|
75
|
+
param(
|
|
76
|
+
[Parameter(Mandatory=$true)]
|
|
77
|
+
[string]$Message
|
|
78
|
+
)
|
|
79
|
+
Write-Warning $Message
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function Write-Err {
|
|
83
|
+
param(
|
|
84
|
+
[Parameter(Mandatory=$true)]
|
|
85
|
+
[string]$Message
|
|
86
|
+
)
|
|
87
|
+
Write-Host "ERROR: $Message" -ForegroundColor Red
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function Validate-Environment {
|
|
91
|
+
if (-not $CURRENT_BRANCH) {
|
|
92
|
+
Write-Err 'Unable to determine current feature'
|
|
93
|
+
if ($HAS_GIT) { Write-Info "Make sure you're on a feature branch" } else { Write-Info 'Set SPECIFY_FEATURE environment variable or create a feature first' }
|
|
94
|
+
exit 1
|
|
95
|
+
}
|
|
96
|
+
if (-not (Test-Path $NEW_PLAN)) {
|
|
97
|
+
Write-Err "No plan.md found at $NEW_PLAN"
|
|
98
|
+
Write-Info 'Ensure you are working on a feature with a corresponding spec directory'
|
|
99
|
+
if (-not $HAS_GIT) { Write-Info 'Use: $env:SPECIFY_FEATURE=your-feature-name or create a new feature first' }
|
|
100
|
+
exit 1
|
|
101
|
+
}
|
|
102
|
+
if (-not (Test-Path $TEMPLATE_FILE)) {
|
|
103
|
+
Write-Err "Template file not found at $TEMPLATE_FILE"
|
|
104
|
+
Write-Info 'Run specify init to scaffold .doit/templates, or add agent-file-template.md there.'
|
|
105
|
+
exit 1
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function Extract-PlanField {
|
|
110
|
+
param(
|
|
111
|
+
[Parameter(Mandatory=$true)]
|
|
112
|
+
[string]$FieldPattern,
|
|
113
|
+
[Parameter(Mandatory=$true)]
|
|
114
|
+
[string]$PlanFile
|
|
115
|
+
)
|
|
116
|
+
if (-not (Test-Path $PlanFile)) { return '' }
|
|
117
|
+
# Lines like **Language/Version**: Python 3.12
|
|
118
|
+
$regex = "^\*\*$([Regex]::Escape($FieldPattern))\*\*: (.+)$"
|
|
119
|
+
Get-Content -LiteralPath $PlanFile -Encoding utf8 | ForEach-Object {
|
|
120
|
+
if ($_ -match $regex) {
|
|
121
|
+
$val = $Matches[1].Trim()
|
|
122
|
+
if ($val -notin @('NEEDS CLARIFICATION','N/A')) { return $val }
|
|
123
|
+
}
|
|
124
|
+
} | Select-Object -First 1
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function Parse-PlanData {
|
|
128
|
+
param(
|
|
129
|
+
[Parameter(Mandatory=$true)]
|
|
130
|
+
[string]$PlanFile
|
|
131
|
+
)
|
|
132
|
+
if (-not (Test-Path $PlanFile)) { Write-Err "Plan file not found: $PlanFile"; return $false }
|
|
133
|
+
Write-Info "Parsing plan data from $PlanFile"
|
|
134
|
+
$script:NEW_LANG = Extract-PlanField -FieldPattern 'Language/Version' -PlanFile $PlanFile
|
|
135
|
+
$script:NEW_FRAMEWORK = Extract-PlanField -FieldPattern 'Primary Dependencies' -PlanFile $PlanFile
|
|
136
|
+
$script:NEW_DB = Extract-PlanField -FieldPattern 'Storage' -PlanFile $PlanFile
|
|
137
|
+
$script:NEW_PROJECT_TYPE = Extract-PlanField -FieldPattern 'Project Type' -PlanFile $PlanFile
|
|
138
|
+
|
|
139
|
+
if ($NEW_LANG) { Write-Info "Found language: $NEW_LANG" } else { Write-WarningMsg 'No language information found in plan' }
|
|
140
|
+
if ($NEW_FRAMEWORK) { Write-Info "Found framework: $NEW_FRAMEWORK" }
|
|
141
|
+
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Info "Found database: $NEW_DB" }
|
|
142
|
+
if ($NEW_PROJECT_TYPE) { Write-Info "Found project type: $NEW_PROJECT_TYPE" }
|
|
143
|
+
return $true
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function Format-TechnologyStack {
|
|
147
|
+
param(
|
|
148
|
+
[Parameter(Mandatory=$false)]
|
|
149
|
+
[string]$Lang,
|
|
150
|
+
[Parameter(Mandatory=$false)]
|
|
151
|
+
[string]$Framework
|
|
152
|
+
)
|
|
153
|
+
$parts = @()
|
|
154
|
+
if ($Lang -and $Lang -ne 'NEEDS CLARIFICATION') { $parts += $Lang }
|
|
155
|
+
if ($Framework -and $Framework -notin @('NEEDS CLARIFICATION','N/A')) { $parts += $Framework }
|
|
156
|
+
if (-not $parts) { return '' }
|
|
157
|
+
return ($parts -join ' + ')
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function Get-ProjectStructure {
|
|
161
|
+
param(
|
|
162
|
+
[Parameter(Mandatory=$false)]
|
|
163
|
+
[string]$ProjectType
|
|
164
|
+
)
|
|
165
|
+
if ($ProjectType -match 'web') { return "backend/`nfrontend/`ntests/" } else { return "src/`ntests/" }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function Get-CommandsForLanguage {
|
|
169
|
+
param(
|
|
170
|
+
[Parameter(Mandatory=$false)]
|
|
171
|
+
[string]$Lang
|
|
172
|
+
)
|
|
173
|
+
switch -Regex ($Lang) {
|
|
174
|
+
'Python' { return "cd src; pytest; ruff check ." }
|
|
175
|
+
'Rust' { return "cargo test; cargo clippy" }
|
|
176
|
+
'JavaScript|TypeScript' { return "npm test; npm run lint" }
|
|
177
|
+
default { return "# Add commands for $Lang" }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function Get-LanguageConventions {
|
|
182
|
+
param(
|
|
183
|
+
[Parameter(Mandatory=$false)]
|
|
184
|
+
[string]$Lang
|
|
185
|
+
)
|
|
186
|
+
if ($Lang) { "${Lang}: Follow standard conventions" } else { 'General: Follow standard conventions' }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function New-AgentFile {
|
|
190
|
+
param(
|
|
191
|
+
[Parameter(Mandatory=$true)]
|
|
192
|
+
[string]$TargetFile,
|
|
193
|
+
[Parameter(Mandatory=$true)]
|
|
194
|
+
[string]$ProjectName,
|
|
195
|
+
[Parameter(Mandatory=$true)]
|
|
196
|
+
[datetime]$Date
|
|
197
|
+
)
|
|
198
|
+
if (-not (Test-Path $TEMPLATE_FILE)) { Write-Err "Template not found at $TEMPLATE_FILE"; return $false }
|
|
199
|
+
$temp = New-TemporaryFile
|
|
200
|
+
Copy-Item -LiteralPath $TEMPLATE_FILE -Destination $temp -Force
|
|
201
|
+
|
|
202
|
+
$projectStructure = Get-ProjectStructure -ProjectType $NEW_PROJECT_TYPE
|
|
203
|
+
$commands = Get-CommandsForLanguage -Lang $NEW_LANG
|
|
204
|
+
$languageConventions = Get-LanguageConventions -Lang $NEW_LANG
|
|
205
|
+
|
|
206
|
+
$escaped_lang = $NEW_LANG
|
|
207
|
+
$escaped_framework = $NEW_FRAMEWORK
|
|
208
|
+
$escaped_branch = $CURRENT_BRANCH
|
|
209
|
+
|
|
210
|
+
$content = Get-Content -LiteralPath $temp -Raw -Encoding utf8
|
|
211
|
+
$content = $content -replace '\[PROJECT NAME\]',$ProjectName
|
|
212
|
+
$content = $content -replace '\[DATE\]',$Date.ToString('yyyy-MM-dd')
|
|
213
|
+
|
|
214
|
+
# Build the technology stack string safely
|
|
215
|
+
$techStackForTemplate = ""
|
|
216
|
+
if ($escaped_lang -and $escaped_framework) {
|
|
217
|
+
$techStackForTemplate = "- $escaped_lang + $escaped_framework ($escaped_branch)"
|
|
218
|
+
} elseif ($escaped_lang) {
|
|
219
|
+
$techStackForTemplate = "- $escaped_lang ($escaped_branch)"
|
|
220
|
+
} elseif ($escaped_framework) {
|
|
221
|
+
$techStackForTemplate = "- $escaped_framework ($escaped_branch)"
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
$content = $content -replace '\[EXTRACTED FROM ALL PLAN.MD FILES\]',$techStackForTemplate
|
|
225
|
+
# For project structure we manually embed (keep newlines)
|
|
226
|
+
$escapedStructure = [Regex]::Escape($projectStructure)
|
|
227
|
+
$content = $content -replace '\[ACTUAL STRUCTURE FROM PLANS\]',$escapedStructure
|
|
228
|
+
# Replace escaped newlines placeholder after all replacements
|
|
229
|
+
$content = $content -replace '\[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES\]',$commands
|
|
230
|
+
$content = $content -replace '\[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE\]',$languageConventions
|
|
231
|
+
|
|
232
|
+
# Build the recent changes string safely
|
|
233
|
+
$recentChangesForTemplate = ""
|
|
234
|
+
if ($escaped_lang -and $escaped_framework) {
|
|
235
|
+
$recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_lang} + ${escaped_framework}"
|
|
236
|
+
} elseif ($escaped_lang) {
|
|
237
|
+
$recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_lang}"
|
|
238
|
+
} elseif ($escaped_framework) {
|
|
239
|
+
$recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_framework}"
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
$content = $content -replace '\[LAST 3 FEATURES AND WHAT THEY ADDED\]',$recentChangesForTemplate
|
|
243
|
+
# Convert literal \n sequences introduced by Escape to real newlines
|
|
244
|
+
$content = $content -replace '\\n',[Environment]::NewLine
|
|
245
|
+
|
|
246
|
+
$parent = Split-Path -Parent $TargetFile
|
|
247
|
+
if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent | Out-Null }
|
|
248
|
+
Set-Content -LiteralPath $TargetFile -Value $content -NoNewline -Encoding utf8
|
|
249
|
+
Remove-Item $temp -Force
|
|
250
|
+
return $true
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function Update-ExistingAgentFile {
|
|
254
|
+
param(
|
|
255
|
+
[Parameter(Mandatory=$true)]
|
|
256
|
+
[string]$TargetFile,
|
|
257
|
+
[Parameter(Mandatory=$true)]
|
|
258
|
+
[datetime]$Date
|
|
259
|
+
)
|
|
260
|
+
if (-not (Test-Path $TargetFile)) { return (New-AgentFile -TargetFile $TargetFile -ProjectName (Split-Path $REPO_ROOT -Leaf) -Date $Date) }
|
|
261
|
+
|
|
262
|
+
$techStack = Format-TechnologyStack -Lang $NEW_LANG -Framework $NEW_FRAMEWORK
|
|
263
|
+
$newTechEntries = @()
|
|
264
|
+
if ($techStack) {
|
|
265
|
+
$escapedTechStack = [Regex]::Escape($techStack)
|
|
266
|
+
if (-not (Select-String -Pattern $escapedTechStack -Path $TargetFile -Quiet)) {
|
|
267
|
+
$newTechEntries += "- $techStack ($CURRENT_BRANCH)"
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if ($NEW_DB -and $NEW_DB -notin @('N/A','NEEDS CLARIFICATION')) {
|
|
271
|
+
$escapedDB = [Regex]::Escape($NEW_DB)
|
|
272
|
+
if (-not (Select-String -Pattern $escapedDB -Path $TargetFile -Quiet)) {
|
|
273
|
+
$newTechEntries += "- $NEW_DB ($CURRENT_BRANCH)"
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
$newChangeEntry = ''
|
|
277
|
+
if ($techStack) { $newChangeEntry = "- ${CURRENT_BRANCH}: Added ${techStack}" }
|
|
278
|
+
elseif ($NEW_DB -and $NEW_DB -notin @('N/A','NEEDS CLARIFICATION')) { $newChangeEntry = "- ${CURRENT_BRANCH}: Added ${NEW_DB}" }
|
|
279
|
+
|
|
280
|
+
$lines = Get-Content -LiteralPath $TargetFile -Encoding utf8
|
|
281
|
+
$output = New-Object System.Collections.Generic.List[string]
|
|
282
|
+
$inTech = $false; $inChanges = $false; $techAdded = $false; $changeAdded = $false; $existingChanges = 0
|
|
283
|
+
|
|
284
|
+
for ($i=0; $i -lt $lines.Count; $i++) {
|
|
285
|
+
$line = $lines[$i]
|
|
286
|
+
if ($line -eq '## Active Technologies') {
|
|
287
|
+
$output.Add($line)
|
|
288
|
+
$inTech = $true
|
|
289
|
+
continue
|
|
290
|
+
}
|
|
291
|
+
if ($inTech -and $line -match '^##\s') {
|
|
292
|
+
if (-not $techAdded -and $newTechEntries.Count -gt 0) { $newTechEntries | ForEach-Object { $output.Add($_) }; $techAdded = $true }
|
|
293
|
+
$output.Add($line); $inTech = $false; continue
|
|
294
|
+
}
|
|
295
|
+
if ($inTech -and [string]::IsNullOrWhiteSpace($line)) {
|
|
296
|
+
if (-not $techAdded -and $newTechEntries.Count -gt 0) { $newTechEntries | ForEach-Object { $output.Add($_) }; $techAdded = $true }
|
|
297
|
+
$output.Add($line); continue
|
|
298
|
+
}
|
|
299
|
+
if ($line -eq '## Recent Changes') {
|
|
300
|
+
$output.Add($line)
|
|
301
|
+
if ($newChangeEntry) { $output.Add($newChangeEntry); $changeAdded = $true }
|
|
302
|
+
$inChanges = $true
|
|
303
|
+
continue
|
|
304
|
+
}
|
|
305
|
+
if ($inChanges -and $line -match '^##\s') { $output.Add($line); $inChanges = $false; continue }
|
|
306
|
+
if ($inChanges -and $line -match '^- ') {
|
|
307
|
+
if ($existingChanges -lt 2) { $output.Add($line); $existingChanges++ }
|
|
308
|
+
continue
|
|
309
|
+
}
|
|
310
|
+
if ($line -match '\*\*Last updated\*\*: .*\d{4}-\d{2}-\d{2}') {
|
|
311
|
+
$output.Add(($line -replace '\d{4}-\d{2}-\d{2}',$Date.ToString('yyyy-MM-dd')))
|
|
312
|
+
continue
|
|
313
|
+
}
|
|
314
|
+
$output.Add($line)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
# Post-loop check: if we're still in the Active Technologies section and haven't added new entries
|
|
318
|
+
if ($inTech -and -not $techAdded -and $newTechEntries.Count -gt 0) {
|
|
319
|
+
$newTechEntries | ForEach-Object { $output.Add($_) }
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
Set-Content -LiteralPath $TargetFile -Value ($output -join [Environment]::NewLine) -Encoding utf8
|
|
323
|
+
return $true
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function Update-AgentFile {
|
|
327
|
+
param(
|
|
328
|
+
[Parameter(Mandatory=$true)]
|
|
329
|
+
[string]$TargetFile,
|
|
330
|
+
[Parameter(Mandatory=$true)]
|
|
331
|
+
[string]$AgentName
|
|
332
|
+
)
|
|
333
|
+
if (-not $TargetFile -or -not $AgentName) { Write-Err 'Update-AgentFile requires TargetFile and AgentName'; return $false }
|
|
334
|
+
Write-Info "Updating $AgentName context file: $TargetFile"
|
|
335
|
+
$projectName = Split-Path $REPO_ROOT -Leaf
|
|
336
|
+
$date = Get-Date
|
|
337
|
+
|
|
338
|
+
$dir = Split-Path -Parent $TargetFile
|
|
339
|
+
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null }
|
|
340
|
+
|
|
341
|
+
if (-not (Test-Path $TargetFile)) {
|
|
342
|
+
if (New-AgentFile -TargetFile $TargetFile -ProjectName $projectName -Date $date) { Write-Success "Created new $AgentName context file" } else { Write-Err 'Failed to create new agent file'; return $false }
|
|
343
|
+
} else {
|
|
344
|
+
try {
|
|
345
|
+
if (Update-ExistingAgentFile -TargetFile $TargetFile -Date $date) { Write-Success "Updated existing $AgentName context file" } else { Write-Err 'Failed to update agent file'; return $false }
|
|
346
|
+
} catch {
|
|
347
|
+
Write-Err "Cannot access or update existing file: $TargetFile. $_"
|
|
348
|
+
return $false
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return $true
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function Update-SpecificAgent {
|
|
355
|
+
param(
|
|
356
|
+
[Parameter(Mandatory=$true)]
|
|
357
|
+
[string]$Type
|
|
358
|
+
)
|
|
359
|
+
switch ($Type) {
|
|
360
|
+
'claude' { Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code' }
|
|
361
|
+
'copilot' { Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot' }
|
|
362
|
+
default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|copilot'; return $false }
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function Update-AllExistingAgents {
|
|
367
|
+
$found = $false
|
|
368
|
+
$ok = $true
|
|
369
|
+
if (Test-Path $CLAUDE_FILE) { if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false }; $found = $true }
|
|
370
|
+
if (Test-Path $COPILOT_FILE) { if (-not (Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot')) { $ok = $false }; $found = $true }
|
|
371
|
+
if (-not $found) {
|
|
372
|
+
Write-Info 'No existing agent files found, creating default Claude file...'
|
|
373
|
+
if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false }
|
|
374
|
+
}
|
|
375
|
+
return $ok
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function Print-Summary {
|
|
379
|
+
Write-Host ''
|
|
380
|
+
Write-Info 'Summary of changes:'
|
|
381
|
+
if ($NEW_LANG) { Write-Host " - Added language: $NEW_LANG" }
|
|
382
|
+
if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" }
|
|
383
|
+
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" }
|
|
384
|
+
Write-Host ''
|
|
385
|
+
Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|copilot]'
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function Main {
|
|
389
|
+
Validate-Environment
|
|
390
|
+
Write-Info "=== Updating agent context files for feature $CURRENT_BRANCH ==="
|
|
391
|
+
if (-not (Parse-PlanData -PlanFile $NEW_PLAN)) { Write-Err 'Failed to parse plan data'; exit 1 }
|
|
392
|
+
$success = $true
|
|
393
|
+
if ($AgentType) {
|
|
394
|
+
Write-Info "Updating specific agent: $AgentType"
|
|
395
|
+
if (-not (Update-SpecificAgent -Type $AgentType)) { $success = $false }
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
Write-Info 'No agent specified, updating all existing agent files...'
|
|
399
|
+
if (-not (Update-AllExistingAgents)) { $success = $false }
|
|
400
|
+
}
|
|
401
|
+
Print-Summary
|
|
402
|
+
if ($success) { Write-Success 'Agent context update completed successfully'; exit 0 } else { Write-Err 'Agent context update completed with errors'; exit 1 }
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
Main
|
|
406
|
+
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Feature Specification: [FEATURE NAME]
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `[###-feature-name]`
|
|
4
|
+
**Created**: [DATE]
|
|
5
|
+
**Status**: Draft
|
|
6
|
+
**Input**: User description: "$ARGUMENTS"
|
|
7
|
+
|
|
8
|
+
## User Scenarios & Testing *(mandatory)*
|
|
9
|
+
|
|
10
|
+
<!--
|
|
11
|
+
IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
|
|
12
|
+
Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
|
|
13
|
+
you should still have a viable MVP (Minimum Viable Product) that delivers value.
|
|
14
|
+
|
|
15
|
+
Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
|
|
16
|
+
Think of each story as a standalone slice of functionality that can be:
|
|
17
|
+
- Developed independently
|
|
18
|
+
- Tested independently
|
|
19
|
+
- Deployed independently
|
|
20
|
+
- Demonstrated to users independently
|
|
21
|
+
-->
|
|
22
|
+
|
|
23
|
+
### User Story 1 - [Brief Title] (Priority: P1)
|
|
24
|
+
|
|
25
|
+
[Describe this user journey in plain language]
|
|
26
|
+
|
|
27
|
+
**Why this priority**: [Explain the value and why it has this priority level]
|
|
28
|
+
|
|
29
|
+
**Independent Test**: [Describe how this can be tested independently - e.g., "Can be fully tested by [specific action] and delivers [specific value]"]
|
|
30
|
+
|
|
31
|
+
**Acceptance Scenarios**:
|
|
32
|
+
|
|
33
|
+
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
|
|
34
|
+
2. **Given** [initial state], **When** [action], **Then** [expected outcome]
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
### User Story 2 - [Brief Title] (Priority: P2)
|
|
39
|
+
|
|
40
|
+
[Describe this user journey in plain language]
|
|
41
|
+
|
|
42
|
+
**Why this priority**: [Explain the value and why it has this priority level]
|
|
43
|
+
|
|
44
|
+
**Independent Test**: [Describe how this can be tested independently]
|
|
45
|
+
|
|
46
|
+
**Acceptance Scenarios**:
|
|
47
|
+
|
|
48
|
+
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### User Story 3 - [Brief Title] (Priority: P3)
|
|
53
|
+
|
|
54
|
+
[Describe this user journey in plain language]
|
|
55
|
+
|
|
56
|
+
**Why this priority**: [Explain the value and why it has this priority level]
|
|
57
|
+
|
|
58
|
+
**Independent Test**: [Describe how this can be tested independently]
|
|
59
|
+
|
|
60
|
+
**Acceptance Scenarios**:
|
|
61
|
+
|
|
62
|
+
1. **Given** [initial state], **When** [action], **Then** [expected outcome]
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
[Add more user stories as needed, each with an assigned priority]
|
|
67
|
+
|
|
68
|
+
### Edge Cases
|
|
69
|
+
|
|
70
|
+
<!--
|
|
71
|
+
ACTION REQUIRED: The content in this section represents placeholders.
|
|
72
|
+
Fill them out with the right edge cases.
|
|
73
|
+
-->
|
|
74
|
+
|
|
75
|
+
- What happens when [boundary condition]?
|
|
76
|
+
- How does system handle [error scenario]?
|
|
77
|
+
|
|
78
|
+
## User Journey Visualization
|
|
79
|
+
|
|
80
|
+
<!--
|
|
81
|
+
AUTO-GENERATED: This section is populated by /doit.specit based on user stories above.
|
|
82
|
+
The flowchart shows each user story as a subgraph with key actions.
|
|
83
|
+
Regenerate by running /doit.specit again.
|
|
84
|
+
-->
|
|
85
|
+
|
|
86
|
+
<!-- BEGIN:AUTO-GENERATED section="user-journey" -->
|
|
87
|
+
```mermaid
|
|
88
|
+
flowchart LR
|
|
89
|
+
subgraph "User Story 1 - [Title]"
|
|
90
|
+
US1_S[Start] --> US1_A[Action] --> US1_E[End]
|
|
91
|
+
end
|
|
92
|
+
subgraph "User Story 2 - [Title]"
|
|
93
|
+
US2_S[Start] --> US2_A[Action] --> US2_E[End]
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
<!-- END:AUTO-GENERATED -->
|
|
97
|
+
|
|
98
|
+
## Entity Relationships *(include if Key Entities defined)*
|
|
99
|
+
|
|
100
|
+
<!--
|
|
101
|
+
AUTO-GENERATED: This section is populated by /doit.specit when Key Entities are defined.
|
|
102
|
+
Shows entity relationships as an ER diagram.
|
|
103
|
+
If no entities are defined, this entire section should be omitted (not left empty).
|
|
104
|
+
-->
|
|
105
|
+
|
|
106
|
+
<!-- BEGIN:AUTO-GENERATED section="entity-relationships" -->
|
|
107
|
+
```mermaid
|
|
108
|
+
erDiagram
|
|
109
|
+
ENTITY1 ||--o{ ENTITY2 : "relationship"
|
|
110
|
+
|
|
111
|
+
ENTITY1 {
|
|
112
|
+
string id PK
|
|
113
|
+
string name
|
|
114
|
+
}
|
|
115
|
+
ENTITY2 {
|
|
116
|
+
string id PK
|
|
117
|
+
string entity1_id FK
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
<!-- END:AUTO-GENERATED -->
|
|
121
|
+
|
|
122
|
+
## Requirements *(mandatory)*
|
|
123
|
+
|
|
124
|
+
<!--
|
|
125
|
+
ACTION REQUIRED: The content in this section represents placeholders.
|
|
126
|
+
Fill them out with the right functional requirements.
|
|
127
|
+
-->
|
|
128
|
+
|
|
129
|
+
### Functional Requirements
|
|
130
|
+
|
|
131
|
+
- **FR-001**: System MUST [specific capability, e.g., "allow users to create accounts"]
|
|
132
|
+
- **FR-002**: System MUST [specific capability, e.g., "validate email addresses"]
|
|
133
|
+
- **FR-003**: Users MUST be able to [key interaction, e.g., "reset their password"]
|
|
134
|
+
- **FR-004**: System MUST [data requirement, e.g., "persist user preferences"]
|
|
135
|
+
- **FR-005**: System MUST [behavior, e.g., "log all security events"]
|
|
136
|
+
|
|
137
|
+
*Example of marking unclear requirements:*
|
|
138
|
+
|
|
139
|
+
- **FR-006**: System MUST authenticate users via [NEEDS CLARIFICATION: auth method not specified - email/password, SSO, OAuth?]
|
|
140
|
+
- **FR-007**: System MUST retain user data for [NEEDS CLARIFICATION: retention period not specified]
|
|
141
|
+
|
|
142
|
+
### Key Entities *(include if feature involves data)*
|
|
143
|
+
|
|
144
|
+
- **[Entity 1]**: [What it represents, key attributes without implementation]
|
|
145
|
+
- **[Entity 2]**: [What it represents, relationships to other entities]
|
|
146
|
+
|
|
147
|
+
## Success Criteria *(mandatory)*
|
|
148
|
+
|
|
149
|
+
<!--
|
|
150
|
+
ACTION REQUIRED: Define measurable success criteria.
|
|
151
|
+
These must be technology-agnostic and measurable.
|
|
152
|
+
-->
|
|
153
|
+
|
|
154
|
+
### Measurable Outcomes
|
|
155
|
+
|
|
156
|
+
- **SC-001**: [Measurable metric, e.g., "Users can complete account creation in under 2 minutes"]
|
|
157
|
+
- **SC-002**: [Measurable metric, e.g., "System handles 1000 concurrent users without degradation"]
|
|
158
|
+
- **SC-003**: [User satisfaction metric, e.g., "90% of users successfully complete primary task on first attempt"]
|
|
159
|
+
- **SC-004**: [Business metric, e.g., "Reduce support tickets related to [X] by 50%"]
|