pcl-mcp 0.1.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 +21 -0
- package/README.md +122 -0
- package/dist/bin/pcl.d.ts +3 -0
- package/dist/bin/pcl.d.ts.map +1 -0
- package/dist/bin/pcl.js +327 -0
- package/dist/bin/pcl.js.map +1 -0
- package/dist/src/db.d.ts +38 -0
- package/dist/src/db.d.ts.map +1 -0
- package/dist/src/db.js +238 -0
- package/dist/src/db.js.map +1 -0
- package/dist/src/embeddings.d.ts +15 -0
- package/dist/src/embeddings.d.ts.map +1 -0
- package/dist/src/embeddings.js +82 -0
- package/dist/src/embeddings.js.map +1 -0
- package/dist/src/indexer.d.ts +19 -0
- package/dist/src/indexer.d.ts.map +1 -0
- package/dist/src/indexer.js +174 -0
- package/dist/src/indexer.js.map +1 -0
- package/dist/src/scanner.d.ts +30 -0
- package/dist/src/scanner.d.ts.map +1 -0
- package/dist/src/scanner.js +290 -0
- package/dist/src/scanner.js.map +1 -0
- package/dist/src/schemas.d.ts +184 -0
- package/dist/src/schemas.d.ts.map +1 -0
- package/dist/src/schemas.js +113 -0
- package/dist/src/schemas.js.map +1 -0
- package/dist/src/search.d.ts +10 -0
- package/dist/src/search.d.ts.map +1 -0
- package/dist/src/search.js +99 -0
- package/dist/src/search.js.map +1 -0
- package/dist/src/server.d.ts +3 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/server.js +156 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/tools.d.ts +111 -0
- package/dist/src/tools.d.ts.map +1 -0
- package/dist/src/tools.js +190 -0
- package/dist/src/tools.js.map +1 -0
- package/dist/src/types.d.ts +31 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Sathya Gorski
|
|
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,122 @@
|
|
|
1
|
+
# PCL — Product Context Layer
|
|
2
|
+
|
|
3
|
+
**Give AI coding agents persistent, structured knowledge of your product.**
|
|
4
|
+
|
|
5
|
+
Instead of re-explaining your personas, journeys, and architecture decisions every session, PCL serves them via MCP on demand. Any agent (Claude Code, Cursor, Windsurf) queries exactly what it needs, when it needs it.
|
|
6
|
+
|
|
7
|
+
## Stack
|
|
8
|
+
|
|
9
|
+
| Layer | Technology | Why |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Protocol | MCP (stdio) | Universal — works with every major agent |
|
|
12
|
+
| Storage | SQLite + FTS5 | Zero infra, git-friendly, offline |
|
|
13
|
+
| Keyword search | BM25 via FTS5 | Best-in-class for exact term matching |
|
|
14
|
+
| Semantic search | `all-MiniLM-L6-v2` (local) | 23MB, zero API cost, ~3ms/doc |
|
|
15
|
+
| Hybrid fusion | Reciprocal Rank Fusion (k=60) | Better than either alone, no tuning |
|
|
16
|
+
| Validation | Zod schemas | Agents rely on predictable frontmatter |
|
|
17
|
+
| File watching | Chokidar v4 | Live reindex on save |
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install pcl-mcp
|
|
23
|
+
npx pcl init # scaffold /product folder
|
|
24
|
+
npm run serve # start MCP server
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Agent configuration
|
|
28
|
+
|
|
29
|
+
### Claude Code — `.claude/mcp.json`
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"mcpServers": {
|
|
33
|
+
"pcl": {
|
|
34
|
+
"command": "node",
|
|
35
|
+
"args": ["./node_modules/pcl-mcp/dist/src/server.js"]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Cursor — `settings.json`
|
|
42
|
+
```json
|
|
43
|
+
"mcp.servers": {
|
|
44
|
+
"pcl": {
|
|
45
|
+
"command": "npx",
|
|
46
|
+
"args": ["pcl-mcp", "serve"]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## File structure
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
/product
|
|
55
|
+
product.md ← north star doc (required)
|
|
56
|
+
personas/
|
|
57
|
+
001-max.md ← one persona per file
|
|
58
|
+
journeys/
|
|
59
|
+
001-onboarding.md ← one user journey per file
|
|
60
|
+
specs/
|
|
61
|
+
001-auth-flow.md ← feature specs with acceptance criteria
|
|
62
|
+
decisions/
|
|
63
|
+
001-use-nextjs.md ← architecture decision records (ADRs)
|
|
64
|
+
domain/
|
|
65
|
+
core-rules.md ← business rules agents must never violate
|
|
66
|
+
.pcl.db ← SQLite index (auto-generated, gitignore this)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Tools available to agents
|
|
70
|
+
|
|
71
|
+
| Tool | When to use |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `pcl_product_summary` | Always — call at session start |
|
|
74
|
+
| `pcl_get_domain("*critical")` | Always — load hard business rules |
|
|
75
|
+
| `pcl_get_persona(id)` | Before any user-facing feature |
|
|
76
|
+
| `pcl_get_journey(id)` | Before any user flow code |
|
|
77
|
+
| `pcl_get_spec(id)` | Before implementing a feature |
|
|
78
|
+
| `pcl_get_decision(id)` | Before architectural decisions |
|
|
79
|
+
| `pcl_list(type)` | Discover what exists |
|
|
80
|
+
| `pcl_search(query)` | When you don't know the ID |
|
|
81
|
+
| `pcl_related(id)` | Discover connected context |
|
|
82
|
+
|
|
83
|
+
## How hybrid search works
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
query: "what does Max find frustrating about onboarding"
|
|
87
|
+
|
|
88
|
+
BM25 (FTS5): [persona-max, journey-onboarding, spec-magic-link, ...]
|
|
89
|
+
↓ ranked by term frequency + IDF
|
|
90
|
+
|
|
91
|
+
Cosine similarity: [journey-onboarding, persona-max, domain-core-rules, ...]
|
|
92
|
+
↓ ranked by embedding dot product (MiniLM-L6-v2)
|
|
93
|
+
|
|
94
|
+
RRF fusion: score(d) = Σ 1 / (60 + rank(d))
|
|
95
|
+
↓ combines both rankings without weight tuning
|
|
96
|
+
|
|
97
|
+
Result: 1. journey-onboarding (0.94)
|
|
98
|
+
2. persona-max (0.87)
|
|
99
|
+
3. spec-onboarding-ux (0.71)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Human workflow
|
|
103
|
+
|
|
104
|
+
The system is only as good as what you put in. Discipline:
|
|
105
|
+
|
|
106
|
+
- **Product decision made?** → Write a `decisions/` ADR (5 min)
|
|
107
|
+
- **New feature being planned?** → Write a `specs/` file first, then code
|
|
108
|
+
- **User research or feedback?** → Update persona `anti_patterns` or `jobs_to_be_done`
|
|
109
|
+
- **Business rule change?** → Update `domain/` first, then code
|
|
110
|
+
- **New user journey discovered?** → Add to `journeys/`
|
|
111
|
+
|
|
112
|
+
The agent does the rest.
|
|
113
|
+
|
|
114
|
+
## Gitignore
|
|
115
|
+
|
|
116
|
+
```gitignore
|
|
117
|
+
product/.pcl.db # SQLite index — auto-regenerated
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pcl.d.ts","sourceRoot":"","sources":["../../bin/pcl.ts"],"names":[],"mappings":""}
|
package/dist/bin/pcl.js
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bin/pcl.ts
|
|
3
|
+
// CLI: pcl init | pcl serve | pcl status
|
|
4
|
+
import { mkdir, writeFile, access } from "node:fs/promises";
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
|
+
import { constants } from "node:fs";
|
|
7
|
+
const cmd = process.argv[2];
|
|
8
|
+
const args = process.argv.slice(3);
|
|
9
|
+
const hasFlag = (flag) => args.includes(flag);
|
|
10
|
+
// ─── Templates ────────────────────────────────────────────────────────────────
|
|
11
|
+
const TEMPLATES = {
|
|
12
|
+
"product.md": `---
|
|
13
|
+
name: "My Product"
|
|
14
|
+
tagline: "One-line description of what it does"
|
|
15
|
+
problem: "The problem this product solves"
|
|
16
|
+
solution: "How it solves that problem"
|
|
17
|
+
primary_persona: "change-this-to-your-persona-id"
|
|
18
|
+
tech_stack:
|
|
19
|
+
- Next.js
|
|
20
|
+
- Supabase
|
|
21
|
+
- TypeScript
|
|
22
|
+
stage: prototype
|
|
23
|
+
repo: ""
|
|
24
|
+
url: ""
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Vision
|
|
28
|
+
|
|
29
|
+
Write your product vision here. What does success look like in 3 years?
|
|
30
|
+
|
|
31
|
+
## North star metric
|
|
32
|
+
|
|
33
|
+
The one number that proves this product is working.
|
|
34
|
+
|
|
35
|
+
## What this product is NOT
|
|
36
|
+
|
|
37
|
+
(Helps agents avoid scope creep — be explicit about what you're not building)
|
|
38
|
+
`,
|
|
39
|
+
"personas/001-example.md": `---
|
|
40
|
+
id: example-user
|
|
41
|
+
name: "Alex"
|
|
42
|
+
role: "Freelance designer"
|
|
43
|
+
age_range: "25-35"
|
|
44
|
+
tech_level: medium
|
|
45
|
+
primary_goal: "Ship client projects faster without sacrificing quality"
|
|
46
|
+
biggest_fear: "Losing a client because a project ran over time or budget"
|
|
47
|
+
jobs_to_be_done:
|
|
48
|
+
- Track project time without friction
|
|
49
|
+
- Communicate progress to clients proactively
|
|
50
|
+
- Avoid scope creep
|
|
51
|
+
anti_patterns:
|
|
52
|
+
- Won't fill out forms longer than 2 minutes
|
|
53
|
+
- Ignores marketing emails, responds to Slack/WhatsApp
|
|
54
|
+
- Doesn't read documentation, prefers watching a 60-second demo
|
|
55
|
+
channels:
|
|
56
|
+
- Twitter/X
|
|
57
|
+
- Dribbble
|
|
58
|
+
- Designer Slack communities
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Context
|
|
62
|
+
|
|
63
|
+
Write 2-3 sentences about Alex's day-to-day life. What does their work look like?
|
|
64
|
+
What tools do they already use? What's the emotional context behind their problem?
|
|
65
|
+
|
|
66
|
+
## Design implications
|
|
67
|
+
|
|
68
|
+
Write specific rules the agent must follow when building anything for this persona:
|
|
69
|
+
- Maximum X steps to complete core action
|
|
70
|
+
- Must work on mobile
|
|
71
|
+
- etc.
|
|
72
|
+
`,
|
|
73
|
+
"journeys/001-onboarding.md": `---
|
|
74
|
+
id: onboarding
|
|
75
|
+
name: "First-time onboarding"
|
|
76
|
+
persona: example-user
|
|
77
|
+
trigger: "User clicks 'Get started free' on landing page"
|
|
78
|
+
success_state: "User completes their first core action within 10 minutes of signup"
|
|
79
|
+
failure_modes:
|
|
80
|
+
- "Drops off at email verification step"
|
|
81
|
+
- "Completes signup but never reaches core feature"
|
|
82
|
+
- "Starts core feature but abandons before saving"
|
|
83
|
+
steps:
|
|
84
|
+
- landing
|
|
85
|
+
- signup
|
|
86
|
+
- verify-email
|
|
87
|
+
- first-action
|
|
88
|
+
- aha-moment
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Step detail
|
|
92
|
+
|
|
93
|
+
### landing
|
|
94
|
+
Goal: Communicate value prop in under 10 seconds.
|
|
95
|
+
Critical: Show social proof above the fold.
|
|
96
|
+
Do not: Ask for credit card on landing page.
|
|
97
|
+
|
|
98
|
+
### signup
|
|
99
|
+
Email + password or magic link only.
|
|
100
|
+
Do NOT ask for name, company, or phone at this step — capture later.
|
|
101
|
+
|
|
102
|
+
### verify-email
|
|
103
|
+
Keep this step as frictionless as possible.
|
|
104
|
+
Provide a "resend" link immediately visible.
|
|
105
|
+
Auto-redirect on verification — don't make user click a button.
|
|
106
|
+
|
|
107
|
+
### first-action
|
|
108
|
+
This is where users must reach immediately after signup.
|
|
109
|
+
Pre-fill as much as possible from their signup email/domain.
|
|
110
|
+
Show a progress indicator: "Step 1 of 3".
|
|
111
|
+
|
|
112
|
+
### aha-moment
|
|
113
|
+
Define what the "aha moment" is for your product.
|
|
114
|
+
Everything before this step is setup — this is where retention begins.
|
|
115
|
+
`,
|
|
116
|
+
"specs/001-example-feature.md": `---
|
|
117
|
+
id: magic-link-auth
|
|
118
|
+
title: "Magic link authentication"
|
|
119
|
+
persona: example-user
|
|
120
|
+
journey: onboarding
|
|
121
|
+
status: draft
|
|
122
|
+
acceptance_criteria:
|
|
123
|
+
- "User enters email and receives a link within 30 seconds"
|
|
124
|
+
- "Link expires after 15 minutes"
|
|
125
|
+
- "Link works only once (single-use token)"
|
|
126
|
+
- "After clicking, user is redirected to /dashboard"
|
|
127
|
+
- "If link is expired, user sees a clear error with a 'Request new link' button"
|
|
128
|
+
out_of_scope:
|
|
129
|
+
- "Social login (OAuth) — deferred to v2"
|
|
130
|
+
- "SMS-based verification"
|
|
131
|
+
design_ref: ""
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Overview
|
|
135
|
+
|
|
136
|
+
Write a short description of the feature from the user's perspective.
|
|
137
|
+
|
|
138
|
+
## Technical notes
|
|
139
|
+
|
|
140
|
+
Any implementation constraints the agent needs to know:
|
|
141
|
+
- Which library to use
|
|
142
|
+
- Which existing patterns to follow
|
|
143
|
+
- Security requirements
|
|
144
|
+
|
|
145
|
+
## Edge cases
|
|
146
|
+
|
|
147
|
+
List edge cases that are NOT covered by acceptance criteria above.
|
|
148
|
+
`,
|
|
149
|
+
"decisions/001-example-adr.md": `---
|
|
150
|
+
id: adr-001
|
|
151
|
+
title: "Use Next.js App Router + Supabase"
|
|
152
|
+
status: accepted
|
|
153
|
+
date: "2025-01-01"
|
|
154
|
+
context: "Need a full-stack framework with good DX, easy auth, and minimal ops overhead for a solo developer."
|
|
155
|
+
decision: "Use Next.js App Router for the frontend/API layer and Supabase for auth, database, and storage."
|
|
156
|
+
consequences:
|
|
157
|
+
- "Edge functions for webhook handling"
|
|
158
|
+
- "Row Level Security (RLS) policies enforce data isolation — agents must always include RLS on new tables"
|
|
159
|
+
- "No separate backend service needed"
|
|
160
|
+
alternatives_rejected:
|
|
161
|
+
- "Remix — less Claude Code tooling support as of Q1 2025"
|
|
162
|
+
- "PlanetScale — cost at scale vs Supabase free tier"
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Detail
|
|
166
|
+
|
|
167
|
+
Write more context here if needed. What trade-offs were made?
|
|
168
|
+
What would make this decision worth revisiting?
|
|
169
|
+
`,
|
|
170
|
+
"domain/core-rules.md": `---
|
|
171
|
+
id: core-business-rules
|
|
172
|
+
critical: true
|
|
173
|
+
title: "Core business rules"
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Rules that must NEVER be violated
|
|
177
|
+
|
|
178
|
+
These are business invariants. No agent should ever write code that contradicts these rules.
|
|
179
|
+
If in doubt, call pcl_get_domain('*critical') before touching the relevant code.
|
|
180
|
+
|
|
181
|
+
### Data ownership
|
|
182
|
+
1. User data is NEVER deleted on account downgrade — only access is restricted
|
|
183
|
+
2. Export must always be available regardless of plan
|
|
184
|
+
|
|
185
|
+
### Billing
|
|
186
|
+
1. Cancellation takes effect immediately — no grace period unless explicitly specified
|
|
187
|
+
2. Downgrade happens at end of billing period, never mid-period
|
|
188
|
+
3. Stripe is the source of truth for subscription status — never trust local DB alone
|
|
189
|
+
|
|
190
|
+
### Authentication
|
|
191
|
+
1. Sessions expire after 30 days of inactivity
|
|
192
|
+
2. Password reset tokens expire after 1 hour
|
|
193
|
+
3. Never log or store plaintext passwords, tokens, or secrets anywhere
|
|
194
|
+
|
|
195
|
+
### Add your own rules below...
|
|
196
|
+
`,
|
|
197
|
+
};
|
|
198
|
+
// ─── Commands ─────────────────────────────────────────────────────────────────
|
|
199
|
+
async function init() {
|
|
200
|
+
const scanMode = hasFlag("--scan");
|
|
201
|
+
const scanOnly = hasFlag("--scan-only");
|
|
202
|
+
// First positional arg that doesn't start with -- is the dir
|
|
203
|
+
const dirArg = args.find((a) => !a.startsWith("--"));
|
|
204
|
+
const productDir = resolve(dirArg ?? "./product");
|
|
205
|
+
console.log(`\nInitialising PCL product folder at: ${productDir}\n`);
|
|
206
|
+
// Track which type categories were covered by scan imports
|
|
207
|
+
const coveredTypes = new Set();
|
|
208
|
+
// ── Scan phase ──
|
|
209
|
+
if (scanMode || scanOnly) {
|
|
210
|
+
const { runScan } = await import("../src/scanner.js");
|
|
211
|
+
const rootDir = process.cwd();
|
|
212
|
+
const summary = await runScan(rootDir, productDir);
|
|
213
|
+
if (scanOnly) {
|
|
214
|
+
console.log("\nDone (scan-only mode).\n");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
for (const r of summary.imported)
|
|
218
|
+
coveredTypes.add(r.type);
|
|
219
|
+
console.log(""); // blank line before template scaffolding
|
|
220
|
+
}
|
|
221
|
+
// ── Template scaffolding ──
|
|
222
|
+
// Map template relative paths to the PCL type category they belong to
|
|
223
|
+
const templateTypeMap = {
|
|
224
|
+
"product.md": "product",
|
|
225
|
+
"personas/001-example.md": "persona",
|
|
226
|
+
"journeys/001-onboarding.md": "journey",
|
|
227
|
+
"specs/001-example-feature.md": "spec",
|
|
228
|
+
"decisions/001-example-adr.md": "decision",
|
|
229
|
+
"domain/core-rules.md": "domain",
|
|
230
|
+
};
|
|
231
|
+
const dirs = ["", "personas", "journeys", "specs", "decisions", "domain"];
|
|
232
|
+
for (const dir of dirs) {
|
|
233
|
+
await mkdir(join(productDir, dir), { recursive: true });
|
|
234
|
+
}
|
|
235
|
+
let created = 0;
|
|
236
|
+
let skipped = 0;
|
|
237
|
+
for (const [rel, content] of Object.entries(TEMPLATES)) {
|
|
238
|
+
// Skip templates for categories already covered by scan imports
|
|
239
|
+
const category = templateTypeMap[rel];
|
|
240
|
+
if (category && coveredTypes.has(category)) {
|
|
241
|
+
console.log(` ↷ ${rel} (category covered by scan, skipped)`);
|
|
242
|
+
skipped++;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const dest = join(productDir, rel);
|
|
246
|
+
try {
|
|
247
|
+
await access(dest, constants.F_OK);
|
|
248
|
+
console.log(` ↷ ${rel} (exists, skipped)`);
|
|
249
|
+
skipped++;
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
await writeFile(dest, content, "utf8");
|
|
253
|
+
console.log(` ✓ ${rel}`);
|
|
254
|
+
created++;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// Write CLAUDE.md bridge
|
|
258
|
+
const claudeMd = join(process.cwd(), "CLAUDE.md");
|
|
259
|
+
const bridge = `
|
|
260
|
+
## Product Context Layer (PCL)
|
|
261
|
+
|
|
262
|
+
This project uses PCL for product knowledge. An MCP server is running (see mcp config).
|
|
263
|
+
|
|
264
|
+
### At the start of every coding session:
|
|
265
|
+
1. Call \`pcl_product_summary\` — orient yourself
|
|
266
|
+
2. Call \`pcl_get_domain("*critical")\` — load non-violable business rules
|
|
267
|
+
|
|
268
|
+
### Before working on any user-facing feature:
|
|
269
|
+
- Call \`pcl_list({ type: "personas" })\` then \`pcl_get_persona(id)\` for the relevant persona
|
|
270
|
+
- Call \`pcl_list({ type: "journeys" })\` then \`pcl_get_journey(id)\` for the relevant journey
|
|
271
|
+
- Call \`pcl_list({ type: "specs" })\` then \`pcl_get_spec(id)\` for the feature spec if it exists
|
|
272
|
+
|
|
273
|
+
### When unsure about product decisions:
|
|
274
|
+
- Call \`pcl_search({ query: "your question here" })\` to find relevant product knowledge
|
|
275
|
+
- Call \`pcl_get_decision(id)\` for architecture decisions affecting your current task
|
|
276
|
+
|
|
277
|
+
### NEVER:
|
|
278
|
+
- Make assumptions about who the user is — always load the persona
|
|
279
|
+
- Violate any rule in domain/core-rules.md
|
|
280
|
+
- Build features not covered by an accepted spec without asking first
|
|
281
|
+
`;
|
|
282
|
+
try {
|
|
283
|
+
await access(claudeMd, constants.F_OK);
|
|
284
|
+
console.log(`\n ↷ CLAUDE.md exists — add the PCL instructions manually (printed above)`);
|
|
285
|
+
console.log(bridge);
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
const existing = "";
|
|
289
|
+
await writeFile(claudeMd, existing + bridge, "utf8");
|
|
290
|
+
console.log(` ✓ CLAUDE.md`);
|
|
291
|
+
created++;
|
|
292
|
+
}
|
|
293
|
+
console.log(`\nDone! Created: ${created}, skipped: ${skipped}`);
|
|
294
|
+
console.log("\nNext steps:");
|
|
295
|
+
console.log(" 1. Edit product/product.md with your actual product details");
|
|
296
|
+
console.log(" 2. Rename and fill in the example persona, journey, and spec files");
|
|
297
|
+
console.log(" 3. Add your MCP server config (see README)");
|
|
298
|
+
console.log(" 4. npm run serve\n");
|
|
299
|
+
}
|
|
300
|
+
// ─── Router ───────────────────────────────────────────────────────────────────
|
|
301
|
+
switch (cmd) {
|
|
302
|
+
case "init":
|
|
303
|
+
init().catch(console.error);
|
|
304
|
+
break;
|
|
305
|
+
case "serve":
|
|
306
|
+
// Delegate to the server module
|
|
307
|
+
import("../src/server.js").catch(console.error);
|
|
308
|
+
break;
|
|
309
|
+
default:
|
|
310
|
+
console.log(`
|
|
311
|
+
pcl — Product Context Layer CLI
|
|
312
|
+
|
|
313
|
+
Commands:
|
|
314
|
+
init [dir] Scaffold /product folder with templates (default: ./product)
|
|
315
|
+
init --scan [dir] Scan repo for existing .md files, import, then scaffold remaining templates
|
|
316
|
+
init --scan-only [dir] Scan and import only, don't scaffold templates
|
|
317
|
+
serve Start the MCP server (reads --product-dir flag)
|
|
318
|
+
|
|
319
|
+
Examples:
|
|
320
|
+
npx pcl-mcp init
|
|
321
|
+
npx pcl-mcp init --scan
|
|
322
|
+
npx pcl-mcp init --scan-only
|
|
323
|
+
npx pcl-mcp init ./my-product-docs
|
|
324
|
+
npx pcl-mcp serve --product-dir ./product
|
|
325
|
+
`);
|
|
326
|
+
}
|
|
327
|
+
//# sourceMappingURL=pcl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pcl.js","sourceRoot":"","sources":["../../bin/pcl.ts"],"names":[],"mappings":"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"}
|
package/dist/src/db.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import type { FileType, IndexedFile } from "./types.js";
|
|
3
|
+
export declare function packEmbedding(vec: number[]): Buffer;
|
|
4
|
+
export declare function unpackEmbedding(buf: Buffer): number[];
|
|
5
|
+
export declare function hashContent(text: string): string;
|
|
6
|
+
export declare function openDB(productDir: string): Database.Database;
|
|
7
|
+
export declare function closeDB(): void;
|
|
8
|
+
export interface DBRow {
|
|
9
|
+
id: string;
|
|
10
|
+
type: FileType;
|
|
11
|
+
path: string;
|
|
12
|
+
frontmatter: string;
|
|
13
|
+
body: string;
|
|
14
|
+
full_text: string;
|
|
15
|
+
title: string;
|
|
16
|
+
summary: string;
|
|
17
|
+
critical: number;
|
|
18
|
+
mtime: number;
|
|
19
|
+
hash: string;
|
|
20
|
+
embedding: Buffer | null;
|
|
21
|
+
}
|
|
22
|
+
export declare function upsertFile(db: Database.Database, file: IndexedFile): void;
|
|
23
|
+
export declare function updateEmbedding(db: Database.Database, path: string, embedding: number[]): void;
|
|
24
|
+
export declare function deleteFile(db: Database.Database, path: string): void;
|
|
25
|
+
export declare function getFileByPath(db: Database.Database, path: string): IndexedFile | null;
|
|
26
|
+
export declare function getFileById(db: Database.Database, type: FileType, id: string): IndexedFile | null;
|
|
27
|
+
export declare function getProductFile(db: Database.Database): IndexedFile | null;
|
|
28
|
+
export declare function listByType(db: Database.Database, type: FileType): IndexedFile[];
|
|
29
|
+
export declare function getCritical(db: Database.Database): IndexedFile[];
|
|
30
|
+
export declare function getAllWithEmbeddings(db: Database.Database): IndexedFile[];
|
|
31
|
+
export declare function getAllWithoutEmbeddings(db: Database.Database): IndexedFile[];
|
|
32
|
+
export interface FTSResult {
|
|
33
|
+
id: string;
|
|
34
|
+
type: string;
|
|
35
|
+
rank: number;
|
|
36
|
+
}
|
|
37
|
+
export declare function keywordSearch(db: Database.Database, query: string, limit?: number): FTSResult[];
|
|
38
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAMA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA2DxD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAEnD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAErD;AAID,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAQD,wBAAgB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAoB5D;AAED,wBAAgB,OAAO,IAAI,IAAI,CAO9B;AAkDD,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAqBD,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAgBzE;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EAAE,GAClB,IAAI,CAGN;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAGpE;AAID,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAGrF;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAGjG;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,WAAW,GAAG,IAAI,CAGxE;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,GAAG,WAAW,EAAE,CAG/E;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,WAAW,EAAE,CAGhE;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,WAAW,EAAE,CAKzE;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,WAAW,EAAE,CAG5E;AAID,MAAM,WAAW,SAAS;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAErE,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,KAAK,SAAK,GACT,SAAS,EAAE,CAeb"}
|