sdtk-kit 0.3.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/README.md +131 -0
  2. package/assets/manifest/toolkit-bundle.manifest.json +303 -0
  3. package/assets/manifest/toolkit-bundle.sha256.txt +59 -0
  4. package/assets/toolkit/toolkit/AGENTS.md +103 -0
  5. package/assets/toolkit/toolkit/install.ps1 +155 -0
  6. package/assets/toolkit/toolkit/runtimes/claude/CLAUDE_TEMPLATE.md +32 -0
  7. package/assets/toolkit/toolkit/runtimes/codex/CODEX_TEMPLATE.md +32 -0
  8. package/assets/toolkit/toolkit/scripts/init-feature.ps1 +253 -0
  9. package/assets/toolkit/toolkit/scripts/install-codex-skills.ps1 +181 -0
  10. package/assets/toolkit/toolkit/scripts/uninstall-codex-skills.ps1 +116 -0
  11. package/assets/toolkit/toolkit/sdtk.config.json +28 -0
  12. package/assets/toolkit/toolkit/sdtk.config.profiles.example.json +50 -0
  13. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/SKILL.md +78 -0
  14. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/references/API_DESIGN_CREATION_RULES.md +212 -0
  15. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/references/FLOWCHART_CREATION_RULES.md +397 -0
  16. package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/scripts/generate_api_design_detail.py +565 -0
  17. package/assets/toolkit/toolkit/skills/sdtk-api-doc/SKILL.md +36 -0
  18. package/assets/toolkit/toolkit/skills/sdtk-api-doc/references/FLOWCHART_CREATION_RULES.md +397 -0
  19. package/assets/toolkit/toolkit/skills/sdtk-arch/SKILL.md +43 -0
  20. package/assets/toolkit/toolkit/skills/sdtk-arch/references/API_DESIGN_CREATION_RULES.md +212 -0
  21. package/assets/toolkit/toolkit/skills/sdtk-arch/references/FLOWCHART_CREATION_RULES.md +397 -0
  22. package/assets/toolkit/toolkit/skills/sdtk-arch/references/FLOW_ACTION_SPEC_CREATION_RULES.md +136 -0
  23. package/assets/toolkit/toolkit/skills/sdtk-ba/SKILL.md +24 -0
  24. package/assets/toolkit/toolkit/skills/sdtk-design-layout/SKILL.md +21 -0
  25. package/assets/toolkit/toolkit/skills/sdtk-dev/SKILL.md +20 -0
  26. package/assets/toolkit/toolkit/skills/sdtk-dev-backend/SKILL.md +17 -0
  27. package/assets/toolkit/toolkit/skills/sdtk-dev-frontend/SKILL.md +15 -0
  28. package/assets/toolkit/toolkit/skills/sdtk-orchestrator/SKILL.md +44 -0
  29. package/assets/toolkit/toolkit/skills/sdtk-pm/SKILL.md +26 -0
  30. package/assets/toolkit/toolkit/skills/sdtk-qa/SKILL.md +22 -0
  31. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/SKILL.md +59 -0
  32. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/FLOW_ACTION_SPEC_CREATION_RULES.md +136 -0
  33. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/excel-image-export.md +51 -0
  34. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/figma-mcp.md +54 -0
  35. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/numbering-rules.md +76 -0
  36. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/scripts/renumber_flow_action_spec_global.py +136 -0
  37. package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/scripts/validate_flow_action_spec_numbering.py +249 -0
  38. package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/SKILL.md +65 -0
  39. package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/references/TEST_CASE_CREATION_RULES.md +129 -0
  40. package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/scripts/validate_test_case_spec.py +97 -0
  41. package/assets/toolkit/toolkit/templates/QUALITY_CHECKLIST.md +124 -0
  42. package/assets/toolkit/toolkit/templates/README.md +56 -0
  43. package/assets/toolkit/toolkit/templates/SHARED_PLANNING.md +80 -0
  44. package/assets/toolkit/toolkit/templates/docs/api/API_DESIGN_CREATION_RULES.md +212 -0
  45. package/assets/toolkit/toolkit/templates/docs/api/API_DESIGN_DETAIL_TEMPLATE.md +62 -0
  46. package/assets/toolkit/toolkit/templates/docs/api/API_ENDPOINTS_TEMPLATE.md +229 -0
  47. package/assets/toolkit/toolkit/templates/docs/api/FEATURE_API_TEMPLATE.yaml +20 -0
  48. package/assets/toolkit/toolkit/templates/docs/api/FLOWCHART_CREATION_RULES.md +397 -0
  49. package/assets/toolkit/toolkit/templates/docs/api/feature_api_flow_list_TEMPLATE.txt +12 -0
  50. package/assets/toolkit/toolkit/templates/docs/architecture/ARCH_DESIGN_TEMPLATE.md +109 -0
  51. package/assets/toolkit/toolkit/templates/docs/database/DATABASE_SPEC_TEMPLATE.md +175 -0
  52. package/assets/toolkit/toolkit/templates/docs/design/DESIGN_LAYOUT_TEMPLATE.md +49 -0
  53. package/assets/toolkit/toolkit/templates/docs/dev/FEATURE_IMPL_PLAN_TEMPLATE.md +73 -0
  54. package/assets/toolkit/toolkit/templates/docs/product/BACKLOG_TEMPLATE.md +50 -0
  55. package/assets/toolkit/toolkit/templates/docs/product/PRD_TEMPLATE.md +66 -0
  56. package/assets/toolkit/toolkit/templates/docs/product/PROJECT_INITIATION_TEMPLATE.md +98 -0
  57. package/assets/toolkit/toolkit/templates/docs/qa/QA_RELEASE_REPORT_TEMPLATE.md +61 -0
  58. package/assets/toolkit/toolkit/templates/docs/qa/TEST_CASE_CREATION_RULES.md +129 -0
  59. package/assets/toolkit/toolkit/templates/docs/qa/TEST_CASE_TEMPLATE.md +104 -0
  60. package/assets/toolkit/toolkit/templates/docs/specs/BA_SPEC_TEMPLATE.md +139 -0
  61. package/assets/toolkit/toolkit/templates/docs/specs/FLOW_ACTION_SPEC_CREATION_RULES.md +136 -0
  62. package/assets/toolkit/toolkit/templates/docs/specs/FLOW_ACTION_SPEC_TEMPLATE.md +160 -0
  63. package/bin/sdtk.js +15 -0
  64. package/package.json +47 -0
  65. package/src/commands/auth.js +85 -0
  66. package/src/commands/generate.js +177 -0
  67. package/src/commands/help.js +69 -0
  68. package/src/commands/init.js +73 -0
  69. package/src/index.js +56 -0
  70. package/src/lib/args.js +116 -0
  71. package/src/lib/errors.js +41 -0
  72. package/src/lib/github-access.js +68 -0
  73. package/src/lib/powershell.js +85 -0
  74. package/src/lib/state.js +83 -0
  75. package/src/lib/toolkit-payload.js +99 -0
