magic-spec 1.0.0 β†’ 1.2.1

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 CHANGED
@@ -1,180 +1,196 @@
1
- # πŸͺ„ Magic Spec
2
-
3
- [![npm version](https://img.shields.io/npm/v/magic-spec)](https://www.npmjs.com/package/magic-spec)
4
- [![PyPI version](https://img.shields.io/pypi/v/magic-spec)](https://pypi.org/project/magic-spec/)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
-
7
- **Specification-Driven Development (SDD) workflow for AI coding agents.**
8
-
9
- Stop your AI from writing code before it understands the problem.
10
- `magic-spec` installs a structured pipeline β€” *Thought β†’ Spec β†’ Plan β†’ Task β†’ Code* β€” directly into any project, regardless of stack.
11
-
12
- ## ✨ What is Magic Spec?
13
-
14
- `magic-spec` is a set of **markdown-based workflow instructions** for AI coding agents (Cursor, Claude, Gemini, Copilot, etc.). It acts as an operating system for agentic development, enforcing a rigorous, structured pipeline:
15
-
16
- ```
17
- πŸ’‘ Idea β†’ πŸ“‹ Specification β†’ πŸ—ΊοΈ Plan β†’ ⚑ Task β†’ πŸš€ Code β†’ πŸ” Retrospective
18
- ```
19
-
20
- Once installed, your AI agent will automatically:
21
-
22
- - Convert raw thoughts into structured specification files.
23
- - Build a phased implementation plan from approved specs.
24
- - Decompose the plan into atomic, trackable tasks.
25
- - Analyze its own workflow and suggest improvements.
26
-
27
- **No code is written until a specification exists. No spec is implemented without a plan.**
28
-
29
- ## πŸš€ Quick Start
30
-
31
- Works with **any project** β€” Rust, Go, Python, JavaScript, or anything else.
32
- No runtime lock-in. Requires only Node.js *or* Python to install.
33
-
34
- ### Option A β€” Node.js (npx)
35
-
36
- ```bash
37
- npx magic-spec@latest
38
- ```
39
-
40
- ### Option B β€” Python (uvx)
41
-
42
- ```bash
43
- uvx magic-spec
44
- ```
45
-
46
- Both commands do exactly the same thing:
47
-
48
- 1. Copy `.magic/` (the SDD engine) into your project.
49
- 2. Copy `.agent/workflows/magic/` (agent trigger wrappers) into your project.
50
- 3. Run the init script β€” creates your `.design/` workspace with `INDEX.md` and `RULES.md`.
51
-
52
- ## 🧭 Core Philosophy
53
-
54
- | Principle | Description |
55
- | :--- | :--- |
56
- | **Specs First, Code Later** | The agent is forbidden from writing code from raw input. All ideas become specs first. |
57
- | **Deterministic Process** | A strict pipeline is enforced: *Thought β†’ Spec β†’ Plan β†’ Task β†’ Code*. |
58
- | **Constitution-Driven** | All project decisions live in `.design/RULES.md` β€” the project's living constitution. |
59
- | **Self-Improving** | The Retrospective workflow analyzes real usage and generates improvement recommendations. |
60
-
61
- ## πŸ“ What Gets Installed
62
-
63
- After running `npx magic-spec@latest` in your project root:
64
-
65
- ```plaintext
66
- your-project/
67
- β”‚
68
- β”œβ”€β”€ .agent/workflows/magic/ # Agent entry points (slash commands)
69
- β”‚ β”œβ”€β”€ plan.md
70
- β”‚ β”œβ”€β”€ retrospective.md
71
- β”‚ β”œβ”€β”€ rule.md
72
- β”‚ β”œβ”€β”€ specification.md
73
- β”‚ └── task.md
74
- β”‚
75
- β”œβ”€β”€ .magic/ # SDD Engine (workflow logic, read-only)
76
- β”‚ β”œβ”€β”€ init.md
77
- β”‚ β”œβ”€β”€ plan.md
78
- β”‚ β”œβ”€β”€ retrospective.md
79
- β”‚ β”œβ”€β”€ rule.md
80
- β”‚ β”œβ”€β”€ specification.md
81
- β”‚ β”œβ”€β”€ task.md
82
- β”‚ └── scripts/
83
- β”‚ β”œβ”€β”€ init.sh # Init for macOS / Linux
84
- β”‚ └── init.ps1 # Init for Windows
85
- β”‚
86
- └── .design/ # Your project workspace (generated)
87
- β”œβ”€β”€ INDEX.md # Spec registry
88
- β”œβ”€β”€ RULES.md # Project constitution
89
- β”œβ”€β”€ PLAN.md # Implementation plan
90
- β”œβ”€β”€ specifications/ # Your specification files
91
- └── tasks/ # Task breakdowns per phase
92
- ```
93
-
94
- ## πŸ”— The Workflow Pipeline
95
-
96
- ```mermaid
97
- graph TD
98
- IDEA["πŸ’‘ Idea"] --> INIT{"πŸ—οΈ Auto-Init"}
99
- INIT -->|.design/ exists| SPEC
100
- INIT -->|.design/ missing| CREATE["Create .design/ structure"] --> SPEC
101
- SPEC["πŸ“‹ Specification"] <--> RULE["πŸ“œ Rule"]
102
- SPEC --> PLAN["πŸ—ΊοΈ Plan"]
103
- PLAN --> TASK["⚑ Task"]
104
- TASK --> CODE["πŸš€ Code"]
105
- CODE --> RETRO["πŸ” Retrospective"]
106
- RETRO -.->|Feedback loop| SPEC
107
- ```
108
-
109
- ### Core Workflows
110
-
111
- | # | Workflow | Purpose |
112
- | :--- | :--- | :--- |
113
- | 1 | **Specification** | Converts raw thoughts into structured specs. Manages statuses: `Draft β†’ RFC β†’ Stable β†’ Deprecated`. |
114
- | 2 | **Plan** | Reads Stable specs, builds a dependency graph, and produces a phased `PLAN.md`. |
115
- | 3 | **Task** | Decomposes the plan into atomic tasks with sequential and parallel execution tracks. |
116
-
117
- ### Auxiliary Workflows
118
-
119
- | Workflow | Purpose |
120
- | :--- | :--- |
121
- | **Rule** | Manages the project constitution (`RULES.md Β§7`). Add, amend, or remove conventions. |
122
- | **Retrospective** | Analyzes SDD usage, collects metrics, and generates improvement recommendations. |
123
-
124
- ## πŸ’¬ How to Use (with any AI agent)
125
-
126
- Just talk to your AI agent naturally. Initialization is **automatic** β€” no setup command required.
127
-
128
- ```plaintext
129
- "Dispatch this thought into specs: I want a user auth system with JWT and Redis..."
130
- β†’ Runs Specification workflow
131
-
132
- "Create an implementation plan"
133
- β†’ Runs Plan workflow
134
-
135
- "Generate tasks for Phase 1"
136
- β†’ Runs Task workflow
137
-
138
- "Execute the next task"
139
- β†’ Runs Task workflow (execution mode)
140
-
141
- "Add rule: always use snake_case for file names"
142
- β†’ Runs Rule workflow
143
-
144
- "Run retrospective"
145
- β†’ Runs Retrospective workflow
146
- ```
147
-
148
- The AI reads the corresponding `.magic/*.md` workflow file and executes the request within the bounds of the SDD system. **No code escapes the pipeline.** ✨
149
-
150
- ## πŸ”„ Updating
151
-
152
- Pull the latest engine improvements without touching your project data:
153
-
154
- ```bash
155
- # Node.js
156
- npx magic-spec@latest --update
157
-
158
- # Python
159
- uvx magic-spec --update
160
- ```
161
-
162
- The update overwrites `.magic/` (the engine) but **never touches** `.design/` (your specs, plans, and tasks).
163
-
164
- ## 🀝 Compatibility
165
-
166
- Works with any AI coding agent that can read markdown workflow files:
167
-
168
- - [Cursor](https://cursor.sh) (`.cursorrules` + Agent mode)
169
- - [Claude](https://claude.ai) (Projects)
170
- - [Gemini](https://gemini.google.com) (via Gemini Code)
171
- - [GitHub Copilot](https://github.com/features/copilot) (Agent mode)
172
- - Any terminal-based or API-driven agent
173
-
174
- ## πŸ“„ License
175
-
176
- [MIT](./LICENSE) Β© 2026 Oleg Alexandrov
177
-
178
- ---
179
-
180
- ## TODO: Magic Spec
1
+ # πŸͺ„ Magic Spec
2
+
3
+ [![npm version](https://img.shields.io/npm/v/magic-spec)](https://www.npmjs.com/package/magic-spec)
4
+ [![PyPI version](https://img.shields.io/pypi/v/magic-spec)](https://pypi.org/project/magic-spec/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
+
7
+ **Specification-Driven Development (SDD) workflow for AI coding agents.**
8
+
9
+ Stop your AI from writing code before it understands the problem.
10
+ `magic-spec` installs a structured pipeline β€” *Thought β†’ Spec β†’ Task β†’ Run β†’ Code* β€” directly into any project, regardless of stack.
11
+
12
+ ## ✨ What is Magic Spec?
13
+
14
+ `magic-spec` is a set of **markdown-based workflow instructions** for AI coding agents (Cursor, Claude, Gemini, Copilot, etc.). It acts as an operating system for agentic development, enforcing a rigorous, structured pipeline:
15
+
16
+ ```
17
+ πŸ’‘ Idea β†’ πŸ“‹ Specification β†’ πŸ—ΊοΈ Task & Plan β†’ ⚑ Run β†’ πŸš€ Code
18
+ ```
19
+
20
+ Once installed, your AI agent will automatically:
21
+
22
+ - Convert raw thoughts into structured specification files.
23
+ - Build a phased implementation plan from approved specs.
24
+ - Decompose the plan into atomic, trackable tasks.
25
+ - Analyze its own workflow and suggest improvements β€” automatically, at phase completion.
26
+
27
+ **No code is written until a specification exists. No spec is implemented without a plan.**
28
+
29
+ ## πŸš€ Quick Start
30
+
31
+ Works with **any project** β€” Rust, Go, Python, JavaScript, or anything else.
32
+ No runtime lock-in. Requires only Node.js *or* Python to install.
33
+
34
+ ### Option A β€” Node.js (npx)
35
+
36
+ ```bash
37
+ npx magic-spec@latest
38
+ ```
39
+
40
+ ### Option B β€” Python (uvx)
41
+
42
+ ```bash
43
+ uvx magic-spec
44
+ ```
45
+
46
+ Both commands do exactly the same thing:
47
+
48
+ 1. Copy `.magic/` (the SDD engine) into your project.
49
+ 2. Copy `.agent/workflows/magic.*.md` (agent trigger wrappers) into your project.
50
+ 3. Run the init script β€” creates your `.design/` workspace with `INDEX.md` and `RULES.md`.
51
+
52
+ ## 🧭 Core Philosophy
53
+
54
+ | Principle | Description |
55
+ | :--- | :--- |
56
+ | **Specs First, Code Later** | The agent is forbidden from writing code from raw input. All ideas become specs first. |
57
+ | **Deterministic Process** | A strict pipeline is enforced: *Thought β†’ Spec β†’ Task β†’ Run β†’ Code*. |
58
+ | **Constitution-Driven** | All project decisions live in `.design/RULES.md` β€” the project's living constitution. |
59
+ | **Self-Improving** | After each phase and at plan completion, the Task workflow automatically runs a retrospective and generates improvement recommendations. |
60
+
61
+ ## 🩺 System Health (CLI Doctor)
62
+
63
+ You can check if your SDD workspace is properly initialized and healthy without invoking the AI. Just append the `--doctor` (or `--check`) flag:
64
+
65
+ ```bash
66
+ npx magic-spec@latest --doctor
67
+ # or
68
+ uvx magic-spec --doctor
69
+ ```
70
+
71
+ This returns a visually formatted validation report of your project's `.design` structure, preventing broken context before you start coding.
72
+
73
+ ## πŸ“ What Gets Installed
74
+
75
+ After running `npx magic-spec@latest` in your project root:
76
+
77
+ ```plaintext
78
+ your-project/
79
+ β”‚
80
+ β”œβ”€β”€ .agent/workflows/ # Agent entry points (slash commands)
81
+ β”‚ β”œβ”€β”€ magic.onboard.md # Interactive tutorial for new devs
82
+ β”‚ β”œβ”€β”€ magic.rule.md
83
+ β”‚ β”œβ”€β”€ magic.run.md
84
+ β”‚ β”œβ”€β”€ magic.spec.md
85
+ β”‚ └── magic.task.md
86
+ β”‚
87
+ β”œβ”€β”€ .magic/ # SDD Engine (workflow logic, read-only)
88
+ β”‚ β”œβ”€β”€ init.md
89
+ β”‚ β”œβ”€β”€ onboard.md # Onboarding script payload
90
+ β”‚ β”œβ”€β”€ retrospective.md
91
+ β”‚ β”œβ”€β”€ rule.md
92
+ β”‚ β”œβ”€β”€ run.md
93
+ β”‚ β”œβ”€β”€ spec.md
94
+ β”‚ β”œβ”€β”€ task.md
95
+ β”‚ └── scripts/
96
+ β”‚ β”œβ”€β”€ check-prerequisites.* # Used by --doctor
97
+ β”‚ β”œβ”€β”€ generate-context.* # Auto-compiles CONTEXT.md
98
+ β”‚ β”œβ”€β”€ init.sh # Init for macOS / Linux
99
+ β”‚ └── init.ps1 # Init for Windows
100
+ β”‚
101
+ └── .design/ # Your project workspace (generated)
102
+ β”œβ”€β”€ INDEX.md # Spec registry
103
+ β”œβ”€β”€ RULES.md # Project constitution
104
+ β”œβ”€β”€ PLAN.md # Implementation plan
105
+ β”œβ”€β”€ specifications/ # Your specification files
106
+ └── tasks/ # Task breakdowns per phase
107
+ ```
108
+
109
+ ## πŸ”— The Workflow Pipeline
110
+
111
+ ```mermaid
112
+ graph TD
113
+ IDEA["πŸ’‘ Idea"] --> INIT{"πŸ—οΈ Auto-Init"}
114
+ INIT -->|.design/ exists| SPEC
115
+ INIT -->|.design/ missing| CREATE["Create .design/ structure"] --> SPEC
116
+ SPEC["πŸ“‹ Specification"] <--> RULE["πŸ“œ Rule"]
117
+ SPEC --> TASK["πŸ—ΊοΈ Task & Plan"]
118
+ TASK --> RUN["⚑ Run"]
119
+ RUN --> CODE["πŸš€ Code"]
120
+ RUN -.->|"auto: phase done"| RETRO["πŸ” Retrospective"]
121
+ RETRO -.->|Feedback loop| SPEC
122
+ ```
123
+
124
+ ### Core Workflows
125
+
126
+ | # | Workflow | Purpose |
127
+ | :--- | :--- | :--- |
128
+ | 1 | **Specification** | Converts raw thoughts into structured specs. Verifies specs against project state. Manages statuses: `Draft β†’ RFC β†’ Stable β†’ Deprecated`. |
129
+ | 2 | **Task** | Reads Stable specs, builds a dependency graph, produces a phased `PLAN.md`, and decomposes into atomic tasks. |
130
+ | 3 | **Run** | Executes tasks with sequential and parallel tracks. Automatically runs a retrospective at phase and plan completion. |
131
+
132
+ ### Auxiliary Workflows
133
+
134
+ | Workflow | Purpose |
135
+ | :--- | :--- |
136
+ | **Rule** | Manages the project constitution (`RULES.md Β§7`). Add, amend, or remove conventions. |
137
+ | **Onboard** | Interactive tutorial guiding new developers through their first Magic SDD cycle. |
138
+
139
+ > **Retrospective** runs automatically inside the Run workflow β€” at phase completion (snapshot) and plan completion (full analysis). No manual command needed.
140
+
141
+ ## πŸ’¬ How to Use (with any AI agent)
142
+
143
+ Just talk to your AI agent naturally. Initialization is **automatic** β€” no setup command required.
144
+
145
+ ```plaintext
146
+ "Dispatch this thought into specs: I want a user auth system with JWT and Redis..."
147
+ β†’ Runs Specification workflow
148
+
149
+ "Create an implementation plan"
150
+ β†’ Runs Task workflow
151
+
152
+ "Generate tasks for Phase 1"
153
+ β†’ Runs Task workflow
154
+
155
+ "Execute the next task"
156
+ β†’ Runs Run workflow
157
+
158
+ "Add rule: always use snake_case for file names"
159
+ β†’ Runs Rule workflow
160
+
161
+ "Check if specs match the actual project state"
162
+ β†’ Runs Specification workflow (Consistency Check)
163
+
164
+ "Start the interactive tutorial"
165
+ β†’ Runs Onboard workflow
166
+ ```
167
+
168
+ The AI reads the corresponding `.magic/*.md` workflow file and executes the request within the bounds of the SDD system. **No code escapes the pipeline.** ✨
169
+
170
+ ## πŸ”„ Updating
171
+
172
+ Pull the latest engine improvements without touching your project data:
173
+
174
+ ```bash
175
+ # Node.js
176
+ npx magic-spec@latest --update
177
+
178
+ # Python
179
+ uvx magic-spec --update
180
+ ```
181
+
182
+ The update overwrites `.magic/` (the engine) but **never touches** `.design/` (your specs, plans, and tasks).
183
+
184
+ ## 🀝 Compatibility
185
+
186
+ Works with any AI coding agent that can read markdown workflow files:
187
+
188
+ - [Cursor](https://cursor.sh) (`.cursorrules` + Agent mode)
189
+ - [Claude](https://claude.ai) (Projects)
190
+ - [Gemini](https://gemini.google.com) (via Gemini Code)
191
+ - [GitHub Copilot](https://github.com/features/copilot) (Agent mode)
192
+ - Any terminal-based or API-driven agent
193
+
194
+ ## πŸ“„ License
195
+
196
+ [MIT](./LICENSE) Β© 2026 Oleg Alexandrov
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { spawnSync } = require('child_process');
6
+ const https = require('https');
7
+ const os = require('os');
8
+ const { version } = require('./package.json');
9
+
10
+ const GITHUB_REPO = 'teratron/magic-spec';
11
+ const cwd = process.cwd();
12
+
13
+ const args = process.argv.slice(2);
14
+ const isUpdate = args.includes('--update');
15
+ const isDoctor = args.includes('--doctor') || args.includes('--check');
16
+ const isFallbackMain = args.includes('--fallback-main');
17
+
18
+ const envFlag = args.find(a => a.startsWith('--env'));
19
+ const envValues = envFlag
20
+ ? envFlag.includes('=')
21
+ ? envFlag.split('=')[1].split(',')
22
+ : (args[args.indexOf(envFlag) + 1] || '').split(',').filter(Boolean)
23
+ : [];
24
+
25
+ function copyDir(src, dest) {
26
+ if (!fs.existsSync(src)) {
27
+ console.warn(`⚠️ Source not found: ${src}`);
28
+ return;
29
+ }
30
+ fs.cpSync(src, dest, { recursive: true, force: true });
31
+ }
32
+
33
+ function installAdapter(sourceRoot, env, adapters) {
34
+ const adapter = adapters[env];
35
+ if (!adapter) {
36
+ console.warn(`⚠️ Unknown --env value: "${env}".`);
37
+ console.warn(` Valid values: ${Object.keys(adapters).join(', ')}`);
38
+ console.warn(` Falling back to default .agent/`);
39
+ copyDir(path.join(sourceRoot, '.agent'), path.join(cwd, '.agent'));
40
+ return;
41
+ }
42
+
43
+ const srcDir = path.join(sourceRoot, '.agent', 'workflows');
44
+ const destDir = path.join(cwd, adapter.dest);
45
+
46
+ if (!fs.existsSync(srcDir)) {
47
+ console.warn(`⚠️ Source .agent/workflows/ not found.`);
48
+ return;
49
+ }
50
+
51
+ fs.mkdirSync(destDir, { recursive: true });
52
+
53
+ const files = fs.readdirSync(srcDir).filter(f => f.endsWith('.md'));
54
+ for (const file of files) {
55
+ const srcFile = path.join(srcDir, file);
56
+ let destName = file.replace(/\.md$/, adapter.ext);
57
+ if (adapter.removePrefix) {
58
+ destName = destName.replace(adapter.removePrefix, '');
59
+ }
60
+ const destFile = path.join(destDir, destName);
61
+ fs.copyFileSync(srcFile, destFile);
62
+ }
63
+
64
+ console.log(`βœ… Adapter installed: ${env} β†’ ${adapter.dest}/ (${adapter.ext})`);
65
+ }
66
+
67
+ function runDoctor() {
68
+ const isWindows = process.platform === 'win32';
69
+ const checkScript = isWindows
70
+ ? path.join(cwd, '.magic', 'scripts', 'check-prerequisites.ps1')
71
+ : path.join(cwd, '.magic', 'scripts', 'check-prerequisites.sh');
72
+
73
+ if (!fs.existsSync(checkScript)) {
74
+ console.error('❌ Error: SDD engine not initialized. Run magic-spec first.');
75
+ process.exit(1);
76
+ }
77
+
78
+ console.log('πŸ” Magic-spec Doctor:');
79
+ try {
80
+ let result;
81
+ if (isWindows) {
82
+ result = spawnSync('powershell.exe', ['-ExecutionPolicy', 'Bypass', '-File', checkScript, '-json'], { encoding: 'utf-8' });
83
+ } else {
84
+ result = spawnSync('bash', [checkScript, '--json'], { encoding: 'utf-8' });
85
+ }
86
+
87
+ let jsonStr = result.stdout.trim();
88
+ const match = jsonStr.match(/\{[\s\S]*\}/);
89
+ if (match) {
90
+ jsonStr = match[0];
91
+ }
92
+
93
+ const data = JSON.parse(jsonStr);
94
+ const arts = data.artifacts || {};
95
+ const checkItem = (name, item, requiredHint) => {
96
+ if (item && item.exists) {
97
+ console.log(`βœ… ${item.path || name} is present`);
98
+ } else {
99
+ const hint = requiredHint ? ` (Hint: ${requiredHint})` : '';
100
+ console.log(`❌ .design/${name} is missing${hint}`);
101
+ }
102
+ };
103
+
104
+ checkItem('INDEX.md', arts['INDEX.md'], 'Run /magic.spec');
105
+ checkItem('RULES.md', arts['RULES.md'], 'Created at init');
106
+
107
+ if (arts['PLAN.md']) {
108
+ checkItem('PLAN.md', arts['PLAN.md'], 'Run /magic.task');
109
+ }
110
+ if (arts['TASKS.md']) {
111
+ checkItem('TASKS.md', arts['TASKS.md'], 'Run /magic.task');
112
+ }
113
+
114
+ if (data.warnings && data.warnings.length > 0) {
115
+ data.warnings.forEach(warn => {
116
+ console.log(`⚠️ ${warn}`);
117
+ });
118
+ }
119
+
120
+ if (arts.specs) {
121
+ const { stable } = arts.specs;
122
+ if (stable > 0) console.log(`βœ… ${stable} specifications are Stable`);
123
+ }
124
+
125
+ } catch (err) {
126
+ console.error('❌ Failed to parse doctor output', err.message);
127
+ }
128
+ process.exit(0);
129
+ }
130
+
131
+ async function downloadPayload(targetVersion) {
132
+ const url = targetVersion === 'main'
133
+ ? `https://github.com/${GITHUB_REPO}/archive/refs/heads/main.tar.gz`
134
+ : `https://github.com/${GITHUB_REPO}/archive/refs/tags/v${targetVersion}.tar.gz`;
135
+
136
+ console.log(`πŸ“₯ Downloading magic-spec payload (${targetVersion}) from GitHub...`);
137
+
138
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'magic-spec-'));
139
+ const archivePath = path.join(tempDir, 'payload.tar.gz');
140
+
141
+ return new Promise((resolve, reject) => {
142
+ const file = fs.createWriteStream(archivePath);
143
+
144
+ const makeRequest = (requestUrl) => {
145
+ https.get(requestUrl, { headers: { 'User-Agent': 'magic-spec-node' } }, (response) => {
146
+ if (response.statusCode === 301 || response.statusCode === 302) {
147
+ // Follow redirect
148
+ return makeRequest(response.headers.location);
149
+ }
150
+
151
+ if (response.statusCode === 404) {
152
+ console.error(`❌ Error: Release ${targetVersion} not found on GitHub.`);
153
+ console.error(' (Use --fallback-main to pull from the main branch instead)');
154
+ reject(new Error('Payload not found'));
155
+ return;
156
+ }
157
+
158
+ if (response.statusCode !== 200) {
159
+ reject(new Error(`Failed with status code: ${response.statusCode}`));
160
+ return;
161
+ }
162
+
163
+ response.pipe(file);
164
+
165
+ file.on('finish', () => {
166
+ file.close();
167
+ console.log('πŸ“¦ Extracting payload...');
168
+
169
+ try {
170
+ // Using spawnSync for tar extraction. Requires 'tar' available on system.
171
+ // For a pure JS solution without dependencies, you would use a package like 'tar'
172
+ const isWindows = process.platform === 'win32';
173
+
174
+ let result;
175
+ if (isWindows) {
176
+ // Use PowerShell to extract tar on Windows 10+
177
+ result = spawnSync('tar', ['-xzf', archivePath, '-C', tempDir]);
178
+ } else {
179
+ // Standard Linux/macOS tar
180
+ result = spawnSync('tar', ['-xzf', archivePath, '-C', tempDir]);
181
+ }
182
+
183
+ if (result.error || result.status !== 0) {
184
+ throw new Error('Tar extraction failed. ' + (result.stderr ? result.stderr.toString() : ''));
185
+ }
186
+
187
+ const items = fs.readdirSync(tempDir);
188
+ const extractedFolder = items.find(item => {
189
+ const p = path.join(tempDir, item);
190
+ return item !== 'payload.tar.gz' && fs.statSync(p).isDirectory();
191
+ });
192
+
193
+ if (extractedFolder) {
194
+ resolve(path.join(tempDir, extractedFolder));
195
+ } else {
196
+ resolve(tempDir);
197
+ }
198
+
199
+ } catch (err) {
200
+ reject(err);
201
+ }
202
+ });
203
+ }).on('error', (err) => {
204
+ fs.unlink(archivePath, () => reject(err));
205
+ });
206
+ };
207
+
208
+ makeRequest(url);
209
+ });
210
+ }
211
+
212
+ async function main() {
213
+ if (isDoctor) {
214
+ runDoctor();
215
+ return;
216
+ }
217
+
218
+ if (args.includes('--help') || args.includes('-h')) {
219
+ console.log("Usage: npx magic-spec [--env <adapter>] [--update] [--doctor | --check] [--fallback-main]");
220
+ process.exit(0);
221
+ }
222
+
223
+ console.log(isUpdate ? 'πŸͺ„ Updating magic-spec (.magic only)...' : 'πŸͺ„ Initializing magic-spec...');
224
+
225
+ const versionToFetch = isFallbackMain ? 'main' : version;
226
+
227
+ try {
228
+ const sourceRoot = await downloadPayload(versionToFetch);
229
+
230
+ let ADAPTERS = {};
231
+ try {
232
+ ADAPTERS = JSON.parse(fs.readFileSync(path.join(sourceRoot, 'installers', 'adapters.json'), 'utf8'));
233
+ } catch (e) { }
234
+
235
+ // 1. Copy .magic
236
+ copyDir(path.join(sourceRoot, '.magic'), path.join(cwd, '.magic'));
237
+
238
+ // 2. Adapters
239
+ if (!isUpdate) {
240
+ if (envValues.length > 0) {
241
+ for (const env of envValues) {
242
+ installAdapter(sourceRoot, env, ADAPTERS);
243
+ }
244
+ } else {
245
+ copyDir(path.join(sourceRoot, '.agent'), path.join(cwd, '.agent'));
246
+ }
247
+ }
248
+
249
+ // 3. Init script
250
+ if (!isUpdate) {
251
+ const isWindows = process.platform === 'win32';
252
+ const initScript = isWindows
253
+ ? path.join(cwd, '.magic', 'scripts', 'init.ps1')
254
+ : path.join(cwd, '.magic', 'scripts', 'init.sh');
255
+
256
+ if (fs.existsSync(initScript)) {
257
+ if (isWindows) {
258
+ spawnSync('powershell.exe', ['-ExecutionPolicy', 'Bypass', '-File', initScript], { stdio: 'inherit' });
259
+ } else {
260
+ fs.chmodSync(initScript, '755');
261
+ spawnSync('bash', [initScript], { stdio: 'inherit' });
262
+ }
263
+ }
264
+ console.log('βœ… magic-spec initialized successfully!');
265
+ } else {
266
+ console.log('βœ… magic-spec updated successfully!');
267
+ }
268
+
269
+ } catch (err) {
270
+ console.error('❌ magic-spec initialization failed:', err.message);
271
+ process.exit(1);
272
+ }
273
+ }
274
+
275
+ main();