@nivora/matrix 0.1.0 → 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/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +3 -3
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +2 -2
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/builder/page.js +11 -11
- package/.next/server/app/builder/page.js.nft.json +1 -1
- package/.next/server/app/builder/page_client-reference-manifest.js +1 -1
- package/.next/server/app/guide/page.js.nft.json +1 -1
- package/.next/server/app/guide/page_client-reference-manifest.js +1 -1
- package/.next/server/app/matrix/page.js.nft.json +1 -1
- package/.next/server/app/matrix/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/releases/[id]/page.js +16 -16
- package/.next/server/app/releases/[id]/page.js.nft.json +1 -1
- package/.next/server/app/releases/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/releases/page.js +3 -3
- package/.next/server/app/releases/page.js.nft.json +1 -1
- package/.next/server/app/releases/page_client-reference-manifest.js +1 -1
- package/.next/server/app/specs/[id]/page.js +2 -2
- package/.next/server/app/specs/[id]/page.js.nft.json +1 -1
- package/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +3 -3
- package/.next/server/chunks/135.js +1 -1
- package/.next/server/chunks/530.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +2 -2
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/app/builder/{page-e10754eb65a4f784.js → page-29ef0d9ec753466c.js} +3 -3
- package/.next/static/chunks/app/releases/[id]/page-467d1893a4442eed.js +1 -0
- package/.next/static/chunks/app/releases/page-6fc2e948b934fbb5.js +1 -0
- package/.next/static/chunks/app/specs/[id]/page-b5f2c99269d194c4.js +1 -0
- package/README.md +220 -134
- package/bin/cli.js +37 -20
- package/bin/cli.ts +12 -12
- package/package.json +7 -2
- package/.next/diagnostics/build-diagnostics.json +0 -6
- package/.next/diagnostics/framework.json +0 -1
- package/.next/static/chunks/app/releases/[id]/page-d8069a1802686478.js +0 -1
- package/.next/static/chunks/app/releases/page-26a520d9789e69f5.js +0 -1
- package/.next/static/chunks/app/specs/[id]/page-7065af5d4d103f16.js +0 -1
- package/.next/trace-build +0 -1
- package/.next/types/app/builder/page.ts +0 -86
- package/.next/types/app/guide/page.ts +0 -86
- package/.next/types/app/layout.ts +0 -86
- package/.next/types/app/matrix/page.ts +0 -86
- package/.next/types/app/page.ts +0 -86
- package/.next/types/app/releases/[id]/page.ts +0 -86
- package/.next/types/app/releases/page.ts +0 -86
- package/.next/types/app/specs/[id]/page.ts +0 -86
- package/.next/types/package.json +0 -1
- package/.next/types/routes.d.ts +0 -63
- package/.next/types/validator.ts +0 -115
- /package/.next/static/{8ZUFcYHRSRlY1FYWZ33gH → p01ytei1EF9z6WCg6Sbk1}/_buildManifest.js +0 -0
- /package/.next/static/{8ZUFcYHRSRlY1FYWZ33gH → p01ytei1EF9z6WCg6Sbk1}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -1,35 +1,78 @@
|
|
|
1
|
-
# GAMP 5
|
|
1
|
+
# Matrix - GAMP 5 Traceability System
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A **spec-as-code** requirements traceability system for regulated environments. Write Gherkin specs, run them as tests, and maintain automatic audit-ready traceability.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- [**User Guide**](./USER_GUIDE.md): How to use the dashboard and CLI.
|
|
7
|
-
- [**Developer Guide**](./DEVELOPER_GUIDE.md): Architecture, setup, and development workflow.
|
|
8
|
-
- [**Philosophy & Approach**](./GAMP_AND_V_MODEL.md): GAMP 5 principles, V-Model, and "Spec-as-Code" reasoning.
|
|
5
|
+
## Quickstart
|
|
9
6
|
|
|
7
|
+
```bash
|
|
8
|
+
bun add @nivora/matrix
|
|
9
|
+
bunx matrix init
|
|
10
|
+
bunx matrix serve
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Dashboard available at: http://localhost:3000
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
---
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
## Core Concepts
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|----------|--------|----------|---------|
|
|
17
|
-
| **URS** | Database | SQLite Table `urs` | High-level business requirements |
|
|
18
|
-
| **FS** | Gherkin | `specs/fs/*.requirement` | Functional specs + embedded test scenarios |
|
|
19
|
-
| **RISK** | Database | SQLite Table `risks` | Risk assessments linked to FS |
|
|
19
|
+
This system implements **GAMP 5** and **V-Model** compliance by making specifications executable:
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
| Artifact | Storage | Purpose |
|
|
22
|
+
|----------|---------|---------|
|
|
23
|
+
| **URS** | SQLite DB | High-level business requirements |
|
|
24
|
+
| **FS** | Gherkin `.requirement` files | Functional specs + test scenarios |
|
|
25
|
+
| **Risk** | SQLite DB | Risk assessments & mitigations |
|
|
26
|
+
| **Release** | SQLite DB | Version management & test results |
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
**Key Insight**: The Gherkin Feature file IS the Functional Spec AND the test. No duplication.
|
|
24
29
|
|
|
25
30
|
```gherkin
|
|
26
31
|
@URS-001 @RISK-001
|
|
27
|
-
Feature: FS-001 User Login
|
|
28
|
-
The system shall
|
|
29
|
-
|
|
32
|
+
Feature: FS-001 User Login
|
|
33
|
+
The system shall authenticate users against stored credentials.
|
|
34
|
+
|
|
35
|
+
Scenario: Successful login
|
|
36
|
+
Given I am on the login page
|
|
37
|
+
When I enter valid credentials
|
|
38
|
+
Then I should see my dashboard
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Workflow
|
|
44
|
+
|
|
45
|
+
### 1. Create User Requirements (URS)
|
|
46
|
+
|
|
47
|
+
**Option A: Dashboard UI**
|
|
48
|
+
1. Navigate to http://localhost:3000/specs
|
|
49
|
+
2. Click "New Specification"
|
|
50
|
+
3. Fill in Title, Business Need, Acceptance Criteria
|
|
51
|
+
4. Save
|
|
52
|
+
|
|
53
|
+
**Option B: Stub Generation (Recommended)**
|
|
54
|
+
|
|
55
|
+
Reference URS IDs in your Gherkin files before they exist:
|
|
56
|
+
|
|
57
|
+
```gherkin
|
|
58
|
+
@URS-011
|
|
59
|
+
Feature: FS-009 Password Reset
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Run `matrix sync` and the system creates a placeholder `URS-011` record. Fill in details via the dashboard later.
|
|
63
|
+
|
|
64
|
+
### 2. Write Functional Specs (FS)
|
|
65
|
+
|
|
66
|
+
Create `.requirement` files in `specs/fs/`:
|
|
67
|
+
|
|
68
|
+
```gherkin
|
|
69
|
+
@URS-001 @URS-002 @RISK-005
|
|
70
|
+
Feature: FS-001 User Authentication
|
|
71
|
+
The system shall authenticate users against stored credentials
|
|
72
|
+
and establish a secure session.
|
|
30
73
|
|
|
31
74
|
Requirements:
|
|
32
|
-
- FR-001.1: Display login form with email and password
|
|
75
|
+
- FR-001.1: Display login form with email and password
|
|
33
76
|
- FR-001.2: Validate credentials against stored hash
|
|
34
77
|
- FR-001.3: Rate limit after 5 failed attempts
|
|
35
78
|
|
|
@@ -37,149 +80,192 @@ Feature: FS-001 User Login Authentication
|
|
|
37
80
|
Given I am on the login page
|
|
38
81
|
When I enter valid credentials
|
|
39
82
|
Then I should be redirected to my dashboard
|
|
83
|
+
|
|
84
|
+
Scenario: Failed login locks account after 5 attempts
|
|
85
|
+
Given I have failed login 4 times
|
|
86
|
+
When I enter invalid credentials
|
|
87
|
+
Then I should see "Account locked"
|
|
40
88
|
```
|
|
41
89
|
|
|
42
|
-
**
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
- **Clear traceability**: `@URS-xxx` and `@RISK-xxx` tags create automatic links
|
|
46
|
-
- **Executable specs**: The `.requirement` files can be run by Cucumber
|
|
90
|
+
**Linking Tags:**
|
|
91
|
+
- `@URS-xxx` — Links to User Requirement
|
|
92
|
+
- `@RISK-xxx` — Links to Risk Assessment
|
|
47
93
|
|
|
48
|
-
|
|
94
|
+
### 3. Create Risk Assessments
|
|
49
95
|
|
|
50
|
-
|
|
51
|
-
docs/
|
|
52
|
-
├── specs/
|
|
53
|
-
│ └── fs/ # Functional Specs (Gherkin)
|
|
54
|
-
│ ├── FS-001-login.requirement
|
|
55
|
-
│ ├── FS-002-session.requirement
|
|
56
|
-
│ ├── FS-003-registration.requirement
|
|
57
|
-
│ ├── FS-004-booking.requirement
|
|
58
|
-
│ ├── FS-005-waitlist.requirement
|
|
59
|
-
│ ├── FS-006-schedule.requirement
|
|
60
|
-
│ └── FS-007-instructor.requirement
|
|
61
|
-
└── src/ # Next.js Dashboard
|
|
62
|
-
```
|
|
96
|
+
**Option A: Dashboard UI** — Same flow as URS
|
|
63
97
|
|
|
64
|
-
|
|
98
|
+
**Option B: Stub Generation** — Reference `@RISK-xxx` in Gherkin, run sync, fill in details later
|
|
65
99
|
|
|
66
|
-
###
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Feature: FS-001 User Login
|
|
100
|
+
### 4. Sync to Database
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
matrix sync
|
|
71
104
|
```
|
|
72
105
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
106
|
+
**What sync does:**
|
|
107
|
+
1. Parses all `.requirement` files in `specs/fs/`
|
|
108
|
+
2. Updates database with Feature titles, descriptions, and scenarios
|
|
109
|
+
3. Extracts `@URS` and `@RISK` tags
|
|
110
|
+
4. Auto-creates stub records for any referenced IDs that don't exist
|
|
111
|
+
|
|
112
|
+
> **Tip:** Write Gherkin first with new IDs, run sync, then fill in URS/Risk details via the dashboard.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Release Management
|
|
117
|
+
|
|
118
|
+
### 1. Create a Release
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
matrix release create -v 1.0.0 -n "MVP Launch" --notes "Initial release"
|
|
78
122
|
```
|
|
79
123
|
|
|
80
|
-
|
|
81
|
-
- **
|
|
82
|
-
- **
|
|
83
|
-
- **
|
|
124
|
+
Creates a release with:
|
|
125
|
+
- **Version**: Semantic version (e.g., 1.0.0)
|
|
126
|
+
- **Name**: Human-readable name
|
|
127
|
+
- **Status**: Defaults to "planning"
|
|
128
|
+
- **Notes**: Optional release notes
|
|
84
129
|
|
|
85
|
-
|
|
130
|
+
### 2. Tag Features to Release
|
|
86
131
|
|
|
87
132
|
```bash
|
|
88
|
-
|
|
89
|
-
bun install
|
|
90
|
-
bun run dev
|
|
133
|
+
matrix release tag REL-001 --fs FS-001 FS-002 FS-003
|
|
91
134
|
```
|
|
92
135
|
|
|
93
|
-
|
|
136
|
+
### 3. Run Tests
|
|
94
137
|
|
|
95
|
-
|
|
138
|
+
Execute Cucumber tests and export results:
|
|
96
139
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
| `/` | Dashboard with stats, coverage, and traceability summary |
|
|
100
|
-
| `/specs` | Browse URS (YAML), FS (Gherkin), and Risk (YAML) |
|
|
101
|
-
| `/matrix` | Full traceability matrix: URS → FS → Scenarios → Risks |
|
|
102
|
-
| `/builder` | Visual editor for creating new FS .requirement files |
|
|
103
|
-
| `/search` | Search across all artifacts |
|
|
104
|
-
|
|
105
|
-
## Creating New Artifacts
|
|
106
|
-
|
|
107
|
-
### New URS (via Dashboard or manually)
|
|
108
|
-
Create `specs/urs/URS-xxx.yaml`:
|
|
109
|
-
```yaml
|
|
110
|
-
id: URS-004
|
|
111
|
-
type: urs
|
|
112
|
-
title: New Business Requirement
|
|
113
|
-
status: draft
|
|
114
|
-
priority: high
|
|
115
|
-
owner: Product Team
|
|
116
|
-
category: Core
|
|
117
|
-
business_need: |
|
|
118
|
-
Description of the business need...
|
|
119
|
-
intended_use: |
|
|
120
|
-
How the system will be used...
|
|
121
|
-
acceptance_criteria:
|
|
122
|
-
- Criterion 1
|
|
123
|
-
- Criterion 2
|
|
124
|
-
regulatory_refs:
|
|
125
|
-
- GAMP 5
|
|
140
|
+
```bash
|
|
141
|
+
npx cucumber-js specs/fs/**/*.requirement --format json:results.json
|
|
126
142
|
```
|
|
127
143
|
|
|
128
|
-
###
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
Requirements:
|
|
136
|
-
- FR-xxx.1: First requirement
|
|
137
|
-
- FR-xxx.2: Second requirement
|
|
144
|
+
### 4. Import Test Results
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
matrix release import-results results.json --releaseId REL-001
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Or use the test command:
|
|
138
151
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
When ...
|
|
142
|
-
Then ...
|
|
152
|
+
```bash
|
|
153
|
+
matrix test import results.json -r REL-001
|
|
143
154
|
```
|
|
144
155
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
- FS-001
|
|
156
|
-
impact: high
|
|
157
|
-
probability: medium
|
|
158
|
-
risk_level: high
|
|
159
|
-
risks:
|
|
160
|
-
- id: R-004.1
|
|
161
|
-
description: Risk description
|
|
162
|
-
impact: high
|
|
163
|
-
probability: medium
|
|
164
|
-
mitigations:
|
|
165
|
-
- risk_id: R-004.1
|
|
166
|
-
control: Control measure
|
|
167
|
-
test: How to test
|
|
168
|
-
residual_risk: acceptable
|
|
156
|
+
The import process:
|
|
157
|
+
- Creates a test run record
|
|
158
|
+
- Stores individual scenario results (pass/fail)
|
|
159
|
+
- Warns if any tests failed
|
|
160
|
+
- Updates release status to "testing"
|
|
161
|
+
|
|
162
|
+
### 5. View Test Results
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
matrix test list REL-001
|
|
169
166
|
```
|
|
170
167
|
|
|
171
|
-
|
|
168
|
+
### 6. Handle Test Failures
|
|
169
|
+
|
|
170
|
+
If tests fail, you have two GAMP-compliant options:
|
|
171
|
+
|
|
172
|
+
**Option A: Fix the Code**
|
|
173
|
+
1. Fix the failing functionality
|
|
174
|
+
2. Re-run tests
|
|
175
|
+
3. Import the new results
|
|
176
|
+
|
|
177
|
+
**Option B: Log a Defect/Deviation**
|
|
178
|
+
1. Go to Release Detail page: `http://localhost:3000/releases/REL-001`
|
|
179
|
+
2. Find the **Defects & Deviations** section
|
|
180
|
+
3. Click **Log Defect** for the failing scenario
|
|
181
|
+
4. Provide:
|
|
182
|
+
- **Description**: What failed and why
|
|
183
|
+
- **Justification**: Why it's acceptable (workaround exists, low impact, etc.)
|
|
184
|
+
- **Status**: Open, Investigating, Resolved, or Accepted
|
|
172
185
|
|
|
173
|
-
|
|
186
|
+
> [!IMPORTANT]
|
|
187
|
+
> You cannot mark a release as "Released" if it has failing tests without corresponding Defect records.
|
|
188
|
+
|
|
189
|
+
### 7. Update Release Status
|
|
174
190
|
|
|
175
191
|
```bash
|
|
176
|
-
#
|
|
177
|
-
|
|
192
|
+
# Move to testing phase
|
|
193
|
+
matrix release status REL-001 --status testing
|
|
194
|
+
|
|
195
|
+
# Mark as released (requires all tests pass or defects logged)
|
|
196
|
+
matrix release status REL-001 --status released
|
|
178
197
|
```
|
|
179
198
|
|
|
199
|
+
### 8. List All Releases
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
matrix release list
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## CLI Reference
|
|
208
|
+
|
|
209
|
+
### Core Commands
|
|
210
|
+
|
|
211
|
+
| Command | Description |
|
|
212
|
+
|---------|-------------|
|
|
213
|
+
| `matrix init` | Initialize a new specs directory |
|
|
214
|
+
| `matrix serve` | Start the dashboard server |
|
|
215
|
+
| `matrix sync` | Parse `.requirement` files and update database |
|
|
216
|
+
| `matrix search <query>` | Semantic search across specs |
|
|
217
|
+
|
|
218
|
+
### Release Commands
|
|
219
|
+
|
|
220
|
+
| Command | Description |
|
|
221
|
+
|---------|-------------|
|
|
222
|
+
| `matrix release list` | List all releases |
|
|
223
|
+
| `matrix release create` | Create a new release |
|
|
224
|
+
| `matrix release tag <id>` | Tag FS records to a release |
|
|
225
|
+
| `matrix release status <id>` | Update release status |
|
|
226
|
+
| `matrix release import-results <file>` | Import Cucumber JSON results |
|
|
227
|
+
|
|
228
|
+
### Test Commands
|
|
229
|
+
|
|
230
|
+
| Command | Description |
|
|
231
|
+
|---------|-------------|
|
|
232
|
+
| `matrix test import <file> -r <releaseId>` | Import Cucumber JSON results |
|
|
233
|
+
| `matrix test list <releaseId>` | List test runs for a release |
|
|
234
|
+
|
|
235
|
+
### Common Options
|
|
236
|
+
|
|
237
|
+
| Option | Description |
|
|
238
|
+
|--------|-------------|
|
|
239
|
+
| `-p, --port <port>` | Port for serve (default: 3000) |
|
|
240
|
+
| `-s, --specs <dir>` | Specs directory (default: ./specs) |
|
|
241
|
+
| `-d, --db <path>` | Database path (default: ./matrix.db) |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Dashboard Pages
|
|
246
|
+
|
|
247
|
+
| Page | URL | Description |
|
|
248
|
+
|------|-----|-------------|
|
|
249
|
+
| Home | `/` | Stats, coverage, and traceability overview |
|
|
250
|
+
| Specs | `/specs` | Browse and edit URS, FS, and Risks |
|
|
251
|
+
| Matrix | `/matrix` | Full traceability matrix: URS → FS → Scenarios → Risks |
|
|
252
|
+
| Releases | `/releases` | Release management and test results |
|
|
253
|
+
| Builder | `/builder` | Visual editor for creating FS files |
|
|
254
|
+
| Search | `/search` | Search across all artifacts |
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
180
258
|
## GAMP 5 Compliance
|
|
181
259
|
|
|
182
|
-
- **
|
|
183
|
-
- **
|
|
184
|
-
- **
|
|
185
|
-
- **
|
|
260
|
+
- **V-Model Integration**: FS files serve as both specification (FS) and test protocol (OQ)
|
|
261
|
+
- **Risk-Based Testing**: `@RISK-xxx` tags prioritize validation effort
|
|
262
|
+
- **Automatic Traceability**: Tag-based linking generates audit-ready matrices
|
|
263
|
+
- **Defect Management**: Failed tests require formal deviation records before release
|
|
264
|
+
- **21 CFR Part 11 Ready**: Full audit trail of changes and test results
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Additional Documentation
|
|
269
|
+
|
|
270
|
+
- [Developer Guide](./DEVELOPER_GUIDE.md) - Architecture and development setup
|
|
271
|
+
- [GAMP & V-Model Philosophy](./GAMP_AND_V_MODEL.md) - Design rationale
|
package/bin/cli.js
CHANGED
|
@@ -2142,7 +2142,7 @@ function getDbPath() {
|
|
|
2142
2142
|
if (process.env.MACHINE_DB_PATH) {
|
|
2143
2143
|
return process.env.MACHINE_DB_PATH;
|
|
2144
2144
|
}
|
|
2145
|
-
return join3(process.cwd(), "
|
|
2145
|
+
return join3(process.cwd(), "matrix.db");
|
|
2146
2146
|
}
|
|
2147
2147
|
function getDb() {
|
|
2148
2148
|
if (!db) {
|
|
@@ -3133,7 +3133,7 @@ import { existsSync, readFileSync } from "fs";
|
|
|
3133
3133
|
import { join, resolve } from "path";
|
|
3134
3134
|
var DEFAULT_CONFIG = {
|
|
3135
3135
|
specsDir: "./specs",
|
|
3136
|
-
dbPath: "./
|
|
3136
|
+
dbPath: "./matrix.db",
|
|
3137
3137
|
port: 3000,
|
|
3138
3138
|
rootDir: process.cwd()
|
|
3139
3139
|
};
|
|
@@ -3204,13 +3204,30 @@ async function serveCommand(config) {
|
|
|
3204
3204
|
};
|
|
3205
3205
|
const packageRoot = join2(__dirname2, "..", "..");
|
|
3206
3206
|
const hasProductionBuild = existsSync2(join2(packageRoot, ".next", "BUILD_ID"));
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3207
|
+
if (hasProductionBuild) {
|
|
3208
|
+
const nextBin = join2(packageRoot, "node_modules", ".bin", "next");
|
|
3209
|
+
const useLocalNext = existsSync2(nextBin);
|
|
3210
|
+
if (useLocalNext) {
|
|
3211
|
+
spawn(nextBin, ["start", "-p", String(config.port)], {
|
|
3212
|
+
cwd: packageRoot,
|
|
3213
|
+
env,
|
|
3214
|
+
stdio: "inherit"
|
|
3215
|
+
});
|
|
3216
|
+
} else {
|
|
3217
|
+
spawn("npx", ["next", "start", "-p", String(config.port)], {
|
|
3218
|
+
cwd: packageRoot,
|
|
3219
|
+
env,
|
|
3220
|
+
stdio: "inherit"
|
|
3221
|
+
});
|
|
3222
|
+
}
|
|
3223
|
+
} else {
|
|
3224
|
+
const runtime = hasBun() ? "bun" : "npm";
|
|
3225
|
+
spawn(runtime, ["run", "dev"], {
|
|
3226
|
+
cwd: packageRoot,
|
|
3227
|
+
env,
|
|
3228
|
+
stdio: "inherit"
|
|
3229
|
+
});
|
|
3230
|
+
}
|
|
3214
3231
|
}
|
|
3215
3232
|
|
|
3216
3233
|
// src/commands/sync.ts
|
|
@@ -3220,7 +3237,7 @@ import { join as join4 } from "path";
|
|
|
3220
3237
|
// src/config.ts
|
|
3221
3238
|
var DEFAULT_CONFIG2 = {
|
|
3222
3239
|
specsDir: "./specs",
|
|
3223
|
-
dbPath: "./
|
|
3240
|
+
dbPath: "./matrix.db",
|
|
3224
3241
|
port: 3000,
|
|
3225
3242
|
rootDir: process.cwd()
|
|
3226
3243
|
};
|
|
@@ -3585,7 +3602,7 @@ async function testCommand(config, action, options) {
|
|
|
3585
3602
|
// bin/cli.ts
|
|
3586
3603
|
var program2 = new Command;
|
|
3587
3604
|
program2.name("machine").description("Requirements documentation system with semantic search").version("0.1.0");
|
|
3588
|
-
program2.command("serve").description("Start the documentation server").option("-p, --port <port>", "Port to run server on", "3000").option("-s, --specs <dir>", "Specs directory", "./specs").option("-d, --db <path>", "Database path", "./
|
|
3605
|
+
program2.command("serve").description("Start the documentation server").option("-p, --port <port>", "Port to run server on", "3000").option("-s, --specs <dir>", "Specs directory", "./specs").option("-d, --db <path>", "Database path", "./matrix.db").action(async (options) => {
|
|
3589
3606
|
const config = await loadConfig({
|
|
3590
3607
|
port: parseInt(options.port, 10),
|
|
3591
3608
|
specsDir: options.specs,
|
|
@@ -3593,7 +3610,7 @@ program2.command("serve").description("Start the documentation server").option("
|
|
|
3593
3610
|
});
|
|
3594
3611
|
await serveCommand(config);
|
|
3595
3612
|
});
|
|
3596
|
-
program2.command("sync").description("Sync FS files to database and index steps").option("-s, --specs <dir>", "Specs directory", "./specs").option("-d, --db <path>", "Database path", "./
|
|
3613
|
+
program2.command("sync").description("Sync FS files to database and index steps").option("-s, --specs <dir>", "Specs directory", "./specs").option("-d, --db <path>", "Database path", "./matrix.db").action(async (options) => {
|
|
3597
3614
|
const config = await loadConfig({
|
|
3598
3615
|
specsDir: options.specs,
|
|
3599
3616
|
dbPath: options.db
|
|
@@ -3606,7 +3623,7 @@ program2.command("init").description("Initialize a new specs directory").option(
|
|
|
3606
3623
|
});
|
|
3607
3624
|
await initCommand(config);
|
|
3608
3625
|
});
|
|
3609
|
-
program2.command("search <query>").description("Semantic search for steps").option("-n, --limit <n>", "Number of results", "10").option("-s, --specs <dir>", "Specs directory", "./specs").option("-d, --db <path>", "Database path", "./
|
|
3626
|
+
program2.command("search <query>").description("Semantic search for steps").option("-n, --limit <n>", "Number of results", "10").option("-s, --specs <dir>", "Specs directory", "./specs").option("-d, --db <path>", "Database path", "./matrix.db").action(async (query, options) => {
|
|
3610
3627
|
const config = await loadConfig({
|
|
3611
3628
|
specsDir: options.specs,
|
|
3612
3629
|
dbPath: options.db
|
|
@@ -3614,11 +3631,11 @@ program2.command("search <query>").description("Semantic search for steps").opti
|
|
|
3614
3631
|
await searchCommand(config, query, parseInt(options.limit, 10));
|
|
3615
3632
|
});
|
|
3616
3633
|
var release = program2.command("release").description("Manage releases");
|
|
3617
|
-
release.command("list").description("List all releases").option("-d, --db <path>", "Database path", "./
|
|
3634
|
+
release.command("list").description("List all releases").option("-d, --db <path>", "Database path", "./matrix.db").action(async (options) => {
|
|
3618
3635
|
const config = await loadConfig({ dbPath: options.db });
|
|
3619
3636
|
await releaseCommand(config, "list");
|
|
3620
3637
|
});
|
|
3621
|
-
release.command("create").description("Create a new release").requiredOption("-v, --version <version>", "Release version (e.g., 1.0.0)").requiredOption("-n, --name <name>", "Release name").option("--notes <notes>", "Release notes").option("-d, --db <path>", "Database path", "./
|
|
3638
|
+
release.command("create").description("Create a new release").requiredOption("-v, --version <version>", "Release version (e.g., 1.0.0)").requiredOption("-n, --name <name>", "Release name").option("--notes <notes>", "Release notes").option("-d, --db <path>", "Database path", "./matrix.db").action(async (options) => {
|
|
3622
3639
|
const config = await loadConfig({ dbPath: options.db });
|
|
3623
3640
|
await releaseCommand(config, "create", {
|
|
3624
3641
|
version: options.version,
|
|
@@ -3626,24 +3643,24 @@ release.command("create").description("Create a new release").requiredOption("-v
|
|
|
3626
3643
|
notes: options.notes
|
|
3627
3644
|
});
|
|
3628
3645
|
});
|
|
3629
|
-
release.command("tag <releaseId>").description("Tag features to a release").requiredOption("--fs <fsIds...>", "FS IDs to tag").option("-d, --db <path>", "Database path", "./
|
|
3646
|
+
release.command("tag <releaseId>").description("Tag features to a release").requiredOption("--fs <fsIds...>", "FS IDs to tag").option("-d, --db <path>", "Database path", "./matrix.db").action(async (releaseId, options) => {
|
|
3630
3647
|
const config = await loadConfig({ dbPath: options.db });
|
|
3631
3648
|
await releaseCommand(config, "tag", { releaseId, fsIds: options.fs });
|
|
3632
3649
|
});
|
|
3633
|
-
release.command("status <releaseId>").description("Update release status").requiredOption("--status <status>", "New status (planning|testing|released)").option("-d, --db <path>", "Database path", "./
|
|
3650
|
+
release.command("status <releaseId>").description("Update release status").requiredOption("--status <status>", "New status (planning|testing|released)").option("-d, --db <path>", "Database path", "./matrix.db").action(async (releaseId, options) => {
|
|
3634
3651
|
const config = await loadConfig({ dbPath: options.db });
|
|
3635
3652
|
await releaseCommand(config, "status", { releaseId, status: options.status });
|
|
3636
3653
|
});
|
|
3637
|
-
release.command("import-results <file>").description("Import Cucumber JSON results into a release").requiredOption("--releaseId <id>", "Release ID").option("-d, --db <path>", "Database path", "./
|
|
3654
|
+
release.command("import-results <file>").description("Import Cucumber JSON results into a release").requiredOption("--releaseId <id>", "Release ID").option("-d, --db <path>", "Database path", "./matrix.db").action(async (file, options) => {
|
|
3638
3655
|
const config = await loadConfig({ dbPath: options.db });
|
|
3639
3656
|
await importResultsCommand(config, file, { releaseId: options.releaseId });
|
|
3640
3657
|
});
|
|
3641
3658
|
var test = program2.command("test").description("Manage test results");
|
|
3642
|
-
test.command("import <jsonPath>").description("Import Cucumber JSON test results").requiredOption("-r, --release <releaseId>", "Release ID").option("-d, --db <path>", "Database path", "./
|
|
3659
|
+
test.command("import <jsonPath>").description("Import Cucumber JSON test results").requiredOption("-r, --release <releaseId>", "Release ID").option("-d, --db <path>", "Database path", "./matrix.db").action(async (jsonPath, options) => {
|
|
3643
3660
|
const config = await loadConfig({ dbPath: options.db });
|
|
3644
3661
|
await testCommand(config, "import", { releaseId: options.release, jsonPath });
|
|
3645
3662
|
});
|
|
3646
|
-
test.command("list <releaseId>").description("List test runs for a release").option("-d, --db <path>", "Database path", "./
|
|
3663
|
+
test.command("list <releaseId>").description("List test runs for a release").option("-d, --db <path>", "Database path", "./matrix.db").action(async (releaseId, options) => {
|
|
3647
3664
|
const config = await loadConfig({ dbPath: options.db });
|
|
3648
3665
|
await testCommand(config, "list", { releaseId });
|
|
3649
3666
|
});
|
package/bin/cli.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
/**
|
|
3
|
-
* @nivora/
|
|
3
|
+
* @nivora/matrix CLI
|
|
4
4
|
*
|
|
5
5
|
* Commands:
|
|
6
6
|
* serve - Start the documentation server
|
|
@@ -25,7 +25,7 @@ import { testCommand } from '../src/commands/test';
|
|
|
25
25
|
const program = new Command();
|
|
26
26
|
|
|
27
27
|
program
|
|
28
|
-
.name('
|
|
28
|
+
.name('matrix')
|
|
29
29
|
.description('Requirements documentation system with semantic search')
|
|
30
30
|
.version('0.1.0');
|
|
31
31
|
|
|
@@ -34,7 +34,7 @@ program
|
|
|
34
34
|
.description('Start the documentation server')
|
|
35
35
|
.option('-p, --port <port>', 'Port to run server on', '3000')
|
|
36
36
|
.option('-s, --specs <dir>', 'Specs directory', './specs')
|
|
37
|
-
.option('-d, --db <path>', 'Database path', './
|
|
37
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
38
38
|
.action(async (options) => {
|
|
39
39
|
const config = await loadConfig({
|
|
40
40
|
port: parseInt(options.port, 10),
|
|
@@ -48,7 +48,7 @@ program
|
|
|
48
48
|
.command('sync')
|
|
49
49
|
.description('Sync FS files to database and index steps')
|
|
50
50
|
.option('-s, --specs <dir>', 'Specs directory', './specs')
|
|
51
|
-
.option('-d, --db <path>', 'Database path', './
|
|
51
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
52
52
|
.action(async (options) => {
|
|
53
53
|
const config = await loadConfig({
|
|
54
54
|
specsDir: options.specs,
|
|
@@ -73,7 +73,7 @@ program
|
|
|
73
73
|
.description('Semantic search for steps')
|
|
74
74
|
.option('-n, --limit <n>', 'Number of results', '10')
|
|
75
75
|
.option('-s, --specs <dir>', 'Specs directory', './specs')
|
|
76
|
-
.option('-d, --db <path>', 'Database path', './
|
|
76
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
77
77
|
.action(async (query, options) => {
|
|
78
78
|
const config = await loadConfig({
|
|
79
79
|
specsDir: options.specs,
|
|
@@ -90,7 +90,7 @@ const release = program
|
|
|
90
90
|
release
|
|
91
91
|
.command('list')
|
|
92
92
|
.description('List all releases')
|
|
93
|
-
.option('-d, --db <path>', 'Database path', './
|
|
93
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
94
94
|
.action(async (options) => {
|
|
95
95
|
const config = await loadConfig({ dbPath: options.db });
|
|
96
96
|
await releaseCommand(config, 'list');
|
|
@@ -102,7 +102,7 @@ release
|
|
|
102
102
|
.requiredOption('-v, --version <version>', 'Release version (e.g., 1.0.0)')
|
|
103
103
|
.requiredOption('-n, --name <name>', 'Release name')
|
|
104
104
|
.option('--notes <notes>', 'Release notes')
|
|
105
|
-
.option('-d, --db <path>', 'Database path', './
|
|
105
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
106
106
|
.action(async (options) => {
|
|
107
107
|
const config = await loadConfig({ dbPath: options.db });
|
|
108
108
|
await releaseCommand(config, 'create', {
|
|
@@ -116,7 +116,7 @@ release
|
|
|
116
116
|
.command('tag <releaseId>')
|
|
117
117
|
.description('Tag features to a release')
|
|
118
118
|
.requiredOption('--fs <fsIds...>', 'FS IDs to tag')
|
|
119
|
-
.option('-d, --db <path>', 'Database path', './
|
|
119
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
120
120
|
.action(async (releaseId, options) => {
|
|
121
121
|
const config = await loadConfig({ dbPath: options.db });
|
|
122
122
|
await releaseCommand(config, 'tag', { releaseId, fsIds: options.fs });
|
|
@@ -126,7 +126,7 @@ release
|
|
|
126
126
|
.command('status <releaseId>')
|
|
127
127
|
.description('Update release status')
|
|
128
128
|
.requiredOption('--status <status>', 'New status (planning|testing|released)')
|
|
129
|
-
.option('-d, --db <path>', 'Database path', './
|
|
129
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
130
130
|
.action(async (releaseId, options) => {
|
|
131
131
|
const config = await loadConfig({ dbPath: options.db });
|
|
132
132
|
await releaseCommand(config, 'status', { releaseId, status: options.status });
|
|
@@ -136,7 +136,7 @@ release
|
|
|
136
136
|
.command('import-results <file>')
|
|
137
137
|
.description('Import Cucumber JSON results into a release')
|
|
138
138
|
.requiredOption('--releaseId <id>', 'Release ID')
|
|
139
|
-
.option('-d, --db <path>', 'Database path', './
|
|
139
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
140
140
|
.action(async (file, options) => {
|
|
141
141
|
const config = await loadConfig({ dbPath: options.db });
|
|
142
142
|
await importResultsCommand(config, file, { releaseId: options.releaseId });
|
|
@@ -152,7 +152,7 @@ test
|
|
|
152
152
|
.command('import <jsonPath>')
|
|
153
153
|
.description('Import Cucumber JSON test results')
|
|
154
154
|
.requiredOption('-r, --release <releaseId>', 'Release ID')
|
|
155
|
-
.option('-d, --db <path>', 'Database path', './
|
|
155
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
156
156
|
.action(async (jsonPath, options) => {
|
|
157
157
|
const config = await loadConfig({ dbPath: options.db });
|
|
158
158
|
await testCommand(config, 'import', { releaseId: options.release, jsonPath });
|
|
@@ -161,7 +161,7 @@ test
|
|
|
161
161
|
test
|
|
162
162
|
.command('list <releaseId>')
|
|
163
163
|
.description('List test runs for a release')
|
|
164
|
-
.option('-d, --db <path>', 'Database path', './
|
|
164
|
+
.option('-d, --db <path>', 'Database path', './matrix.db')
|
|
165
165
|
.action(async (releaseId, options) => {
|
|
166
166
|
const config = await loadConfig({ dbPath: options.db });
|
|
167
167
|
await testCommand(config, 'list', { releaseId });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nivora/matrix",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Requirements documentation system with semantic search",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"bin",
|
|
14
14
|
"dist",
|
|
15
|
-
".next",
|
|
15
|
+
".next/*.json",
|
|
16
|
+
".next/*.js",
|
|
17
|
+
".next/BUILD_ID",
|
|
18
|
+
".next/package.json",
|
|
19
|
+
".next/server",
|
|
20
|
+
".next/static",
|
|
16
21
|
"public",
|
|
17
22
|
"next.config.ts"
|
|
18
23
|
],
|