-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfigure.ps1
More file actions
299 lines (265 loc) · 13.5 KB
/
Copy pathconfigure.ps1
File metadata and controls
299 lines (265 loc) · 13.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
<#
Configure Copilot Resources
Main entry point for all Copilot resource management operations.
Chains the scripts in the correct order:
1. sync-awesome-copilot.ps1 -- fetch latest from github/awesome-copilot
2. init-user.ps1 -- (prompted) user-level agents → %APPDATA%\Code\User\prompts\
3. init-repo.ps1 -- (prompted) per-repo .github/ setup
Usage:
# Full interactive run: sync + prompt for both steps
.\configure.ps1
# Sync + prompt for user and repo pickers
.\configure.ps1 -Install
# Sync + go straight to pickers without prompting — use -Scope to target a specific scope
.\configure.ps1 -Install -Scope repo # repo only, no prompt
.\configure.ps1 -Install -Scope user # user only, no prompt
.\configure.ps1 -Install -Scope both # both, no prompts
# Sync only (skip repo setup)
.\configure.ps1 -SkipInit
# Preview without writing any files
.\configure.ps1 -DryRun
# Check for and apply all upstream updates (no pickers)
.\configure.ps1 -Update
.\configure.ps1 -Update -Scope repo # repo subscriptions only
.\configure.ps1 -Update -Scope user # user subscriptions only
.\configure.ps1 -Update -Force # skip confirmation prompts
.\configure.ps1 -Update -Category "agents" # only update agent subscriptions
.\configure.ps1 -Update -DryRun # preview what would be updated
# Filter which categories to install (pickers for listed categories only)
.\configure.ps1 -Install -Category "agents,skills"
.\configure.ps1 -Install -Scope repo -Category "hooks,workflows,plugins"
# Init a specific repo (not the current working directory)
.\configure.ps1 -SkipSync -RepoPath "C:\Projects\my-app"
# Remove installed resources — use -Scope to target a specific scope
.\configure.ps1 -Uninstall # removes both user + repo
.\configure.ps1 -Uninstall -Scope repo # repo .github/ only
.\configure.ps1 -Uninstall -Scope user # user-level only
# Skip a specific step
.\configure.ps1 -SkipUser
.\configure.ps1 -SkipInit
#>
[CmdletBinding()] param(
[switch]$SkipSync,
[switch]$SkipInit,
[switch]$SkipUser, # Skip user-level resource setup
[switch]$Install, # Sync + run pickers; add -Scope to skip prompts and target a specific scope
[switch]$Uninstall, # Remove installed resources; add -Scope to target a specific scope
[switch]$Update, # Sync + run update scripts only (no pickers); use -Scope, -Force, -DryRun, -Category
[switch]$Force, # Skip update confirmation prompt (passes -Force to update scripts)
[ValidateSet('repo', 'user', 'both')]
[string]$Scope = '', # Scope for -Install, -Uninstall, or -Update: 'repo', 'user', or 'both'
[string]$Category = '', # Comma-separated categories to process: agents,hooks,instructions,plugins,skills,workflows
[switch]$User, # Backwards-compat alias for: -Install -Scope user
[Parameter(Position = 0)]
[string]$RepoPath = (Get-Location).Path,
[switch]$DryRun
)
#region Initialisation
$ErrorActionPreference = 'Stop'
$ScriptDir = Join-Path $PSScriptRoot 'scripts'
function Log($m, [string]$level = 'INFO') {
$ts = (Get-Date).ToString('s')
$color = switch ($level) { 'ERROR' { 'Red' } 'WARN' { 'Yellow' } 'SUCCESS' { 'Green' } default { 'Cyan' } }
Write-Host "[$ts][$level] $m" -ForegroundColor $color
}
function Step($label) {
Write-Host ""
Write-Host " ── $label ──" -ForegroundColor Magenta
Write-Host ""
}
# Show cache state
$manifest = "$HOME\.awesome-copilot\manifest.json"
if (Test-Path $manifest) {
try {
$m = Get-Content $manifest -Raw | ConvertFrom-Json
Log "Cache last synced: $($m.fetchedAt) Items: $($m.items.Count)"
} catch {}
} else {
Log "No local cache found — sync will download everything fresh." 'WARN'
}
# -User backwards-compat alias: maps to -Install -Scope user
if ($User -and -not $Install) { $Install = $true; if ($Scope -eq '') { $Scope = 'user' } }
# -Scope restricts which steps run (applies to both -Install and -Uninstall)
if ($Scope -eq 'repo') { $SkipUser = $true } # repo scope: skip user step entirely
if ($Scope -eq 'user') { $SkipInit = $true } # user scope: skip repo step entirely
# 'both' or '' : neither step is skipped by scope
# -Uninstall never needs to sync
if ($Uninstall) { $SkipSync = $true }
# -Update and -Uninstall are mutually exclusive
if ($Update -and $Uninstall) { Log "-Update and -Uninstall cannot be used together." 'ERROR'; exit 1 }
#endregion # Initialisation
#region Step 1 — Sync
if (-not $SkipSync) {
Step "Sync from github/awesome-copilot"
$syncArgs = @{}
if ($DryRun) { $syncArgs['Plan'] = $true }
& (Join-Path $ScriptDir 'sync-awesome-copilot.ps1') @syncArgs
if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Log "Sync failed (exit $LASTEXITCODE)" 'ERROR'; exit $LASTEXITCODE }
}
#endregion # Step 1
#region -Update shortcut
if ($Update) {
if (-not $SkipUser) {
$userManifestFile = "$HOME\.awesome-copilot\user-subscriptions.json"
$userSubCount = 0
if (Test-Path $userManifestFile) {
$userSubCount = try { (@((Get-Content $userManifestFile -Raw | ConvertFrom-Json).subscriptions)).Count } catch { 0 }
}
if ($userSubCount -gt 0) {
Step "Update user-level resources"
$updateArgs = @{}
if ($DryRun) { $updateArgs['DryRun'] = $true }
if ($Force) { $updateArgs['Force'] = $true }
if ($Category) { $updateArgs['Category'] = $Category }
& (Join-Path $ScriptDir 'update-user.ps1') @updateArgs
if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Log "update-user failed (exit $LASTEXITCODE)" 'ERROR'; exit $LASTEXITCODE }
} else {
Log "No user-level subscriptions found — nothing to update." 'WARN'
}
}
if (-not $SkipInit) {
$subscriptionsFile = Join-Path $RepoPath '.github\.copilot-subscriptions.json'
$subCount = 0
if (Test-Path $subscriptionsFile) {
$subCount = try { (@((Get-Content $subscriptionsFile -Raw | ConvertFrom-Json).subscriptions)).Count } catch { 0 }
}
if ($subCount -gt 0) {
Step "Update repo resources"
$updateArgs = @{}
if ($DryRun) { $updateArgs['DryRun'] = $true }
if ($Force) { $updateArgs['Force'] = $true }
if ($RepoPath) { $updateArgs['RepoPath'] = $RepoPath }
if ($Category) { $updateArgs['Category'] = $Category }
& (Join-Path $ScriptDir 'update-repo.ps1') @updateArgs
if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Log "update-repo failed (exit $LASTEXITCODE)" 'ERROR'; exit $LASTEXITCODE }
} else {
Log "No repo subscriptions found for $RepoPath — nothing to update." 'WARN'
}
}
Write-Host ""
Log "Done." 'SUCCESS'
exit 0
}
#endregion # -Update shortcut
#region Step 1.5 — User-level resources
if (-not $SkipUser) {
$userManifestFile = "$HOME\.awesome-copilot\user-subscriptions.json"
$userSubCount = 0
if (Test-Path $userManifestFile) {
$userSubCount = try { (@((Get-Content $userManifestFile -Raw | ConvertFrom-Json).subscriptions)).Count } catch { 0 }
if ($userSubCount -gt 0) {
Step "Check for updates to user-level resources"
$updateArgs = @{}
if ($DryRun) { $updateArgs['DryRun'] = $true }
if ($Force) { $updateArgs['Force'] = $true }
if ($Category) { $updateArgs['Category'] = $Category }
& (Join-Path $ScriptDir 'update-user.ps1') @updateArgs
}
} else {
# Manifest missing — check whether cache-origin files are already installed on disk.
# This happens when resources were installed before v2.0.0 (which introduced the
# manifest), or when configure.ps1 was run but the user-level step was skipped.
# Auto-bootstrap registers all installed cache-origin files so update-user.ps1
# can manage them going forward.
$cacheRoot = "$HOME\.awesome-copilot"
$promptsDir = [System.Environment]::GetFolderPath('ApplicationData') + '\Code\User\prompts'
$skillsDir = "$HOME\.copilot\skills"
$untrackedCount = 0
foreach ($cat in @('agents','instructions','skills')) {
$cDir = Join-Path $cacheRoot $cat
if (-not (Test-Path $cDir)) { continue }
if ($cat -eq 'skills') {
$untrackedCount += (Get-ChildItem $cDir -Directory -EA SilentlyContinue |
Where-Object { Test-Path (Join-Path $skillsDir $_.Name) }).Count
} else {
$pattern = if ($cat -eq 'agents') { '*.agent.md' } else { '*.instructions.md' }
$untrackedCount += (Get-ChildItem $cDir -Filter $pattern -EA SilentlyContinue |
Where-Object { Test-Path (Join-Path $promptsDir $_.Name) }).Count
}
}
if ($untrackedCount -gt 0) {
Log "Detected $untrackedCount user-level resource(s) installed from the cache with no tracking record." 'WARN'
Log "Bootstrapping user-subscriptions.json so update-user.ps1 can manage them..." 'WARN'
$bootstrapArgs = @{ Bootstrap = $true }
if ($DryRun) { $bootstrapArgs['DryRun'] = $true }
& (Join-Path $ScriptDir 'init-user.ps1') @bootstrapArgs
if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Log "Bootstrap failed (exit $LASTEXITCODE)" 'ERROR'; exit $LASTEXITCODE }
# Reload count so the update step fires on next configure run
if (Test-Path $userManifestFile) {
$userSubCount = try { (@((Get-Content $userManifestFile -Raw | ConvertFrom-Json).subscriptions)).Count } catch { 0 }
}
}
}
Step "User-level resources (agents, instructions & skills — available in all repos)"
if ($Uninstall -or ($Install -and $Scope -in @('user','both'))) {
# Uninstall (always explicit) or install scoped to user/both: skip the Y/N prompt
$userArgs = @{}
if ($DryRun) { $userArgs['DryRun'] = $true }
if ($Uninstall) { $userArgs['Uninstall'] = $true }
if ($Category) { $userArgs['Category'] = $Category }
& (Join-Path $ScriptDir 'init-user.ps1') @userArgs
if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Log "init-user failed (exit $LASTEXITCODE)" 'ERROR'; exit $LASTEXITCODE }
} else {
Write-Host " Add/update user-level resources (agents, instructions & skills)?" -ForegroundColor Yellow
Write-Host " These are available in ALL repos — no .github/ needed." -ForegroundColor DarkGray
Write-Host " [Y] Yes [N] No (default): " -NoNewline -ForegroundColor Yellow
$answer = (Read-Host).Trim()
if ($answer -match '^[Yy]') {
$userArgs = @{}
if ($DryRun) { $userArgs['DryRun'] = $true }
if ($Category) { $userArgs['Category'] = $Category }
& (Join-Path $ScriptDir 'init-user.ps1') @userArgs
if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { Log "init-user failed (exit $LASTEXITCODE)" 'ERROR'; exit $LASTEXITCODE }
} else {
Log "init-user skipped."
}
}
}
#endregion # Step 1.5
#region Step 2 — Init repo
if (-not $SkipInit) {
# If a subscriptions manifest exists with entries, check for updates first
$subscriptionsFile = Join-Path $RepoPath '.github\.copilot-subscriptions.json'
$subCount = 0
if (Test-Path $subscriptionsFile) {
$subCount = try { (@((Get-Content $subscriptionsFile -Raw | ConvertFrom-Json).subscriptions)).Count } catch { 0 }
if ($subCount -gt 0) {
Step "Check for updates to subscribed repo resources"
$updateArgs = @{}
if ($DryRun) { $updateArgs['DryRun'] = $true }
if ($Force) { $updateArgs['Force'] = $true }
if ($RepoPath) { $updateArgs['RepoPath'] = $RepoPath }
if ($Category) { $updateArgs['Category'] = $Category }
& (Join-Path $ScriptDir 'update-repo.ps1') @updateArgs
}
}
Step "Init repo"
$doRepoUninstall = [bool]$Uninstall
if ($doRepoUninstall -and $subCount -eq 0) {
Log "Nothing to uninstall — no subscriptions recorded for this repo."
} elseif ($doRepoUninstall -or ($Install -and $Scope -in @('repo','both'))) {
# Uninstall (always explicit) or install scoped to repo/both: skip the Y/N prompt
$initArgs = @{}
if ($DryRun) { $initArgs['DryRun'] = $true }
if ($RepoPath) { $initArgs['RepoPath'] = $RepoPath }
if ($doRepoUninstall) { $initArgs['Uninstall'] = $true }
if ($Category) { $initArgs['Category'] = $Category }
& (Join-Path $ScriptDir 'init-repo.ps1') @initArgs
} else {
Write-Host " Add agents/hooks/instructions/plugins/skills/workflows to .github/ in the current repo?" -ForegroundColor Yellow
Write-Host " [Y] Yes [N] No (default): " -NoNewline -ForegroundColor Yellow
$answer = (Read-Host).Trim()
if ($answer -match '^[Yy]') {
$initArgs = @{}
if ($DryRun) { $initArgs['DryRun'] = $true }
if ($RepoPath) { $initArgs['RepoPath'] = $RepoPath }
if ($Category) { $initArgs['Category'] = $Category }
& (Join-Path $ScriptDir 'init-repo.ps1') @initArgs
} else {
Log "init-repo skipped."
}
}
}
#endregion # Step 2
Write-Host ""
Log "Done." 'SUCCESS'