its-magic 0.1.2-10

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 (97) hide show
  1. package/.cursor/agents/curator.mdc +21 -0
  2. package/.cursor/agents/dev.mdc +20 -0
  3. package/.cursor/agents/po.mdc +19 -0
  4. package/.cursor/agents/qa.mdc +19 -0
  5. package/.cursor/agents/release.mdc +19 -0
  6. package/.cursor/agents/tech-lead.mdc +21 -0
  7. package/.cursor/commands/architecture.md +29 -0
  8. package/.cursor/commands/auto.md +27 -0
  9. package/.cursor/commands/discovery.md +27 -0
  10. package/.cursor/commands/execute.md +32 -0
  11. package/.cursor/commands/intake.md +28 -0
  12. package/.cursor/commands/map-codebase.md +25 -0
  13. package/.cursor/commands/milestone-complete.md +24 -0
  14. package/.cursor/commands/milestone-start.md +26 -0
  15. package/.cursor/commands/pause.md +25 -0
  16. package/.cursor/commands/phase-context.md +25 -0
  17. package/.cursor/commands/plan-verify.md +26 -0
  18. package/.cursor/commands/qa.md +28 -0
  19. package/.cursor/commands/quick.md +24 -0
  20. package/.cursor/commands/refresh-context.md +26 -0
  21. package/.cursor/commands/release.md +29 -0
  22. package/.cursor/commands/research.md +28 -0
  23. package/.cursor/commands/resume.md +26 -0
  24. package/.cursor/commands/sprint-plan.md +30 -0
  25. package/.cursor/commands/verify-work.md +25 -0
  26. package/.cursor/hooks/README.md +13 -0
  27. package/.cursor/hooks/hook.py +197 -0
  28. package/.cursor/hooks.json +26 -0
  29. package/.cursor/plans/cursor-gsd-team-kit_8cfee9b8.plan.md +57 -0
  30. package/.cursor/remote.json +18 -0
  31. package/.cursor/rules/core.mdc +18 -0
  32. package/.cursor/rules/escalation.mdc +11 -0
  33. package/.cursor/rules/handoffs.mdc +10 -0
  34. package/.cursor/rules/quality.mdc +15 -0
  35. package/.cursor/scratchpad.md +34 -0
  36. package/.cursor/skills/its-magic/SKILL.md +39 -0
  37. package/.cursor/skills/its-magic/templates/acceptance.json +10 -0
  38. package/.cursor/skills/its-magic/templates/acceptance.md +7 -0
  39. package/.cursor/skills/its-magic/templates/architecture.json +11 -0
  40. package/.cursor/skills/its-magic/templates/architecture.md +14 -0
  41. package/.cursor/skills/its-magic/templates/decision.json +14 -0
  42. package/.cursor/skills/its-magic/templates/decision.md +19 -0
  43. package/.cursor/skills/its-magic/templates/handoff.json +6 -0
  44. package/.cursor/skills/its-magic/templates/handoff.md +12 -0
  45. package/.cursor/skills/its-magic/templates/milestone.json +7 -0
  46. package/.cursor/skills/its-magic/templates/phase-context.json +6 -0
  47. package/.cursor/skills/its-magic/templates/plan-verify.json +11 -0
  48. package/.cursor/skills/its-magic/templates/sprint.json +6 -0
  49. package/.cursor/skills/its-magic/templates/sprint.md +11 -0
  50. package/.cursor/skills/its-magic/templates/story.json +9 -0
  51. package/.cursor/skills/its-magic/templates/story.md +15 -0
  52. package/.cursor/skills/its-magic/templates/uat.json +15 -0
  53. package/.github/workflows/ci.yml +49 -0
  54. package/.github/workflows/deploy.yml +56 -0
  55. package/README.md +755 -0
  56. package/bin/its-magic.js +86 -0
  57. package/decisions/DEC-0001.md +21 -0
  58. package/decisions/DEC-0002.md +21 -0
  59. package/docs/engineering/architecture.md +354 -0
  60. package/docs/engineering/codebase-map.md +14 -0
  61. package/docs/engineering/context/phase-template.json +6 -0
  62. package/docs/engineering/decisions.md +6 -0
  63. package/docs/engineering/dependencies.json +5 -0
  64. package/docs/engineering/research.md +11 -0
  65. package/docs/engineering/runbook.md +32 -0
  66. package/docs/engineering/state.md +33 -0
  67. package/docs/product/acceptance.md +6 -0
  68. package/docs/product/backlog.md +7 -0
  69. package/docs/product/vision.md +46 -0
  70. package/handoffs/dev_to_qa.md +8 -0
  71. package/handoffs/po_to_tl.md +8 -0
  72. package/handoffs/qa_to_dev.md +6 -0
  73. package/handoffs/release_notes.md +14 -0
  74. package/handoffs/resume_brief.md +8 -0
  75. package/handoffs/tl_to_dev.md +7 -0
  76. package/installer.ps1 +189 -0
  77. package/installer.py +195 -0
  78. package/installer.sh +201 -0
  79. package/milestones/M0001/milestone.json +7 -0
  80. package/milestones/M0001/phases.json +9 -0
  81. package/milestones/M0001/progress.md +3 -0
  82. package/milestones/M0001/summary.md +3 -0
  83. package/package.json +38 -0
  84. package/scripts/generate-release-notes.ps1 +74 -0
  85. package/scripts/generate-release-notes.sh +63 -0
  86. package/scripts/release-all.ps1 +423 -0
  87. package/scripts/release-all.sh +226 -0
  88. package/sprints/S0001/plan-verify.json +5 -0
  89. package/sprints/S0001/progress.md +4 -0
  90. package/sprints/S0001/qa-findings.md +113 -0
  91. package/sprints/S0001/sprint.md +70 -0
  92. package/sprints/S0001/summary.md +46 -0
  93. package/sprints/S0001/tasks.md +35 -0
  94. package/sprints/S0001/uat.json +8 -0
  95. package/sprints/S0001/uat.md +8 -0
  96. package/sprints/quick/Q0001/summary.md +3 -0
  97. package/sprints/quick/Q0001/task.json +6 -0
