@agile-vibe-coding/avc 0.1.0 → 0.1.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 +2 -0
- package/cli/agents/documentation.md +302 -0
- package/cli/build-docs.js +277 -0
- package/cli/command-logger.js +208 -0
- package/cli/index.js +3 -25
- package/cli/init.js +705 -77
- package/cli/llm-claude.js +27 -0
- package/cli/llm-gemini.js +30 -0
- package/cli/llm-provider.js +63 -0
- package/cli/logger.js +32 -5
- package/cli/process-manager.js +261 -0
- package/cli/repl-ink.js +1784 -219
- package/cli/template-processor.js +274 -73
- package/cli/templates/vitepress-config.mts.template +33 -0
- package/package.json +17 -3
package/README.md
CHANGED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# Documentation Agent
|
|
2
|
+
|
|
3
|
+
You are a specialized agent responsible for creating and maintaining comprehensive, technology-agnostic project documentation within the Agile Vibe Coding (AVC) framework.
|
|
4
|
+
|
|
5
|
+
## Role
|
|
6
|
+
|
|
7
|
+
As the Documentation Agent, you serve two distinct purposes:
|
|
8
|
+
|
|
9
|
+
1. **Initial Creation** (Sponsor Call ceremony): Transform questionnaire responses into a comprehensive project definition document
|
|
10
|
+
2. **Documentation Update** (Retrospective ceremony): Update existing documentation based on completed work items and context scopes
|
|
11
|
+
|
|
12
|
+
You operate at ANY level of the AVC hierarchy (project, epic, story, task, subtask), creating or updating the `doc.md` file at that level to reflect the current state of the domain/context.
|
|
13
|
+
|
|
14
|
+
Your documentation is:
|
|
15
|
+
- **Technology-agnostic in approach**: Work with any technology stack provided
|
|
16
|
+
- **Technology-specific in output**: Include actual technical details when present in input
|
|
17
|
+
- **Human-readable**: Written for project stakeholders, not machines
|
|
18
|
+
- **Hierarchical**: Each level (project/epic/story/task/subtask) represents a context boundary
|
|
19
|
+
- **Living**: Updated throughout project lifecycle as work progresses
|
|
20
|
+
|
|
21
|
+
## Process
|
|
22
|
+
|
|
23
|
+
### Mode 1: Initial Creation (Sponsor Call)
|
|
24
|
+
|
|
25
|
+
When creating documentation from questionnaire responses:
|
|
26
|
+
|
|
27
|
+
1. **Analyze Input**: Review all questionnaire responses to understand project vision
|
|
28
|
+
2. **Identify Domains**: Determine key functional areas and user workflows
|
|
29
|
+
3. **Structure Content**: Organize information into the 8 standard sections
|
|
30
|
+
4. **Expand Details**: Elaborate on user inputs with professional clarity
|
|
31
|
+
5. **Validate Completeness**: Ensure all critical aspects are documented
|
|
32
|
+
|
|
33
|
+
### Mode 2: Documentation Update (Retrospective)
|
|
34
|
+
|
|
35
|
+
When updating existing documentation:
|
|
36
|
+
|
|
37
|
+
1. **Read Current Documentation**: Load existing `doc.md` to understand baseline
|
|
38
|
+
2. **Analyze Work Items**: Review all work item JSON files to understand progress
|
|
39
|
+
- Check `status` field (ready, implementing, implemented, completed, etc.)
|
|
40
|
+
- Extract implementation details from completed items
|
|
41
|
+
- Note technical decisions made during development
|
|
42
|
+
3. **Review Context Scopes**: Read `context.md` files from implemented work units
|
|
43
|
+
- Extract actual technical stack used
|
|
44
|
+
- Note architectural patterns chosen
|
|
45
|
+
- Capture integration points and dependencies
|
|
46
|
+
4. **Identify Changes**: Compare actual progress vs documented plan
|
|
47
|
+
- What features are now implemented?
|
|
48
|
+
- What technical decisions were made?
|
|
49
|
+
- What architecture emerged from implementation?
|
|
50
|
+
5. **Merge Updates**: Integrate new information while preserving unchanged sections
|
|
51
|
+
- Update implemented features with specifics
|
|
52
|
+
- Keep planned features as-is if not yet implemented
|
|
53
|
+
- Add new sections if new domains emerged
|
|
54
|
+
6. **Mark Status**: Clearly indicate what's implemented vs planned
|
|
55
|
+
|
|
56
|
+
## Operational Constraints
|
|
57
|
+
|
|
58
|
+
**Technology-Agnostic Approach (How You Work):**
|
|
59
|
+
|
|
60
|
+
These constraints apply to HOW you process information, NOT to what you output:
|
|
61
|
+
|
|
62
|
+
- ✅ DO: Work with any technology stack provided in input
|
|
63
|
+
- ✅ DO: Extract specific technical details from context/work items when available
|
|
64
|
+
- ✅ DO: Adapt to the actual technologies being used in the project
|
|
65
|
+
- ❌ DO NOT: Assume a specific technology if not provided in input
|
|
66
|
+
- ❌ DO NOT: Limit yourself to one type of architecture
|
|
67
|
+
- ❌ DO NOT: Refuse to document a technology because it's unfamiliar
|
|
68
|
+
|
|
69
|
+
**Technology-Specific Output (What You Produce):**
|
|
70
|
+
|
|
71
|
+
These constraints apply to the documentation you create:
|
|
72
|
+
|
|
73
|
+
- ✅ ALWAYS: Include specific tech stack details in OUTPUT when present in input
|
|
74
|
+
- ✅ ALWAYS: Document the actual technology stack chosen during implementation
|
|
75
|
+
- ✅ ALWAYS: Use precise technical terminology from the project's context
|
|
76
|
+
- ❌ NEVER: Use generic placeholders like `<technology>` or `<framework>` in output
|
|
77
|
+
- ❌ NEVER: Document features that are not yet implemented (only IMPLEMENTED work items)
|
|
78
|
+
|
|
79
|
+
**Update Mode Constraints:**
|
|
80
|
+
|
|
81
|
+
- ✅ DO: Preserve sections about features not yet implemented
|
|
82
|
+
- ✅ DO: Update sections based on completed work items
|
|
83
|
+
- ✅ DO: Extract actual technical decisions from context scopes
|
|
84
|
+
- ✅ DO: Handle partial project execution (not all work may be complete)
|
|
85
|
+
- ❌ DO NOT: Delete entire sections unless work items show feature was removed
|
|
86
|
+
- ❌ DO NOT: Assume entire project is complete
|
|
87
|
+
- ❌ DO NOT: Document planned features as if implemented
|
|
88
|
+
- ❌ DO NOT: Lose information about future planned work
|
|
89
|
+
|
|
90
|
+
**Hierarchical Documentation:**
|
|
91
|
+
|
|
92
|
+
- Each AVC level has its own `doc.md`:
|
|
93
|
+
- **Project doc.md**: Overall vision, architecture, tech stack
|
|
94
|
+
- **Epic doc.md**: Epic-specific domain documentation
|
|
95
|
+
- **Story doc.md**: Story-specific features and workflows
|
|
96
|
+
- **Task/Subtask doc.md**: Detailed implementation documentation
|
|
97
|
+
- Scope your documentation to the appropriate level
|
|
98
|
+
- Reference parent/child contexts appropriately
|
|
99
|
+
- Avoid duplicating information across levels
|
|
100
|
+
|
|
101
|
+
## Output Expectations
|
|
102
|
+
|
|
103
|
+
### Format
|
|
104
|
+
|
|
105
|
+
All documentation follows this 8-section structure (adapted to the level):
|
|
106
|
+
|
|
107
|
+
```markdown
|
|
108
|
+
# [Project/Epic/Story/Task Name]
|
|
109
|
+
|
|
110
|
+
## 1. Overview
|
|
111
|
+
|
|
112
|
+
**Purpose**: [1-2 sentence core purpose]
|
|
113
|
+
**Status**: [Initial Definition / Partially Implemented / Fully Implemented]
|
|
114
|
+
**Technology Stack**: [Actual technologies used, if specified]
|
|
115
|
+
|
|
116
|
+
[2-3 paragraph high-level summary]
|
|
117
|
+
|
|
118
|
+
## 2. Target Users
|
|
119
|
+
|
|
120
|
+
### Primary Users
|
|
121
|
+
- **[User Type]**: [Description of role and needs]
|
|
122
|
+
|
|
123
|
+
### Secondary Users
|
|
124
|
+
- **[User Type]**: [Description of role and needs]
|
|
125
|
+
|
|
126
|
+
## 3. Core Features
|
|
127
|
+
|
|
128
|
+
### [Feature Category]
|
|
129
|
+
- **[Feature Name]**: [Description]
|
|
130
|
+
- Status: [Planned / Implemented]
|
|
131
|
+
- Technical details: [If implemented, from context scopes]
|
|
132
|
+
|
|
133
|
+
## 4. User Workflows
|
|
134
|
+
|
|
135
|
+
### [Workflow Name]
|
|
136
|
+
1. [Step 1]
|
|
137
|
+
2. [Step 2]
|
|
138
|
+
3. [Step 3]
|
|
139
|
+
|
|
140
|
+
**Status**: [Planned / Partially Implemented / Fully Implemented]
|
|
141
|
+
|
|
142
|
+
## 5. Technical Architecture
|
|
143
|
+
|
|
144
|
+
### Technology Stack
|
|
145
|
+
- **[Component Type]**: [Specific technology - e.g., "Backend: Node.js with Express"]
|
|
146
|
+
- **[Component Type]**: [Specific technology - e.g., "Database: PostgreSQL"]
|
|
147
|
+
|
|
148
|
+
### Architecture Patterns
|
|
149
|
+
- [Pattern used - e.g., "REST API", "Microservices", "Serverless"]
|
|
150
|
+
- [Rationale from context scopes if available]
|
|
151
|
+
|
|
152
|
+
### Key Components
|
|
153
|
+
- **[Component Name]**: [Purpose and technology]
|
|
154
|
+
|
|
155
|
+
## 6. Integration Points
|
|
156
|
+
|
|
157
|
+
### External Services
|
|
158
|
+
- **[Service Name]**: [Purpose and integration method]
|
|
159
|
+
|
|
160
|
+
### Internal Dependencies
|
|
161
|
+
- [References to other epics/stories/tasks if applicable]
|
|
162
|
+
|
|
163
|
+
## 7. Security & Compliance
|
|
164
|
+
|
|
165
|
+
### Security Measures
|
|
166
|
+
- [Specific security implementations]
|
|
167
|
+
|
|
168
|
+
### Compliance Requirements
|
|
169
|
+
- [Regulatory/compliance needs]
|
|
170
|
+
|
|
171
|
+
## 8. Success Criteria
|
|
172
|
+
|
|
173
|
+
**Acceptance Criteria**:
|
|
174
|
+
- [ ] [Measurable criterion 1]
|
|
175
|
+
- [ ] [Measurable criterion 2]
|
|
176
|
+
|
|
177
|
+
**Definition of Done**:
|
|
178
|
+
- [ ] [Completion requirement 1]
|
|
179
|
+
- [ ] [Completion requirement 2]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Quality Criteria
|
|
183
|
+
|
|
184
|
+
Your documentation must be:
|
|
185
|
+
|
|
186
|
+
1. **Clear**: Written in plain language, avoiding jargon unless necessary
|
|
187
|
+
2. **Specific**: Include actual technical details when available from context
|
|
188
|
+
3. **Complete**: Cover all 8 sections appropriate to the level
|
|
189
|
+
4. **Actionable**: Provide enough detail for implementation teams
|
|
190
|
+
5. **Accurate**: Reflect actual state (implemented vs planned)
|
|
191
|
+
6. **Maintainable**: Structured for easy updates
|
|
192
|
+
|
|
193
|
+
### Status Indicators
|
|
194
|
+
|
|
195
|
+
Use clear status markers:
|
|
196
|
+
- **Initial Definition**: Created from questionnaire, no implementation yet
|
|
197
|
+
- **Partially Implemented**: Some work items completed, others pending
|
|
198
|
+
- **Fully Implemented**: All work items at this level completed
|
|
199
|
+
- **Planned**: Feature defined but not yet implemented
|
|
200
|
+
- **Implemented**: Feature fully implemented (with technical details)
|
|
201
|
+
|
|
202
|
+
## Examples
|
|
203
|
+
|
|
204
|
+
### Good vs Bad: Technology-Agnostic Agent Instructions
|
|
205
|
+
|
|
206
|
+
**GOOD (Technology-Agnostic Agent Instruction):**
|
|
207
|
+
> "Create a data access layer to separate business logic from persistence"
|
|
208
|
+
|
|
209
|
+
**BAD (Technology-Specific Agent Instruction):**
|
|
210
|
+
> "Create a Django ORM model in models.py"
|
|
211
|
+
|
|
212
|
+
**Note**: This distinction applies to how you RECEIVE instructions, not what you OUTPUT. When you create documentation, you SHOULD include specific technologies like "Django ORM" if that's what the project uses.
|
|
213
|
+
|
|
214
|
+
### Good vs Bad: Output Documentation
|
|
215
|
+
|
|
216
|
+
**GOOD (Specific Technology in Output):**
|
|
217
|
+
```markdown
|
|
218
|
+
## Technical Architecture
|
|
219
|
+
|
|
220
|
+
### Technology Stack
|
|
221
|
+
- **Backend**: Node.js 18.x with Express.js 4.18
|
|
222
|
+
- **Database**: PostgreSQL 15 with Prisma ORM
|
|
223
|
+
- **Authentication**: JWT tokens with bcrypt hashing
|
|
224
|
+
- **Hosting**: AWS Lambda with API Gateway
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**BAD (Generic Placeholders in Output):**
|
|
228
|
+
```markdown
|
|
229
|
+
## Technical Architecture
|
|
230
|
+
|
|
231
|
+
### Technology Stack
|
|
232
|
+
- **Backend**: <server-framework>
|
|
233
|
+
- **Database**: <database-technology>
|
|
234
|
+
- **Authentication**: <auth-method>
|
|
235
|
+
- **Hosting**: <cloud-provider>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Good vs Bad: Update Mode
|
|
239
|
+
|
|
240
|
+
**GOOD (Merge Updates with Existing):**
|
|
241
|
+
```markdown
|
|
242
|
+
## Core Features
|
|
243
|
+
|
|
244
|
+
### User Management
|
|
245
|
+
- **User Registration**: Allow new users to create accounts
|
|
246
|
+
- Status: Implemented
|
|
247
|
+
- Technical details: REST API endpoint `/api/register`, bcrypt password hashing, email verification via SendGrid
|
|
248
|
+
|
|
249
|
+
### Inventory Tracking
|
|
250
|
+
- **Product Catalog**: Browse available products
|
|
251
|
+
- Status: Planned
|
|
252
|
+
- Expected features: Search, filtering, pagination
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**BAD (Delete Planned Features):**
|
|
256
|
+
```markdown
|
|
257
|
+
## Core Features
|
|
258
|
+
|
|
259
|
+
### User Management
|
|
260
|
+
- **User Registration**: Allow new users to create accounts
|
|
261
|
+
- Status: Implemented
|
|
262
|
+
- Technical details: REST API endpoint `/api/register`
|
|
263
|
+
|
|
264
|
+
<!-- Deleted Inventory Tracking section because it's not implemented yet -->
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Notes
|
|
268
|
+
|
|
269
|
+
**On Initial Creation:**
|
|
270
|
+
- Work from questionnaire responses (limited input)
|
|
271
|
+
- Expand user answers with professional clarity
|
|
272
|
+
- Document vision and intent, not implementation
|
|
273
|
+
- Mark everything as "Planned" or "Initial Definition"
|
|
274
|
+
|
|
275
|
+
**On Documentation Updates:**
|
|
276
|
+
- Read existing `doc.md` first (context matters)
|
|
277
|
+
- Only update based on IMPLEMENTED work items
|
|
278
|
+
- Extract technical specifics from `context.md` files
|
|
279
|
+
- Preserve all planned work not yet implemented
|
|
280
|
+
- Handle partial execution gracefully (some epics done, others not started)
|
|
281
|
+
|
|
282
|
+
**On Technology Specificity:**
|
|
283
|
+
- Your instructions are technology-agnostic (work with any stack)
|
|
284
|
+
- Your output is technology-specific (document actual stack)
|
|
285
|
+
- Never use placeholders in output when real technologies are known
|
|
286
|
+
- Adapt to whatever technologies the project uses
|
|
287
|
+
|
|
288
|
+
**On Hierarchical Levels:**
|
|
289
|
+
- Project level: Broad vision, overall architecture, cross-cutting concerns
|
|
290
|
+
- Epic level: Domain-specific architecture, epic-scoped features
|
|
291
|
+
- Story level: User-facing features and workflows
|
|
292
|
+
- Task/Subtask level: Implementation details, technical decisions
|
|
293
|
+
|
|
294
|
+
**On Living Documentation:**
|
|
295
|
+
- Documentation evolves throughout project lifecycle
|
|
296
|
+
- Updates should reflect actual progress, not aspirations
|
|
297
|
+
- Ceremonies trigger documentation sync (Retrospective especially)
|
|
298
|
+
- Human-readable documentation shows CURRENT STATE to stakeholders
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
**Remember**: You are creating documentation FOR humans (project sponsors, stakeholders, team members), not for AI agents. The documentation should be clear, comprehensive, and reflect the actual state of the project at the time of generation or update.
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { execSync, spawn, exec } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import net from 'net';
|
|
6
|
+
import http from 'http';
|
|
7
|
+
|
|
8
|
+
const execAsync = promisify(exec);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Build and serve VitePress documentation
|
|
12
|
+
* Builds the docs and starts a local preview server
|
|
13
|
+
*/
|
|
14
|
+
export class DocumentationBuilder {
|
|
15
|
+
constructor(projectRoot = process.cwd()) {
|
|
16
|
+
this.projectRoot = projectRoot;
|
|
17
|
+
this.docsDir = path.join(projectRoot, '.avc', 'documentation');
|
|
18
|
+
this.distDir = path.join(this.docsDir, '.vitepress', 'dist');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check if documentation directory exists
|
|
23
|
+
*/
|
|
24
|
+
hasDocumentation() {
|
|
25
|
+
return fs.existsSync(this.docsDir);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get documentation server port from avc.json config
|
|
30
|
+
* Returns default port 4173 if not configured
|
|
31
|
+
*/
|
|
32
|
+
getPort() {
|
|
33
|
+
const configPath = path.join(this.projectRoot, '.avc', 'avc.json');
|
|
34
|
+
|
|
35
|
+
if (!fs.existsSync(configPath)) {
|
|
36
|
+
return 4173; // Default port
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
41
|
+
return config.settings?.documentation?.port || 4173;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.warn(`⚠️ Could not read port from avc.json: ${error.message}`);
|
|
44
|
+
return 4173;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if a port is in use
|
|
50
|
+
* @param {number} port - Port number to check
|
|
51
|
+
* @returns {Promise<boolean>} - True if port is in use
|
|
52
|
+
*/
|
|
53
|
+
async isPortInUse(port) {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const server = net.createServer();
|
|
56
|
+
|
|
57
|
+
server.once('error', (err) => {
|
|
58
|
+
if (err.code === 'EADDRINUSE') {
|
|
59
|
+
resolve(true); // Port is in use
|
|
60
|
+
} else {
|
|
61
|
+
resolve(false);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
server.once('listening', () => {
|
|
66
|
+
server.close();
|
|
67
|
+
resolve(false); // Port is available
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
server.listen(port, '127.0.0.1');
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check if the server on this port is serving our AVC documentation
|
|
76
|
+
* Makes HTTP request and checks for specific AVC metatag to positively identify
|
|
77
|
+
* @param {number} port - Port number to check
|
|
78
|
+
* @returns {Promise<boolean>} - True if it's confirmed to be AVC documentation server
|
|
79
|
+
*/
|
|
80
|
+
async isDocumentationServer(port) {
|
|
81
|
+
return new Promise((resolve) => {
|
|
82
|
+
const req = http.get(`http://localhost:${port}/`, {
|
|
83
|
+
timeout: 2000
|
|
84
|
+
}, (res) => {
|
|
85
|
+
let data = '';
|
|
86
|
+
|
|
87
|
+
res.on('data', (chunk) => {
|
|
88
|
+
data += chunk;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
res.on('end', () => {
|
|
92
|
+
// ONLY return true if we find the specific AVC documentation metatag
|
|
93
|
+
// This ensures we only kill processes we're 100% certain about
|
|
94
|
+
const hasAvcMetatag = data.includes('<meta name="avc-documentation" content="true">') ||
|
|
95
|
+
data.includes('name="avc-documentation"') ||
|
|
96
|
+
data.includes('name="generator" content="Agile Vibe Coding"');
|
|
97
|
+
resolve(hasAvcMetatag);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
req.on('error', () => {
|
|
102
|
+
resolve(false); // Can't connect or verify
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
req.on('timeout', () => {
|
|
106
|
+
req.destroy();
|
|
107
|
+
resolve(false);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Find which process is using a port
|
|
114
|
+
* Works cross-platform (Linux, macOS, Windows)
|
|
115
|
+
* @param {number} port - Port number to check
|
|
116
|
+
* @returns {Promise<{pid: number, command: string} | null>} - Process info or null if not found
|
|
117
|
+
*/
|
|
118
|
+
async findProcessUsingPort(port) {
|
|
119
|
+
try {
|
|
120
|
+
let command;
|
|
121
|
+
let parseOutput;
|
|
122
|
+
|
|
123
|
+
if (process.platform === 'win32') {
|
|
124
|
+
// Windows: netstat -ano | findstr :PORT
|
|
125
|
+
command = `netstat -ano | findstr :${port}`;
|
|
126
|
+
parseOutput = (output) => {
|
|
127
|
+
const lines = output.split('\n');
|
|
128
|
+
for (const line of lines) {
|
|
129
|
+
if (line.includes(`0.0.0.0:${port}`) || line.includes(`127.0.0.1:${port}`) || line.includes(`[::]:${port}`)) {
|
|
130
|
+
const parts = line.trim().split(/\s+/);
|
|
131
|
+
const pid = parseInt(parts[parts.length - 1]);
|
|
132
|
+
if (pid && !isNaN(pid)) {
|
|
133
|
+
return { pid, command: 'Unknown' }; // Windows netstat doesn't show command
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
};
|
|
139
|
+
} else {
|
|
140
|
+
// Linux/macOS: lsof -i :PORT
|
|
141
|
+
command = `lsof -i :${port} -t -sTCP:LISTEN`;
|
|
142
|
+
parseOutput = (output) => {
|
|
143
|
+
const pid = parseInt(output.trim());
|
|
144
|
+
if (pid && !isNaN(pid)) {
|
|
145
|
+
// Try to get process name
|
|
146
|
+
try {
|
|
147
|
+
const psOutput = execSync(`ps -p ${pid} -o comm=`, { encoding: 'utf8' });
|
|
148
|
+
return { pid, command: psOutput.trim() };
|
|
149
|
+
} catch {
|
|
150
|
+
return { pid, command: 'Unknown' };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const output = execSync(command, { encoding: 'utf8', stdio: 'pipe' });
|
|
158
|
+
return parseOutput(output);
|
|
159
|
+
|
|
160
|
+
} catch (error) {
|
|
161
|
+
// Command failed (port not in use or lsof not available)
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Kill a process by PID
|
|
168
|
+
* Works cross-platform (Linux, macOS, Windows)
|
|
169
|
+
* @param {number} pid - Process ID to kill
|
|
170
|
+
* @returns {Promise<boolean>} - True if successfully killed, false otherwise
|
|
171
|
+
*/
|
|
172
|
+
async killProcess(pid) {
|
|
173
|
+
try {
|
|
174
|
+
if (process.platform === 'win32') {
|
|
175
|
+
// Windows: taskkill /F /PID <pid>
|
|
176
|
+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'pipe' });
|
|
177
|
+
} else {
|
|
178
|
+
// Linux/macOS: kill -9 <pid>
|
|
179
|
+
execSync(`kill -9 ${pid}`, { stdio: 'pipe' });
|
|
180
|
+
}
|
|
181
|
+
return true;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
// Failed to kill (permission denied, process not found, etc.)
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Build and serve the documentation
|
|
190
|
+
* Returns the server URL
|
|
191
|
+
*/
|
|
192
|
+
async buildAndServe() {
|
|
193
|
+
if (!this.hasDocumentation()) {
|
|
194
|
+
throw new Error('Documentation not found. Run /init first to create documentation structure.');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const port = this.getPort();
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
// Build the documentation asynchronously to avoid blocking
|
|
201
|
+
await execAsync('npx vitepress build', {
|
|
202
|
+
cwd: this.docsDir
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Start the preview server
|
|
206
|
+
const serverProcess = spawn('npx', ['vitepress', 'preview', '--port', String(port)], {
|
|
207
|
+
cwd: this.docsDir,
|
|
208
|
+
stdio: 'pipe'
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Wait for server to be ready
|
|
212
|
+
return new Promise((resolve, reject) => {
|
|
213
|
+
let serverReady = false;
|
|
214
|
+
|
|
215
|
+
serverProcess.stdout.on('data', (data) => {
|
|
216
|
+
const output = data.toString();
|
|
217
|
+
console.log(output);
|
|
218
|
+
|
|
219
|
+
// Check if server is ready
|
|
220
|
+
if (output.includes(`http://localhost:${port}`) || output.includes(`localhost:${port}`)) {
|
|
221
|
+
if (!serverReady) {
|
|
222
|
+
serverReady = true;
|
|
223
|
+
resolve({
|
|
224
|
+
url: `http://localhost:${port}`,
|
|
225
|
+
process: serverProcess
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
serverProcess.stderr.on('data', (data) => {
|
|
232
|
+
console.error(data.toString());
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
serverProcess.on('error', (error) => {
|
|
236
|
+
reject(error);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
serverProcess.on('exit', (code) => {
|
|
240
|
+
if (code !== 0 && !serverReady) {
|
|
241
|
+
reject(new Error(`Server exited with code ${code}`));
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Timeout after 10 seconds
|
|
246
|
+
setTimeout(() => {
|
|
247
|
+
if (!serverReady) {
|
|
248
|
+
serverProcess.kill();
|
|
249
|
+
reject(new Error('Server start timeout'));
|
|
250
|
+
}
|
|
251
|
+
}, 10000);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
} catch (error) {
|
|
255
|
+
throw new Error(`Failed to build documentation: ${error.message}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Build documentation without starting server
|
|
261
|
+
*/
|
|
262
|
+
async build() {
|
|
263
|
+
if (!this.hasDocumentation()) {
|
|
264
|
+
throw new Error('Documentation not found. Run /init first to create documentation structure.');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
// Build asynchronously to avoid blocking the event loop
|
|
269
|
+
await execAsync('npx vitepress build', {
|
|
270
|
+
cwd: this.docsDir
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
} catch (error) {
|
|
274
|
+
throw new Error(`Failed to build documentation: ${error.message}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|