its-magic 0.1.2-13 → 0.1.2-15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -7
- package/bin/its-magic.js +102 -9
- package/installer.ps1 +130 -20
- package/installer.py +134 -39
- package/installer.sh +111 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,17 +69,48 @@ its-magic --target . --mode overwrite --backup
|
|
|
69
69
|
2. Run `/intake` with your idea
|
|
70
70
|
3. Follow the workflow
|
|
71
71
|
|
|
72
|
+
### CLI quick commands
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Show banner + help
|
|
76
|
+
its-magic
|
|
77
|
+
|
|
78
|
+
# Show version only
|
|
79
|
+
its-magic --version
|
|
80
|
+
|
|
81
|
+
# Install workflow files into current repo
|
|
82
|
+
its-magic --target . --mode missing
|
|
83
|
+
|
|
84
|
+
# Clean previously installed workflow artifacts
|
|
85
|
+
its-magic --clean-repo --target .
|
|
86
|
+
```
|
|
87
|
+
|
|
72
88
|
### Installer options
|
|
73
89
|
|
|
90
|
+
**Install options**
|
|
91
|
+
|
|
92
|
+
| Flag | Description |
|
|
93
|
+
|------|-------------|
|
|
94
|
+
| `--target <path>` | Path to the repository where workflow files are installed. If omitted you are prompted interactively. |
|
|
95
|
+
| `--mode missing` | **Default.** Only copy files that do not exist yet. Safe for repos that already have some workflow files. |
|
|
96
|
+
| `--mode overwrite` | Replace every file, even if it already exists. Combine with `--backup` to keep a snapshot first. |
|
|
97
|
+
| `--mode interactive` | Ask per file whether to overwrite or skip. Useful when you want to cherry-pick updates. |
|
|
98
|
+
| `--backup` | Before overwriting, save existing files to `backups/<timestamp>/`. Ignored in `missing` mode (nothing gets replaced). |
|
|
99
|
+
| `--create` | Create the target directory if it does not exist. |
|
|
100
|
+
|
|
101
|
+
**Clean options**
|
|
102
|
+
|
|
103
|
+
| Flag | Description |
|
|
104
|
+
|------|-------------|
|
|
105
|
+
| `--clean-repo` | Remove all its-magic workflow artifacts from the target repo (`.cursor`, `docs/product`, `docs/engineering`, `sprints`, `handoffs`, `decisions`). Your own source code is never touched. |
|
|
106
|
+
| `--yes` | Skip the confirmation prompt when cleaning. |
|
|
107
|
+
|
|
108
|
+
**Info**
|
|
109
|
+
|
|
74
110
|
| Flag | Description |
|
|
75
111
|
|------|-------------|
|
|
76
|
-
| `--
|
|
77
|
-
| `--
|
|
78
|
-
| `--mode overwrite` | Replace existing files |
|
|
79
|
-
| `--mode interactive` | Prompt per file |
|
|
80
|
-
| `--backup` | Save replaced files into `backups/<timestamp>/` |
|
|
81
|
-
| `--create` | Create target directory |
|
|
82
|
-
| `--help` | Show usage |
|
|
112
|
+
| `--help`, `-h` | Show banner, version, repo URL, and full usage reference. |
|
|
113
|
+
| `--version`, `-v` | Print the installed its-magic version and exit. |
|
|
83
114
|
|
|
84
115
|
## How-to
|
|
85
116
|
|
package/bin/its-magic.js
CHANGED
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const { spawnSync } = require("child_process");
|
|
4
|
+
const packageJson = require("../package.json");
|
|
5
|
+
|
|
6
|
+
const REPO_URL = "https://github.com/fl0wm0ti0n/its-magic";
|
|
7
|
+
|
|
8
|
+
function printBanner() {
|
|
9
|
+
const M = "\x1b[1;35m";
|
|
10
|
+
const C = "\x1b[1;36m";
|
|
11
|
+
const Y = "\x1b[1;33m";
|
|
12
|
+
const R = "\x1b[0m";
|
|
13
|
+
console.log("");
|
|
14
|
+
console.log(`${M} ██╗████████╗███████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗${R}`);
|
|
15
|
+
console.log(`${M} ██║╚══██╔══╝██╔════╝ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝${R}`);
|
|
16
|
+
console.log(`${M} ██║ ██║ ███████╗█████╗██╔████╔██║███████║██║ ███╗██║██║ ${R}`);
|
|
17
|
+
console.log(`${C} ██║ ██║ ╚════██║╚════╝██║╚██╔╝██║██╔══██║██║ ██║██║██║ ${R}`);
|
|
18
|
+
console.log(`${C} ██║ ██║ ███████║ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗${R}`);
|
|
19
|
+
console.log(`${C} ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝${R}`);
|
|
20
|
+
console.log("");
|
|
21
|
+
console.log(`${Y} AI dev team${R}`);
|
|
22
|
+
console.log("");
|
|
23
|
+
}
|
|
4
24
|
|
|
5
25
|
function parseArgs(argv) {
|
|
6
|
-
const args = {
|
|
26
|
+
const args = {
|
|
27
|
+
target: process.cwd(),
|
|
28
|
+
mode: "missing",
|
|
29
|
+
backup: false,
|
|
30
|
+
create: false,
|
|
31
|
+
cleanRepo: false,
|
|
32
|
+
yes: false,
|
|
33
|
+
help: false,
|
|
34
|
+
version: false,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (argv.length === 0) {
|
|
38
|
+
args.help = true;
|
|
39
|
+
return args;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const first = argv[0];
|
|
43
|
+
if (first === "help") return { ...args, help: true };
|
|
44
|
+
if (first === "version") return { ...args, version: true };
|
|
45
|
+
if (first === "clean") {
|
|
46
|
+
args.cleanRepo = true;
|
|
47
|
+
argv = argv.slice(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
7
50
|
for (let i = 0; i < argv.length; i += 1) {
|
|
8
51
|
const a = argv[i];
|
|
9
52
|
if (a === "--target" && argv[i + 1]) {
|
|
@@ -24,24 +67,66 @@ function parseArgs(argv) {
|
|
|
24
67
|
args.create = true;
|
|
25
68
|
continue;
|
|
26
69
|
}
|
|
70
|
+
if (a === "--clean-repo") {
|
|
71
|
+
args.cleanRepo = true;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (a === "--yes") {
|
|
75
|
+
args.yes = true;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
27
78
|
if (a === "--help" || a === "-h") {
|
|
28
|
-
|
|
79
|
+
args.help = true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (a === "--version" || a === "-v") {
|
|
83
|
+
args.version = true;
|
|
84
|
+
continue;
|
|
29
85
|
}
|
|
30
86
|
}
|
|
31
87
|
return args;
|
|
32
88
|
}
|
|
33
89
|
|
|
34
90
|
function printHelp() {
|
|
35
|
-
|
|
91
|
+
printBanner();
|
|
92
|
+
console.log(`its-magic v${packageJson.version}
|
|
93
|
+
Repository: ${REPO_URL}
|
|
94
|
+
|
|
95
|
+
Install AI dev team workflow files into any Cursor repository.
|
|
36
96
|
|
|
37
97
|
Usage:
|
|
38
|
-
|
|
98
|
+
its-magic --target <path> [--mode <mode>] [--backup] [--create]
|
|
99
|
+
its-magic --clean-repo [--target <path>] [--yes]
|
|
100
|
+
its-magic --help | --version
|
|
39
101
|
|
|
40
|
-
|
|
41
|
-
--target
|
|
42
|
-
|
|
43
|
-
--
|
|
44
|
-
|
|
102
|
+
Install options:
|
|
103
|
+
--target <path> Path to the repository where workflow files are installed.
|
|
104
|
+
If omitted you will be prompted interactively.
|
|
105
|
+
--mode <mode> How to handle files that already exist in the target:
|
|
106
|
+
missing Only copy files that do not exist yet (default).
|
|
107
|
+
Safe for repos that already have some workflow files.
|
|
108
|
+
overwrite Replace every file, even if it already exists.
|
|
109
|
+
Combine with --backup to keep a snapshot first.
|
|
110
|
+
interactive Ask per file whether to overwrite or skip.
|
|
111
|
+
--backup Before overwriting, save existing files to backups/<timestamp>/.
|
|
112
|
+
Ignored when mode is "missing" (nothing gets replaced).
|
|
113
|
+
--create Create the target directory if it does not exist.
|
|
114
|
+
|
|
115
|
+
Clean options:
|
|
116
|
+
--clean-repo Remove all its-magic workflow artifacts from the target repo
|
|
117
|
+
(.cursor, docs/product, docs/engineering, sprints, handoffs,
|
|
118
|
+
decisions). Your own source code is never touched.
|
|
119
|
+
--target <path> Repo to clean (default: current directory).
|
|
120
|
+
--yes Skip the confirmation prompt.
|
|
121
|
+
|
|
122
|
+
Info:
|
|
123
|
+
--help, -h Show this help and exit.
|
|
124
|
+
--version, -v Print the installed version and exit.
|
|
125
|
+
|
|
126
|
+
Examples:
|
|
127
|
+
its-magic --target . --mode missing Safe first-time setup
|
|
128
|
+
its-magic --target . --mode overwrite --backup Update all files, keep backup
|
|
129
|
+
its-magic --clean-repo --target . --yes Remove workflow artifacts silently
|
|
45
130
|
`);
|
|
46
131
|
}
|
|
47
132
|
|
|
@@ -50,6 +135,10 @@ if (args.help) {
|
|
|
50
135
|
printHelp();
|
|
51
136
|
process.exit(0);
|
|
52
137
|
}
|
|
138
|
+
if (args.version) {
|
|
139
|
+
console.log(`its-magic v${packageJson.version}`);
|
|
140
|
+
process.exit(0);
|
|
141
|
+
}
|
|
53
142
|
|
|
54
143
|
const root = path.resolve(__dirname, "..");
|
|
55
144
|
const isWin = process.platform === "win32";
|
|
@@ -68,6 +157,8 @@ if (isWin) {
|
|
|
68
157
|
];
|
|
69
158
|
if (args.backup) psArgs.push("-Backup");
|
|
70
159
|
if (args.create) psArgs.push("-Create");
|
|
160
|
+
if (args.cleanRepo) psArgs.push("-CleanRepo");
|
|
161
|
+
if (args.yes) psArgs.push("-Yes");
|
|
71
162
|
const res = spawnSync("powershell", psArgs, { stdio: "inherit" });
|
|
72
163
|
process.exit(res.status || 0);
|
|
73
164
|
} else {
|
|
@@ -81,6 +172,8 @@ if (isWin) {
|
|
|
81
172
|
];
|
|
82
173
|
if (args.backup) shArgs.push("--backup");
|
|
83
174
|
if (args.create) shArgs.push("--create");
|
|
175
|
+
if (args.cleanRepo) shArgs.push("--clean-repo");
|
|
176
|
+
if (args.yes) shArgs.push("--yes");
|
|
84
177
|
const res = spawnSync("sh", shArgs, { stdio: "inherit" });
|
|
85
178
|
process.exit(res.status || 0);
|
|
86
179
|
}
|
package/installer.ps1
CHANGED
|
@@ -3,7 +3,11 @@ Param(
|
|
|
3
3
|
[ValidateSet("missing","overwrite","interactive")]
|
|
4
4
|
[string]$Mode,
|
|
5
5
|
[switch]$Backup,
|
|
6
|
-
[switch]$Create
|
|
6
|
+
[switch]$Create,
|
|
7
|
+
[switch]$CleanRepo,
|
|
8
|
+
[switch]$Yes,
|
|
9
|
+
[switch]$Help,
|
|
10
|
+
[switch]$Version
|
|
7
11
|
)
|
|
8
12
|
|
|
9
13
|
$ErrorActionPreference = "Stop"
|
|
@@ -69,7 +73,128 @@ function Prompt-YesNo($Label, $Default = $false) {
|
|
|
69
73
|
return @("y","yes") -contains $value
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
function Get-AppVersion($SourceRoot) {
|
|
77
|
+
try {
|
|
78
|
+
$pkgPath = Join-Path $SourceRoot "package.json"
|
|
79
|
+
if (Test-Path $pkgPath -PathType Leaf) {
|
|
80
|
+
$pkg = Get-Content -Path $pkgPath -Raw | ConvertFrom-Json
|
|
81
|
+
if ($pkg.version) { return [string]$pkg.version }
|
|
82
|
+
}
|
|
83
|
+
} catch {}
|
|
84
|
+
return "unknown"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function Show-ItsMagicBanner([switch]$IncludeInstallMessage) {
|
|
88
|
+
$prev = [Console]::OutputEncoding
|
|
89
|
+
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
90
|
+
$b64 = 'ICDilojilojilZfilojilojilojilojilojilojilojilojilZfilojilojilojilojilojilojilojilZcgICAgICDilojilojilojilZcgICDilojilojilojilZcg4paI4paI4paI4paI4paI4pWXICDilojilojilojilojilojilojilZcg4paI4paI4pWXIOKWiOKWiOKWiOKWiOKWiOKWiOKVlwogIOKWiOKWiOKVkeKVmuKVkOKVkOKWiOKWiOKVlOKVkOKVkOKVneKWiOKWiOKVlOKVkOKVkOKVkOKVkOKVnSAgICAgIOKWiOKWiOKWiOKWiOKVlyDilojilojilojilojilZHilojilojilZTilZDilZDilojilojilZfilojilojilZTilZDilZDilZDilZDilZ0g4paI4paI4pWR4paI4paI4pWU4pWQ4pWQ4pWQ4pWQ4pWdCiAg4paI4paI4pWRICAg4paI4paI4pWRICAg4paI4paI4paI4paI4paI4paI4paI4pWX4paI4paI4paI4paI4paI4pWX4paI4paI4pWU4paI4paI4paI4paI4pWU4paI4paI4pWR4paI4paI4paI4paI4paI4paI4paI4pWR4paI4paI4pWRICDilojilojilojilZfilojilojilZHilojilojilZEgICAgIAogIOKWiOKWiOKVkSAgIOKWiOKWiOKVkSAgIOKVmuKVkOKVkOKVkOKVkOKWiOKWiOKVkeKVmuKVkOKVkOKVkOKVkOKVneKWiOKWiOKVkeKVmuKWiOKWiOKVlOKVneKWiOKWiOKVkeKWiOKWiOKVlOKVkOKVkOKWiOKWiOKVkeKWiOKWiOKVkSAgIOKWiOKWiOKVkeKWiOKWiOKVkeKWiOKWiOKVkSAgICAgCiAg4paI4paI4pWRICAg4paI4paI4pWRICAg4paI4paI4paI4paI4paI4paI4paI4pWRICAgICAg4paI4paI4pWRIOKVmuKVkOKVnSDilojilojilZHilojilojilZEgIOKWiOKWiOKVkeKVmuKWiOKWiOKWiOKWiOKWiOKWiOKVlOKVneKWiOKWiOKVkeKVmuKWiOKWiOKWiOKWiOKWiOKWiOKVlwogIOKVmuKVkOKVnSAgIOKVmuKVkOKVnSAgIOKVmuKVkOKVkOKVkOKVkOKVkOKVkOKVnSAgICAgIOKVmuKVkOKVnSAgICAg4pWa4pWQ4pWd4pWa4pWQ4pWdICDilZrilZDilZ0g4pWa4pWQ4pWQ4pWQ4pWQ4pWQ4pWdIOKVmuKVkOKVnSDilZrilZDilZDilZDilZDilZDilZ0='
|
|
91
|
+
$art = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($b64))
|
|
92
|
+
$lines = $art -split "`n"
|
|
93
|
+
$colors = @('Magenta','Magenta','Magenta','Cyan','Cyan','Cyan')
|
|
94
|
+
Write-Host ""
|
|
95
|
+
for ($i = 0; $i -lt $lines.Count; $i++) {
|
|
96
|
+
Write-Host $lines[$i] -ForegroundColor $colors[$i]
|
|
97
|
+
}
|
|
98
|
+
Write-Host ""
|
|
99
|
+
Write-Host " AI dev team" -ForegroundColor Yellow
|
|
100
|
+
if ($IncludeInstallMessage) {
|
|
101
|
+
Write-Host " Installation complete!" -ForegroundColor Green
|
|
102
|
+
}
|
|
103
|
+
Write-Host ""
|
|
104
|
+
[Console]::OutputEncoding = $prev
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function Show-ItsMagicHelp($VersionString, $RepoUrl) {
|
|
108
|
+
Show-ItsMagicBanner
|
|
109
|
+
Write-Host "its-magic v$VersionString"
|
|
110
|
+
Write-Host "Repository: $RepoUrl"
|
|
111
|
+
Write-Host ""
|
|
112
|
+
Write-Host "Install AI dev team workflow files into any Cursor repository."
|
|
113
|
+
Write-Host ""
|
|
114
|
+
Write-Host "Usage:"
|
|
115
|
+
Write-Host " its-magic --target <path> [--mode <mode>] [--backup] [--create]"
|
|
116
|
+
Write-Host " its-magic --clean-repo [--target <path>] [--yes]"
|
|
117
|
+
Write-Host " its-magic --help | --version"
|
|
118
|
+
Write-Host ""
|
|
119
|
+
Write-Host "Install options:"
|
|
120
|
+
Write-Host " --target <path> Path to the repository where workflow files are installed."
|
|
121
|
+
Write-Host " If omitted you will be prompted interactively."
|
|
122
|
+
Write-Host " --mode <mode> How to handle files that already exist in the target:"
|
|
123
|
+
Write-Host " missing Only copy files that do not exist yet (default)."
|
|
124
|
+
Write-Host " Safe for repos that already have some workflow files."
|
|
125
|
+
Write-Host " overwrite Replace every file, even if it already exists."
|
|
126
|
+
Write-Host " Combine with --backup to keep a snapshot first."
|
|
127
|
+
Write-Host " interactive Ask per file whether to overwrite or skip."
|
|
128
|
+
Write-Host " --backup Before overwriting, save existing files to backups/<timestamp>/."
|
|
129
|
+
Write-Host " Ignored when mode is 'missing' (nothing gets replaced)."
|
|
130
|
+
Write-Host " --create Create the target directory if it does not exist."
|
|
131
|
+
Write-Host ""
|
|
132
|
+
Write-Host "Clean options:"
|
|
133
|
+
Write-Host " --clean-repo Remove all its-magic workflow artifacts from the target repo"
|
|
134
|
+
Write-Host " (.cursor, docs/product, docs/engineering, sprints, handoffs,"
|
|
135
|
+
Write-Host " decisions). Your own source code is never touched."
|
|
136
|
+
Write-Host " --target <path> Repo to clean (default: current directory)."
|
|
137
|
+
Write-Host " --yes Skip the confirmation prompt."
|
|
138
|
+
Write-Host ""
|
|
139
|
+
Write-Host "Info:"
|
|
140
|
+
Write-Host " --help Show this help and exit."
|
|
141
|
+
Write-Host " --version Print the installed version and exit."
|
|
142
|
+
Write-Host ""
|
|
143
|
+
Write-Host "Examples:"
|
|
144
|
+
Write-Host " its-magic --target . --mode missing Safe first-time setup"
|
|
145
|
+
Write-Host " its-magic --target . --mode overwrite --backup Update all files, keep backup"
|
|
146
|
+
Write-Host " its-magic --clean-repo --target . --yes Remove workflow artifacts silently"
|
|
147
|
+
Write-Host ""
|
|
148
|
+
}
|
|
149
|
+
|
|
72
150
|
$sourceRoot = Normalize-PathSafe (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
|
151
|
+
$repoUrl = "https://github.com/fl0wm0ti0n/its-magic"
|
|
152
|
+
$appVersion = Get-AppVersion $sourceRoot
|
|
153
|
+
$noArgs = $PSBoundParameters.Count -eq 0
|
|
154
|
+
|
|
155
|
+
if ($Version) {
|
|
156
|
+
Write-Host "its-magic v$appVersion"
|
|
157
|
+
exit 0
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if ($Help -or $noArgs) {
|
|
161
|
+
Show-ItsMagicHelp -VersionString $appVersion -RepoUrl $repoUrl
|
|
162
|
+
exit 0
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if ($CleanRepo) {
|
|
166
|
+
if (-not $Target) { $Target = "." }
|
|
167
|
+
$targetRoot = Normalize-PathSafe $Target
|
|
168
|
+
if (-not (Test-Path $targetRoot -PathType Container)) {
|
|
169
|
+
Write-Host "Target directory does not exist."
|
|
170
|
+
exit 1
|
|
171
|
+
}
|
|
172
|
+
if (-not $Yes) {
|
|
173
|
+
$proceed = Prompt-YesNo "Clean its-magic workflow artifacts in $targetRoot?" $false
|
|
174
|
+
if (-not $proceed) {
|
|
175
|
+
Write-Host "Aborted."
|
|
176
|
+
exit 1
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
$cleanPaths = @(
|
|
180
|
+
".cursor",
|
|
181
|
+
"docs\product",
|
|
182
|
+
"docs\engineering",
|
|
183
|
+
"sprints",
|
|
184
|
+
"handoffs",
|
|
185
|
+
"decisions"
|
|
186
|
+
)
|
|
187
|
+
foreach ($rel in $cleanPaths) {
|
|
188
|
+
$fullPath = Join-Path $targetRoot $rel
|
|
189
|
+
if (Test-Path $fullPath) {
|
|
190
|
+
Remove-Item -Path $fullPath -Recurse -Force
|
|
191
|
+
Write-Host "Removed: $rel"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
Write-Host "Clean completed."
|
|
195
|
+
exit 0
|
|
196
|
+
}
|
|
197
|
+
|
|
73
198
|
if (-not $Target) {
|
|
74
199
|
$Target = Read-Host "Target repository path"
|
|
75
200
|
}
|
|
@@ -165,24 +290,9 @@ foreach ($rel in $files) {
|
|
|
165
290
|
}
|
|
166
291
|
}
|
|
167
292
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
$art = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($b64))
|
|
173
|
-
$lines = $art -split "`n"
|
|
174
|
-
$colors = @('Magenta','Magenta','Magenta','Cyan','Cyan','Cyan')
|
|
175
|
-
Write-Host ""
|
|
176
|
-
for ($i = 0; $i -lt $lines.Count; $i++) {
|
|
177
|
-
Write-Host $lines[$i] -ForegroundColor $colors[$i]
|
|
178
|
-
}
|
|
179
|
-
Write-Host ""
|
|
180
|
-
Write-Host " AI dev team" -ForegroundColor Yellow
|
|
181
|
-
Write-Host " Installation complete!" -ForegroundColor Green
|
|
182
|
-
Write-Host ""
|
|
183
|
-
[Console]::OutputEncoding = $prev
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
Show-ItsMagicBanner
|
|
293
|
+
Show-ItsMagicBanner -IncludeInstallMessage
|
|
294
|
+
Write-Host "its-magic v$appVersion"
|
|
295
|
+
Write-Host "Repository: $repoUrl"
|
|
296
|
+
Write-Host ""
|
|
187
297
|
exit 0
|
|
188
298
|
|
package/installer.py
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
import json
|
|
2
3
|
import os
|
|
3
4
|
import shutil
|
|
4
5
|
import sys
|
|
5
6
|
from datetime import datetime
|
|
6
7
|
|
|
8
|
+
REPO_URL = "https://github.com/fl0wm0ti0n/its-magic"
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
def normalize(path):
|
|
9
12
|
return os.path.normpath(os.path.abspath(path))
|
|
10
13
|
|
|
11
14
|
|
|
15
|
+
def read_version(source_root):
|
|
16
|
+
package_path = os.path.join(source_root, "package.json")
|
|
17
|
+
try:
|
|
18
|
+
with open(package_path, "r", encoding="utf-8") as f:
|
|
19
|
+
return json.load(f).get("version", "unknown")
|
|
20
|
+
except Exception:
|
|
21
|
+
return "unknown"
|
|
22
|
+
|
|
23
|
+
|
|
12
24
|
def list_source_files(source_root, include_paths):
|
|
13
25
|
files = []
|
|
14
26
|
for rel in include_paths:
|
|
@@ -63,29 +75,130 @@ def prompt_yes_no(label, default=False):
|
|
|
63
75
|
return value in ("y", "yes")
|
|
64
76
|
|
|
65
77
|
|
|
78
|
+
def show_banner(include_install_message=False):
|
|
79
|
+
try:
|
|
80
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
81
|
+
except Exception:
|
|
82
|
+
pass
|
|
83
|
+
m = "\033[1;35m"
|
|
84
|
+
c = "\033[1;36m"
|
|
85
|
+
y = "\033[1;33m"
|
|
86
|
+
g = "\033[1;32m"
|
|
87
|
+
r = "\033[0m"
|
|
88
|
+
print()
|
|
89
|
+
print(f"{m} ██╗████████╗███████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗{r}")
|
|
90
|
+
print(f"{m} ██║╚══██╔══╝██╔════╝ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝{r}")
|
|
91
|
+
print(f"{m} ██║ ██║ ███████╗█████╗██╔████╔██║███████║██║ ███╗██║██║ {r}")
|
|
92
|
+
print(f"{c} ██║ ██║ ╚════██║╚════╝██║╚██╔╝██║██╔══██║██║ ██║██║██║ {r}")
|
|
93
|
+
print(f"{c} ██║ ██║ ███████║ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗{r}")
|
|
94
|
+
print(f"{c} ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝{r}")
|
|
95
|
+
print()
|
|
96
|
+
print(f"{y} AI dev team{r}")
|
|
97
|
+
if include_install_message:
|
|
98
|
+
print(f"{g} Installation complete!{r}")
|
|
99
|
+
print()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def show_help(version):
|
|
103
|
+
show_banner(include_install_message=False)
|
|
104
|
+
print(f"its-magic v{version}")
|
|
105
|
+
print(f"Repository: {REPO_URL}")
|
|
106
|
+
print()
|
|
107
|
+
print("Install AI dev team workflow files into any Cursor repository.")
|
|
108
|
+
print()
|
|
109
|
+
print("Usage:")
|
|
110
|
+
print(" its-magic --target <path> [--mode <mode>] [--backup] [--create]")
|
|
111
|
+
print(" its-magic --clean-repo [--target <path>] [--yes]")
|
|
112
|
+
print(" its-magic --help | --version")
|
|
113
|
+
print()
|
|
114
|
+
print("Install options:")
|
|
115
|
+
print(" --target <path> Path to the repository where workflow files are installed.")
|
|
116
|
+
print(" If omitted you will be prompted interactively.")
|
|
117
|
+
print(" --mode <mode> How to handle files that already exist in the target:")
|
|
118
|
+
print(" missing Only copy files that do not exist yet (default).")
|
|
119
|
+
print(" Safe for repos that already have some workflow files.")
|
|
120
|
+
print(" overwrite Replace every file, even if it already exists.")
|
|
121
|
+
print(" Combine with --backup to keep a snapshot first.")
|
|
122
|
+
print(" interactive Ask per file whether to overwrite or skip.")
|
|
123
|
+
print(" --backup Before overwriting, save existing files to backups/<timestamp>/.")
|
|
124
|
+
print(" Ignored when mode is 'missing' (nothing gets replaced).")
|
|
125
|
+
print(" --create Create the target directory if it does not exist.")
|
|
126
|
+
print()
|
|
127
|
+
print("Clean options:")
|
|
128
|
+
print(" --clean-repo Remove all its-magic workflow artifacts from the target repo")
|
|
129
|
+
print(" (.cursor, docs/product, docs/engineering, sprints, handoffs,")
|
|
130
|
+
print(" decisions). Your own source code is never touched.")
|
|
131
|
+
print(" --target <path> Repo to clean (default: current directory).")
|
|
132
|
+
print(" --yes Skip the confirmation prompt.")
|
|
133
|
+
print()
|
|
134
|
+
print("Info:")
|
|
135
|
+
print(" --help, -h Show this help and exit.")
|
|
136
|
+
print(" --version, -v Print the installed version and exit.")
|
|
137
|
+
print()
|
|
138
|
+
print("Examples:")
|
|
139
|
+
print(" its-magic --target . --mode missing Safe first-time setup")
|
|
140
|
+
print(" its-magic --target . --mode overwrite --backup Update all files, keep backup")
|
|
141
|
+
print(" its-magic --clean-repo --target . --yes Remove workflow artifacts silently")
|
|
142
|
+
print()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def clean_repo(target_root):
|
|
146
|
+
clean_paths = [
|
|
147
|
+
".cursor",
|
|
148
|
+
os.path.join("docs", "product"),
|
|
149
|
+
os.path.join("docs", "engineering"),
|
|
150
|
+
"sprints",
|
|
151
|
+
"handoffs",
|
|
152
|
+
"decisions",
|
|
153
|
+
]
|
|
154
|
+
for rel in clean_paths:
|
|
155
|
+
full = os.path.join(target_root, rel)
|
|
156
|
+
if os.path.exists(full):
|
|
157
|
+
shutil.rmtree(full)
|
|
158
|
+
print(f"Removed: {rel}")
|
|
159
|
+
print("Clean completed.")
|
|
160
|
+
|
|
161
|
+
|
|
66
162
|
def main():
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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",
|
|
163
|
+
source_root = normalize(os.path.dirname(__file__))
|
|
164
|
+
version = read_version(source_root)
|
|
165
|
+
|
|
166
|
+
parser = argparse.ArgumentParser(
|
|
167
|
+
description="Install its-magic into a repo",
|
|
168
|
+
add_help=False,
|
|
83
169
|
)
|
|
170
|
+
parser.add_argument("--target", help="Target repository path")
|
|
171
|
+
parser.add_argument("--mode", choices=["missing", "overwrite", "interactive"], help="Install mode")
|
|
172
|
+
parser.add_argument("--backup", action="store_true", help="Backup files before overwriting")
|
|
173
|
+
parser.add_argument("--create", action="store_true", help="Create target directory if missing")
|
|
174
|
+
parser.add_argument("--clean-repo", action="store_true", help="Remove installed workflow artifacts")
|
|
175
|
+
parser.add_argument("--yes", action="store_true", help="Skip clean confirmation prompt")
|
|
176
|
+
parser.add_argument("--help", "-h", action="store_true", help="Show help")
|
|
177
|
+
parser.add_argument("--version", "-v", action="store_true", help="Show version")
|
|
84
178
|
args = parser.parse_args()
|
|
85
179
|
|
|
86
|
-
|
|
180
|
+
if len(sys.argv) == 1 or args.help:
|
|
181
|
+
show_help(version)
|
|
182
|
+
return 0
|
|
183
|
+
|
|
184
|
+
if args.version:
|
|
185
|
+
print(f"its-magic v{version}")
|
|
186
|
+
return 0
|
|
187
|
+
|
|
87
188
|
target_root = normalize(args.target) if args.target else None
|
|
88
189
|
|
|
190
|
+
if args.clean_repo:
|
|
191
|
+
if not target_root:
|
|
192
|
+
target_root = normalize(".")
|
|
193
|
+
if not os.path.isdir(target_root):
|
|
194
|
+
print("Target directory does not exist.")
|
|
195
|
+
return 1
|
|
196
|
+
if not args.yes and not prompt_yes_no(f"Clean its-magic workflow artifacts in {target_root}?", default=False):
|
|
197
|
+
print("Aborted.")
|
|
198
|
+
return 1
|
|
199
|
+
clean_repo(target_root)
|
|
200
|
+
return 0
|
|
201
|
+
|
|
89
202
|
if not target_root:
|
|
90
203
|
target_root = normalize(input("Target repository path: ").strip())
|
|
91
204
|
|
|
@@ -164,30 +277,12 @@ def main():
|
|
|
164
277
|
print(f"Backed up: {rel} -> {backup_root}")
|
|
165
278
|
ensure_parent(dst)
|
|
166
279
|
shutil.copy2(src, dst)
|
|
167
|
-
else:
|
|
168
|
-
continue
|
|
169
|
-
|
|
170
|
-
show_banner()
|
|
171
|
-
return 0
|
|
172
|
-
|
|
173
280
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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}")
|
|
281
|
+
show_banner(include_install_message=True)
|
|
282
|
+
print(f"its-magic v{version}")
|
|
283
|
+
print(f"Repository: {REPO_URL}")
|
|
190
284
|
print()
|
|
285
|
+
return 0
|
|
191
286
|
|
|
192
287
|
|
|
193
288
|
if __name__ == "__main__":
|
package/installer.sh
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
2
|
set -e
|
|
3
3
|
|
|
4
|
+
SOURCE_ROOT=$(cd "$(dirname "$0")" && pwd)
|
|
5
|
+
REPO_URL="https://github.com/fl0wm0ti0n/its-magic"
|
|
6
|
+
APP_VERSION=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SOURCE_ROOT/package.json" | head -n 1)
|
|
7
|
+
[ -z "$APP_VERSION" ] && APP_VERSION="unknown"
|
|
8
|
+
|
|
9
|
+
show_banner() {
|
|
10
|
+
printf "\n"
|
|
11
|
+
printf "\033[1;35m ██╗████████╗███████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗\033[0m\n"
|
|
12
|
+
printf "\033[1;35m ██║╚══██╔══╝██╔════╝ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝\033[0m\n"
|
|
13
|
+
printf "\033[1;35m ██║ ██║ ███████╗█████╗██╔████╔██║███████║██║ ███╗██║██║ \033[0m\n"
|
|
14
|
+
printf "\033[1;36m ██║ ██║ ╚════██║╚════╝██║╚██╔╝██║██╔══██║██║ ██║██║██║ \033[0m\n"
|
|
15
|
+
printf "\033[1;36m ██║ ██║ ███████║ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗\033[0m\n"
|
|
16
|
+
printf "\033[1;36m ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝\033[0m\n"
|
|
17
|
+
printf "\n"
|
|
18
|
+
printf "\033[1;33m AI dev team\033[0m\n"
|
|
19
|
+
printf "\n"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
show_help() {
|
|
23
|
+
show_banner
|
|
24
|
+
printf "its-magic v%s\n" "$APP_VERSION"
|
|
25
|
+
printf "Repository: %s\n\n" "$REPO_URL"
|
|
26
|
+
printf "Install AI dev team workflow files into any Cursor repository.\n\n"
|
|
27
|
+
printf "Usage:\n"
|
|
28
|
+
printf " its-magic --target <path> [--mode <mode>] [--backup] [--create]\n"
|
|
29
|
+
printf " its-magic --clean-repo [--target <path>] [--yes]\n"
|
|
30
|
+
printf " its-magic --help | --version\n\n"
|
|
31
|
+
printf "Install options:\n"
|
|
32
|
+
printf " --target <path> Path to the repository where workflow files are installed.\n"
|
|
33
|
+
printf " If omitted you will be prompted interactively.\n"
|
|
34
|
+
printf " --mode <mode> How to handle files that already exist in the target:\n"
|
|
35
|
+
printf " missing Only copy files that do not exist yet (default).\n"
|
|
36
|
+
printf " Safe for repos that already have some workflow files.\n"
|
|
37
|
+
printf " overwrite Replace every file, even if it already exists.\n"
|
|
38
|
+
printf " Combine with --backup to keep a snapshot first.\n"
|
|
39
|
+
printf " interactive Ask per file whether to overwrite or skip.\n"
|
|
40
|
+
printf " --backup Before overwriting, save existing files to backups/<timestamp>/.\n"
|
|
41
|
+
printf " Ignored when mode is 'missing' (nothing gets replaced).\n"
|
|
42
|
+
printf " --create Create the target directory if it does not exist.\n\n"
|
|
43
|
+
printf "Clean options:\n"
|
|
44
|
+
printf " --clean-repo Remove all its-magic workflow artifacts from the target repo\n"
|
|
45
|
+
printf " (.cursor, docs/product, docs/engineering, sprints, handoffs,\n"
|
|
46
|
+
printf " decisions). Your own source code is never touched.\n"
|
|
47
|
+
printf " --target <path> Repo to clean (default: current directory).\n"
|
|
48
|
+
printf " --yes Skip the confirmation prompt.\n\n"
|
|
49
|
+
printf "Info:\n"
|
|
50
|
+
printf " --help, -h Show this help and exit.\n"
|
|
51
|
+
printf " --version, -v Print the installed version and exit.\n\n"
|
|
52
|
+
printf "Examples:\n"
|
|
53
|
+
printf " its-magic --target . --mode missing Safe first-time setup\n"
|
|
54
|
+
printf " its-magic --target . --mode overwrite --backup Update all files, keep backup\n"
|
|
55
|
+
printf " its-magic --clean-repo --target . --yes Remove workflow artifacts silently\n\n"
|
|
56
|
+
}
|
|
4
57
|
|
|
5
58
|
ensure_parent() {
|
|
6
59
|
dir=$(dirname "$1")
|
|
@@ -68,6 +121,14 @@ TARGET=""
|
|
|
68
121
|
MODE=""
|
|
69
122
|
BACKUP="false"
|
|
70
123
|
CREATE="false"
|
|
124
|
+
CLEAN_REPO="false"
|
|
125
|
+
ASSUME_YES="false"
|
|
126
|
+
SHOW_HELP="false"
|
|
127
|
+
SHOW_VERSION="false"
|
|
128
|
+
|
|
129
|
+
if [ $# -eq 0 ]; then
|
|
130
|
+
SHOW_HELP="true"
|
|
131
|
+
fi
|
|
71
132
|
|
|
72
133
|
while [ $# -gt 0 ]; do
|
|
73
134
|
case "$1" in
|
|
@@ -75,11 +136,57 @@ while [ $# -gt 0 ]; do
|
|
|
75
136
|
--mode) MODE="$2"; shift 2 ;;
|
|
76
137
|
--backup) BACKUP="true"; shift 1 ;;
|
|
77
138
|
--create) CREATE="true"; shift 1 ;;
|
|
139
|
+
--clean-repo) CLEAN_REPO="true"; shift 1 ;;
|
|
140
|
+
--yes) ASSUME_YES="true"; shift 1 ;;
|
|
141
|
+
--help|-h) SHOW_HELP="true"; shift 1 ;;
|
|
142
|
+
--version|-v) SHOW_VERSION="true"; shift 1 ;;
|
|
78
143
|
*) shift 1 ;;
|
|
79
144
|
esac
|
|
80
145
|
done
|
|
81
146
|
|
|
82
|
-
|
|
147
|
+
if [ "$SHOW_VERSION" = "true" ]; then
|
|
148
|
+
printf "its-magic v%s\n" "$APP_VERSION"
|
|
149
|
+
exit 0
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
if [ "$SHOW_HELP" = "true" ]; then
|
|
153
|
+
show_help
|
|
154
|
+
exit 0
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
if [ "$CLEAN_REPO" = "true" ]; then
|
|
158
|
+
if [ -z "$TARGET" ]; then
|
|
159
|
+
TARGET="."
|
|
160
|
+
fi
|
|
161
|
+
if [ ! -d "$TARGET" ]; then
|
|
162
|
+
printf "%s\n" "Target directory does not exist."
|
|
163
|
+
exit 1
|
|
164
|
+
fi
|
|
165
|
+
TARGET_ROOT=$(cd "$TARGET" && pwd)
|
|
166
|
+
if [ "$ASSUME_YES" != "true" ]; then
|
|
167
|
+
if ! prompt_yes_no "Clean its-magic workflow artifacts in $TARGET_ROOT?" "false"; then
|
|
168
|
+
printf "%s\n" "Aborted."
|
|
169
|
+
exit 1
|
|
170
|
+
fi
|
|
171
|
+
fi
|
|
172
|
+
CLEAN_PATHS="
|
|
173
|
+
.cursor
|
|
174
|
+
docs/product
|
|
175
|
+
docs/engineering
|
|
176
|
+
sprints
|
|
177
|
+
handoffs
|
|
178
|
+
decisions
|
|
179
|
+
"
|
|
180
|
+
for rel in $CLEAN_PATHS; do
|
|
181
|
+
path="$TARGET_ROOT/$rel"
|
|
182
|
+
if [ -e "$path" ]; then
|
|
183
|
+
rm -rf "$path"
|
|
184
|
+
printf "%s\n" "Removed: $rel"
|
|
185
|
+
fi
|
|
186
|
+
done
|
|
187
|
+
printf "%s\n" "Clean completed."
|
|
188
|
+
exit 0
|
|
189
|
+
fi
|
|
83
190
|
|
|
84
191
|
if [ -z "$TARGET" ]; then
|
|
85
192
|
printf "%s" "Target repository path: "
|
|
@@ -180,20 +287,9 @@ for rel in $FILES; do
|
|
|
180
287
|
fi
|
|
181
288
|
done
|
|
182
289
|
|
|
183
|
-
show_banner() {
|
|
184
|
-
printf "\n"
|
|
185
|
-
printf "\033[1;35m ██╗████████╗███████╗ ███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗\033[0m\n"
|
|
186
|
-
printf "\033[1;35m ██║╚══██╔══╝██╔════╝ ████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝\033[0m\n"
|
|
187
|
-
printf "\033[1;35m ██║ ██║ ███████╗█████╗██╔████╔██║███████║██║ ███╗██║██║ \033[0m\n"
|
|
188
|
-
printf "\033[1;36m ██║ ██║ ╚════██║╚════╝██║╚██╔╝██║██╔══██║██║ ██║██║██║ \033[0m\n"
|
|
189
|
-
printf "\033[1;36m ██║ ██║ ███████║ ██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗\033[0m\n"
|
|
190
|
-
printf "\033[1;36m ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝\033[0m\n"
|
|
191
|
-
printf "\n"
|
|
192
|
-
printf "\033[1;33m AI dev team\033[0m\n"
|
|
193
|
-
printf "\033[1;32m Installation complete!\033[0m\n"
|
|
194
|
-
printf "\n"
|
|
195
|
-
}
|
|
196
|
-
|
|
197
290
|
show_banner
|
|
291
|
+
printf "its-magic v%s\n" "$APP_VERSION"
|
|
292
|
+
printf "Repository: %s\n\n" "$REPO_URL"
|
|
293
|
+
printf "\033[1;32m Installation complete!\033[0m\n\n"
|
|
198
294
|
exit 0
|
|
199
295
|
|