@ojokesusu/lintasai 1.1.2

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 (86) hide show
  1. package/.github/workflows/publish-npm.yml +40 -0
  2. package/.github/workflows/validate.yml +93 -0
  3. package/AUDIT_POST_SETUP_PROMPT_v1.md +280 -0
  4. package/BOOTSTRAP_PROJECT_DOCS_PROMPT_v1.md +3 -0
  5. package/CHANGELOG.md +313 -0
  6. package/CLAUDE_universal_v1.md +1021 -0
  7. package/CONTRIBUTING.md +101 -0
  8. package/FIRST_SESSION_PROMPT_v1.md +7 -0
  9. package/JALANKAN_KIT.md +188 -0
  10. package/LICENSE +21 -0
  11. package/MULAI_DI_SINI.md +145 -0
  12. package/PROJECT_KICKOFF_PROMPT_v1.md +3 -0
  13. package/PROJECT_LIFECYCLE_PROMPT_v1.md +536 -0
  14. package/PROJECT_MIGRATION_PROMPT_v1.md +3 -0
  15. package/README.md +505 -0
  16. package/SETUP_POLA_B_PROMPT_v1.md +5 -0
  17. package/SPLIT_REPO_MIGRATION_PROMPT_v1.md +485 -0
  18. package/TEAM_ROLLOUT_GUIDE_v1.md +172 -0
  19. package/UPDATE_DOCS_PROMPT_v1.md +3 -0
  20. package/UPDATE_KIT_PROMPT_v1.md +213 -0
  21. package/bin/lintasai.js +81 -0
  22. package/docs/SIGNED_RELEASE.md +162 -0
  23. package/install-windows.ps1 +225 -0
  24. package/kit.ps1 +508 -0
  25. package/lib/agents-md.ps1 +174 -0
  26. package/lib/git-helpers.ps1 +104 -0
  27. package/lib/kit-files.psd1 +133 -0
  28. package/lib/manifest-signing.ps1 +65 -0
  29. package/lib/manifest.ps1 +267 -0
  30. package/lib/rollback.ps1 +241 -0
  31. package/lib/safety.ps1 +193 -0
  32. package/lib/template-deploy.ps1 +242 -0
  33. package/lib/version-detect.ps1 +161 -0
  34. package/package.json +36 -0
  35. package/setup-pola-b.ps1 +687 -0
  36. package/templates/ANALOGI_LIBRARY.md +7 -0
  37. package/templates/CLAUDE_TEAM_GUIDE.md +505 -0
  38. package/templates/CROSS_REPO_TYPES_PIPELINE.md +473 -0
  39. package/templates/DB_SCHEMA_SCAN_PROMPT.md +194 -0
  40. package/templates/DISCORD_BOT_INTEGRATION.md +187 -0
  41. package/templates/GLOSSARY_NON_PROGRAMMER.md +361 -0
  42. package/templates/INDEX.md +157 -0
  43. package/templates/MCP_SETUP.md +1145 -0
  44. package/templates/MIGRATE_TO_SUBFOLDER_PROMPT_v1.md +220 -0
  45. package/templates/ONBOARDING.md +172 -0
  46. package/templates/PROJECT_STARTER_TEMPLATES.md +264 -0
  47. package/templates/PROMPT_LIBRARY.md +790 -0
  48. package/templates/RLS_SETUP_PROMPT.md +167 -0
  49. package/templates/SECURITY_INCIDENT_PLAYBOOK.md +191 -0
  50. package/templates/SPLIT_REPO_AGENTS_TEMPLATES.md +32 -0
  51. package/templates/SPLIT_REPO_NON_PROGRAMMER_PROMPTS.md +604 -0
  52. package/templates/SPLIT_REPO_TOOLS_SETUP.md +388 -0
  53. package/templates/STACK_DETECTION_PATTERN.md +261 -0
  54. package/templates/STACK_GUIDE.md +564 -0
  55. package/templates/STACK_MIGRATION_GUIDE.md +154 -0
  56. package/templates/STACK_VERSIONS.md +31 -0
  57. package/templates/UPDATE_GUIDE.md +246 -0
  58. package/templates/_EXAMPLE.md +110 -0
  59. package/templates/_PATTERNS.md +173 -0
  60. package/templates/architecture.md +180 -0
  61. package/templates/architecture_auto.md +61 -0
  62. package/templates/decisions/README.md +108 -0
  63. package/templates/decisions/_TEMPLATE.md +84 -0
  64. package/templates/feature-flags-advanced.md +171 -0
  65. package/templates/github/CODEOWNERS.template +61 -0
  66. package/templates/github/GENERATE_TYPES_SCRIPT.md +77 -0
  67. package/templates/github/PUBLISH_SHARED_WORKFLOW.yml +52 -0
  68. package/templates/github/RECEIVE_BACKEND_UPDATE.yml +106 -0
  69. package/templates/github/RENOVATE_FRONTEND.json +28 -0
  70. package/templates/github/TRIGGER_FRONTEND_UPDATE.yml +29 -0
  71. package/templates/github/pull_request_template.md +44 -0
  72. package/templates/github/scripts/ai-review.js +153 -0
  73. package/templates/github/workflows/ai-review.yml +61 -0
  74. package/templates/github/workflows/backup-schemas.yml +169 -0
  75. package/templates/glossary.md +110 -0
  76. package/templates/split-agents/BACKEND.md +149 -0
  77. package/templates/split-agents/FRONTEND.md +141 -0
  78. package/templates/split-agents/SHARED.md +82 -0
  79. package/templates/split-agents/TOOLS.md +77 -0
  80. package/tests/Run-Tests.ps1 +19 -0
  81. package/tests/lib-safety.Tests.ps1 +66 -0
  82. package/tests/rollback.Tests.ps1 +66 -0
  83. package/tests/uninstall.Tests.ps1 +265 -0
  84. package/tests/update-kit.Tests.ps1 +78 -0
  85. package/uninstall.ps1 +794 -0
  86. package/update-kit.ps1 +907 -0