@@ -0,0 +1,155 @@
1
+ param(
2
+ [string]$ProjectPath,
3
+ [switch]$Force,
4
+ [switch]$SkipSkills,
5
+ [switch]$Quiet,
6
+ [ValidateSet('codex', 'claude')]
7
+ [string]$Runtime = 'codex'
8
+ )
9
+
10
+ $ErrorActionPreference = 'Stop'
11
+ Set-StrictMode -Version Latest
12
+
13
+ function Get-FileSha256 {
14
+ param(
15
+ [Parameter(Mandatory = $true)][string]$Path
16
+ )
17
+
18
+ if (-not (Test-Path -LiteralPath $Path)) {
19
+ return $null
20
+ }
21
+
22
+ $stream = [System.IO.File]::OpenRead($Path)
23
+ try {
24
+ $sha = [System.Security.Cryptography.SHA256]::Create()
25
+ $hashBytes = $sha.ComputeHash($stream)
26
+ return [BitConverter]::ToString($hashBytes).Replace('-', '')
27
+ } finally {
28
+ $stream.Close()
29
+ }
30
+ }
31
+
32
+ function Copy-File {
33
+ param(
34
+ [Parameter(Mandatory = $true)][string]$SourcePath,
35
+ [Parameter(Mandatory = $true)][string]$DestinationPath,
36
+ [Parameter(Mandatory = $true)][bool]$Overwrite
37
+ )
38
+
39
+ if (-not (Test-Path -LiteralPath $SourcePath)) {
40
+ throw "Missing source: $SourcePath"
41
+ }
42
+
43
+ if (Test-Path -LiteralPath $DestinationPath) {
44
+ if (-not $Overwrite) {
45
+ Write-Warning "Already exists (skipping). Use -Force to overwrite: $DestinationPath"
46
+ return
47
+ }
48
+ }
49
+
50
+ $parent = Split-Path -Parent $DestinationPath
51
+ if ($parent -and -not (Test-Path -LiteralPath $parent)) {
52
+ New-Item -ItemType Directory -Force -Path $parent | Out-Null
53
+ }
54
+
55
+ Copy-Item -LiteralPath $SourcePath -Destination $DestinationPath -Force
56
+ }
57
+
58
+ function Install-RuntimeAdapter {
59
+ param(
60
+ [Parameter(Mandatory = $true)][string]$ToolkitRoot,
61
+ [Parameter(Mandatory = $true)][string]$ProjectRoot,
62
+ [Parameter(Mandatory = $true)][string]$RuntimeName,
63
+ [Parameter(Mandatory = $true)][bool]$Overwrite
64
+ )
65
+
66
+ if ($RuntimeName -eq 'codex') {
67
+ $source = Join-Path $ToolkitRoot 'runtimes/codex/CODEX_TEMPLATE.md'
68
+ $dest = Join-Path $ProjectRoot 'CODEX.md'
69
+ Copy-File -SourcePath $source -DestinationPath $dest -Overwrite $Overwrite
70
+ return
71
+ }
72
+
73
+ if ($RuntimeName -eq 'claude') {
74
+ $source = Join-Path $ToolkitRoot 'runtimes/claude/CLAUDE_TEMPLATE.md'
75
+ $dest = Join-Path $ProjectRoot 'CLAUDE.md'
76
+ Copy-File -SourcePath $source -DestinationPath $dest -Overwrite $Overwrite
77
+ return
78
+ }
79
+
80
+ throw "Unsupported runtime: $RuntimeName"
81
+ }
82
+
83
+ $toolkitRoot = Resolve-Path $PSScriptRoot
84
+ $canonicalRulesPath = Join-Path $toolkitRoot 'templates/docs/api/FLOWCHART_CREATION_RULES.md'
85
+ $canonicalRulesHash = Get-FileSha256 -Path $canonicalRulesPath
86
+ $apiDesignRulesPath = Join-Path $toolkitRoot 'templates/docs/api/API_DESIGN_CREATION_RULES.md'
87
+ $apiDesignRulesHash = Get-FileSha256 -Path $apiDesignRulesPath
88
+ $flowActionRulesPath = Join-Path $toolkitRoot 'templates/docs/specs/FLOW_ACTION_SPEC_CREATION_RULES.md'
89
+ $flowActionRulesHash = Get-FileSha256 -Path $flowActionRulesPath
90
+
91
+ if (-not $ProjectPath) {
92
+ $ProjectPath = (Resolve-Path (Join-Path $toolkitRoot '..')).Path
93
+ }
94
+ $projectRoot = Resolve-Path -LiteralPath $ProjectPath
95
+
96
+ if (-not $Quiet) {
97
+ Write-Host "SDTK toolkit : $toolkitRoot"
98
+ Write-Host "Project root : $projectRoot"
99
+ Write-Host "Runtime : $Runtime"
100
+ if ($canonicalRulesHash) {
101
+ Write-Host "API ruleset : $canonicalRulesPath"
102
+ Write-Host "Ruleset hash : $canonicalRulesHash"
103
+ } else {
104
+ Write-Warning "API ruleset not found: $canonicalRulesPath"
105
+ }
106
+ if ($apiDesignRulesHash) {
107
+ Write-Host "API design ruleset: $apiDesignRulesPath"
108
+ Write-Host "Ruleset hash : $apiDesignRulesHash"
109
+ } else {
110
+ Write-Warning "API design ruleset not found: $apiDesignRulesPath"
111
+ }
112
+ if ($flowActionRulesHash) {
113
+ Write-Host "Flow ruleset : $flowActionRulesPath"
114
+ Write-Host "Ruleset hash : $flowActionRulesHash"
115
+ } else {
116
+ Write-Warning "Flow ruleset not found: $flowActionRulesPath"
117
+ }
118
+ }
119
+
120
+ Copy-File -SourcePath (Join-Path $toolkitRoot 'AGENTS.md') -DestinationPath (Join-Path $projectRoot 'AGENTS.md') -Overwrite ([bool]$Force)
121
+ Copy-File -SourcePath (Join-Path $toolkitRoot 'sdtk.config.json') -DestinationPath (Join-Path $projectRoot 'sdtk.config.json') -Overwrite ([bool]$Force)
122
+ Copy-File -SourcePath (Join-Path $toolkitRoot 'sdtk.config.profiles.example.json') -DestinationPath (Join-Path $projectRoot 'sdtk.config.profiles.example.json') -Overwrite ([bool]$Force)
123
+ Install-RuntimeAdapter -ToolkitRoot $toolkitRoot -ProjectRoot $projectRoot -RuntimeName $Runtime -Overwrite ([bool]$Force)
124
+
125
+ if (($Runtime -eq 'codex') -and (-not $SkipSkills)) {
126
+ $skillInstaller = Join-Path $toolkitRoot 'scripts/install-codex-skills.ps1'
127
+ if (-not (Test-Path -LiteralPath $skillInstaller)) {
128
+ throw "Missing skill installer script: $skillInstaller"
129
+ }
130
+
131
+ Write-Host ""
132
+ Write-Host "Installing Codex skills globally..."
133
+ if ($Force) {
134
+ & $skillInstaller -Force | Out-Host
135
+ } else {
136
+ & $skillInstaller | Out-Host
137
+ }
138
+ }
139
+ elseif (($Runtime -eq 'claude') -and (-not $SkipSkills) -and (-not $Quiet)) {
140
+ Write-Warning "Runtime 'claude' does not install Codex skills. Skipping skill installation."
141
+ }
142
+
143
+ if (-not $Quiet) {
144
+ Write-Host ""
145
+ Write-Host "Install complete."
146
+ Write-Host "Next:"
147
+ Write-Host "1) Edit project config: $((Join-Path $projectRoot 'sdtk.config.json'))"
148
+ if ($Runtime -eq 'codex') {
149
+ Write-Host "2) Restart Codex (to load runtime adapter and skills)"
150
+ } else {
151
+ Write-Host "2) Restart Claude Code (to load CLAUDE.md adapter)"
152
+ }
153
+ Write-Host '3) Generate feature docs:'
154
+ Write-Host ' sdtk generate --feature-key YOUR_FEATURE --feature-name "Your Feature"'
155
+ }
@@ -0,0 +1,32 @@
1
+ # CLAUDE.md
2
+
3
+ Version: 1.0
4
+ Last Updated: 2026-02-25
5
+ Owner: SDTK Core Team
6
+
7
+ This file defines runtime guidance for Claude Code sessions in projects using SDTK.
8
+
9
+ ## 1) Rule Priority
10
+ 1. Explicit user request
11
+ 2. `AGENTS.md` (project root)
12
+ 3. `toolkit/AGENTS.md`
13
+ 4. This file (`CLAUDE.md`)
14
+ 5. Other supporting docs
15
+
16
+ ## 2) Runtime Model
17
+ - Primary workflow: PM -> BA -> ARCH -> DEV -> QA
18
+ - Role tags: `/pm`, `/ba`, `/arch`, `/dev`, `/qa`
19
+ - Shared state files:
20
+ - `SHARED_PLANNING.md`
21
+ - `QUALITY_CHECKLIST.md`
22
+
23
+ ## 3) Minimal Session Flow
24
+ 1. Start with `/pm` to define feature scope.
25
+ 2. Move phase-by-phase without skipping gates.
26
+ 3. Keep traceability from requirements to design, implementation, and tests.
27
+ 4. Require code review completion before QA release decision.
28
+
29
+ ## 4) References
30
+ - `toolkit/SDTK_TOOLKIT.md`
31
+ - `toolkit/AGENTS.md`
32
+ - `sdtk.config.json`
@@ -0,0 +1,32 @@
1
+ # CODEX.md
2
+
3
+ Version: 1.0
4
+ Last Updated: 2026-02-25
5
+ Owner: SDTK Core Team
6
+
7
+ This file defines runtime guidance for Codex sessions in projects using SDTK.
8
+
9
+ ## 1) Rule Priority
10
+ 1. Explicit user request
11
+ 2. `AGENTS.md` (project root)
12
+ 3. `toolkit/AGENTS.md`
13
+ 4. This file (`CODEX.md`)
14
+ 5. Other supporting docs
15
+
16
+ ## 2) Runtime Model
17
+ - Primary workflow: PM -> BA -> ARCH -> DEV -> QA
18
+ - Role tags: `/pm`, `/ba`, `/arch`, `/dev`, `/qa`
19
+ - Shared state files:
20
+ - `SHARED_PLANNING.md`
21
+ - `QUALITY_CHECKLIST.md`
22
+
23
+ ## 3) Minimal Session Flow
24
+ 1. Start with `/pm` to define feature scope.
25
+ 2. Move phase-by-phase without skipping gates.
26
+ 3. Keep traceability from requirements to design, implementation, and tests.
27
+ 4. Require code review completion before QA release decision.
28
+
29
+ ## 4) References
30
+ - `toolkit/SDTK_TOOLKIT.md`
31
+ - `toolkit/AGENTS.md`
32
+ - `sdtk.config.json`
@@ -0,0 +1,253 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [string]$FeatureKey,
4
+
5
+ [Parameter(Mandatory = $true)]
6
+ [string]$FeatureName,
7
+
8
+ [string]$ProjectPath,
9
+
10
+ [switch]$Force,
11
+
12
+ [switch]$ValidateOnly
13
+ )
14
+
15
+ $ErrorActionPreference = 'Stop'
16
+ Set-StrictMode -Version Latest
17
+
18
+ function ConvertTo-PascalCase {
19
+ param([Parameter(Mandatory = $true)][string]$Text)
20
+
21
+ $parts = $Text -split '[^A-Za-z0-9]+' | Where-Object { $_ -and $_.Trim().Length -gt 0 }
22
+ if (-not $parts -or $parts.Count -eq 0) {
23
+ return ''
24
+ }
25
+
26
+ return ($parts | ForEach-Object {
27
+ if ($_.Length -eq 1) { $_.Substring(0, 1).ToUpper() }
28
+ else { $_.Substring(0, 1).ToUpper() + $_.Substring(1) }
29
+ }) -join ''
30
+ }
31
+
32
+ function Render-Template {
33
+ param(
34
+ [Parameter(Mandatory = $true)][string]$TemplatePath,
35
+ [Parameter(Mandatory = $true)][hashtable]$Tokens
36
+ )
37
+
38
+ $content = Get-Content -Raw -Path $TemplatePath
39
+ # Strip BOM if present (Windows PowerShell 5.1 may read BOM into string)
40
+ if ($content.Length -gt 0 -and $content[0] -eq [char]0xFEFF) {
41
+ $content = $content.Substring(1)
42
+ }
43
+ foreach ($key in $Tokens.Keys) {
44
+ $content = $content.Replace("{{${key}}}", [string]$Tokens[$key])
45
+ }
46
+ return $content
47
+ }
48
+
49
+ function Write-RenderedFile {
50
+ param(
51
+ [Parameter(Mandatory = $true)][string]$DestinationPath,
52
+ [Parameter(Mandatory = $true)][string]$TemplatePath,
53
+ [Parameter(Mandatory = $true)][hashtable]$Tokens,
54
+ [Parameter(Mandatory = $true)][bool]$Overwrite
55
+ )
56
+
57
+ if ((Test-Path -LiteralPath $DestinationPath) -and -not $Overwrite) {
58
+ throw "Refusing to overwrite existing file (use -Force): $DestinationPath"
59
+ }
60
+
61
+ $parent = Split-Path -Parent $DestinationPath
62
+ if ($parent -and -not (Test-Path -LiteralPath $parent)) {
63
+ New-Item -ItemType Directory -Force -Path $parent | Out-Null
64
+ }
65
+
66
+ $rendered = Render-Template -TemplatePath $TemplatePath -Tokens $Tokens
67
+ $utf8NoBom = New-Object System.Text.UTF8Encoding($false)
68
+ [System.IO.File]::WriteAllText($DestinationPath, $rendered, $utf8NoBom)
69
+ }
70
+
71
+ $config = $null
72
+ function Get-StringOrDefault {
73
+ param(
74
+ [AllowNull()][object]$Value,
75
+ [Parameter(Mandatory = $true)][string]$Default
76
+ )
77
+
78
+ if ($null -eq $Value) {
79
+ return $Default
80
+ }
81
+ $text = ([string]$Value).Trim()
82
+ if ($text.Length -eq 0) {
83
+ return $Default
84
+ }
85
+ return $text
86
+ }
87
+
88
+ function Get-PropValue {
89
+ param(
90
+ [AllowNull()][object]$Object,
91
+ [Parameter(Mandatory = $true)][string]$Name
92
+ )
93
+
94
+ if ($null -eq $Object) {
95
+ return $null
96
+ }
97
+ $prop = $Object.PSObject.Properties[$Name]
98
+ if ($null -eq $prop) {
99
+ return $null
100
+ }
101
+ return $prop.Value
102
+ }
103
+
104
+ $toolkitRoot = Resolve-Path (Join-Path $PSScriptRoot '..')
105
+
106
+ if ($ProjectPath) {
107
+ if (-not (Test-Path -LiteralPath $ProjectPath)) {
108
+ New-Item -ItemType Directory -Force -Path $ProjectPath | Out-Null
109
+ }
110
+ $projectRoot = Resolve-Path -LiteralPath $ProjectPath
111
+ } else {
112
+ $projectRoot = Resolve-Path (Join-Path $toolkitRoot '..')
113
+ }
114
+
115
+ $templateRoot = Join-Path $toolkitRoot 'templates'
116
+
117
+ if (-not (Test-Path -LiteralPath $templateRoot)) {
118
+ throw "Missing templates directory: $templateRoot"
119
+ }
120
+
121
+ $configPath = Join-Path $projectRoot 'sdtk.config.json'
122
+ if (-not (Test-Path -LiteralPath $configPath)) {
123
+ $configPath = Join-Path $toolkitRoot 'sdtk.config.json'
124
+ }
125
+
126
+ if (Test-Path -LiteralPath $configPath) {
127
+ try {
128
+ $config = Get-Content -Raw -LiteralPath $configPath | ConvertFrom-Json
129
+ } catch {
130
+ throw "Failed to parse config file: $configPath`n$($_.Exception.Message)"
131
+ }
132
+ }
133
+
134
+ $FeatureKey = $FeatureKey.Trim()
135
+ $FeatureName = $FeatureName.Trim()
136
+
137
+ if (-not $FeatureKey) { throw "FeatureKey is empty." }
138
+ if ($FeatureKey -notmatch '^[A-Z][A-Z0-9_]*$') {
139
+ throw "Invalid FeatureKey. Use UPPER_SNAKE_CASE (A-Z, 0-9, _)."
140
+ }
141
+ if (-not $FeatureName) { throw "FeatureName is empty." }
142
+
143
+ $now = Get-Date
144
+ $date = $now.ToString('yyyy-MM-dd')
145
+ $dateTime = $now.ToString('yyyy-MM-dd HH:mm')
146
+
147
+ $featureSnake = $FeatureKey.ToLower()
148
+ $featurePascal = ConvertTo-PascalCase -Text $FeatureName
149
+ if (-not $featurePascal) {
150
+ $featurePascal = ConvertTo-PascalCase -Text $FeatureKey
151
+ }
152
+
153
+ $stack = Get-PropValue -Object $config -Name 'stack'
154
+ $commands = Get-PropValue -Object $config -Name 'commands'
155
+
156
+ $stackBackend = Get-StringOrDefault -Value (Get-PropValue -Object $stack -Name 'backend') -Default 'TBD'
157
+ $stackFrontend = Get-StringOrDefault -Value (Get-PropValue -Object $stack -Name 'frontend') -Default 'TBD'
158
+ $stackMobile = Get-StringOrDefault -Value (Get-PropValue -Object $stack -Name 'mobile') -Default 'TBD'
159
+ $stackDatabase = Get-StringOrDefault -Value (Get-PropValue -Object $stack -Name 'database') -Default 'TBD'
160
+ $stackAuth = Get-StringOrDefault -Value (Get-PropValue -Object $stack -Name 'auth') -Default 'TBD'
161
+
162
+ $cmdBackendTests = Get-StringOrDefault -Value (Get-PropValue -Object $commands -Name 'backendTests') -Default 'TBD'
163
+ $cmdBackendTypecheck = Get-StringOrDefault -Value (Get-PropValue -Object $commands -Name 'backendTypecheck') -Default 'TBD'
164
+ $cmdBackendLint = Get-StringOrDefault -Value (Get-PropValue -Object $commands -Name 'backendLint') -Default 'TBD'
165
+ $cmdFrontendTests = Get-StringOrDefault -Value (Get-PropValue -Object $commands -Name 'frontendTests') -Default 'TBD'
166
+ $cmdFrontendLint = Get-StringOrDefault -Value (Get-PropValue -Object $commands -Name 'frontendLint') -Default 'TBD'
167
+ $cmdE2eTests = Get-StringOrDefault -Value (Get-PropValue -Object $commands -Name 'e2eTests') -Default 'TBD'
168
+
169
+ $tokens = @{
170
+ FEATURE_KEY = $FeatureKey
171
+ FEATURE_NAME = $FeatureName
172
+ FEATURE_PASCAL = $featurePascal
173
+ FEATURE_SNAKE = $featureSnake
174
+ DATE = $date
175
+ DATETIME = $dateTime
176
+
177
+ STACK_BACKEND = $stackBackend
178
+ STACK_FRONTEND = $stackFrontend
179
+ STACK_MOBILE = $stackMobile
180
+ STACK_DATABASE = $stackDatabase
181
+ STACK_AUTH = $stackAuth
182
+
183
+ CMD_BACKEND_TESTS = $cmdBackendTests
184
+ CMD_BACKEND_TYPECHECK = $cmdBackendTypecheck
185
+ CMD_BACKEND_LINT = $cmdBackendLint
186
+ CMD_FRONTEND_TESTS = $cmdFrontendTests
187
+ CMD_FRONTEND_LINT = $cmdFrontendLint
188
+ CMD_E2E_TESTS = $cmdE2eTests
189
+ }
190
+
191
+ $outputs = @(
192
+ @{ Dest = (Join-Path $projectRoot 'SHARED_PLANNING.md'); Template = (Join-Path $templateRoot 'SHARED_PLANNING.md') },
193
+ @{ Dest = (Join-Path $projectRoot 'QUALITY_CHECKLIST.md'); Template = (Join-Path $templateRoot 'QUALITY_CHECKLIST.md') },
194
+
195
+ @{ Dest = (Join-Path $projectRoot "docs/product/PROJECT_INITIATION_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/product/PROJECT_INITIATION_TEMPLATE.md') },
196
+ @{ Dest = (Join-Path $projectRoot "docs/specs/BA_SPEC_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/specs/BA_SPEC_TEMPLATE.md') },
197
+ @{ Dest = (Join-Path $projectRoot "docs/specs/${FeatureKey}_FLOW_ACTION_SPEC.md"); Template = (Join-Path $templateRoot 'docs/specs/FLOW_ACTION_SPEC_TEMPLATE.md') },
198
+ @{ Dest = (Join-Path $projectRoot "docs/product/PRD_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/product/PRD_TEMPLATE.md') },
199
+ @{ Dest = (Join-Path $projectRoot "docs/product/BACKLOG_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/product/BACKLOG_TEMPLATE.md') },
200
+ @{ Dest = (Join-Path $projectRoot "docs/architecture/ARCH_DESIGN_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/architecture/ARCH_DESIGN_TEMPLATE.md') },
201
+ @{ Dest = (Join-Path $projectRoot "docs/database/DATABASE_SPEC_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/database/DATABASE_SPEC_TEMPLATE.md') },
202
+
203
+ @{ Dest = (Join-Path $projectRoot "docs/api/${featurePascal}_API.yaml"); Template = (Join-Path $templateRoot 'docs/api/FEATURE_API_TEMPLATE.yaml') },
204
+ @{ Dest = (Join-Path $projectRoot "docs/api/${FeatureKey}_ENDPOINTS.md"); Template = (Join-Path $templateRoot 'docs/api/API_ENDPOINTS_TEMPLATE.md') },
205
+ @{ Dest = (Join-Path $projectRoot "docs/api/${FeatureKey}_API_DESIGN_DETAIL.md"); Template = (Join-Path $templateRoot 'docs/api/API_DESIGN_DETAIL_TEMPLATE.md') },
206
+ @{ Dest = (Join-Path $projectRoot "docs/api/${featureSnake}_api_flow_list.txt"); Template = (Join-Path $templateRoot 'docs/api/feature_api_flow_list_TEMPLATE.txt') },
207
+ @{ Dest = (Join-Path $projectRoot "docs/design/DESIGN_LAYOUT_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/design/DESIGN_LAYOUT_TEMPLATE.md') },
208
+
209
+ @{ Dest = (Join-Path $projectRoot "docs/dev/FEATURE_IMPL_PLAN_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/dev/FEATURE_IMPL_PLAN_TEMPLATE.md') },
210
+ @{ Dest = (Join-Path $projectRoot "docs/qa/${FeatureKey}_TEST_CASE.md"); Template = (Join-Path $templateRoot 'docs/qa/TEST_CASE_TEMPLATE.md') },
211
+ @{ Dest = (Join-Path $projectRoot "docs/qa/QA_RELEASE_REPORT_$FeatureKey.md"); Template = (Join-Path $templateRoot 'docs/qa/QA_RELEASE_REPORT_TEMPLATE.md') }
212
+ )
213
+
214
+ if ($ValidateOnly) {
215
+ foreach ($item in $outputs) {
216
+ $tmpl = [string]$item.Template
217
+ if (-not (Test-Path -LiteralPath $tmpl)) {
218
+ throw "Missing template file: $tmpl"
219
+ }
220
+ }
221
+
222
+ Write-Host "Validation only: inputs and templates are valid."
223
+ Write-Host "No files were written because -ValidateOnly was specified."
224
+ return
225
+ }
226
+
227
+ $created = New-Object System.Collections.Generic.List[string]
228
+ foreach ($item in $outputs) {
229
+ $dest = [string]$item.Dest
230
+ $tmpl = [string]$item.Template
231
+ if (-not (Test-Path -LiteralPath $tmpl)) {
232
+ throw "Missing template file: $tmpl"
233
+ }
234
+
235
+ $willOverwrite = (Test-Path -LiteralPath $dest)
236
+ Write-RenderedFile -DestinationPath $dest -TemplatePath $tmpl -Tokens $tokens -Overwrite ([bool]$Force)
237
+ if (-not $willOverwrite) {
238
+ $created.Add($dest) | Out-Null
239
+ }
240
+ }
241
+
242
+ Write-Host "Initialized feature: $FeatureKey ($FeatureName)"
243
+ Write-Host "FeaturePascal: $featurePascal"
244
+ Write-Host "FeatureSnake: $featureSnake"
245
+
246
+ if ($created.Count -gt 0) {
247
+ Write-Host ""
248
+ Write-Host "Created files:"
249
+ $created | ForEach-Object { Write-Host " - $_" }
250
+ } else {
251
+ Write-Host ""
252
+ Write-Host "No new files created (all existed); use -Force to overwrite if needed."
253
+ }
@@ -0,0 +1,181 @@
1
+ param(
2
+ [switch]$Force
3
+ )
4
+
5
+ $ErrorActionPreference = 'Stop'
6
+ Set-StrictMode -Version Latest
7
+
8
+ function Get-FileSha256 {
9
+ param(
10
+ [Parameter(Mandatory = $true)][string]$Path
11
+ )
12
+
13
+ if (-not (Test-Path -LiteralPath $Path)) {
14
+ return $null
15
+ }
16
+
17
+ $stream = [System.IO.File]::OpenRead($Path)
18
+ try {
19
+ $sha = [System.Security.Cryptography.SHA256]::Create()
20
+ $hashBytes = $sha.ComputeHash($stream)
21
+ return [BitConverter]::ToString($hashBytes).Replace('-', '')
22
+ } finally {
23
+ $stream.Close()
24
+ }
25
+ }
26
+
27
+ $repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..')
28
+ $skillsSrc = Join-Path $repoRoot 'skills'
29
+ $canonicalRulesPath = Join-Path $repoRoot 'templates/docs/api/FLOWCHART_CREATION_RULES.md'
30
+ $canonicalRulesHash = Get-FileSha256 -Path $canonicalRulesPath
31
+ $canonicalApiDesignRulesPath = Join-Path $repoRoot 'templates/docs/api/API_DESIGN_CREATION_RULES.md'
32
+ $canonicalApiDesignRulesHash = Get-FileSha256 -Path $canonicalApiDesignRulesPath
33
+ $canonicalFlowRulesPath = Join-Path $repoRoot 'templates/docs/specs/FLOW_ACTION_SPEC_CREATION_RULES.md'
34
+ $canonicalFlowRulesHash = Get-FileSha256 -Path $canonicalFlowRulesPath
35
+ $canonicalTestCaseRulesPath = Join-Path $repoRoot 'templates/docs/qa/TEST_CASE_CREATION_RULES.md'
36
+ $canonicalTestCaseRulesHash = Get-FileSha256 -Path $canonicalTestCaseRulesPath
37
+
38
+ if (-not (Test-Path -LiteralPath $skillsSrc)) {
39
+ throw "Missing skills directory: $skillsSrc"
40
+ }
41
+
42
+ $codexHome = $env:CODEX_HOME
43
+ if (-not $codexHome) {
44
+ $codexHome = Join-Path $HOME '.codex'
45
+ }
46
+
47
+ $skillsDest = Join-Path $codexHome 'skills'
48
+ New-Item -ItemType Directory -Force -Path $skillsDest | Out-Null
49
+
50
+ Get-ChildItem -LiteralPath $skillsSrc -Directory | ForEach-Object {
51
+ $dest = Join-Path $skillsDest $_.Name
52
+ if (Test-Path -LiteralPath $dest) {
53
+ if (-not $Force) {
54
+ Write-Warning "Skill already installed (skipping). Use -Force to overwrite: $($_.Name)"
55
+ $existingSkillRulesPath = Join-Path $dest 'references/FLOWCHART_CREATION_RULES.md'
56
+ $existingSkillRulesHash = Get-FileSha256 -Path $existingSkillRulesPath
57
+ if ($existingSkillRulesHash) {
58
+ if ($canonicalRulesHash -and ($existingSkillRulesHash -eq $canonicalRulesHash)) {
59
+ Write-Host " - Existing ruleset: FLOWCHART_CREATION_RULES.md (SHA256=$existingSkillRulesHash, source-sync=OK)"
60
+ } elseif ($canonicalRulesHash) {
61
+ Write-Warning " - Existing ruleset hash mismatch for $($_.Name): skill=$existingSkillRulesHash template=$canonicalRulesHash"
62
+ } else {
63
+ Write-Host " - Existing ruleset: FLOWCHART_CREATION_RULES.md (SHA256=$existingSkillRulesHash)"
64
+ }
65
+ }
66
+ $existingFlowRulesPath = Join-Path $dest 'references/FLOW_ACTION_SPEC_CREATION_RULES.md'
67
+ $existingFlowRulesHash = Get-FileSha256 -Path $existingFlowRulesPath
68
+ if ($existingFlowRulesHash) {
69
+ if ($canonicalFlowRulesHash -and ($existingFlowRulesHash -eq $canonicalFlowRulesHash)) {
70
+ Write-Host " - Existing ruleset: FLOW_ACTION_SPEC_CREATION_RULES.md (SHA256=$existingFlowRulesHash, source-sync=OK)"
71
+ } elseif ($canonicalFlowRulesHash) {
72
+ Write-Warning " - Existing ruleset hash mismatch for $($_.Name): skill=$existingFlowRulesHash template=$canonicalFlowRulesHash"
73
+ } else {
74
+ Write-Host " - Existing ruleset: FLOW_ACTION_SPEC_CREATION_RULES.md (SHA256=$existingFlowRulesHash)"
75
+ }
76
+ }
77
+ $existingApiDesignRulesPath = Join-Path $dest 'references/API_DESIGN_CREATION_RULES.md'
78
+ $existingApiDesignRulesHash = Get-FileSha256 -Path $existingApiDesignRulesPath
79
+ if ($existingApiDesignRulesHash) {
80
+ if ($canonicalApiDesignRulesHash -and ($existingApiDesignRulesHash -eq $canonicalApiDesignRulesHash)) {
81
+ Write-Host " - Existing ruleset: API_DESIGN_CREATION_RULES.md (SHA256=$existingApiDesignRulesHash, source-sync=OK)"
82
+ } elseif ($canonicalApiDesignRulesHash) {
83
+ Write-Warning " - Existing ruleset hash mismatch for $($_.Name): skill=$existingApiDesignRulesHash template=$canonicalApiDesignRulesHash"
84
+ } else {
85
+ Write-Host " - Existing ruleset: API_DESIGN_CREATION_RULES.md (SHA256=$existingApiDesignRulesHash)"
86
+ }
87
+ }
88
+ $existingTestCaseRulesPath = Join-Path $dest 'references/TEST_CASE_CREATION_RULES.md'
89
+ $existingTestCaseRulesHash = Get-FileSha256 -Path $existingTestCaseRulesPath
90
+ if ($existingTestCaseRulesHash) {
91
+ if ($canonicalTestCaseRulesHash -and ($existingTestCaseRulesHash -eq $canonicalTestCaseRulesHash)) {
92
+ Write-Host " - Existing ruleset: TEST_CASE_CREATION_RULES.md (SHA256=$existingTestCaseRulesHash, source-sync=OK)"
93
+ } elseif ($canonicalTestCaseRulesHash) {
94
+ Write-Warning " - Existing ruleset hash mismatch for $($_.Name): skill=$existingTestCaseRulesHash template=$canonicalTestCaseRulesHash"
95
+ } else {
96
+ Write-Host " - Existing ruleset: TEST_CASE_CREATION_RULES.md (SHA256=$existingTestCaseRulesHash)"
97
+ }
98
+ }
99
+ return
100
+ }
101
+ Remove-Item -LiteralPath $dest -Recurse -Force
102
+ }
103
+ Copy-Item -LiteralPath $_.FullName -Destination $dest -Recurse -Force
104
+ Write-Host "Installed: $($_.Name)"
105
+
106
+ $skillRulesPath = Join-Path $dest 'references/FLOWCHART_CREATION_RULES.md'
107
+ $skillRulesHash = Get-FileSha256 -Path $skillRulesPath
108
+ if ($skillRulesHash) {
109
+ if ($canonicalRulesHash -and ($skillRulesHash -eq $canonicalRulesHash)) {
110
+ Write-Host " - Ruleset: FLOWCHART_CREATION_RULES.md (SHA256=$skillRulesHash, source-sync=OK)"
111
+ } elseif ($canonicalRulesHash) {
112
+ Write-Warning " - Ruleset hash mismatch for $($_.Name): skill=$skillRulesHash template=$canonicalRulesHash"
113
+ } else {
114
+ Write-Host " - Ruleset: FLOWCHART_CREATION_RULES.md (SHA256=$skillRulesHash)"
115
+ }
116
+ }
117
+
118
+ $skillFlowRulesPath = Join-Path $dest 'references/FLOW_ACTION_SPEC_CREATION_RULES.md'
119
+ $skillFlowRulesHash = Get-FileSha256 -Path $skillFlowRulesPath
120
+ if ($skillFlowRulesHash) {
121
+ if ($canonicalFlowRulesHash -and ($skillFlowRulesHash -eq $canonicalFlowRulesHash)) {
122
+ Write-Host " - Ruleset: FLOW_ACTION_SPEC_CREATION_RULES.md (SHA256=$skillFlowRulesHash, source-sync=OK)"
123
+ } elseif ($canonicalFlowRulesHash) {
124
+ Write-Warning " - Ruleset hash mismatch for $($_.Name): skill=$skillFlowRulesHash template=$canonicalFlowRulesHash"
125
+ } else {
126
+ Write-Host " - Ruleset: FLOW_ACTION_SPEC_CREATION_RULES.md (SHA256=$skillFlowRulesHash)"
127
+ }
128
+ }
129
+
130
+ $skillApiDesignRulesPath = Join-Path $dest 'references/API_DESIGN_CREATION_RULES.md'
131
+ $skillApiDesignRulesHash = Get-FileSha256 -Path $skillApiDesignRulesPath
132
+ if ($skillApiDesignRulesHash) {
133
+ if ($canonicalApiDesignRulesHash -and ($skillApiDesignRulesHash -eq $canonicalApiDesignRulesHash)) {
134
+ Write-Host " - Ruleset: API_DESIGN_CREATION_RULES.md (SHA256=$skillApiDesignRulesHash, source-sync=OK)"
135
+ } elseif ($canonicalApiDesignRulesHash) {
136
+ Write-Warning " - Ruleset hash mismatch for $($_.Name): skill=$skillApiDesignRulesHash template=$canonicalApiDesignRulesHash"
137
+ } else {
138
+ Write-Host " - Ruleset: API_DESIGN_CREATION_RULES.md (SHA256=$skillApiDesignRulesHash)"
139
+ }
140
+ }
141
+
142
+ $skillTestCaseRulesPath = Join-Path $dest 'references/TEST_CASE_CREATION_RULES.md'
143
+ $skillTestCaseRulesHash = Get-FileSha256 -Path $skillTestCaseRulesPath
144
+ if ($skillTestCaseRulesHash) {
145
+ if ($canonicalTestCaseRulesHash -and ($skillTestCaseRulesHash -eq $canonicalTestCaseRulesHash)) {
146
+ Write-Host " - Ruleset: TEST_CASE_CREATION_RULES.md (SHA256=$skillTestCaseRulesHash, source-sync=OK)"
147
+ } elseif ($canonicalTestCaseRulesHash) {
148
+ Write-Warning " - Ruleset hash mismatch for $($_.Name): skill=$skillTestCaseRulesHash template=$canonicalTestCaseRulesHash"
149
+ } else {
150
+ Write-Host " - Ruleset: TEST_CASE_CREATION_RULES.md (SHA256=$skillTestCaseRulesHash)"
151
+ }
152
+ }
153
+ }
154
+
155
+ Write-Host ""
156
+ Write-Host "Skills installed into: $skillsDest"
157
+ if ($canonicalRulesHash) {
158
+ Write-Host "Canonical API ruleset: $canonicalRulesPath"
159
+ Write-Host "Canonical API ruleset SHA256: $canonicalRulesHash"
160
+ } else {
161
+ Write-Warning "Canonical API ruleset not found: $canonicalRulesPath"
162
+ }
163
+ if ($canonicalApiDesignRulesHash) {
164
+ Write-Host "Canonical API design ruleset: $canonicalApiDesignRulesPath"
165
+ Write-Host "Canonical API design ruleset SHA256: $canonicalApiDesignRulesHash"
166
+ } else {
167
+ Write-Warning "Canonical API design ruleset not found: $canonicalApiDesignRulesPath"
168
+ }
169
+ if ($canonicalFlowRulesHash) {
170
+ Write-Host "Canonical Flow Action ruleset: $canonicalFlowRulesPath"
171
+ Write-Host "Canonical Flow Action ruleset SHA256: $canonicalFlowRulesHash"
172
+ } else {
173
+ Write-Warning "Canonical Flow Action ruleset not found: $canonicalFlowRulesPath"
174
+ }
175
+ if ($canonicalTestCaseRulesHash) {
176
+ Write-Host "Canonical Test Case ruleset: $canonicalTestCaseRulesPath"
177
+ Write-Host "Canonical Test Case ruleset SHA256: $canonicalTestCaseRulesHash"
178
+ } else {
179
+ Write-Warning "Canonical Test Case ruleset not found: $canonicalTestCaseRulesPath"
180
+ }
181
+ Write-Host "Restart Codex to pick up new skills."