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.
- package/README.md +131 -0
- package/assets/manifest/toolkit-bundle.manifest.json +303 -0
- package/assets/manifest/toolkit-bundle.sha256.txt +59 -0
- package/assets/toolkit/toolkit/AGENTS.md +103 -0
- package/assets/toolkit/toolkit/install.ps1 +155 -0
- package/assets/toolkit/toolkit/runtimes/claude/CLAUDE_TEMPLATE.md +32 -0
- package/assets/toolkit/toolkit/runtimes/codex/CODEX_TEMPLATE.md +32 -0
- package/assets/toolkit/toolkit/scripts/init-feature.ps1 +253 -0
- package/assets/toolkit/toolkit/scripts/install-codex-skills.ps1 +181 -0
- package/assets/toolkit/toolkit/scripts/uninstall-codex-skills.ps1 +116 -0
- package/assets/toolkit/toolkit/sdtk.config.json +28 -0
- package/assets/toolkit/toolkit/sdtk.config.profiles.example.json +50 -0
- package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/SKILL.md +78 -0
- package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/references/API_DESIGN_CREATION_RULES.md +212 -0
- package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/references/FLOWCHART_CREATION_RULES.md +397 -0
- package/assets/toolkit/toolkit/skills/sdtk-api-design-spec/scripts/generate_api_design_detail.py +565 -0
- package/assets/toolkit/toolkit/skills/sdtk-api-doc/SKILL.md +36 -0
- package/assets/toolkit/toolkit/skills/sdtk-api-doc/references/FLOWCHART_CREATION_RULES.md +397 -0
- package/assets/toolkit/toolkit/skills/sdtk-arch/SKILL.md +43 -0
- package/assets/toolkit/toolkit/skills/sdtk-arch/references/API_DESIGN_CREATION_RULES.md +212 -0
- package/assets/toolkit/toolkit/skills/sdtk-arch/references/FLOWCHART_CREATION_RULES.md +397 -0
- package/assets/toolkit/toolkit/skills/sdtk-arch/references/FLOW_ACTION_SPEC_CREATION_RULES.md +136 -0
- package/assets/toolkit/toolkit/skills/sdtk-ba/SKILL.md +24 -0
- package/assets/toolkit/toolkit/skills/sdtk-design-layout/SKILL.md +21 -0
- package/assets/toolkit/toolkit/skills/sdtk-dev/SKILL.md +20 -0
- package/assets/toolkit/toolkit/skills/sdtk-dev-backend/SKILL.md +17 -0
- package/assets/toolkit/toolkit/skills/sdtk-dev-frontend/SKILL.md +15 -0
- package/assets/toolkit/toolkit/skills/sdtk-orchestrator/SKILL.md +44 -0
- package/assets/toolkit/toolkit/skills/sdtk-pm/SKILL.md +26 -0
- package/assets/toolkit/toolkit/skills/sdtk-qa/SKILL.md +22 -0
- package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/SKILL.md +59 -0
- package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/FLOW_ACTION_SPEC_CREATION_RULES.md +136 -0
- package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/excel-image-export.md +51 -0
- package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/figma-mcp.md +54 -0
- package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/references/numbering-rules.md +76 -0
- package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/scripts/renumber_flow_action_spec_global.py +136 -0
- package/assets/toolkit/toolkit/skills/sdtk-screen-design-spec/scripts/validate_flow_action_spec_numbering.py +249 -0
- package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/SKILL.md +65 -0
- package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/references/TEST_CASE_CREATION_RULES.md +129 -0
- package/assets/toolkit/toolkit/skills/sdtk-test-case-spec/scripts/validate_test_case_spec.py +97 -0
- package/assets/toolkit/toolkit/templates/QUALITY_CHECKLIST.md +124 -0
- package/assets/toolkit/toolkit/templates/README.md +56 -0
- package/assets/toolkit/toolkit/templates/SHARED_PLANNING.md +80 -0
- package/assets/toolkit/toolkit/templates/docs/api/API_DESIGN_CREATION_RULES.md +212 -0
- package/assets/toolkit/toolkit/templates/docs/api/API_DESIGN_DETAIL_TEMPLATE.md +62 -0
- package/assets/toolkit/toolkit/templates/docs/api/API_ENDPOINTS_TEMPLATE.md +229 -0
- package/assets/toolkit/toolkit/templates/docs/api/FEATURE_API_TEMPLATE.yaml +20 -0
- package/assets/toolkit/toolkit/templates/docs/api/FLOWCHART_CREATION_RULES.md +397 -0
- package/assets/toolkit/toolkit/templates/docs/api/feature_api_flow_list_TEMPLATE.txt +12 -0
- package/assets/toolkit/toolkit/templates/docs/architecture/ARCH_DESIGN_TEMPLATE.md +109 -0
- package/assets/toolkit/toolkit/templates/docs/database/DATABASE_SPEC_TEMPLATE.md +175 -0
- package/assets/toolkit/toolkit/templates/docs/design/DESIGN_LAYOUT_TEMPLATE.md +49 -0
- package/assets/toolkit/toolkit/templates/docs/dev/FEATURE_IMPL_PLAN_TEMPLATE.md +73 -0
- package/assets/toolkit/toolkit/templates/docs/product/BACKLOG_TEMPLATE.md +50 -0
- package/assets/toolkit/toolkit/templates/docs/product/PRD_TEMPLATE.md +66 -0
- package/assets/toolkit/toolkit/templates/docs/product/PROJECT_INITIATION_TEMPLATE.md +98 -0
- package/assets/toolkit/toolkit/templates/docs/qa/QA_RELEASE_REPORT_TEMPLATE.md +61 -0
- package/assets/toolkit/toolkit/templates/docs/qa/TEST_CASE_CREATION_RULES.md +129 -0
- package/assets/toolkit/toolkit/templates/docs/qa/TEST_CASE_TEMPLATE.md +104 -0
- package/assets/toolkit/toolkit/templates/docs/specs/BA_SPEC_TEMPLATE.md +139 -0
- package/assets/toolkit/toolkit/templates/docs/specs/FLOW_ACTION_SPEC_CREATION_RULES.md +136 -0
- package/assets/toolkit/toolkit/templates/docs/specs/FLOW_ACTION_SPEC_TEMPLATE.md +160 -0
- package/bin/sdtk.js +15 -0
- package/package.json +47 -0
- package/src/commands/auth.js +85 -0
- package/src/commands/generate.js +177 -0
- package/src/commands/help.js +69 -0
- package/src/commands/init.js +73 -0
- package/src/index.js +56 -0
- package/src/lib/args.js +116 -0
- package/src/lib/errors.js +41 -0
- package/src/lib/github-access.js +68 -0
- package/src/lib/powershell.js +85 -0
- package/src/lib/state.js +83 -0
- 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."
|