package/kit.ps1 ADDED
@@ -0,0 +1,508 @@
1
+ <#
2
+ .SYNOPSIS
3
+ kit.ps1 - Single entry point untuk operasi kit lintasAI
4
+
5
+ .DESCRIPTION
6
+ Router yang delegate ke script per-operation. Tujuan: 1 command yang gampang
7
+ diingat staff IT, daripada hafal 3 nama script berbeda.
8
+
9
+ Subcommand yang tersedia:
10
+ setup - Setup Pola B di proyek (delegate ke setup-pola-b.ps1)
11
+ update - Update kit ke versi terbaru via re-clone (delegate ke update-kit.ps1)
12
+ uninstall - Hapus kit dari proyek dengan AMAN (manifest-based, delegate ke uninstall.ps1)
13
+ doctor - Diagnostic: cek versi + file utuh + broken cross-ref + integrity (sha256)
14
+ scan - Re-run scan project (tanpa setup) — generate ringkasan kandidat CRITICAL
15
+ version - Print versi kit aktif (dari manifest)
16
+ rollback - Rollback kit ke snapshot sebelum update (delegate ke lib\rollback.ps1)
17
+ help - Tampilkan usage
18
+
19
+ .PARAMETER Command
20
+ Subcommand yang mau dijalankan. Required.
21
+
22
+ .PARAMETER Args
23
+ Arguments yang di-pass ke subcommand. Optional.
24
+
25
+ .EXAMPLE
26
+ .\.claude-kit\kit.ps1 setup
27
+ .\.claude-kit\kit.ps1 setup -Force
28
+ .\.claude-kit\kit.ps1 update
29
+ .\.claude-kit\kit.ps1 update -NoBackup
30
+ .\.claude-kit\kit.ps1 uninstall -DryRun
31
+ .\.claude-kit\kit.ps1 uninstall -Force
32
+ .\.claude-kit\kit.ps1 doctor
33
+ .\.claude-kit\kit.ps1 scan
34
+ .\.claude-kit\kit.ps1 version
35
+ .\.claude-kit\kit.ps1 help
36
+
37
+ .NOTES
38
+ Versi : 1.0
39
+ Tanggal: 2026-06-03
40
+ Run : .\.claude-kit\kit.ps1 <command>
41
+ Atau : powershell -ExecutionPolicy Bypass -File .\.claude-kit\kit.ps1 <command>
42
+
43
+ Backward compatibility: setup-pola-b.ps1 + update-kit.ps1 tetap bisa dipanggil
44
+ langsung (tidak deprecated). kit.ps1 cuma alternative entry point yang lebih ringkas.
45
+ #>
46
+
47
+ [CmdletBinding()]
48
+ param(
49
+ [Parameter(Position = 0)]
50
+ [ValidateSet('setup', 'update', 'uninstall', 'doctor', 'scan', 'version', 'rollback', 'help', '')]
51
+ [string]$Command = '',
52
+
53
+ [Parameter(ValueFromRemainingArguments = $true)]
54
+ [string[]]$ExtraArgs
55
+ )
56
+
57
+ $ErrorActionPreference = 'Stop'
58
+
59
+ # ---- Resolve paths ----
60
+ $KitDir = if ($PSScriptRoot) { $PSScriptRoot } elseif ($MyInvocation.MyCommand.Path) { Split-Path -Parent $MyInvocation.MyCommand.Path } else { (Get-Location).Path }
61
+ $ProjectRoot = Split-Path -Parent $KitDir
62
+
63
+ # ---- Resolve lib paths (optional dependencies) ----
64
+ $libRollback = Join-Path $PSScriptRoot 'lib\rollback.ps1'
65
+ $libSafety = Join-Path $PSScriptRoot 'lib\safety.ps1'
66
+
67
+ # ---- Helper: detect kit version (defense-in-depth fallback chain) ----
68
+ # Source 1: .install-manifest.json -> metadata.kit_version (PRIMARY — what was installed)
69
+ # Source 2: $script:KIT_VERSION constant (kit.ps1's own version awareness)
70
+ # Source 3: CHANGELOG.md first "## v X.Y.Z" line, or "## [X.Y.Z]" entry
71
+ # Last resort: "unknown" (NOT "not installed" — misleading; the kit itself is present)
72
+ function Get-KitVersion {
73
+ $ver = $null
74
+
75
+ # Source 1: manifest
76
+ $manifestPath = Join-Path $KitDir '.install-manifest.json'
77
+ if (Test-Path $manifestPath) {
78
+ try {
79
+ $json = [System.IO.File]::ReadAllText($manifestPath, [System.Text.Encoding]::UTF8)
80
+ $m = ConvertFrom-Json $json -ErrorAction Stop
81
+ if ($m.metadata -and $m.metadata.kit_version) {
82
+ $ver = $m.metadata.kit_version
83
+ }
84
+ } catch { }
85
+ }
86
+
87
+ # Source 2: $script:KIT_VERSION constant (optional — may not be defined)
88
+ if (-not $ver -and $script:KIT_VERSION) {
89
+ $ver = $script:KIT_VERSION
90
+ }
91
+
92
+ # Source 3: CHANGELOG.md — try "## v1.2.3" first, then "## [1.2.3]"
93
+ if (-not $ver) {
94
+ $changelogPath = Join-Path $KitDir 'CHANGELOG.md'
95
+ if (Test-Path $changelogPath) {
96
+ try {
97
+ $first = Get-Content $changelogPath -Encoding UTF8 -ErrorAction Stop |
98
+ Where-Object { $_ -match '^##\s+v\d+\.' } |
99
+ Select-Object -First 1
100
+ if ($first -and ($first -match '(v\d+\.\d+\.\d+)')) {
101
+ $ver = $matches[1]
102
+ } else {
103
+ $bracket = Select-String -Path $changelogPath -Pattern '## \[(\d+\.\d+\.\d+)\]' -List -ErrorAction SilentlyContinue
104
+ if ($bracket) { $ver = 'v' + $bracket.Matches[0].Groups[1].Value }
105
+ }
106
+ } catch { }
107
+ }
108
+ }
109
+
110
+ # Last resort
111
+ if (-not $ver) { $ver = 'unknown' }
112
+
113
+ return $ver
114
+ }
115
+
116
+ # ---- Helper: print usage ----
117
+ function Show-Help {
118
+ Write-Host ""
119
+ Write-Host "kit.ps1 - Single entry point untuk kit lintasAI (v$(Get-KitVersion))" -ForegroundColor Cyan
120
+ Write-Host ""
121
+ Write-Host "USAGE:" -ForegroundColor Cyan
122
+ Write-Host " .\.claude-kit\kit.ps1 <command> [args]"
123
+ Write-Host ""
124
+ Write-Host "COMMANDS:" -ForegroundColor Cyan
125
+ Write-Host " setup - Setup Pola B di proyek (copy AGENTS.md, docs skeleton, file tim)"
126
+ Write-Host " Args: -Force, -DryRun, -SkipTeamFiles"
127
+ Write-Host ""
128
+ Write-Host " update - Update kit ke versi terbaru via re-clone fresh dari GitHub"
129
+ Write-Host " Args: -NoBackup, -RepoUrl <url>, -Branch <name>, -DryRun"
130
+ Write-Host ""
131
+ Write-Host " uninstall - Hapus kit dari proyek dengan AMAN (manifest-based diff)"
132
+ Write-Host " Args: -DryRun, -Force, -DeleteAgents, -KeepKit, -Yes, -AllowProjectRootMismatch"
133
+ Write-Host " File project (yang BUKAN dari kit) AMAN tidak terhapus."
134
+ Write-Host " Path traversal + symlink protection aktif by default."
135
+ Write-Host ""
136
+ Write-Host " doctor - Diagnostic: cek versi + file inti utuh + cross-ref"
137
+ Write-Host " (no args)"
138
+ Write-Host ""
139
+ Write-Host " scan - Re-run scan project untuk identifikasi kandidat CRITICAL"
140
+ Write-Host " (tanpa setup ulang)"
141
+ Write-Host ""
142
+ Write-Host " version - Print versi kit aktif (dari .install-manifest.json)"
143
+ Write-Host ""
144
+ Write-Host " rollback - Rollback kit ke snapshot sebelum update terakhir"
145
+ Write-Host " (delegate ke lib\rollback.ps1)"
146
+ Write-Host ""
147
+ Write-Host " help - Tampilkan help ini"
148
+ Write-Host ""
149
+ Write-Host "EXAMPLES:" -ForegroundColor Cyan
150
+ Write-Host " .\.claude-kit\kit.ps1 setup -Force"
151
+ Write-Host " .\.claude-kit\kit.ps1 update"
152
+ Write-Host " .\.claude-kit\kit.ps1 doctor"
153
+ Write-Host ""
154
+ Write-Host "BACKWARD COMPATIBILITY:" -ForegroundColor Cyan
155
+ Write-Host " Setup script lama tetap bisa dipanggil langsung:"
156
+ Write-Host " .\.claude-kit\setup-pola-b.ps1 -Force"
157
+ Write-Host " .\.claude-kit\update-kit.ps1"
158
+ Write-Host ""
159
+ Write-Host " kit.ps1 cuma alternative entry point yang lebih ringkas."
160
+ Write-Host ""
161
+ }
162
+
163
+ # ---- Helper: doctor diagnostic ----
164
+ function Invoke-Doctor {
165
+ Write-Host ""
166
+ Write-Host "=== Kit Doctor (diagnostic) ===" -ForegroundColor Cyan
167
+ Write-Host ""
168
+
169
+ $ok = 0
170
+ $warn = 0
171
+ $err = 0
172
+
173
+ # 1. Kit version
174
+ $version = Get-KitVersion
175
+ if ($version -match '^v?\d+\.\d+\.\d+') {
176
+ $display = if ($version -match '^v') { $version } else { "v$version" }
177
+ Write-Host ("OK Kit version: {0}" -f $display) -ForegroundColor Green
178
+ $ok++
179
+ } elseif ($version -eq 'unknown') {
180
+ Write-Host "WARN Kit version: unknown (manifest hilang, `$script:KIT_VERSION kosong, CHANGELOG.md tidak parseable)" -ForegroundColor Yellow
181
+ $warn++
182
+ } else {
183
+ Write-Host ("ERROR Kit version: format tidak dikenali ('{0}')" -f $version) -ForegroundColor Red
184
+ $err++
185
+ }
186
+
187
+ # 2. File inti check
188
+ # Source of truth: lib\kit-files.psd1 (single manifest, di-load semua konsumen)
189
+ $kitFilesPsd1 = Join-Path $KitDir 'lib\kit-files.psd1'
190
+ if (-not (Test-Path $kitFilesPsd1)) {
191
+ Write-Host "ERROR lib\kit-files.psd1 hilang (manifest single-source-of-truth)" -ForegroundColor Red
192
+ $err++
193
+ $wajibAda = @()
194
+ } else {
195
+ $kitFiles = Import-PowerShellDataFile -Path $kitFilesPsd1
196
+ $wajibAda = @(
197
+ $kitFiles.core_prompts +
198
+ $kitFiles.universal_rules +
199
+ $kitFiles.scripts +
200
+ $kitFiles.lib_files +
201
+ $kitFiles.templates +
202
+ $kitFiles.docs +
203
+ $kitFiles.tests +
204
+ $kitFiles.ci +
205
+ $kitFiles.meta
206
+ ) | ForEach-Object { $_ -replace '/', '\' }
207
+ }
208
+
209
+ if ($wajibAda.Count -gt 0) {
210
+ $missing = @()
211
+ foreach ($f in $wajibAda) {
212
+ $p = Join-Path $KitDir $f
213
+ if (-not (Test-Path $p)) { $missing += $f }
214
+ }
215
+ if ($missing.Count -eq 0) {
216
+ Write-Host ("OK {0} file inti utuh" -f $wajibAda.Count) -ForegroundColor Green
217
+ $ok++
218
+ } else {
219
+ Write-Host ("ERROR {0} file missing:" -f $missing.Count) -ForegroundColor Red
220
+ $missing | ForEach-Object { Write-Host (" - {0}" -f $_) -ForegroundColor Red }
221
+ $err++
222
+ Write-Host " Saran: .\.claude-kit\kit.ps1 update (re-clone fresh)" -ForegroundColor Yellow
223
+ }
224
+ }
225
+
226
+ # 2b. Integrity check (sha256) — verifies files haven't been modified since install
227
+ $manifestPath = Join-Path $KitDir '.install-manifest.json'
228
+ if (Test-Path $manifestPath) {
229
+ try {
230
+ $manifestRaw = Get-Content -Path $manifestPath -Raw -ErrorAction Stop
231
+ $manifest = $manifestRaw | ConvertFrom-Json -ErrorAction Stop
232
+ } catch {
233
+ Write-Host ("WARN Integrity check skipped: gagal parse manifest ({0})" -f $_.Exception.Message) -ForegroundColor Yellow
234
+ $warn++
235
+ $manifest = $null
236
+ }
237
+
238
+ if ($manifest -ne $null) {
239
+ $pristine = 0
240
+ $modifiedList = @()
241
+ $integrityMissing = 0
242
+
243
+ $entries = @()
244
+ if ($manifest.files) { $entries = $manifest.files }
245
+ elseif ($manifest.entries) { $entries = $manifest.entries }
246
+
247
+ foreach ($entry in $entries) {
248
+ $relPath = $null
249
+ if ($entry.path) { $relPath = $entry.path }
250
+ elseif ($entry.file) { $relPath = $entry.file }
251
+ if (-not $relPath) { continue }
252
+
253
+ $expectedSha = $null
254
+ if ($entry.sha256) { $expectedSha = $entry.sha256 }
255
+ if (-not $expectedSha) { continue }
256
+
257
+ $relPathNorm = $relPath -replace '/', '\'
258
+ # Manifest stores paths relative to PROJECT ROOT (e.g. ".claude-kit/lib/rollback.ps1",
259
+ # "AGENTS.md"), bukan relative ke $KitDir. Lihat setup-pola-b.ps1 Add-ToManifest:
260
+ # `$relPath = $FilePath.Replace($script:ProjectRoot, '')`. Pakai $ProjectRoot
261
+ # (sudah didefine di line ~61) supaya tidak double-prefix ".claude-kit/.claude-kit/...".
262
+ $absPath = Join-Path $ProjectRoot $relPathNorm
263
+
264
+ if (-not (Test-Path $absPath)) {
265
+ $integrityMissing++
266
+ continue
267
+ }
268
+
269
+ try {
270
+ $actualSha = (Get-FileHash -Path $absPath -Algorithm SHA256 -ErrorAction Stop).Hash
271
+ if ($actualSha -eq $expectedSha.ToUpper() -or $actualSha.ToLower() -eq $expectedSha.ToLower()) {
272
+ $pristine++
273
+ } else {
274
+ $modifiedList += $relPath
275
+ }
276
+ } catch {
277
+ $modifiedList += ("{0} (hash error: {1})" -f $relPath, $_.Exception.Message)
278
+ }
279
+ }
280
+
281
+ $modifiedCount = $modifiedList.Count
282
+ Write-Host ("OK Integrity: PRISTINE={0}, MODIFIED={1}, MISSING={2}" -f $pristine, $modifiedCount, $integrityMissing) -ForegroundColor Green
283
+ if ($modifiedCount -gt 0) {
284
+ Write-Host "WARN File berikut dimodifikasi sejak install (mungkin disengaja):" -ForegroundColor Yellow
285
+ $modifiedList | ForEach-Object { Write-Host (" - {0}" -f $_) -ForegroundColor Yellow }
286
+ $warn++
287
+ } else {
288
+ $ok++
289
+ }
290
+ if ($integrityMissing -gt 0) {
291
+ Write-Host ("ERROR Integrity: {0} file di manifest tapi tidak ada di disk" -f $integrityMissing) -ForegroundColor Red
292
+ $err++
293
+ }
294
+ }
295
+ } else {
296
+ Write-Host "INFO Integrity check skipped: .install-manifest.json tidak ada (kit pre-manifest atau belum di-install)" -ForegroundColor Cyan
297
+ }
298
+
299
+ # 3. AGENTS.md di root proyek
300
+ $agentsAtRoot = Join-Path $ProjectRoot 'AGENTS.md'
301
+ if (Test-Path $agentsAtRoot) {
302
+ Write-Host "OK AGENTS.md ada di root proyek" -ForegroundColor Green
303
+ $ok++
304
+ } else {
305
+ Write-Host "WARN AGENTS.md belum di-copy ke root proyek" -ForegroundColor Yellow
306
+ Write-Host " Saran: .\.claude-kit\kit.ps1 setup" -ForegroundColor Yellow
307
+ $warn++
308
+ }
309
+
310
+ # 4. docs/ folder
311
+ $docsDir = Join-Path $ProjectRoot 'docs'
312
+ if (Test-Path $docsDir) {
313
+ $docsCount = (Get-ChildItem $docsDir -Recurse -File).Count
314
+ Write-Host ("OK docs/ ada ({0} file)" -f $docsCount) -ForegroundColor Green
315
+ $ok++
316
+ } else {
317
+ Write-Host "WARN docs/ belum dibuat" -ForegroundColor Yellow
318
+ Write-Host " Saran: .\.claude-kit\kit.ps1 setup" -ForegroundColor Yellow
319
+ $warn++
320
+ }
321
+
322
+ # 5. .github/ folder (team mode files)
323
+ $githubDir = Join-Path $ProjectRoot '.github'
324
+ if (Test-Path $githubDir) {
325
+ Write-Host "OK .github/ ada (Team Mode aktif)" -ForegroundColor Green
326
+ $ok++
327
+ } else {
328
+ Write-Host "INFO .github/ tidak ada (Team Mode skipped, atau project non-GitHub)" -ForegroundColor Cyan
329
+ }
330
+
331
+ # 6. .git/ internal (should NOT exist for Pola B clone)
332
+ $internalGit = Join-Path $KitDir '.git'
333
+ if (Test-Path $internalGit) {
334
+ Write-Host "WARN .claude-kit\.git\ masih ada (sisa dari clone)" -ForegroundColor Yellow
335
+ Write-Host " Saran: Remove-Item '$internalGit' -Recurse -Force" -ForegroundColor Yellow
336
+ $warn++
337
+ } else {
338
+ Write-Host "OK .claude-kit/ tidak ada .git/ internal" -ForegroundColor Green
339
+ $ok++
340
+ }
341
+
342
+ # Ringkasan
343
+ Write-Host ""
344
+ Write-Host ("Result: OK={0} WARN={1} ERROR={2}" -f $ok, $warn, $err) -ForegroundColor Cyan
345
+ if ($err -eq 0 -and $warn -eq 0) {
346
+ Write-Host "Kit sehat. Siap dipakai." -ForegroundColor Green
347
+ return 0
348
+ } elseif ($err -eq 0) {
349
+ Write-Host "Kit OK dengan warning. Bisa dipakai, tapi fix warning kalau bisa." -ForegroundColor Yellow
350
+ return 0
351
+ } else {
352
+ Write-Host "Kit BERMASALAH. Fix ERROR di atas dulu." -ForegroundColor Red
353
+ return 1
354
+ }
355
+ }
356
+
357
+ # ---- Helper: scan project ----
358
+ function Invoke-Scan {
359
+ Write-Host ""
360
+ Write-Host "=== Kit Scan — Universal Adaptive Scan (kit v$(Get-KitVersion)) ===" -ForegroundColor Cyan
361
+ Write-Host ""
362
+ Write-Host "Catatan: kit.ps1 scan = scan ringan untuk count kandidat." -ForegroundColor Yellow
363
+ Write-Host " Untuk bulk-bootstrap actual, paste JALANKAN_KIT.md ke Claude Code (yang trigger AI workflow)." -ForegroundColor Yellow
364
+ Write-Host ""
365
+
366
+ # Patterns CRITICAL (universal, sesuai JALANKAN_KIT)
367
+ $patterns = @{
368
+ 'Auth' = @('auth*', 'session*', 'login*', 'oauth*', 'jwt*', 'passport*')
369
+ 'DB' = @('db.*', 'prisma*', 'drizzle*', 'repository*', 'schema*', 'models')
370
+ 'Security' = @('crypto*', 'encrypt*', 'decrypt*', 'permissions*', 'acl*', 'policies*', '*-guard*', 'rate-limit*', 'csrf*', 'cors*')
371
+ 'API/Router' = @('routes', 'controllers', 'handlers', 'api', 'endpoints', 'resolvers', 'actions')
372
+ 'Entry/MW' = @('main.*', 'index.*', 'app.*', 'server.*', 'layout.*', 'middleware.*', 'interceptor.*')
373
+ }
374
+
375
+ $sourceFolders = @('src', 'app', 'lib', 'internal', 'pkg', 'cmd', 'features', 'modules', 'routes', 'controllers', 'handlers', 'services', 'domain')
376
+ $skipFolders = @('node_modules', 'dist', '.next', 'target', 'build', 'vendor', '__pycache__', '.venv', 'generated', '.git')
377
+
378
+ $totalByCategory = @{}
379
+ foreach ($cat in $patterns.Keys) { $totalByCategory[$cat] = 0 }
380
+
381
+ foreach ($src in $sourceFolders) {
382
+ $srcPath = Join-Path $ProjectRoot $src
383
+ if (-not (Test-Path $srcPath)) { continue }
384
+
385
+ $allFiles = Get-ChildItem -Path $srcPath -Recurse -File -ErrorAction SilentlyContinue |
386
+ Where-Object {
387
+ $skipped = $false
388
+ foreach ($skip in $skipFolders) {
389
+ if ($_.FullName -match "[\\/]$skip[\\/]") { $skipped = $true; break }
390
+ }
391
+ -not $skipped
392
+ }
393
+
394
+ foreach ($cat in $patterns.Keys) {
395
+ foreach ($p in $patterns[$cat]) {
396
+ $matched = $allFiles | Where-Object { $_.Name -like $p -or $_.FullName -match $p }
397
+ $totalByCategory[$cat] += $matched.Count
398
+ }
399
+ }
400
+ }
401
+
402
+ Write-Host "Kandidat CRITICAL per kategori (rough estimate):" -ForegroundColor Cyan
403
+ $grandTotal = 0
404
+ foreach ($cat in $patterns.Keys) {
405
+ $count = $totalByCategory[$cat]
406
+ Write-Host (" {0,-15} {1,4} file" -f $cat, $count)
407
+ $grandTotal += $count
408
+ }
409
+ Write-Host ""
410
+ Write-Host ("Total kandidat (rough, may include duplicates): {0}" -f $grandTotal) -ForegroundColor Yellow
411
+ Write-Host ""
412
+
413
+ if ($grandTotal -ge 30) {
414
+ Write-Host "Saran: total >= 30, pakai subfolder grouping saat bulk-bootstrap." -ForegroundColor Cyan
415
+ Write-Host " Mapping: docs/api/, docs/lib/, docs/security/, docs/features/<n>/, dst." -ForegroundColor Cyan
416
+ } else {
417
+ Write-Host "Saran: total < 30, flat docs/ masih oke." -ForegroundColor Cyan
418
+ }
419
+
420
+ Write-Host ""
421
+ Write-Host "Next step:" -ForegroundColor Cyan
422
+ Write-Host " 1. Paste isi .claude-kit\JALANKAN_KIT.md ke Claude Code untuk full workflow."
423
+ Write-Host " 2. AI akan tanya pilih (1)/(2)/(3)/(4) di step 12 (default (3) Skeleton-first)."
424
+ Write-Host ""
425
+
426
+ return 0
427
+ }
428
+
429
+ # ---- Helper: print version ----
430
+ # Uses Get-KitVersion fallback chain (manifest -> $script:KIT_VERSION -> CHANGELOG -> "unknown").
431
+ function Show-Version {
432
+ Write-Host (Get-KitVersion)
433
+ }
434
+
435
+ # ---- Router ----
436
+ switch ($Command) {
437
+ 'setup' {
438
+ $script = Join-Path $KitDir 'setup-pola-b.ps1'
439
+ if (-not (Test-Path $script)) {
440
+ Write-Host "ERROR: setup-pola-b.ps1 tidak ada di $KitDir" -ForegroundColor Red
441
+ exit 1
442
+ }
443
+ & $script @ExtraArgs
444
+ exit $LASTEXITCODE
445
+ }
446
+ 'update' {
447
+ $script = Join-Path $KitDir 'update-kit.ps1'
448
+ if (-not (Test-Path $script)) {
449
+ Write-Host "ERROR: update-kit.ps1 tidak ada di $KitDir" -ForegroundColor Red
450
+ exit 1
451
+ }
452
+ & $script @ExtraArgs
453
+ exit $LASTEXITCODE
454
+ }
455
+ 'uninstall' {
456
+ $script = Join-Path $KitDir 'uninstall.ps1'
457
+ if (-not (Test-Path $script)) {
458
+ Write-Host "ERROR: uninstall.ps1 tidak ada di $KitDir" -ForegroundColor Red
459
+ Write-Host " Kit ini di-install pakai versi <v1.0.0 (sebelum uninstall.ps1 ada)." -ForegroundColor Red
460
+ Write-Host " Saran: update kit dulu (.\.claude-kit\kit.ps1 update), atau hapus manual." -ForegroundColor Red
461
+ exit 1
462
+ }
463
+ & $script @ExtraArgs
464
+ exit $LASTEXITCODE
465
+ }
466
+ 'doctor' {
467
+ $code = Invoke-Doctor
468
+ exit $code
469
+ }
470
+ 'scan' {
471
+ $code = Invoke-Scan
472
+ exit $code
473
+ }
474
+ 'version' {
475
+ Show-Version
476
+ exit 0
477
+ }
478
+ 'rollback' {
479
+ if (Test-Path $libRollback) {
480
+ try {
481
+ . $libRollback
482
+ $result = Invoke-Rollback -ProjectRoot $ProjectRoot
483
+ # Result hash bisa di-suppress kalau dipanggil di pipe; di sini kita
484
+ # tidak butuh nilainya — biarin function-nya yang print status.
485
+ $null = $result
486
+ $global:LASTEXITCODE = 0
487
+ exit 0
488
+ } catch {
489
+ Write-Host ("[ERROR] Rollback gagal: {0}" -f $_) -ForegroundColor Red
490
+ $global:LASTEXITCODE = 2
491
+ exit 2
492
+ }
493
+ } else {
494
+ Write-Host "ERROR: lib\rollback.ps1 tidak ada di $KitDir" -ForegroundColor Red
495
+ Write-Host " Kit ini di-install pakai versi <v1.x (sebelum rollback ada)." -ForegroundColor Red
496
+ Write-Host " Saran: update kit dulu (.\.claude-kit\kit.ps1 update)." -ForegroundColor Red
497
+ exit 1
498
+ }
499
+ }
500
+ 'help' {
501
+ Show-Help
502
+ exit 0
503
+ }
504
+ default {
505
+ Show-Help
506
+ if ($Command -eq '') { exit 0 } else { exit 1 }
507
+ }
508
+ }
@@ -0,0 +1,174 @@
1
+ <#
2
+ .SYNOPSIS
3
+ lib/agents-md.ps1 - Library helper untuk deploy AGENTS.md dari template kit.
4
+
5
+ .DESCRIPTION
6
+ Extracted dari setup-pola-b.ps1 (v1.9) supaya logic fill AGENTS.md.template
7
+ reusable dari kit.ps1, update-kit.ps1, atau script lain yang butuh refresh
8
+ AGENTS.md tanpa run ulang full setup.
9
+
10
+ Tanggung jawab:
11
+ 1. Detect AGENTS.md existing di project root (preserve customization)
12
+ 2. Backup pre-overwrite ke AGENTS.md.backup-<timestamp>
13
+ 3. Fill template dengan placeholder set yang dikasih caller
14
+ 4. Tulis UTF-8 tanpa BOM (PS 5.1 default = with BOM, beberapa tool sensitif)
15
+ 5. Pakai .Replace() literal (bukan -replace regex) supaya input user dengan
16
+ karakter $0/$1/$ tidak corrupt output (defense vs regex injection)
17
+
18
+ TIDAK tangani:
19
+ - Manifest tracking (caller wajib panggil Add-ToManifest sendiri kalau perlu)
20
+ - Template file resolution (caller kasih -TemplatePath absolute)
21
+ - Project root validation (caller wajib pastikan path valid)
22
+
23
+ .NOTES
24
+ Versi : 1.0
25
+ Tanggal: 2026-06-06
26
+ Target : PowerShell 5.1+ (Windows Server 2025 / Win10 / Win11)
27
+ Encoding: UTF-8 tanpa BOM (System.Text.UTF8Encoding $false)
28
+ #>
29
+
30
+ # Module-level guard supaya re-dot-source tidak duplikasi function definition
31
+ if ($script:__lintasAI_AgentsMdLoaded) { return }
32
+ $script:__lintasAI_AgentsMdLoaded = $true
33
+
34
+ function Deploy-AgentsMd {
35
+ <#
36
+ .SYNOPSIS
37
+ Deploy AGENTS.md ke project root: fill template + backup existing.
38
+
39
+ .DESCRIPTION
40
+ Tiga mode behavior berdasarkan state existing AGENTS.md + flag -Preserve:
41
+ - Tidak ada existing -> CREATE (write template-filled fresh)
42
+ - Existing + -Preserve -> PRESERVE (skip, jangan timpa, return action=preserved)
43
+ - Existing + tanpa flag -> BACKUP + UPDATE (rename existing ke .backup-<timestamp>, tulis fresh)
44
+
45
+ Placeholders adalah hashtable @{ '<KEY>' = 'value' } - caller bebas tentukan
46
+ key set. Template biasanya pakai <NAMA_PROYEK>, <TANGGAL_HARI_INI>, <NAMA_KAMU>,
47
+ <URL_REPO_STANDAR>, <VERSI_KIT>, tapi function ini agnostic - apa pun yang
48
+ ada di hashtable di-replace pakai .Replace() literal.
49
+
50
+ .PARAMETER ProjectRoot
51
+ Absolute path ke root proyek (parent dari .claude-kit/). AGENTS.md akan
52
+ ditulis ke <ProjectRoot>\AGENTS.md.
53
+
54
+ .PARAMETER TemplatePath
55
+ Absolute path ke AGENTS.md.template (biasanya <KitDir>\AGENTS.md.template).
56
+
57
+ .PARAMETER Placeholders
58
+ Hashtable berisi pair @{ '<PLACEHOLDER>' = 'replacement_value' }.
59
+ Key biasanya wrap dengan angle bracket (e.g. '<NAMA_PROYEK>') sesuai konvensi
60
+ template, tapi function tidak enforce - replace literal apa adanya.
61
+
62
+ .PARAMETER Preserve
63
+ Kalau aktif DAN AGENTS.md existing ada -> SKIP overwrite, return action='preserved'.
64
+ Anti-destruktif default: protect user customization.
65
+
66
+ Tanpa flag ini, behavior default = backup + overwrite (untuk -Force scenario).
67
+
68
+ .OUTPUTS
69
+ PSCustomObject:
70
+ action : 'created' | 'updated' | 'preserved'
71
+ backup_path : string (path file backup) atau $null kalau tidak ada backup
72
+ target_path : string (path AGENTS.md final di project root)
73
+ placeholders_applied : int (jumlah key di hashtable yang di-replace)
74
+
75
+ .EXAMPLE
76
+ # Setup awal, project belum punya AGENTS.md
77
+ $result = Deploy-AgentsMd `
78
+ -ProjectRoot 'C:\proyek\akses' `
79
+ -TemplatePath 'C:\proyek\akses\.claude-kit\AGENTS.md.template' `
80
+ -Placeholders @{
81
+ '<NAMA_PROYEK>' = 'akses'
82
+ '<TANGGAL_HARI_INI>' = '2026-06-06'
83
+ '<NAMA_KAMU>' = 'dokterbrutal'
84
+ '<URL_REPO_STANDAR>' = 'https://github.com/foo/akses'
85
+ '<VERSI_KIT>' = 'v1.5.0'
86
+ }
87
+ # $result.action = 'created', $result.backup_path = $null
88
+
89
+ .EXAMPLE
90
+ # Re-run setup, AGENTS.md existing - mau preserve customization user
91
+ $result = Deploy-AgentsMd `
92
+ -ProjectRoot 'C:\proyek\akses' `
93
+ -TemplatePath 'C:\proyek\akses\.claude-kit\AGENTS.md.template' `
94
+ -Placeholders @{ '<NAMA_PROYEK>' = 'akses' } `
95
+ -Preserve
96
+ # $result.action = 'preserved', $result.backup_path = $null
97
+ #>
98
+ [CmdletBinding()]
99
+ param(
100
+ [Parameter(Mandatory = $true)]
101
+ [string]$ProjectRoot,
102
+
103
+ [Parameter(Mandatory = $true)]
104
+ [string]$TemplatePath,
105
+
106
+ [Parameter(Mandatory = $true)]
107
+ [hashtable]$Placeholders,
108
+
109
+ [switch]$Preserve
110
+ )
111
+
112
+ # ---- Validasi input ----
113
+ if (-not (Test-Path -LiteralPath $ProjectRoot -PathType Container)) {
114
+ throw "Deploy-AgentsMd: ProjectRoot tidak ditemukan atau bukan folder: $ProjectRoot"
115
+ }
116
+ if (-not (Test-Path -LiteralPath $TemplatePath -PathType Leaf)) {
117
+ throw "Deploy-AgentsMd: TemplatePath tidak ditemukan: $TemplatePath"
118
+ }
119
+
120
+ $target = Join-Path $ProjectRoot 'AGENTS.md'
121
+ $existing = Test-Path -LiteralPath $target -PathType Leaf
122
+
123
+ # ---- Mode PRESERVE: existing + flag aktif -> skip, return early ----
124
+ if ($existing -and $Preserve) {
125
+ return [PSCustomObject]@{
126
+ action = 'preserved'
127
+ backup_path = $null
128
+ target_path = $target
129
+ placeholders_applied = 0
130
+ }
131
+ }
132
+
133
+ # ---- Mode BACKUP: existing tanpa Preserve -> rename ke backup ----
134
+ $backupPath = $null
135
+ if ($existing) {
136
+ $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
137
+ $backupPath = "$target.backup-$timestamp"
138
+ try {
139
+ Copy-Item -LiteralPath $target -Destination $backupPath -Force -ErrorAction Stop
140
+ } catch {
141
+ throw "Deploy-AgentsMd: Gagal backup AGENTS.md existing ke '$backupPath': $_"
142
+ }
143
+ }
144
+
145
+ # ---- Fill template + tulis ----
146
+ try {
147
+ $content = Get-Content -LiteralPath $TemplatePath -Raw -Encoding UTF8
148
+ } catch {
149
+ throw "Deploy-AgentsMd: Gagal baca template '$TemplatePath': $_"
150
+ }
151
+
152
+ # Pakai .Replace() literal (bukan -replace regex) - input user dengan $0/$1/$
153
+ # tidak akan corrupt output. Defensive default vs regex injection.
154
+ $applied = 0
155
+ foreach ($key in $Placeholders.Keys) {
156
+ $val = [string]$Placeholders[$key]
157
+ $content = $content.Replace([string]$key, $val)
158
+ $applied++
159
+ }
160
+
161
+ # Tulis UTF-8 tanpa BOM (PS 5.1 default UTF8 = with BOM, beberapa tool sensitif)
162
+ try {
163
+ [System.IO.File]::WriteAllText($target, $content, (New-Object System.Text.UTF8Encoding $false))
164
+ } catch {
165
+ throw "Deploy-AgentsMd: Gagal tulis AGENTS.md ke '$target': $_"
166
+ }
167
+
168
+ return [PSCustomObject]@{
169
+ action = $(if ($existing) { 'updated' } else { 'created' })
170
+ backup_path = $backupPath
171
+ target_path = $target
172
+ placeholders_applied = $applied
173
+ }
174
+ }