vibesuite 1.0.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 (117) hide show
  1. package/.agent/skills/agent-recovery/SKILL.md +147 -0
  2. package/.agent/skills/code-review/SKILL.md +81 -0
  3. package/.agent/skills/component-analysis/SKILL.md +103 -0
  4. package/.agent/skills/git-worktree/SKILL.md +78 -0
  5. package/.agent/skills/github-ops/SKILL.md +220 -0
  6. package/.agent/skills/github-ops/scripts/publish_issues.ps1 +443 -0
  7. package/.agent/skills/github-ops/scripts/smart-ops.ps1 +128 -0
  8. package/.agent/skills/github-ops/scripts/smart-ops.sh +130 -0
  9. package/.agent/skills/google-trends/SKILL.md +157 -0
  10. package/.agent/skills/google-trends/scripts/node_modules/.modules.yaml +21 -0
  11. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/LICENSE +22 -0
  12. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/Readme.md +1157 -0
  13. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/esm.mjs +16 -0
  14. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/index.js +24 -0
  15. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/argument.js +149 -0
  16. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js +2509 -0
  17. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/error.js +39 -0
  18. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/help.js +520 -0
  19. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/option.js +330 -0
  20. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/suggestSimilar.js +101 -0
  21. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/package-support.json +16 -0
  22. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/package.json +84 -0
  23. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/typings/esm.d.mts +3 -0
  24. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/commander@12.1.0/node_modules/commander/typings/index.d.ts +969 -0
  25. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/CHANGES.md +132 -0
  26. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/LICENSE +21 -0
  27. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/README.md +561 -0
  28. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/lib/google-trends-api.min.js +2 -0
  29. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/package.json +68 -0
  30. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/src/api.js +18 -0
  31. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/src/index.js +27 -0
  32. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/src/request.js +69 -0
  33. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/google-trends-api@4.9.2/node_modules/google-trends-api/src/utilities.js +395 -0
  34. package/.agent/skills/google-trends/scripts/node_modules/.pnpm/lock.yaml +31 -0
  35. package/.agent/skills/google-trends/scripts/node_modules/.pnpm-workspace-state-v1.json +25 -0
  36. package/.agent/skills/google-trends/scripts/package.json +17 -0
  37. package/.agent/skills/google-trends/scripts/pnpm-lock.yaml +31 -0
  38. package/.agent/skills/google-trends/scripts/search.js +168 -0
  39. package/.agent/skills/high-fidelity-extraction/SKILL.md +59 -0
  40. package/.agent/skills/prime-agent/SKILL.md +97 -0
  41. package/.agent/skills/security-audit/SKILL.md +81 -0
  42. package/.agent/skills/seo-ready/SKILL.md +133 -0
  43. package/.agent/skills/spawn-task/SKILL.md +130 -0
  44. package/.agent/skills/sync-docs/SKILL.md +88 -0
  45. package/.agent/skills/vercel-ai-sdk/SKILL.md +34083 -0
  46. package/.agent/skills/youtube-pipeline/SKILL.md +194 -0
  47. package/.agent/skills/youtube-pipeline/resources/youtube-phase1-strategy.md +224 -0
  48. package/.agent/skills/youtube-pipeline/resources/youtube-phase2-packaging.md +148 -0
  49. package/.agent/skills/youtube-pipeline/resources/youtube-phase3-scripting.md +197 -0
  50. package/.agent/skills/youtube-pipeline/resources/youtube-phase3.5-shorts.md +271 -0
  51. package/.agent/skills/youtube-pipeline/resources/youtube-phase4-production.md +193 -0
  52. package/.agent/skills/youtube-pipeline/resources/youtube-phase5-repurposing.md +159 -0
  53. package/.agent/skills/youtube-pipeline/resources/youtube-pipeline.md +161 -0
  54. package/.agent/skills/youtube-pipeline/scripts/parse_yt_studio.ps1 +150 -0
  55. package/.agent/workflows/LEGACY/ANTIGRAVITY_TOOLBOX.md +200 -0
  56. package/.agent/workflows/LEGACY/analyze_component.md +141 -0
  57. package/.agent/workflows/LEGACY/build_vibecode_project.md +154 -0
  58. package/.agent/workflows/LEGACY/deep_code_audit.md +79 -0
  59. package/.agent/workflows/LEGACY/gemini-orchestrate.md +63 -0
  60. package/.agent/workflows/LEGACY/git_worktree.md +71 -0
  61. package/.agent/workflows/LEGACY/init_smart_ops.md +101 -0
  62. package/.agent/workflows/LEGACY/multi_agent_strategy.md +62 -0
  63. package/.agent/workflows/LEGACY/orchestrate.md +321 -0
  64. package/.agent/workflows/LEGACY/seo_ready.md +249 -0
  65. package/.agent/workflows/LEGACY/vibe-orchestrator.md +305 -0
  66. package/.agent/workflows/LEGACY/youtube-phase1-strategy.md +224 -0
  67. package/.agent/workflows/LEGACY/youtube-phase2-packaging.md +148 -0
  68. package/.agent/workflows/LEGACY/youtube-phase3-scripting.md +197 -0
  69. package/.agent/workflows/LEGACY/youtube-phase3.5-shorts.md +271 -0
  70. package/.agent/workflows/LEGACY/youtube-phase4-production.md +193 -0
  71. package/.agent/workflows/LEGACY/youtube-phase5-repurposing.md +159 -0
  72. package/.agent/workflows/LEGACY/youtube-pipeline.md +161 -0
  73. package/.agent/workflows/README.md +349 -0
  74. package/.agent/workflows/Vercel Ai SDK.md +34083 -0
  75. package/.agent/workflows/agent_reset.md +138 -0
  76. package/.agent/workflows/build_vibecode_project_v2.md +158 -0
  77. package/.agent/workflows/escalate.md +112 -0
  78. package/.agent/workflows/init_vibecode_design.md +98 -0
  79. package/.agent/workflows/init_vibecode_genesis.md +137 -0
  80. package/.agent/workflows/migrate.md +135 -0
  81. package/.agent/workflows/prime_agent.md +211 -0
  82. package/.agent/workflows/reverse_genesis.md +132 -0
  83. package/.agent/workflows/review_code.md +133 -0
  84. package/.agent/workflows/spawn-jstar-code-review.md +121 -0
  85. package/.agent/workflows/spawn_task.md +187 -0
  86. package/.agent/workflows/sync_docs.md +90 -0
  87. package/Legacy (Manual Method)/0 VibeCode User Manual.md +173 -0
  88. package/Legacy (Manual Method)/1 Project Genesis Protocol The VibeCode Workflow.md +89 -0
  89. package/Legacy (Manual Method)/2/342/234/250 ULTIMATE ORCHESTRATION PROMPT/342/234/250.md" +114 -0
  90. package/Legacy (Manual Method)/3 Design System Genesis Protocol.md +75 -0
  91. package/Legacy (Manual Method)/3.1.1 my_design_system_rules.md +177 -0
  92. package/Legacy (Manual Method)/3.1.2 Material You M3 Genesis Protocol.md +73 -0
  93. package/Legacy (Manual Method)/4 The Ultimate GitHub Issue Meta-Prompt Template.md +54 -0
  94. package/Legacy (Manual Method)/5 The Escalation & Handoff Protocol.md +97 -0
  95. package/Legacy (Manual Method)/8 The Seamless Migration Meta-Prompt (Your Reusable Tool).md +38 -0
  96. package/Legacy (Manual Method)/9 The Reverse Genesis Protocol.md +75 -0
  97. package/README.md +209 -0
  98. package/VibeCode-Agents (e.g Kilo-code)/README.md +142 -0
  99. package/VibeCode-Agents (e.g Kilo-code)/vibe-analyzer.yaml +254 -0
  100. package/VibeCode-Agents (e.g Kilo-code)/vibe-architect.yaml +397 -0
  101. package/VibeCode-Agents (e.g Kilo-code)/vibe-auditor.yaml +325 -0
  102. package/VibeCode-Agents (e.g Kilo-code)/vibe-builder.yaml +472 -0
  103. package/VibeCode-Agents (e.g Kilo-code)/vibe-designer.yaml +305 -0
  104. package/VibeCode-Agents (e.g Kilo-code)/vibe-documentor.yaml +222 -0
  105. package/VibeCode-Agents (e.g Kilo-code)/vibe-escalator.yaml +255 -0
  106. package/VibeCode-Agents (e.g Kilo-code)/vibe-isolator.yaml +332 -0
  107. package/VibeCode-Agents (e.g Kilo-code)/vibe-onboarder.yaml +335 -0
  108. package/VibeCode-Agents (e.g Kilo-code)/vibe-orchestrator.yaml +365 -0
  109. package/VibeCode-Agents (e.g Kilo-code)/vibe-orchestrator_legacy.yaml +284 -0
  110. package/VibeCode-Agents (e.g Kilo-code)/vibe-orchestrator_v1.yaml +336 -0
  111. package/VibeCode-Agents (e.g Kilo-code)/vibe-primer.yaml +213 -0
  112. package/VibeCode-Agents (e.g Kilo-code)/vibe-reviewer.yaml +233 -0
  113. package/VibeCode-Agents (e.g Kilo-code)/vibe-spawner.yaml +259 -0
  114. package/bin/vibesuite.js +2 -0
  115. package/package.json +43 -0
  116. package/src/cli.js +159 -0
  117. package/src/utils.js +76 -0