@@ -0,0 +1,14 @@
1
+ # Release Notes
2
+
3
+ ## Summary
4
+ - ...
5
+
6
+ ## Changes
7
+ - ...
8
+
9
+ ## Known issues
10
+ - ...
11
+
12
+ ## Deploy steps
13
+ - ...
14
+
@@ -0,0 +1,8 @@
1
+ # Resume Brief
2
+
3
+ ## Current status
4
+ - ...
5
+
6
+ ## Next actions
7
+ - ...
8
+
@@ -0,0 +1,7 @@
1
+ # TL -> Dev Handoff
2
+
3
+ ## Summary
4
+ - ...
5
+
6
+ ## Tasks
7
+ - ...
package/installer.ps1 ADDED
@@ -0,0 +1,189 @@
1
+ Param(
2
+ [string]$Target,
3
+ [ValidateSet("missing","overwrite","interactive")]
4
+ [string]$Mode,
5
+ [switch]$Backup,
6
+ [switch]$Create
7
+ )
8
+
9
+ $ErrorActionPreference = "Stop"
10
+
11
+ function Normalize-PathSafe($Path) {
12
+ return [System.IO.Path]::GetFullPath($Path)
13
+ }
14
+
15
+ function Ensure-Parent($Path) {
16
+ $parent = Split-Path -Parent $Path
17
+ if ($parent -and -not (Test-Path $parent)) {
18
+ New-Item -ItemType Directory -Path $parent -Force | Out-Null
19
+ }
20
+ }
21
+
22
+ function List-SourceFiles($SourceRoot, $IncludePaths) {
23
+ $files = New-Object System.Collections.Generic.List[string]
24
+ foreach ($rel in $IncludePaths) {
25
+ $src = Join-Path $SourceRoot $rel
26
+ if (Test-Path $src -PathType Leaf) {
27
+ $files.Add($rel)
28
+ } elseif (Test-Path $src -PathType Container) {
29
+ Get-ChildItem -Path $src -Recurse -File | ForEach-Object {
30
+ $relPath = $_.FullName.Substring($SourceRoot.Length).TrimStart("\","/")
31
+ $files.Add($relPath)
32
+ }
33
+ }
34
+ }
35
+ return $files | Select-Object -Unique | Sort-Object
36
+ }
37
+
38
+ function Backup-Files($TargetRoot, $RelPaths) {
39
+ $timestamp = (Get-Date).ToUniversalTime().ToString("yyyyMMdd-HHmmssZ")
40
+ $backupRoot = Join-Path $TargetRoot ("backups\" + $timestamp)
41
+ foreach ($rel in $RelPaths) {
42
+ $src = Join-Path $TargetRoot $rel
43
+ if (Test-Path $src -PathType Leaf) {
44
+ $dst = Join-Path $backupRoot $rel
45
+ Ensure-Parent $dst
46
+ Copy-Item -Path $src -Destination $dst -Force
47
+ }
48
+ }
49
+ return $backupRoot
50
+ }
51
+
52
+ function Choose-Mode {
53
+ Write-Host "Select install mode:"
54
+ Write-Host "1) missing-only (copy only files that do not exist)"
55
+ Write-Host "2) overwrite-all (replace existing files)"
56
+ Write-Host "3) interactive (prompt per file)"
57
+ $choice = Read-Host "Enter 1, 2, or 3"
58
+ switch ($choice) {
59
+ "1" { return "missing" }
60
+ "2" { return "overwrite" }
61
+ Default { return "interactive" }
62
+ }
63
+ }
64
+
65
+ function Prompt-YesNo($Label, $Default = $false) {
66
+ $suffix = if ($Default) { "Y/n" } else { "y/N" }
67
+ $value = (Read-Host "$Label [$suffix]").ToLowerInvariant()
68
+ if ([string]::IsNullOrWhiteSpace($value)) { return $Default }
69
+ return @("y","yes") -contains $value
70
+ }
71
+
72
+ $sourceRoot = Normalize-PathSafe (Split-Path -Parent $MyInvocation.MyCommand.Path)
73
+ if (-not $Target) {
74
+ $Target = Read-Host "Target repository path"
75
+ }
76
+ $targetRoot = Normalize-PathSafe $Target
77
+
78
+ if (-not (Test-Path $targetRoot -PathType Container)) {
79
+ if ($Create -or (Prompt-YesNo "Target missing. Create?" $false)) {
80
+ New-Item -ItemType Directory -Path $targetRoot -Force | Out-Null
81
+ } else {
82
+ Write-Host "Target directory does not exist."
83
+ exit 1
84
+ }
85
+ }
86
+
87
+ $mode = if ($Mode) { $Mode } else { Choose-Mode }
88
+ $backupEnabled = $Backup.IsPresent
89
+ if (($mode -eq "overwrite" -or $mode -eq "interactive") -and -not $backupEnabled) {
90
+ $backupEnabled = Prompt-YesNo "Backup existing files before overwrite?" $false
91
+ }
92
+
93
+ $includePaths = @(
94
+ ".cursor/commands",
95
+ ".cursor/rules",
96
+ ".cursor/skills",
97
+ ".cursor/agents",
98
+ ".cursor/hooks",
99
+ ".cursor/hooks.json",
100
+ ".cursor/scratchpad.md",
101
+ "docs",
102
+ "sprints",
103
+ "handoffs",
104
+ "decisions",
105
+ ".github/workflows",
106
+ "README.md",
107
+ "installer.py",
108
+ "installer.ps1",
109
+ "installer.sh"
110
+ )
111
+
112
+ $files = List-SourceFiles $sourceRoot $includePaths
113
+ if ($files.Count -eq 0) {
114
+ Write-Host "No source files found to install."
115
+ exit 1
116
+ }
117
+
118
+ if ($backupEnabled -and $mode -eq "overwrite") {
119
+ $overwriteCandidates = @()
120
+ foreach ($rel in $files) {
121
+ $dst = Join-Path $targetRoot $rel
122
+ if (Test-Path $dst -PathType Leaf) { $overwriteCandidates += $rel }
123
+ }
124
+ if ($overwriteCandidates.Count -gt 0) {
125
+ $backupRoot = Backup-Files $targetRoot $overwriteCandidates
126
+ Write-Host "Backup created at: $backupRoot"
127
+ }
128
+ }
129
+
130
+ foreach ($rel in $files) {
131
+ $src = Join-Path $sourceRoot $rel
132
+ $dst = Join-Path $targetRoot $rel
133
+ $exists = Test-Path $dst -PathType Leaf
134
+
135
+ if ($mode -eq "missing") {
136
+ if ($exists) { continue }
137
+ Ensure-Parent $dst
138
+ Copy-Item -Path $src -Destination $dst -Force
139
+ continue
140
+ }
141
+
142
+ if ($mode -eq "overwrite") {
143
+ Ensure-Parent $dst
144
+ Copy-Item -Path $src -Destination $dst -Force
145
+ continue
146
+ }
147
+
148
+ if ($mode -eq "interactive") {
149
+ if (-not $exists) {
150
+ Ensure-Parent $dst
151
+ Copy-Item -Path $src -Destination $dst -Force
152
+ continue
153
+ }
154
+ $answer = (Read-Host "File exists: $rel | [o]verwrite [s]kip [q]uit").ToLowerInvariant()
155
+ if ($answer -eq "q") {
156
+ Write-Host "Aborted."
157
+ exit 1
158
+ }
159
+ if ($answer -eq "o") {
160
+ if ($backupEnabled) {
161
+ $backupRoot = Backup-Files $targetRoot @($rel)
162
+ Write-Host "Backed up: $rel -> $backupRoot"
163
+ }
164
+ Ensure-Parent $dst
165
+ Copy-Item -Path $src -Destination $dst -Force
166
+ }
167
+ }
168
+ }
169
+
170
+ function Show-ItsMagicBanner {
171
+ $prev = [Console]::OutputEncoding
172
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
173
+ Write-Host ""
174
+ Write-Host " ██╗████████╗███████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗" -ForegroundColor Magenta
175
+ Write-Host " ██║╚══██╔══╝██╔════╝ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝" -ForegroundColor Magenta
176
+ Write-Host " ██║ ██║ ███████╗█████╗██╔████╔██║███████║██║ ███╗██║██║ " -ForegroundColor Magenta
177
+ Write-Host " ██║ ██║ ╚════██║╚════╝██║╚██╔╝██║██╔══██║██║ ██║██║██║ " -ForegroundColor Cyan
178
+ Write-Host " ██║ ██║ ███████║ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗" -ForegroundColor Cyan
179
+ Write-Host " ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝" -ForegroundColor Cyan
180
+ Write-Host ""
181
+ Write-Host " AI dev team" -ForegroundColor Yellow
182
+ Write-Host " Installation complete!" -ForegroundColor Green
183
+ Write-Host ""
184
+ [Console]::OutputEncoding = $prev
185
+ }
186
+
187
+ Show-ItsMagicBanner
188
+ exit 0
189
+
package/installer.py ADDED
@@ -0,0 +1,195 @@
1
+ import argparse
2
+ import os
3
+ import shutil
4
+ import sys
5
+ from datetime import datetime
6
+
7
+
8
+ def normalize(path):
9
+ return os.path.normpath(os.path.abspath(path))
10
+
11
+
12
+ def list_source_files(source_root, include_paths):
13
+ files = []
14
+ for rel in include_paths:
15
+ src = os.path.join(source_root, rel)
16
+ if os.path.isfile(src):
17
+ files.append(rel)
18
+ elif os.path.isdir(src):
19
+ for root, _, filenames in os.walk(src):
20
+ for name in filenames:
21
+ full = os.path.join(root, name)
22
+ rel_path = os.path.relpath(full, source_root)
23
+ files.append(rel_path)
24
+ return sorted(set(files))
25
+
26
+
27
+ def ensure_parent(path):
28
+ parent = os.path.dirname(path)
29
+ if parent and not os.path.isdir(parent):
30
+ os.makedirs(parent, exist_ok=True)
31
+
32
+
33
+ def backup_files(target_root, rel_paths):
34
+ timestamp = datetime.utcnow().strftime("%Y%m%d-%H%M%SZ")
35
+ backup_root = os.path.join(target_root, "backups", timestamp)
36
+ for rel in rel_paths:
37
+ src = os.path.join(target_root, rel)
38
+ if os.path.isfile(src):
39
+ dst = os.path.join(backup_root, rel)
40
+ ensure_parent(dst)
41
+ shutil.copy2(src, dst)
42
+ return backup_root
43
+
44
+
45
+ def choose_mode():
46
+ print("Select install mode:")
47
+ print("1) missing-only (copy only files that do not exist)")
48
+ print("2) overwrite-all (replace existing files)")
49
+ print("3) interactive (prompt per file)")
50
+ choice = input("Enter 1, 2, or 3: ").strip()
51
+ if choice == "1":
52
+ return "missing"
53
+ if choice == "2":
54
+ return "overwrite"
55
+ return "interactive"
56
+
57
+
58
+ def prompt_yes_no(label, default=False):
59
+ suffix = "Y/n" if default else "y/N"
60
+ value = input(f"{label} [{suffix}]: ").strip().lower()
61
+ if not value:
62
+ return default
63
+ return value in ("y", "yes")
64
+
65
+
66
+ def main():
67
+ parser = argparse.ArgumentParser(description="Install its-magic into a repo")
68
+ parser.add_argument("--target", help="Target repository path")
69
+ parser.add_argument(
70
+ "--mode",
71
+ choices=["missing", "overwrite", "interactive"],
72
+ help="Install mode",
73
+ )
74
+ parser.add_argument(
75
+ "--backup",
76
+ action="store_true",
77
+ help="Backup files before overwriting",
78
+ )
79
+ parser.add_argument(
80
+ "--create",
81
+ action="store_true",
82
+ help="Create target directory if missing",
83
+ )
84
+ args = parser.parse_args()
85
+
86
+ source_root = normalize(os.path.dirname(__file__))
87
+ target_root = normalize(args.target) if args.target else None
88
+
89
+ if not target_root:
90
+ target_root = normalize(input("Target repository path: ").strip())
91
+
92
+ if not os.path.isdir(target_root):
93
+ if args.create or prompt_yes_no("Target missing. Create?", default=False):
94
+ os.makedirs(target_root, exist_ok=True)
95
+ else:
96
+ print("Target directory does not exist.")
97
+ return 1
98
+
99
+ mode = args.mode or choose_mode()
100
+ backup_enabled = args.backup
101
+ if mode in ("overwrite", "interactive") and not args.backup:
102
+ backup_enabled = prompt_yes_no("Backup existing files before overwrite?", False)
103
+
104
+ include_paths = [
105
+ ".cursor/commands",
106
+ ".cursor/rules",
107
+ ".cursor/skills",
108
+ ".cursor/agents",
109
+ ".cursor/hooks",
110
+ ".cursor/hooks.json",
111
+ ".cursor/scratchpad.md",
112
+ "docs",
113
+ "sprints",
114
+ "handoffs",
115
+ "decisions",
116
+ ".github/workflows",
117
+ "README.md",
118
+ "installer.py",
119
+ ]
120
+
121
+ files = list_source_files(source_root, include_paths)
122
+ if not files:
123
+ print("No source files found to install.")
124
+ return 1
125
+
126
+ overwrite_candidates = []
127
+ if backup_enabled and mode == "overwrite":
128
+ for rel in files:
129
+ if os.path.isfile(os.path.join(target_root, rel)):
130
+ overwrite_candidates.append(rel)
131
+ if overwrite_candidates:
132
+ backup_root = backup_files(target_root, overwrite_candidates)
133
+ print(f"Backup created at: {backup_root}")
134
+
135
+ for rel in files:
136
+ src = os.path.join(source_root, rel)
137
+ dst = os.path.join(target_root, rel)
138
+ exists = os.path.isfile(dst)
139
+
140
+ if mode == "missing":
141
+ if exists:
142
+ continue
143
+ ensure_parent(dst)
144
+ shutil.copy2(src, dst)
145
+ continue
146
+
147
+ if mode == "overwrite":
148
+ ensure_parent(dst)
149
+ shutil.copy2(src, dst)
150
+ continue
151
+
152
+ if mode == "interactive":
153
+ if not exists:
154
+ ensure_parent(dst)
155
+ shutil.copy2(src, dst)
156
+ continue
157
+ answer = input(f"File exists: {rel} | [o]verwrite [s]kip [q]uit: ").strip().lower()
158
+ if answer == "q":
159
+ print("Aborted.")
160
+ return 1
161
+ if answer == "o":
162
+ if backup_enabled:
163
+ backup_root = backup_files(target_root, [rel])
164
+ print(f"Backed up: {rel} -> {backup_root}")
165
+ ensure_parent(dst)
166
+ shutil.copy2(src, dst)
167
+ else:
168
+ continue
169
+
170
+ show_banner()
171
+ return 0
172
+
173
+
174
+ def show_banner():
175
+ M = "\033[1;35m"
176
+ C = "\033[1;36m"
177
+ Y = "\033[1;33m"
178
+ G = "\033[1;32m"
179
+ R = "\033[0m"
180
+ print()
181
+ print(f"{M} ██╗████████╗███████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗{R}")
182
+ print(f"{M} ██║╚══██╔══╝██╔════╝ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝{R}")
183
+ print(f"{M} ██║ ██║ ███████╗█████╗██╔████╔██║███████║██║ ███╗██║██║ {R}")
184
+ print(f"{C} ██║ ██║ ╚════██║╚════╝██║╚██╔╝██║██╔══██║██║ ██║██║██║ {R}")
185
+ print(f"{C} ██║ ██║ ███████║ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗{R}")
186
+ print(f"{C} ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝{R}")
187
+ print()
188
+ print(f"{Y} AI dev team{R}")
189
+ print(f"{G} Installation complete!{R}")
190
+ print()
191
+
192
+
193
+ if __name__ == "__main__":
194
+ raise SystemExit(main())
195
+
package/installer.sh ADDED
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env sh
2
+ set -e
3
+
4
+
5
+ ensure_parent() {
6
+ dir=$(dirname "$1")
7
+ [ -d "$dir" ] || mkdir -p "$dir"
8
+ }
9
+
10
+ list_source_files() {
11
+ source_root="$1"
12
+ shift
13
+ for rel in "$@"; do
14
+ src="$source_root/$rel"
15
+ if [ -f "$src" ]; then
16
+ echo "$rel"
17
+ elif [ -d "$src" ]; then
18
+ find "$src" -type f | sed "s|^$source_root/||"
19
+ fi
20
+ done | sort -u
21
+ }
22
+
23
+ backup_files() {
24
+ target_root="$1"
25
+ shift
26
+ timestamp=$(date -u +"%Y%m%d-%H%M%SZ")
27
+ backup_root="$target_root/backups/$timestamp"
28
+ for rel in "$@"; do
29
+ src="$target_root/$rel"
30
+ if [ -f "$src" ]; then
31
+ dst="$backup_root/$rel"
32
+ ensure_parent "$dst"
33
+ cp -p "$src" "$dst"
34
+ fi
35
+ done
36
+ echo "$backup_root"
37
+ }
38
+
39
+ choose_mode() {
40
+ printf "%s\n" "Select install mode:"
41
+ printf "%s\n" "1) missing-only (copy only files that do not exist)"
42
+ printf "%s\n" "2) overwrite-all (replace existing files)"
43
+ printf "%s\n" "3) interactive (prompt per file)"
44
+ printf "%s" "Enter 1, 2, or 3: "
45
+ read -r choice
46
+ case "$choice" in
47
+ 1) echo "missing" ;;
48
+ 2) echo "overwrite" ;;
49
+ *) echo "interactive" ;;
50
+ esac
51
+ }
52
+
53
+ prompt_yes_no() {
54
+ label="$1"
55
+ default="$2"
56
+ suffix="y/N"
57
+ [ "$default" = "true" ] && suffix="Y/n"
58
+ printf "%s [%s]: " "$label" "$suffix"
59
+ read -r value
60
+ value=$(printf "%s" "$value" | tr 'A-Z' 'a-z')
61
+ if [ -z "$value" ]; then
62
+ [ "$default" = "true" ] && return 0 || return 1
63
+ fi
64
+ [ "$value" = "y" ] || [ "$value" = "yes" ]
65
+ }
66
+
67
+ TARGET=""
68
+ MODE=""
69
+ BACKUP="false"
70
+ CREATE="false"
71
+
72
+ while [ $# -gt 0 ]; do
73
+ case "$1" in
74
+ --target) TARGET="$2"; shift 2 ;;
75
+ --mode) MODE="$2"; shift 2 ;;
76
+ --backup) BACKUP="true"; shift 1 ;;
77
+ --create) CREATE="true"; shift 1 ;;
78
+ *) shift 1 ;;
79
+ esac
80
+ done
81
+
82
+ SOURCE_ROOT=$(cd "$(dirname "$0")" && pwd)
83
+
84
+ if [ -z "$TARGET" ]; then
85
+ printf "%s" "Target repository path: "
86
+ read -r TARGET
87
+ fi
88
+
89
+ if [ ! -d "$TARGET" ]; then
90
+ if [ "$CREATE" = "true" ] || prompt_yes_no "Target missing. Create?" "false"; then
91
+ mkdir -p "$TARGET"
92
+ else
93
+ printf "%s\n" "Target directory does not exist."
94
+ exit 1
95
+ fi
96
+ fi
97
+ TARGET_ROOT=$(cd "$TARGET" && pwd)
98
+
99
+ if [ -z "$MODE" ]; then
100
+ MODE=$(choose_mode)
101
+ fi
102
+
103
+ if [ "$MODE" = "overwrite" ] || [ "$MODE" = "interactive" ]; then
104
+ if [ "$BACKUP" = "false" ]; then
105
+ if prompt_yes_no "Backup existing files before overwrite?" "false"; then
106
+ BACKUP="true"
107
+ fi
108
+ fi
109
+ fi
110
+
111
+ INCLUDE_PATHS="
112
+ .cursor/commands
113
+ .cursor/rules
114
+ .cursor/skills
115
+ .cursor/agents
116
+ .cursor/hooks
117
+ .cursor/hooks.json
118
+ .cursor/scratchpad.md
119
+ docs
120
+ sprints
121
+ handoffs
122
+ decisions
123
+ .github/workflows
124
+ README.md
125
+ installer.py
126
+ installer.ps1
127
+ installer.sh
128
+ "
129
+
130
+ FILES=$(list_source_files "$SOURCE_ROOT" $INCLUDE_PATHS)
131
+ if [ -z "$FILES" ]; then
132
+ printf "%s\n" "No source files found to install."
133
+ exit 1
134
+ fi
135
+
136
+ if [ "$BACKUP" = "true" ] && [ "$MODE" = "overwrite" ]; then
137
+ overwrite_candidates=""
138
+ for rel in $FILES; do
139
+ [ -f "$TARGET_ROOT/$rel" ] && overwrite_candidates="$overwrite_candidates $rel"
140
+ done
141
+ if [ -n "$overwrite_candidates" ]; then
142
+ backup_root=$(backup_files "$TARGET_ROOT" $overwrite_candidates)
143
+ printf "%s\n" "Backup created at: $backup_root"
144
+ fi
145
+ fi
146
+
147
+ for rel in $FILES; do
148
+ src="$SOURCE_ROOT/$rel"
149
+ dst="$TARGET_ROOT/$rel"
150
+ if [ "$MODE" = "missing" ]; then
151
+ [ -f "$dst" ] && continue
152
+ ensure_parent "$dst"
153
+ cp -p "$src" "$dst"
154
+ continue
155
+ fi
156
+ if [ "$MODE" = "overwrite" ]; then
157
+ ensure_parent "$dst"
158
+ cp -p "$src" "$dst"
159
+ continue
160
+ fi
161
+ if [ "$MODE" = "interactive" ]; then
162
+ if [ ! -f "$dst" ]; then
163
+ ensure_parent "$dst"
164
+ cp -p "$src" "$dst"
165
+ continue
166
+ fi
167
+ printf "%s" "File exists: $rel | [o]verwrite [s]kip [q]uit: "
168
+ read -r answer
169
+ answer=$(printf "%s" "$answer" | tr 'A-Z' 'a-z')
170
+ if [ "$answer" = "q" ]; then
171
+ printf "%s\n" "Aborted."
172
+ exit 1
173
+ fi
174
+ if [ "$answer" = "o" ]; then
175
+ if [ "$BACKUP" = "true" ]; then
176
+ backup_root=$(backup_files "$TARGET_ROOT" "$rel")
177
+ printf "%s\n" "Backed up: $rel -> $backup_root"
178
+ fi
179
+ ensure_parent "$dst"
180
+ cp -p "$src" "$dst"
181
+ fi
182
+ fi
183
+ done
184
+
185
+ show_banner() {
186
+ printf "\n"
187
+ printf "\033[1;35m ██╗████████╗███████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗\033[0m\n"
188
+ printf "\033[1;35m ██║╚══██╔══╝██╔════╝ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝\033[0m\n"
189
+ printf "\033[1;35m ██║ ██║ ███████╗█████╗██╔████╔██║███████║██║ ███╗██║██║ \033[0m\n"
190
+ printf "\033[1;36m ██║ ██║ ╚════██║╚════╝██║╚██╔╝██║██╔══██║██║ ██║██║██║ \033[0m\n"
191
+ printf "\033[1;36m ██║ ██║ ███████║ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗\033[0m\n"
192
+ printf "\033[1;36m ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝\033[0m\n"
193
+ printf "\n"
194
+ printf "\033[1;33m AI dev team\033[0m\n"
195
+ printf "\033[1;32m Installation complete!\033[0m\n"
196
+ printf "\n"
197
+ }
198
+
199
+ show_banner
200
+ exit 0
201
+
@@ -0,0 +1,7 @@
1
+ {
2
+ "id": "M0001",
3
+ "name": "",
4
+ "goal": "",
5
+ "scope": [],
6
+ "status": "active"
7
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "milestone": "M0001",
3
+ "phases": [
4
+ {
5
+ "name": "intake",
6
+ "status": "pending"
7
+ }
8
+ ]
9
+ }
@@ -0,0 +1,3 @@
1
+ # Milestone Progress
2
+
3
+ - ...
@@ -0,0 +1,3 @@
1
+ # Milestone Summary
2
+
3
+ - ...
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "its-magic",
3
+ "version": "0.1.2-10",
4
+ "description": "its-magic - AI dev team workflow for Cursor.",
5
+ "license": "MIT",
6
+ "bin": {
7
+ "its-magic": "bin/its-magic.js"
8
+ },
9
+ "files": [
10
+ ".cursor/",
11
+ ".github/",
12
+ "decisions/",
13
+ "docs/",
14
+ "handoffs/",
15
+ "milestones/",
16
+ "scripts/",
17
+ "sprints/",
18
+ "installer.ps1",
19
+ "installer.sh",
20
+ "installer.py",
21
+ "README.md",
22
+ "bin/its-magic.js"
23
+ ],
24
+ "scripts": {
25
+ "release:patch": "npm version patch && npm publish",
26
+ "release:minor": "npm version minor && npm publish",
27
+ "release:major": "npm version major && npm publish",
28
+ "release:all": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1",
29
+ "release:all:patch": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1 -Bump patch",
30
+ "release:all:minor": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1 -Bump minor",
31
+ "release:all:major": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1 -Bump major",
32
+ "release:all:beta": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1 -Bump prerelease -NpmTag beta",
33
+ "release:all:dry": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1 -DryRun",
34
+ "release:npm-only": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1 -SkipChoco -SkipBrew",
35
+ "release:choco-only": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1 -SkipNpm -SkipBrew",
36
+ "release:brew-only": "powershell -ExecutionPolicy Bypass -File scripts/release-all.ps1 -SkipNpm -SkipChoco"
37
+ }
38
+ }