prd-parser 0.2.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 David Habedank
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,443 @@
1
+ # prd-parser
2
+
3
+ > **🚧 Active Development** - This project is new and actively evolving. Expect breaking changes. Contributions and feedback welcome!
4
+
5
+ **Turn your PRD into a ready-to-work beads project in one command.**
6
+
7
+ prd-parser uses LLM guardrails to transform Product Requirements Documents into a hierarchical issue structure (Epics → Tasks → Subtasks) and creates them directly in [beads](https://github.com/beads-project/beads) - the git-backed issue tracker for AI-driven development.
8
+
9
+ ```bash
10
+ # One command: PRD → structured beads issues
11
+ prd-parser parse ./docs/prd.md
12
+ ```
13
+
14
+ ## The 0→1 Problem
15
+
16
+ Starting a new project is exciting. You have a vision, maybe a PRD, and you're ready to build. But then:
17
+
18
+ 1. **The breakdown problem** - You need to turn that PRD into actionable tasks. This is tedious and error-prone. You lose context as you go.
19
+
20
+ 2. **The context problem** - By the time you're implementing subtask #47, you've forgotten why it matters. What was the business goal? Who are the users? What constraints apply?
21
+
22
+ 3. **The handoff problem** - If you're using AI to help implement, it needs that context too. Copy-pasting from your PRD for every task doesn't scale.
23
+
24
+ **prd-parser + beads solves all three.** Write your PRD once, run one command, and get a complete project structure with context propagated to every level - ready for you or Claude to start implementing.
25
+
26
+ ## Why prd-parser + beads?
27
+
28
+ **For greenfield projects**, this is the fastest path from idea to structured, trackable work:
29
+
30
+ | Without prd-parser | With prd-parser |
31
+ |-------------------|-----------------|
32
+ | Read PRD, manually create issues | One command |
33
+ | Forget context by subtask #10 | Context propagated everywhere |
34
+ | Testing requirements? Maybe later | Testing enforced at every level |
35
+ | Dependencies tracked in your head | Dependencies explicit and tracked |
36
+ | Copy-paste context for AI helpers | AI has full context in every issue |
37
+
38
+ **How it works**: prd-parser uses Go struct guardrails to force the LLM to output valid, hierarchical JSON with:
39
+ - **Context propagation** - Business purpose flows from PRD → Epic → Task → Subtask
40
+ - **Testing at every level** - Unit, integration, type, and E2E requirements enforced
41
+ - **Dependencies tracked** - Issues know what blocks them
42
+ - **Direct beads integration** - Issues created with one command, ready to work
43
+
44
+ ## Getting Started: Your First PRD → beads Project
45
+
46
+ ### 1. Install prd-parser
47
+
48
+ **Via npm/bun (easiest):**
49
+ ```bash
50
+ npm install -g prd-parser
51
+ # or
52
+ bun install -g prd-parser
53
+ # or
54
+ npx prd-parser parse ./docs/prd.md # run without installing
55
+ ```
56
+
57
+ **Via Go:**
58
+ ```bash
59
+ go install github.com/dhabedank/prd-parser@latest
60
+ ```
61
+
62
+ **From source:**
63
+ ```bash
64
+ cd /tmp && git clone https://github.com/dhabedank/prd-parser.git && cd prd-parser && make install
65
+ ```
66
+
67
+ If you see "Make sure ~/go/bin is in your PATH", run:
68
+ ```bash
69
+ echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
70
+ ```
71
+
72
+ Now go back to your project.
73
+
74
+ ### 2. Create a new project with beads
75
+
76
+ ```bash
77
+ mkdir my-project && cd my-project
78
+ git init
79
+ bd init --prefix my-project
80
+ ```
81
+
82
+ ### 3. Write your PRD
83
+
84
+ Create `docs/prd.md` with your product requirements. Include:
85
+ - What you're building and why
86
+ - Who the target users are
87
+ - Technical constraints
88
+ - Key features
89
+
90
+ Example:
91
+ ```markdown
92
+ # Task Management CLI
93
+
94
+ ## Overview
95
+ A fast, developer-friendly command-line task manager for teams
96
+ who prefer terminal workflows.
97
+
98
+ ## Target Users
99
+ Software developers who live in the terminal and want sub-100ms
100
+ task operations without context-switching to a GUI.
101
+
102
+ ## Core Features
103
+ 1. Create tasks with title, description, priority
104
+ 2. List and filter tasks by status/priority
105
+ 3. Update task status (todo → in-progress → done)
106
+ 4. Local JSON storage for offline-first operation
107
+
108
+ ## Technical Constraints
109
+ - Sub-100ms response for all operations
110
+ - Single binary, no runtime dependencies
111
+ - Config stored in ~/.taskman/
112
+ ```
113
+
114
+ ### 4. Parse your PRD into beads issues
115
+
116
+ ```bash
117
+ prd-parser parse docs/prd.md
118
+ ```
119
+
120
+ That's it. Your PRD is now a structured beads project with **readable hierarchical IDs**:
121
+
122
+ ```bash
123
+ $ bd list
124
+ â—‹ my-project-e1 [P1] [epic] - Core Task Management System
125
+ â—‹ my-project-e1t1 [P0] [task] - Implement Task Data Model
126
+ â—‹ my-project-e1t1s1 [P2] [task] - Define Task struct with JSON tags
127
+ â—‹ my-project-e1t1s2 [P2] [task] - Implement JSON file storage
128
+ â—‹ my-project-e1t2 [P1] [task] - Build CLI Interface
129
+ â—‹ my-project-e2 [P1] [epic] - User Authentication
130
+ ...
131
+ ```
132
+
133
+ IDs follow a logical hierarchy: `e1` (epic 1) → `e1t1` (task 1) → `e1t1s1` (subtask 1). Use `bd show <id>` to see parent/children relationships.
134
+
135
+ ### 5. Start working with beads + Claude
136
+
137
+ ```bash
138
+ # See what's ready to work on
139
+ bd ready
140
+
141
+ # Pick an issue and let Claude implement it
142
+ bd show my-project-4og # Shows full context, testing requirements
143
+
144
+ # Or let Claude pick and work autonomously
145
+ # (beads integrates with Claude Code via the beads skill)
146
+ ```
147
+
148
+ ## What prd-parser Creates
149
+
150
+ ### Hierarchical Structure
151
+
152
+ ```
153
+ Epic: Core Task Management System
154
+ ├── Task: Implement Task Data Model
155
+ │ ├── Subtask: Define Task struct with JSON tags
156
+ │ └── Subtask: Implement JSON file storage
157
+ ├── Task: Build CLI Interface
158
+ │ ├── Subtask: Implement create command
159
+ │ └── Subtask: Implement list command
160
+ └── ...
161
+ ```
162
+
163
+ ### Context Propagation
164
+
165
+ Every issue includes propagated context so implementers understand WHY:
166
+
167
+ ```markdown
168
+ **Context:**
169
+ - **Business Context:** Developers need fast, frictionless task management
170
+ - **Target Users:** Terminal-first developers who want <100ms operations
171
+ - **Success Metrics:** All CRUD operations complete in under 100ms
172
+ ```
173
+
174
+ ### Testing Requirements
175
+
176
+ Every issue specifies what testing is needed:
177
+
178
+ ```markdown
179
+ **Testing Requirements:**
180
+ - **Unit Tests:** Task struct validation, JSON marshaling/unmarshaling
181
+ - **Integration Tests:** Full storage layer integration, concurrent access
182
+ - **Type Tests:** Go struct tags validation, JSON schema compliance
183
+ ```
184
+
185
+ ### Priority Evaluation
186
+
187
+ The LLM evaluates each task and assigns appropriate priority (not just a default):
188
+
189
+ | Priority | When to Use |
190
+ |----------|-------------|
191
+ | **P0 (critical)** | Blocks all work, security issues, launch blockers |
192
+ | **P1 (high)** | Core functionality, enables other tasks |
193
+ | **P2 (medium)** | Important features, standard work |
194
+ | **P3 (low)** | Nice-to-haves, polish |
195
+ | **P4 (very-low)** | Future considerations, can defer indefinitely |
196
+
197
+ Foundation/setup work gets higher priority. Polish/UI tweaks get lower priority.
198
+
199
+ ### Labels
200
+
201
+ Issues are automatically labeled based on:
202
+ - **Layer**: frontend, backend, api, database, infra
203
+ - **Domain**: auth, payments, search, notifications
204
+ - **Skill**: react, go, sql, typescript
205
+ - **Type**: setup, feature, refactor, testing
206
+
207
+ Labels are extracted from the PRD's tech stack and feature descriptions.
208
+
209
+ ### Design Notes & Acceptance Criteria
210
+
211
+ - **Epics** include acceptance criteria for when the epic is complete
212
+ - **Tasks** include design notes for technical approach
213
+
214
+ ### Time Estimates
215
+
216
+ All items include time estimates that flow to beads:
217
+ - Epics: estimated days
218
+ - Tasks: estimated hours
219
+ - Subtasks: estimated minutes
220
+
221
+ ### Dependencies
222
+
223
+ Issues are linked with proper blocking relationships:
224
+ - Tasks depend on setup tasks
225
+ - Subtasks depend on parent task completion
226
+ - Cross-epic dependencies are tracked
227
+
228
+ ## Configuration
229
+
230
+ ### Parse Options
231
+
232
+ ```bash
233
+ # Control structure size
234
+ prd-parser parse ./prd.md --epics 5 --tasks 8 --subtasks 4
235
+
236
+ # Set default priority
237
+ prd-parser parse ./prd.md --priority high
238
+
239
+ # Choose testing level
240
+ prd-parser parse ./prd.md --testing comprehensive # or minimal, standard
241
+
242
+ # Preview without creating (dry run)
243
+ prd-parser parse ./prd.md --dry-run
244
+
245
+ # Include/exclude sections in issue descriptions
246
+ prd-parser parse ./prd.md --include-context --include-testing
247
+ ```
248
+
249
+ ### Full Options
250
+
251
+ | Flag | Short | Default | Description |
252
+ |------|-------|---------|-------------|
253
+ | `--epics` | `-e` | 3 | Target number of epics |
254
+ | `--tasks` | `-t` | 5 | Target tasks per epic |
255
+ | `--subtasks` | `-s` | 4 | Target subtasks per task |
256
+ | `--priority` | `-p` | medium | Default priority (critical/high/medium/low) |
257
+ | `--testing` | | comprehensive | Testing level (minimal/standard/comprehensive) |
258
+ | `--llm` | `-l` | auto | LLM provider (auto/claude-cli/codex-cli/anthropic-api) |
259
+ | `--model` | `-m` | | Model to use (provider-specific) |
260
+ | `--multi-stage` | | | Force multi-stage parsing |
261
+ | `--single-shot` | | | Force single-shot parsing |
262
+ | `--smart-threshold` | | 300 | Line count for auto multi-stage (0 to disable) |
263
+ | `--validate` | | false | Run validation pass to check for gaps |
264
+ | `--subtask-model` | | | Model for subtasks in multi-stage (can be faster/cheaper) |
265
+ | `--output` | `-o` | beads | Output adapter (beads/json) |
266
+ | `--output-path` | | | Output path for JSON adapter |
267
+ | `--working-dir` | `-w` | . | Working directory for beads |
268
+ | `--dry-run` | | false | Preview without creating items |
269
+ | `--include-context` | | true | Include context in descriptions |
270
+ | `--include-testing` | | true | Include testing requirements |
271
+
272
+ ### Smart Parsing (Default Behavior)
273
+
274
+ prd-parser automatically chooses the best parsing strategy based on PRD size:
275
+
276
+ - **Small PRDs** (< 300 lines): Single-shot parsing (faster)
277
+ - **Large PRDs** (≥ 300 lines): Multi-stage parallel parsing (more reliable)
278
+
279
+ Override with `--single-shot` or `--multi-stage` flags, or adjust threshold with `--smart-threshold`.
280
+
281
+ ### Validation Pass
282
+
283
+ Use `--validate` to run a final review that checks for gaps in the generated plan:
284
+
285
+ ```bash
286
+ prd-parser parse ./prd.md --validate
287
+ ```
288
+
289
+ This asks the LLM to review the complete plan and identify:
290
+ - Missing setup/initialization tasks
291
+ - Backend without UI to test it
292
+ - Dependencies not installed
293
+ - Acceptance criteria that can't be verified
294
+ - Tasks in wrong order
295
+
296
+ Example output:
297
+ ```
298
+ ✓ Plan validation passed - no gaps found
299
+ ```
300
+ or
301
+ ```
302
+ âš  Plan validation found gaps:
303
+ • No task to install dependencies after adding @clerk/nextjs
304
+ • Auth API built but no login page to test it
305
+ ```
306
+
307
+ ## LLM Providers
308
+
309
+ ### Zero-Config (Recommended)
310
+
311
+ prd-parser auto-detects installed LLM CLIs - no API keys needed:
312
+
313
+ ```bash
314
+ # If you have Claude Code installed, it just works
315
+ prd-parser parse ./prd.md
316
+
317
+ # If you have Codex installed, it just works
318
+ prd-parser parse ./prd.md
319
+ ```
320
+
321
+ ### Detection Priority
322
+
323
+ 1. **Claude Code CLI** (`claude`) - Preferred, already authenticated
324
+ 2. **Codex CLI** (`codex`) - Already authenticated
325
+ 3. **Anthropic API** - Fallback if `ANTHROPIC_API_KEY` is set
326
+
327
+ ### Explicit Selection
328
+
329
+ ```bash
330
+ # Force specific provider
331
+ prd-parser parse ./prd.md --llm claude-cli
332
+ prd-parser parse ./prd.md --llm codex-cli
333
+ prd-parser parse ./prd.md --llm anthropic-api
334
+
335
+ # Specify model
336
+ prd-parser parse ./prd.md --llm claude-cli --model claude-sonnet-4-20250514
337
+ prd-parser parse ./prd.md --llm codex-cli --model o3
338
+ ```
339
+
340
+ ## Output Options
341
+
342
+ ### beads (Default)
343
+
344
+ Creates issues directly in the current beads-initialized project:
345
+
346
+ ```bash
347
+ bd init --prefix myproject
348
+ prd-parser parse ./prd.md --output beads
349
+ bd list # See created issues
350
+ ```
351
+
352
+ ### JSON
353
+
354
+ Export to JSON for inspection or custom processing:
355
+
356
+ ```bash
357
+ # Write to file
358
+ prd-parser parse ./prd.md --output json --output-path tasks.json
359
+
360
+ # Write to stdout (pipe to other tools)
361
+ prd-parser parse ./prd.md --output json | jq '.epics[0].tasks'
362
+ ```
363
+
364
+ ## The Guardrails System
365
+
366
+ prd-parser isn't just a prompt wrapper. It uses Go structs as **guardrails** to enforce valid output:
367
+
368
+ ```go
369
+ type Epic struct {
370
+ TempID string `json:"temp_id"`
371
+ Title string `json:"title"`
372
+ Description string `json:"description"`
373
+ Context interface{} `json:"context"`
374
+ AcceptanceCriteria []string `json:"acceptance_criteria"`
375
+ Testing TestingRequirements `json:"testing"`
376
+ Tasks []Task `json:"tasks"`
377
+ DependsOn []string `json:"depends_on"`
378
+ }
379
+
380
+ type TestingRequirements struct {
381
+ UnitTests *string `json:"unit_tests,omitempty"`
382
+ IntegrationTests *string `json:"integration_tests,omitempty"`
383
+ TypeTests *string `json:"type_tests,omitempty"`
384
+ E2ETests *string `json:"e2e_tests,omitempty"`
385
+ }
386
+ ```
387
+
388
+ The LLM MUST produce output that matches these structs. Missing required fields? Validation fails. Wrong types? Parse fails. This ensures every PRD produces consistent, complete issue structures.
389
+
390
+ ## Architecture
391
+
392
+ ```
393
+ prd-parser/
394
+ ├── cmd/ # CLI commands (Cobra)
395
+ │ └── parse.go # Main parse command
396
+ ├── internal/
397
+ │ ├── core/ # Core types and orchestration
398
+ │ │ ├── types.go # Hierarchical structs (guardrails)
399
+ │ │ ├── prompts.go # Embedded system/user prompts
400
+ │ │ └── parser.go # LLM → Output orchestration
401
+ │ ├── llm/ # LLM adapters
402
+ │ │ ├── adapter.go # Interface definition
403
+ │ │ ├── claude_cli.go # Claude Code CLI adapter
404
+ │ │ ├── codex_cli.go # Codex CLI adapter
405
+ │ │ ├── anthropic_api.go # API fallback
406
+ │ │ └── detector.go # Auto-detection logic
407
+ │ └── output/ # Output adapters
408
+ │ ├── adapter.go # Interface definition
409
+ │ ├── beads.go # beads issue tracker
410
+ │ └── json.go # JSON file output
411
+ └── tests/ # Unit tests
412
+ ```
413
+
414
+ ## Adding Custom Adapters
415
+
416
+ ### Custom LLM Adapter
417
+
418
+ ```go
419
+ type Adapter interface {
420
+ Name() string
421
+ IsAvailable() bool
422
+ Generate(ctx context.Context, systemPrompt, userPrompt string) (*core.ParseResponse, error)
423
+ }
424
+ ```
425
+
426
+ ### Custom Output Adapter
427
+
428
+ ```go
429
+ type Adapter interface {
430
+ Name() string
431
+ IsAvailable() (bool, error)
432
+ CreateItems(response *core.ParseResponse, config Config) (*CreateResult, error)
433
+ }
434
+ ```
435
+
436
+ ## Related Projects
437
+
438
+ - **[beads](https://github.com/beads-project/beads)** - Git-backed issue tracker for AI-driven development
439
+ - **[Claude Code](https://claude.ai/claude-code)** - Claude's official CLI with beads integration
440
+
441
+ ## License
442
+
443
+ MIT
package/bin/prd-parser ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+
3
+ // This is a placeholder that gets replaced by the actual binary during install.
4
+ // If you see this message, the installation may have failed.
5
+
6
+ console.error('prd-parser binary not found.');
7
+ console.error('');
8
+ console.error('Try reinstalling:');
9
+ console.error(' npm install -g prd-parser');
10
+ console.error('');
11
+ console.error('Or install manually from:');
12
+ console.error(' https://github.com/dhabedank/prd-parser/releases');
13
+
14
+ process.exit(1);
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "prd-parser",
3
+ "version": "0.2.0",
4
+ "description": "Turn your PRD into a ready-to-work beads project in one command",
5
+ "keywords": [
6
+ "prd",
7
+ "parser",
8
+ "beads",
9
+ "task",
10
+ "project-management",
11
+ "ai",
12
+ "llm"
13
+ ],
14
+ "author": "David Habedank",
15
+ "license": "MIT",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/dhabedank/prd-parser.git"
19
+ },
20
+ "homepage": "https://github.com/dhabedank/prd-parser#readme",
21
+ "bugs": {
22
+ "url": "https://github.com/dhabedank/prd-parser/issues"
23
+ },
24
+ "bin": {
25
+ "prd-parser": "bin/prd-parser"
26
+ },
27
+ "scripts": {
28
+ "postinstall": "node scripts/install.js"
29
+ },
30
+ "files": [
31
+ "bin",
32
+ "scripts"
33
+ ],
34
+ "engines": {
35
+ "node": ">=16.0.0"
36
+ },
37
+ "os": [
38
+ "darwin",
39
+ "linux",
40
+ "win32"
41
+ ],
42
+ "cpu": [
43
+ "x64",
44
+ "arm64"
45
+ ]
46
+ }
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const https = require('https');
7
+ const { createWriteStream, chmodSync, existsSync, mkdirSync } = require('fs');
8
+
9
+ const REPO = 'dhabedank/prd-parser';
10
+ const BIN_NAME = 'prd-parser';
11
+
12
+ // Map Node.js platform/arch to Go naming
13
+ function getPlatformInfo() {
14
+ const platform = process.platform;
15
+ const arch = process.arch;
16
+
17
+ const platformMap = {
18
+ darwin: 'darwin',
19
+ linux: 'linux',
20
+ win32: 'windows',
21
+ };
22
+
23
+ const archMap = {
24
+ x64: 'amd64',
25
+ arm64: 'arm64',
26
+ };
27
+
28
+ const goPlatform = platformMap[platform];
29
+ const goArch = archMap[arch];
30
+
31
+ if (!goPlatform || !goArch) {
32
+ throw new Error(`Unsupported platform: ${platform}/${arch}`);
33
+ }
34
+
35
+ const ext = platform === 'win32' ? '.exe' : '';
36
+ return { goPlatform, goArch, ext };
37
+ }
38
+
39
+ // Get the latest release version from GitHub
40
+ async function getLatestVersion() {
41
+ return new Promise((resolve, reject) => {
42
+ const options = {
43
+ hostname: 'api.github.com',
44
+ path: `/repos/${REPO}/releases/latest`,
45
+ headers: { 'User-Agent': 'prd-parser-installer' },
46
+ };
47
+
48
+ https.get(options, (res) => {
49
+ let data = '';
50
+ res.on('data', (chunk) => (data += chunk));
51
+ res.on('end', () => {
52
+ try {
53
+ const release = JSON.parse(data);
54
+ resolve(release.tag_name);
55
+ } catch (e) {
56
+ reject(new Error('Failed to parse GitHub response'));
57
+ }
58
+ });
59
+ }).on('error', reject);
60
+ });
61
+ }
62
+
63
+ // Download file with redirect support
64
+ function downloadFile(url, dest) {
65
+ return new Promise((resolve, reject) => {
66
+ const file = createWriteStream(dest);
67
+
68
+ const request = (url) => {
69
+ https.get(url, { headers: { 'User-Agent': 'prd-parser-installer' } }, (res) => {
70
+ // Handle redirects
71
+ if (res.statusCode === 302 || res.statusCode === 301) {
72
+ request(res.headers.location);
73
+ return;
74
+ }
75
+
76
+ if (res.statusCode !== 200) {
77
+ reject(new Error(`Download failed with status ${res.statusCode}`));
78
+ return;
79
+ }
80
+
81
+ res.pipe(file);
82
+ file.on('finish', () => {
83
+ file.close();
84
+ resolve();
85
+ });
86
+ }).on('error', (err) => {
87
+ fs.unlink(dest, () => {});
88
+ reject(err);
89
+ });
90
+ };
91
+
92
+ request(url);
93
+ });
94
+ }
95
+
96
+ // Extract tar.gz archive
97
+ function extractTarGz(archive, dest) {
98
+ execSync(`tar -xzf "${archive}" -C "${dest}"`, { stdio: 'inherit' });
99
+ }
100
+
101
+ // Extract zip archive
102
+ function extractZip(archive, dest) {
103
+ if (process.platform === 'win32') {
104
+ execSync(`powershell -Command "Expand-Archive -Path '${archive}' -DestinationPath '${dest}'"`, { stdio: 'inherit' });
105
+ } else {
106
+ execSync(`unzip -o "${archive}" -d "${dest}"`, { stdio: 'inherit' });
107
+ }
108
+ }
109
+
110
+ async function main() {
111
+ console.log('Installing prd-parser...');
112
+
113
+ try {
114
+ const { goPlatform, goArch, ext } = getPlatformInfo();
115
+ console.log(`Platform: ${goPlatform}/${goArch}`);
116
+
117
+ // Get latest version
118
+ let version;
119
+ try {
120
+ version = await getLatestVersion();
121
+ console.log(`Latest version: ${version}`);
122
+ } catch (e) {
123
+ console.log('Could not fetch latest version, using v0.1.0');
124
+ version = 'v0.1.0';
125
+ }
126
+
127
+ // Determine archive format
128
+ const archiveExt = goPlatform === 'windows' ? '.zip' : '.tar.gz';
129
+ const archiveName = `prd-parser_${version.replace('v', '')}_${goPlatform}_${goArch}${archiveExt}`;
130
+ const downloadUrl = `https://github.com/${REPO}/releases/download/${version}/${archiveName}`;
131
+
132
+ console.log(`Downloading from: ${downloadUrl}`);
133
+
134
+ // Create temp directory
135
+ const tempDir = path.join(__dirname, '..', '.temp');
136
+ if (!existsSync(tempDir)) {
137
+ mkdirSync(tempDir, { recursive: true });
138
+ }
139
+
140
+ const archivePath = path.join(tempDir, archiveName);
141
+ await downloadFile(downloadUrl, archivePath);
142
+ console.log('Download complete');
143
+
144
+ // Extract
145
+ console.log('Extracting...');
146
+ if (archiveExt === '.zip') {
147
+ extractZip(archivePath, tempDir);
148
+ } else {
149
+ extractTarGz(archivePath, tempDir);
150
+ }
151
+
152
+ // Move binary to bin directory
153
+ const binDir = path.join(__dirname, '..', 'bin');
154
+ if (!existsSync(binDir)) {
155
+ mkdirSync(binDir, { recursive: true });
156
+ }
157
+
158
+ const srcBinary = path.join(tempDir, `${BIN_NAME}${ext}`);
159
+ const destBinary = path.join(binDir, `${BIN_NAME}${ext}`);
160
+
161
+ fs.copyFileSync(srcBinary, destBinary);
162
+
163
+ // Make executable on Unix
164
+ if (goPlatform !== 'windows') {
165
+ chmodSync(destBinary, 0o755);
166
+ }
167
+
168
+ // Cleanup
169
+ fs.rmSync(tempDir, { recursive: true, force: true });
170
+
171
+ console.log(`✓ prd-parser installed successfully to ${destBinary}`);
172
+ console.log('Run "prd-parser --help" to get started');
173
+
174
+ } catch (error) {
175
+ console.error('Installation failed:', error.message);
176
+ console.error('');
177
+ console.error('You can install manually:');
178
+ console.error(' 1. Download from https://github.com/dhabedank/prd-parser/releases');
179
+ console.error(' 2. Extract and move prd-parser to a directory in your PATH');
180
+ process.exit(1);
181
+ }
182
+ }
183
+
184
+ main();