@@ -0,0 +1,443 @@
1
+ param(
2
+ [switch]$DryRun = $false,
3
+ [switch]$Update = $false, # Update existing issues instead of skipping
4
+ [switch]$SyncDates = $false, # Sync dates to GitHub Project
5
+ [switch]$AutoArchive = $false, # Move completed issues to closed/ subfolder
6
+ [switch]$Force = $false, # Force sync all files (ignore change detection)
7
+
8
+ # Required for SyncDates (auto-detected from repo if not provided)
9
+ [string]$ProjectOwner = "",
10
+ [int]$ProjectNumber = 0,
11
+ [string]$ProjectId = "",
12
+ [string]$StartDateFieldId = "",
13
+ [string]$TargetDateFieldId = "",
14
+ [int]$TargetWeeks = 4,
15
+
16
+ [string]$IssueDir = "docs/issues"
17
+ )
18
+
19
+ <#
20
+ .SYNOPSIS
21
+ Smart Issue Sync - Syncs markdown issue specs to GitHub with intelligent change detection.
22
+
23
+ .DESCRIPTION
24
+ Features:
25
+ - SMART SYNC: Only processes files that changed since last run (uses .issue-sync-state.json)
26
+ - AUTO-ARCHIVE: Moves completed .md files to closed/ subfolder
27
+ - AUTO-CLOSE: Closes GitHub issues when all checkboxes are ticked
28
+ - NATURAL SORT: Processes Issue_1, Issue_2, ... Issue_10 (not 1, 10, 11)
29
+ - DATE SYNC: Sets Start/Target dates on GitHub Projects
30
+
31
+ .EXAMPLE
32
+ # Smart sync (only changed files)
33
+ .\publish_issues.ps1 -Update -AutoArchive
34
+
35
+ # Force full resync
36
+ .\publish_issues.ps1 -Update -AutoArchive -Force
37
+
38
+ # Dry run
39
+ .\publish_issues.ps1 -Update -AutoArchive -DryRun
40
+ #>
41
+
42
+ # ============ AUTO-DETECT REPO INFO ============
43
+ $repoJson = gh repo view --json owner,name 2>$null | ConvertFrom-Json
44
+ if (-not $repoJson) {
45
+ Write-Host "ERROR: Not in a GitHub repository or gh CLI not authenticated" -ForegroundColor Red
46
+ exit 1
47
+ }
48
+ $REPO_OWNER = $repoJson.owner.login
49
+ $REPO_NAME = $repoJson.name
50
+ $REPO = "$REPO_OWNER/$REPO_NAME"
51
+
52
+ Write-Host "Repository: $REPO" -ForegroundColor Cyan
53
+
54
+ # ============ STATE FILE FOR CHANGE DETECTION ============
55
+ $stateFile = Join-Path $IssueDir ".issue-sync-state.json"
56
+ $syncState = @{}
57
+
58
+ if (Test-Path $stateFile) {
59
+ try {
60
+ $syncState = Get-Content $stateFile -Raw | ConvertFrom-Json -AsHashtable
61
+ } catch {
62
+ $syncState = @{}
63
+ }
64
+ }
65
+
66
+ function Save-SyncState {
67
+ if (-not $DryRun) {
68
+ $syncState | ConvertTo-Json -Depth 10 | Set-Content $stateFile -Encoding UTF8
69
+ }
70
+ }
71
+
72
+ function Get-FileHash256 {
73
+ param([string]$Path)
74
+ $hash = Get-FileHash -Path $Path -Algorithm SHA256
75
+ return $hash.Hash
76
+ }
77
+
78
+ function Test-FileChanged {
79
+ param([string]$FilePath)
80
+
81
+ if ($Force) { return $true }
82
+
83
+ $fileName = Split-Path $FilePath -Leaf
84
+ $currentHash = Get-FileHash256 -Path $FilePath
85
+
86
+ if ($syncState.ContainsKey($fileName)) {
87
+ $lastHash = $syncState[$fileName].hash
88
+ return $currentHash -ne $lastHash
89
+ }
90
+
91
+ return $true # New file, never synced
92
+ }
93
+
94
+ function Update-FileState {
95
+ param(
96
+ [string]$FilePath,
97
+ [string]$Status, # "synced", "archived"
98
+ [int]$IssueNumber = 0
99
+ )
100
+
101
+ $fileName = Split-Path $FilePath -Leaf
102
+ $syncState[$fileName] = @{
103
+ hash = (Get-FileHash256 -Path $FilePath)
104
+ lastSync = (Get-Date -Format "yyyy-MM-ddTHH:mm:ss")
105
+ status = $Status
106
+ issueNumber = $IssueNumber
107
+ }
108
+ }
109
+
110
+ # ============ VALIDATE SYNC DATES CONFIG ============
111
+ if ($SyncDates) {
112
+ if (-not $ProjectOwner) { $ProjectOwner = $REPO_OWNER }
113
+
114
+ $missingConfig = @()
115
+ if ($ProjectNumber -eq 0) { $missingConfig += "-ProjectNumber" }
116
+ if (-not $ProjectId) { $missingConfig += "-ProjectId" }
117
+ if (-not $StartDateFieldId) { $missingConfig += "-StartDateFieldId" }
118
+ if (-not $TargetDateFieldId) { $missingConfig += "-TargetDateFieldId" }
119
+
120
+ if ($missingConfig.Count -gt 0) {
121
+ Write-Host "ERROR: -SyncDates requires: $($missingConfig -join ', ')" -ForegroundColor Red
122
+ exit 1
123
+ }
124
+ }
125
+
126
+ # ============ FIND ISSUE FILES (Natural Sort) ============
127
+ $closedDir = Join-Path $IssueDir "closed"
128
+
129
+ # Get files and sort naturally (Issue_1, Issue_2, ... Issue_10)
130
+ $issueFiles = Get-ChildItem "$IssueDir/*.md" -ErrorAction SilentlyContinue |
131
+ Where-Object { $_.Name -ne "ALL_ISSUES.md" } |
132
+ Sort-Object {
133
+ if ($_.Name -match 'Issue_(\d+)') {
134
+ [int]$matches[1]
135
+ } else {
136
+ $_.Name
137
+ }
138
+ }
139
+
140
+ if ($issueFiles.Count -eq 0) {
141
+ Write-Host "No issue files found in $IssueDir/" -ForegroundColor Yellow
142
+ exit 0
143
+ }
144
+
145
+ Write-Host "Found $($issueFiles.Count) issue files" -ForegroundColor Gray
146
+
147
+ # ============ FILTER TO CHANGED FILES ONLY ============
148
+ $changedFiles = @()
149
+ $skippedFiles = @()
150
+
151
+ foreach ($file in $issueFiles) {
152
+ if (Test-FileChanged -FilePath $file.FullName) {
153
+ $changedFiles += $file
154
+ } else {
155
+ $skippedFiles += $file
156
+ }
157
+ }
158
+
159
+ if ($skippedFiles.Count -gt 0 -and -not $Force) {
160
+ Write-Host "Skipping $($skippedFiles.Count) unchanged files" -ForegroundColor DarkGray
161
+ }
162
+
163
+ if ($changedFiles.Count -eq 0) {
164
+ Write-Host "No files have changed since last sync. Use -Force to resync all." -ForegroundColor Yellow
165
+ exit 0
166
+ }
167
+
168
+ Write-Host "Processing $($changedFiles.Count) changed files..." -ForegroundColor Cyan
169
+ Write-Host ""
170
+
171
+ # ============ CACHE EXISTING ISSUES ============
172
+ Write-Host "Fetching existing GitHub issues..." -ForegroundColor Gray
173
+ $existingIssues = gh issue list --repo $REPO --state all --limit 500 --json number,title,state | ConvertFrom-Json
174
+ $issueTitleMap = @{}
175
+ $issueStateMap = @{}
176
+ foreach ($issue in $existingIssues) {
177
+ $issueTitleMap[$issue.title] = $issue.number
178
+ $issueStateMap[$issue.title] = $issue.state
179
+ }
180
+ Write-Host "Found $($existingIssues.Count) existing issues on GitHub" -ForegroundColor Gray
181
+ Write-Host ""
182
+
183
+ # ============ HELPER FUNCTIONS ============
184
+
185
+ function Ensure-Label {
186
+ param($LabelName)
187
+ if (-not $DryRun) {
188
+ $ErrorActionPreference = "SilentlyContinue"
189
+ gh label create "$LabelName" --repo $REPO --color "0e8a16" 2>$null
190
+ $ErrorActionPreference = "Continue"
191
+ }
192
+ }
193
+
194
+ function Add-ToProject {
195
+ param([int]$IssueNumber)
196
+
197
+ if (-not $SyncDates -or $DryRun) { return }
198
+
199
+ try {
200
+ $url = "https://github.com/$REPO/issues/$IssueNumber"
201
+ gh project item-add $ProjectNumber --owner $ProjectOwner --url $url 2>$null
202
+ } catch { }
203
+ }
204
+
205
+ function Sync-ProjectDates {
206
+ param([int]$IssueNumber, [string]$StartDate, [string]$TargetDate)
207
+
208
+ if (-not $SyncDates) { return }
209
+
210
+ Add-ToProject -IssueNumber $IssueNumber
211
+
212
+ $itemsJson = gh project item-list $ProjectNumber --owner $ProjectOwner --format json 2>$null
213
+ if (-not $itemsJson) { return }
214
+
215
+ $items = $itemsJson | ConvertFrom-Json
216
+ $item = $items.items | Where-Object { $_.content.number -eq $IssueNumber } | Select-Object -First 1
217
+
218
+ if (-not $item) { return }
219
+
220
+ if (-not $DryRun) {
221
+ gh project item-edit --id $item.id --project-id $ProjectId --field-id $StartDateFieldId --date $StartDate 2>$null
222
+ gh project item-edit --id $item.id --project-id $ProjectId --field-id $TargetDateFieldId --date $TargetDate 2>$null
223
+ Write-Host " Dates: $StartDate -> $TargetDate" -ForegroundColor Blue
224
+ }
225
+ }
226
+
227
+ function Parse-IssueMetadata {
228
+ param($Content)
229
+
230
+ $result = @{ title = $null; labels = @() }
231
+
232
+ # Try YAML frontmatter
233
+ if ($Content -match '^---\s*[\r\n]+([\s\S]*?)[\r\n]+---') {
234
+ $yaml = $matches[1]
235
+ if ($yaml -match 'title:\s*["\u0027]?([^"\u0027\r\n]+)["\u0027]?') {
236
+ $result.title = $matches[1].Trim()
237
+ }
238
+ if ($yaml -match 'labels:\s*([^\r\n]+)') {
239
+ $result.labels = ($matches[1].Trim() -split ',') | ForEach-Object { $_.Trim() } | Where-Object { $_ }
240
+ }
241
+ }
242
+
243
+ # Try Bold markdown
244
+ if (-not $result.title -and $Content -match '\*\*Title:\*\*\s*(.+)') {
245
+ $result.title = $matches[1].Trim()
246
+ }
247
+ if ($result.labels.Count -eq 0 -and $Content -match '\*\*Labels:\*\*\s*(.+)') {
248
+ $result.labels = ($matches[1] -replace '`', '' -replace '\s', '' -split ',') | Where-Object { $_ }
249
+ }
250
+
251
+ # Try Markdown headers
252
+ if (-not $result.title -and $Content -match '## Title\s*[\r\n]+(.+)') {
253
+ $result.title = $matches[1].Trim()
254
+ }
255
+ if ($result.labels.Count -eq 0 -and $Content -match '## Labels\s*[\r\n]+(.+)') {
256
+ $result.labels = ($matches[1] -replace '`', '' -replace '\s', '' -split ',') | Where-Object { $_ }
257
+ }
258
+
259
+ return $result
260
+ }
261
+
262
+ function Get-CheckboxStatus {
263
+ param($Content)
264
+
265
+ $unchecked = [regex]::Matches($Content, '[-*]\s*\[\s*\]').Count
266
+ $checked = [regex]::Matches($Content, '[-*]\s*\[[xX]\]').Count
267
+
268
+ return @{
269
+ Total = $unchecked + $checked
270
+ Checked = $checked
271
+ AllComplete = (($unchecked + $checked) -gt 0 -and $unchecked -eq 0)
272
+ }
273
+ }
274
+
275
+ function Move-ToClosedFolder {
276
+ param([string]$FilePath)
277
+
278
+ if (-not $AutoArchive) { return }
279
+
280
+ if (-not (Test-Path $closedDir)) {
281
+ if (-not $DryRun) {
282
+ New-Item -ItemType Directory -Path $closedDir -Force | Out-Null
283
+ }
284
+ }
285
+
286
+ $fileName = Split-Path $FilePath -Leaf
287
+ $destPath = Join-Path $closedDir $fileName
288
+
289
+ if (-not $DryRun) {
290
+ Move-Item -Path $FilePath -Destination $destPath -Force
291
+ # Remove from state since it's archived
292
+ $syncState.Remove($fileName)
293
+ Write-Host " Archived to closed/$fileName" -ForegroundColor DarkMagenta
294
+ } else {
295
+ Write-Host " [DryRun] Would archive to closed/$fileName" -ForegroundColor Gray
296
+ }
297
+ }
298
+
299
+ function Get-CleanIssueBody {
300
+ param($Content)
301
+
302
+ $clean = $Content -replace '(?ms)^---\s*[\r\n]+.*?[\r\n]+---\s*[\r\n]*', ''
303
+ $clean = $clean -replace '(?ms)^## Title.*?(?=##|\Z)', ''
304
+ $clean = $clean -replace '(?ms)^## Labels.*?(?=##|\Z)', ''
305
+ $clean = $clean -replace '(?ms)^# GitHub Issue:.*?(?=##|\Z)', ''
306
+ return $clean.Trim()
307
+ }
308
+
309
+ # ============ MAIN LOOP ============
310
+
311
+ $processedCount = 0
312
+ $archivedCount = 0
313
+
314
+ foreach ($file in $changedFiles) {
315
+ $content = Get-Content $file.FullName -Raw
316
+ $parsed = Parse-IssueMetadata -Content $content
317
+
318
+ if (-not $parsed.title) {
319
+ Write-Warning "Could not find title for $($file.Name) - skipping"
320
+ continue
321
+ }
322
+
323
+ $title = $parsed.title
324
+ # Sanitize title: replace double quotes with single quotes to avoid CLI issues
325
+ $title = $title -replace '"', "'"
326
+ $labelArray = $parsed.labels
327
+ $checkboxStatus = Get-CheckboxStatus -Content $content
328
+ $isComplete = $checkboxStatus.AllComplete
329
+
330
+ # Calculate dates
331
+ $fileInfo = Get-Item $file.FullName
332
+ $startDate = $fileInfo.CreationTime.ToString("yyyy-MM-dd")
333
+ $targetDate = if ($isComplete) {
334
+ $fileInfo.LastWriteTime.ToString("yyyy-MM-dd")
335
+ } else {
336
+ $fileInfo.CreationTime.AddDays($TargetWeeks * 7).ToString("yyyy-MM-dd")
337
+ }
338
+
339
+ Write-Host "Processing: $($file.Name)" -ForegroundColor Cyan
340
+ Write-Host " Title: $title"
341
+ if ($checkboxStatus.Total -gt 0) {
342
+ $color = if ($isComplete) { "Green" } else { "Yellow" }
343
+ Write-Host " Checkboxes: $($checkboxStatus.Checked)/$($checkboxStatus.Total)" -ForegroundColor $color
344
+ }
345
+
346
+ $cleanBody = Get-CleanIssueBody -Content $content
347
+ $tempBodyFile = [System.IO.Path]::GetTempFileName()
348
+ Set-Content -Path $tempBodyFile -Value $cleanBody -Encoding UTF8
349
+
350
+ try {
351
+ $existingNumber = $issueTitleMap[$title]
352
+ $currentState = $issueStateMap[$title]
353
+
354
+ if ($existingNumber) {
355
+ if ($Update) {
356
+ Write-Host " Existing: #$existingNumber ($currentState) - UPDATING" -ForegroundColor Yellow
357
+
358
+ foreach ($l in $labelArray) {
359
+ if (![string]::IsNullOrWhiteSpace($l)) { Ensure-Label -LabelName $l }
360
+ }
361
+
362
+ if (-not $DryRun) {
363
+ $ghArgs = @("issue", "edit", "$existingNumber", "--repo", "$REPO", "--title", "$title", "--body-file", "$tempBodyFile")
364
+ foreach ($l in $labelArray) {
365
+ if (![string]::IsNullOrWhiteSpace($l)) {
366
+ $ghArgs += "--add-label"; $ghArgs += "$l"
367
+ }
368
+ }
369
+ & gh $ghArgs
370
+
371
+ # Close if complete and currently open
372
+ if ($isComplete -and $currentState -eq "OPEN") {
373
+ gh issue close $existingNumber --repo $REPO --comment "✅ All acceptance criteria completed"
374
+ Write-Host " Closed #$existingNumber" -ForegroundColor Magenta
375
+ }
376
+
377
+ Write-Host " Updated #$existingNumber" -ForegroundColor Green
378
+ Sync-ProjectDates -IssueNumber $existingNumber -StartDate $startDate -TargetDate $targetDate
379
+ Update-FileState -FilePath $file.FullName -Status "synced" -IssueNumber $existingNumber
380
+ $processedCount++
381
+
382
+ # Archive if complete (whether just closed or already closed)
383
+ if ($isComplete) {
384
+ Move-ToClosedFolder -FilePath $file.FullName
385
+ $archivedCount++
386
+ }
387
+ } else {
388
+ Write-Host " [DryRun] Would update #$existingNumber" -ForegroundColor Gray
389
+ if ($isComplete) {
390
+ if ($currentState -eq "OPEN") {
391
+ Write-Host " [DryRun] Would CLOSE" -ForegroundColor Magenta
392
+ }
393
+ Write-Host " [DryRun] Would ARCHIVE" -ForegroundColor DarkMagenta
394
+ }
395
+ }
396
+ } else {
397
+ Write-Host " Existing: #$existingNumber - SKIPPING (use -Update)" -ForegroundColor DarkGray
398
+ }
399
+ } else {
400
+ Write-Host " New issue - CREATING" -ForegroundColor Green
401
+
402
+ foreach ($l in $labelArray) {
403
+ if (![string]::IsNullOrWhiteSpace($l)) { Ensure-Label -LabelName $l }
404
+ }
405
+
406
+ if (-not $DryRun) {
407
+ $ghArgs = @("issue", "create", "--repo", "$REPO", "--title", "$title", "--body-file", "$tempBodyFile")
408
+ foreach ($l in $labelArray) {
409
+ if (![string]::IsNullOrWhiteSpace($l)) {
410
+ $ghArgs += "--label"; $ghArgs += "$l"
411
+ }
412
+ }
413
+ $issueUrl = & gh $ghArgs
414
+
415
+ if ($issueUrl -match '/issues/(\d+)$') {
416
+ $newNum = [int]$matches[1]
417
+ Write-Host " Created #$newNum" -ForegroundColor Green
418
+ Sync-ProjectDates -IssueNumber $newNum -StartDate $startDate -TargetDate $targetDate
419
+ Update-FileState -FilePath $file.FullName -Status "synced" -IssueNumber $newNum
420
+ $processedCount++
421
+ }
422
+ } else {
423
+ Write-Host " [DryRun] Would create issue" -ForegroundColor Gray
424
+ }
425
+ }
426
+ } finally {
427
+ if (Test-Path $tempBodyFile) { Remove-Item $tempBodyFile -Force }
428
+ }
429
+ Write-Host "-------------------"
430
+ }
431
+
432
+ # Save state file
433
+ Save-SyncState
434
+
435
+ Write-Host ""
436
+ Write-Host "Done!" -ForegroundColor Green
437
+ Write-Host " Processed: $processedCount issues"
438
+ if ($archivedCount -gt 0) {
439
+ Write-Host " Archived: $archivedCount completed issues" -ForegroundColor Magenta
440
+ }
441
+ if ($skippedFiles.Count -gt 0 -and -not $Force) {
442
+ Write-Host " Skipped: $($skippedFiles.Count) unchanged files" -ForegroundColor DarkGray
443
+ }
@@ -0,0 +1,128 @@
1
+ # Smart Ops - GitHub Automation Script (PowerShell)
2
+ # Copy to: scripts/smart-ops.ps1
3
+ # Replace {{PLACEHOLDERS}} with actual values
4
+
5
+ $ErrorActionPreference = "Stop"
6
+
7
+ # ============ CONFIGURATION ============
8
+ $REPO_OWNER = "{{OWNER}}"
9
+ $REPO_NAME = "{{REPO}}"
10
+ $REPO = "$REPO_OWNER/$REPO_NAME"
11
+
12
+ # GitHub Projects (optional - leave empty if not using)
13
+ $PROJECT_NUMBER = "{{PROJECT_NUMBER}}"
14
+ $PROJECT_ID = "{{PROJECT_ID}}"
15
+ $STATUS_FIELD_ID = "{{STATUS_FIELD_ID}}"
16
+ $TODO_OPTION_ID = "{{TODO_OPTION_ID}}"
17
+ $IN_PROGRESS_OPTION_ID = "{{IN_PROGRESS_OPTION_ID}}"
18
+ $DONE_OPTION_ID = "{{DONE_OPTION_ID}}"
19
+ $START_DATE_FIELD_ID = "{{START_DATE_FIELD_ID}}"
20
+ $TARGET_DATE_FIELD_ID = "{{TARGET_DATE_FIELD_ID}}"
21
+
22
+ $DEBUG = $env:DEBUG -eq "1"
23
+
24
+ # ============ HELPERS ============
25
+
26
+ function Test-Prerequisites {
27
+ $errors = 0
28
+ try { $null = Get-Command gh -ErrorAction Stop } catch {
29
+ Write-Host "X GitHub CLI not installed" -ForegroundColor Red
30
+ $errors++
31
+ }
32
+ try { $null = gh auth status 2>&1; if ($LASTEXITCODE -ne 0) { throw } } catch {
33
+ Write-Host "X Not authenticated. Run: gh auth login" -ForegroundColor Red
34
+ $errors++
35
+ }
36
+ if ($errors -gt 0) { exit 1 }
37
+ }
38
+
39
+ function Get-Today { return (Get-Date -Format "yyyy-MM-dd") }
40
+ function Get-FutureDate { param([int]$Days = 7); return (Get-Date).AddDays($Days).ToString("yyyy-MM-dd") }
41
+
42
+ # ============ COMMANDS ============
43
+
44
+ function Start-Scan {
45
+ Write-Host "Scanning open issues..." -ForegroundColor Cyan
46
+ gh issue list --repo $REPO --state open --json number,title,labels --limit 20
47
+ }
48
+
49
+ function Complete-Scan {
50
+ Write-Host "Issues ready for completion..." -ForegroundColor Cyan
51
+ gh issue list --repo $REPO --state open --json number,title --limit 20
52
+ Write-Host "`nToday: $(Get-Today)"
53
+ Write-Host 'Close with: .\smart-ops.ps1 close [number]' -ForegroundColor Gray
54
+ }
55
+
56
+ function New-Issue {
57
+ param([string]$Title, [string]$Body = "", [string]$Labels = "enhancement", [int]$Days = 7)
58
+ if ([string]::IsNullOrWhiteSpace($Title)) { Write-Host "X Title required" -ForegroundColor Red; return }
59
+
60
+ Write-Host "Creating: $Title (${Days}d)" -ForegroundColor Cyan
61
+ $url = gh issue create --repo $REPO --title $Title --body $Body --label $Labels
62
+
63
+ if ($url -match '/(\d+)$') {
64
+ Write-Host "Created #$($Matches[1])" -ForegroundColor Green
65
+ Write-Host $url
66
+ }
67
+ }
68
+
69
+ function Close-Issue {
70
+ param([string]$Num, [string]$Comment = "Completed")
71
+ if ([string]::IsNullOrWhiteSpace($Num)) { Write-Host "X Issue number required" -ForegroundColor Red; return }
72
+
73
+ $confirm = Read-Host "Close #${Num}? (y/N)"
74
+ if ($confirm -ne 'y') { return }
75
+
76
+ gh issue close $Num --repo $REPO --comment $Comment
77
+ Write-Host "Closed #$Num" -ForegroundColor Green
78
+ }
79
+
80
+ function Move-ToProgress {
81
+ param([string]$Id)
82
+ if ([string]::IsNullOrWhiteSpace($PROJECT_ID)) { Write-Host "X No project configured" -ForegroundColor Red; return }
83
+ gh project item-edit --id $Id --field-id $STATUS_FIELD_ID --project-id $PROJECT_ID --single-select-option-id $IN_PROGRESS_OPTION_ID
84
+ Write-Host "-> In Progress" -ForegroundColor Green
85
+ }
86
+
87
+ function Move-ToDone {
88
+ param([string]$Id)
89
+ if ([string]::IsNullOrWhiteSpace($PROJECT_ID)) { Write-Host "X No project configured" -ForegroundColor Red; return }
90
+ gh project item-edit --id $Id --field-id $STATUS_FIELD_ID --project-id $PROJECT_ID --single-select-option-id $DONE_OPTION_ID
91
+ Write-Host "-> Done" -ForegroundColor Green
92
+ }
93
+
94
+ function Show-Help {
95
+ Write-Host @'
96
+ Smart Ops - GitHub Automation
97
+
98
+ Usage: .\smart-ops.ps1 [command] [args]
99
+
100
+ Commands:
101
+ start List open issues
102
+ complete List for completion
103
+ create [title] [body] [labels] [days]
104
+ close [number] [comment]
105
+ progress [item_id] Move to In Progress
106
+ done [item_id] Move to Done
107
+
108
+ Examples:
109
+ .\smart-ops.ps1 create "Fix bug" "Description" "bug" 3
110
+ .\smart-ops.ps1 close 42 "Fixed"
111
+ '@ -ForegroundColor Cyan
112
+ }
113
+
114
+ # ============ MAIN ============
115
+
116
+ Test-Prerequisites
117
+
118
+ $cmd = if ($args.Count -gt 0) { $args[0] } else { "help" }
119
+
120
+ switch ($cmd.ToLower()) {
121
+ "start" { Start-Scan }
122
+ "complete" { Complete-Scan }
123
+ "create" { New-Issue -Title $args[1] -Body $args[2] -Labels $args[3] -Days ([int]$args[4]) }
124
+ "close" { Close-Issue -Num $args[1] -Comment $args[2] }
125
+ "progress" { Move-ToProgress -Id $args[1] }
126
+ "done" { Move-ToDone -Id $args[1] }
127
+ default { Show-Help }
128
+ }
@@ -0,0 +1,130 @@
1
+ #!/bin/bash
2
+ # Smart Ops - GitHub Automation Script (Bash)
3
+ # Copy to: scripts/smart-ops.sh
4
+ # Replace {{PLACEHOLDERS}} with actual values
5
+
6
+ set -e
7
+
8
+ # ============ CONFIGURATION ============
9
+ REPO_OWNER="{{OWNER}}"
10
+ REPO_NAME="{{REPO}}"
11
+ REPO="${REPO_OWNER}/${REPO_NAME}"
12
+
13
+ # GitHub Projects (optional - leave empty if not using)
14
+ PROJECT_NUMBER="{{PROJECT_NUMBER}}"
15
+ PROJECT_ID="{{PROJECT_ID}}"
16
+ STATUS_FIELD_ID="{{STATUS_FIELD_ID}}"
17
+ TODO_OPTION_ID="{{TODO_OPTION_ID}}"
18
+ IN_PROGRESS_OPTION_ID="{{IN_PROGRESS_OPTION_ID}}"
19
+ DONE_OPTION_ID="{{DONE_OPTION_ID}}"
20
+ START_DATE_FIELD_ID="{{START_DATE_FIELD_ID}}"
21
+ TARGET_DATE_FIELD_ID="{{TARGET_DATE_FIELD_ID}}"
22
+
23
+ DEBUG="${DEBUG:-0}"
24
+
25
+ # ============ HELPERS ============
26
+
27
+ check_prerequisites() {
28
+ local errors=0
29
+ command -v gh &> /dev/null || { echo "❌ GitHub CLI not installed"; errors=$((errors + 1)); }
30
+ gh auth status &> /dev/null || { echo "❌ Not authenticated. Run: gh auth login"; errors=$((errors + 1)); }
31
+ [ "$errors" -gt 0 ] && exit 1
32
+ }
33
+
34
+ get_today() { date +%Y-%m-%d; }
35
+ get_future_date() {
36
+ local days="${1:-7}"
37
+ if [[ "$OSTYPE" == "darwin"* ]]; then
38
+ date -v+${days}d +%Y-%m-%d
39
+ else
40
+ date -d "+${days} days" +%Y-%m-%d
41
+ fi
42
+ }
43
+
44
+ # ============ COMMANDS ============
45
+
46
+ start_scan() {
47
+ echo "🔍 Scanning open issues..."
48
+ gh issue list --repo "$REPO" --state open --json number,title,labels --limit 20
49
+ }
50
+
51
+ complete_scan() {
52
+ echo "📋 Issues ready for completion..."
53
+ gh issue list --repo "$REPO" --state open --json number,title --limit 20
54
+ echo ""
55
+ echo "Today: $(get_today)"
56
+ echo "Close with: ./smart-ops.sh close <number>"
57
+ }
58
+
59
+ create_issue() {
60
+ local title="$1"
61
+ local body="$2"
62
+ local labels="${3:-enhancement}"
63
+ local days="${4:-7}"
64
+
65
+ [ -z "$title" ] && { echo "❌ Title required"; return 1; }
66
+
67
+ echo "📝 Creating: $title (${days}d)"
68
+ gh issue create --repo "$REPO" --title "$title" --body "$body" --label "$labels"
69
+ }
70
+
71
+ close_issue() {
72
+ local num="$1"
73
+ local comment="${2:-Completed}"
74
+
75
+ [ -z "$num" ] && { echo "❌ Issue number required"; return 1; }
76
+
77
+ read -p "Close #$num? (y/N): " -n 1 -r; echo
78
+ [[ ! $REPLY =~ ^[Yy]$ ]] && return 0
79
+
80
+ gh issue close "$num" --repo "$REPO" --comment "$comment"
81
+ echo "✅ Closed #$num"
82
+ }
83
+
84
+ move_to_progress() {
85
+ local id="$1"
86
+ [ -z "$PROJECT_ID" ] && { echo "❌ No project configured"; return 1; }
87
+ gh project item-edit --id "$id" --field-id "$STATUS_FIELD_ID" --project-id "$PROJECT_ID" --single-select-option-id "$IN_PROGRESS_OPTION_ID"
88
+ echo "✅ → In Progress"
89
+ }
90
+
91
+ move_to_done() {
92
+ local id="$1"
93
+ [ -z "$PROJECT_ID" ] && { echo "❌ No project configured"; return 1; }
94
+ gh project item-edit --id "$id" --field-id "$STATUS_FIELD_ID" --project-id "$PROJECT_ID" --single-select-option-id "$DONE_OPTION_ID"
95
+ echo "✅ → Done"
96
+ }
97
+
98
+ show_help() {
99
+ cat << 'EOF'
100
+ Smart Ops - GitHub Automation
101
+
102
+ Usage: ./smart-ops.sh <command> [args]
103
+
104
+ Commands:
105
+ start List open issues
106
+ complete List for completion
107
+ create <title> [body] [labels] [days]
108
+ close <number> [comment]
109
+ progress <item_id> Move to In Progress
110
+ done <item_id> Move to Done
111
+
112
+ Examples:
113
+ ./smart-ops.sh create "Fix bug" "Description" "bug" 3
114
+ ./smart-ops.sh close 42 "Fixed"
115
+ EOF
116
+ }
117
+
118
+ # ============ MAIN ============
119
+
120
+ check_prerequisites
121
+
122
+ case "${1:-help}" in
123
+ start) start_scan ;;
124
+ complete) complete_scan ;;
125
+ create) create_issue "$2" "$3" "$4" "$5" ;;
126
+ close) close_issue "$2" "$3" ;;
127
+ progress) move_to_progress "$2" ;;
128
+ done) move_to_done "$2" ;;
129
+ *) show_help ;;
130
+ esac