gateproof 0.1.1 → 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/README.md +224 -55
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/prd/define-prd.d.ts +7 -0
- package/dist/prd/define-prd.d.ts.map +1 -0
- package/dist/prd/define-prd.js +8 -0
- package/dist/prd/define-prd.js.map +1 -0
- package/dist/prd/index.d.ts +5 -0
- package/dist/prd/index.d.ts.map +1 -0
- package/dist/prd/index.js +4 -0
- package/dist/prd/index.js.map +1 -0
- package/dist/prd/runner.d.ts +22 -0
- package/dist/prd/runner.d.ts.map +1 -0
- package/dist/prd/runner.js +221 -0
- package/dist/prd/runner.js.map +1 -0
- package/dist/prd/scope-check.d.ts +28 -0
- package/dist/prd/scope-check.d.ts.map +1 -0
- package/dist/prd/scope-check.js +135 -0
- package/dist/prd/scope-check.js.map +1 -0
- package/dist/prd/types.d.ts +21 -0
- package/dist/prd/types.d.ts.map +1 -0
- package/dist/prd/types.js +2 -0
- package/dist/prd/types.js.map +1 -0
- package/dist/report.d.ts +67 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +51 -0
- package/dist/report.js.map +1 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,47 +1,108 @@
|
|
|
1
1
|
# gateproof
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build software in reverse. PRD defines what should exist. Gates verify reality. Agent iterations refine until gates pass.
|
|
4
4
|
|
|
5
5
|
## What gateproof does
|
|
6
6
|
|
|
7
|
-
gateproof **
|
|
7
|
+
gateproof enables **agent iterations** with minimal context overhead.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**The workflow:**
|
|
10
|
+
1. PRD defines stories (what should exist)
|
|
11
|
+
2. Gates verify reality (does it work?)
|
|
12
|
+
3. Agent gets PRD + gate failure (minimal context)
|
|
13
|
+
4. Agent fixes, gates re-run
|
|
14
|
+
5. Iterate until all gates pass
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
**Why this works:**
|
|
17
|
+
- PRD is single source of truth (clear intent, minimal context)
|
|
18
|
+
- Gates provide concrete feedback (not vague requirements)
|
|
19
|
+
- Agent gets context only when needed (efficient)
|
|
20
|
+
- Iteration ensures correctness (converges to working code)
|
|
21
|
+
|
|
22
|
+
gateproof **executes gates**. It does not define intent, plans, or workflows. A gate is a test specification: observe logs, run actions, assert results. gateproof runs it and returns evidence.
|
|
12
23
|
|
|
13
24
|
**Authority chain:**
|
|
14
|
-
- **PRD (`prd.ts`
|
|
25
|
+
- **PRD (`prd.ts`)** — authority on intent, order, and dependencies (if you use the PRD runner)
|
|
15
26
|
- **Gate implementations** — authority on how reality is observed
|
|
16
27
|
- **gateproof runtime** — authority on enforcement only
|
|
17
28
|
|
|
18
|
-
gateproof never decides *what* to build. It
|
|
29
|
+
gateproof never decides *what* to build. It returns results; your CI/CD decides whether you are allowed to proceed.
|
|
30
|
+
|
|
31
|
+
## Agent Iterations: The Loop
|
|
32
|
+
|
|
33
|
+
The core innovation: agents work from PRD only, gates verify, iterate until correct.
|
|
34
|
+
|
|
35
|
+
**The iteration loop:**
|
|
36
|
+
1. Run PRD → executes gates in dependency order
|
|
37
|
+
2. Gate fails → agent gets: codebase context (e.g., `AGENTS.md`) + failure output
|
|
38
|
+
3. Agent fixes → makes changes to codebase
|
|
39
|
+
4. Loop repeats → re-run PRD, check if gates pass
|
|
40
|
+
5. All gates pass → done
|
|
41
|
+
|
|
42
|
+
**Why minimal context:**
|
|
43
|
+
- Agent starts with PRD only (no full codebase upfront)
|
|
44
|
+
- Agent gets context only when gates fail (just-in-time)
|
|
45
|
+
- PRD stays as authority (what to build)
|
|
46
|
+
- Gates provide concrete feedback (what's wrong)
|
|
47
|
+
|
|
48
|
+
**Example loop script:**
|
|
49
|
+
```bash
|
|
50
|
+
# patterns/prd/agent-iteration-loop.sh
|
|
51
|
+
while true; do
|
|
52
|
+
bun run prd.ts || {
|
|
53
|
+
# Gate failed - agent gets PRD + failure output
|
|
54
|
+
agent --context prd.ts --failure "$(cat gate-output.txt)"
|
|
55
|
+
# Agent fixes, loop continues
|
|
56
|
+
}
|
|
57
|
+
break # All gates passed
|
|
58
|
+
done
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**The guardrails:**
|
|
62
|
+
- Max failures (default: 5) → auto-pause if stuck
|
|
63
|
+
- Git diff check → agent must make changes
|
|
64
|
+
- Pause file → manual control
|
|
65
|
+
|
|
66
|
+
This solves the context management problem: agents don't need full codebase context upfront. They get minimal context (PRD), concrete feedback (gate failures), and iterate until correct.
|
|
19
67
|
|
|
20
68
|
## Stories as gates
|
|
21
69
|
|
|
22
70
|
A PRD (Product Requirements Document) defines stories. Stories are gates. Each story references a gate file. The gate file verifies the story against reality.
|
|
23
71
|
|
|
24
|
-
Reality
|
|
72
|
+
Reality is the source of truth; gates make it enforceable in CI.
|
|
25
73
|
|
|
26
74
|
### prd.ts example
|
|
27
75
|
|
|
28
76
|
```typescript
|
|
29
77
|
// prd.ts
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
78
|
+
import { definePrd } from "gateproof/prd";
|
|
79
|
+
|
|
80
|
+
export const prd = definePrd({
|
|
81
|
+
stories: [
|
|
82
|
+
{
|
|
83
|
+
id: "user-signup",
|
|
84
|
+
title: "User can sign up",
|
|
85
|
+
gateFile: "./gates/user-signup.gate.ts",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: "email-verification",
|
|
89
|
+
title: "User receives verification email",
|
|
90
|
+
gateFile: "./gates/email-verification.gate.ts",
|
|
91
|
+
dependsOn: ["user-signup"],
|
|
92
|
+
},
|
|
93
|
+
] as const, // keep story IDs as literal types
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Make it executable
|
|
97
|
+
if (import.meta.main) {
|
|
98
|
+
const { runPrd } = await import("gateproof/prd");
|
|
99
|
+
const result = await runPrd(prd);
|
|
100
|
+
if (!result.success) {
|
|
101
|
+
if (result.failedStory) console.error(`Failed at: ${result.failedStory.id}`);
|
|
102
|
+
process.exit(1);
|
|
43
103
|
}
|
|
44
|
-
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
45
106
|
```
|
|
46
107
|
|
|
47
108
|
Each story references a gate file. The gate file uses gateproof's API:
|
|
@@ -51,55 +112,111 @@ Each story references a gate file. The gate file uses gateproof's API:
|
|
|
51
112
|
import { Gate, Act, Assert } from "gateproof";
|
|
52
113
|
import { CloudflareProvider } from "gateproof/cloudflare";
|
|
53
114
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
115
|
+
export async function run() {
|
|
116
|
+
const provider = CloudflareProvider({
|
|
117
|
+
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
|
|
118
|
+
apiToken: process.env.CLOUDFLARE_API_TOKEN!,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const result = await Gate.run({
|
|
122
|
+
name: "user-signup",
|
|
123
|
+
observe: provider.observe({ backend: "analytics", dataset: "worker_logs" }),
|
|
124
|
+
act: [Act.browser({ url: "https://app.example.com/signup" })],
|
|
125
|
+
assert: [
|
|
126
|
+
Assert.noErrors(),
|
|
127
|
+
Assert.hasAction("user_created"),
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return { status: result.status };
|
|
132
|
+
}
|
|
133
|
+
```
|
|
58
134
|
|
|
59
|
-
|
|
60
|
-
name: "user-signup",
|
|
61
|
-
observe: provider.observe({ backend: "analytics", dataset: "worker_logs" }),
|
|
62
|
-
act: [Act.browser({ url: "https://app.example.com/signup" })],
|
|
63
|
-
assert: [
|
|
64
|
-
Assert.noErrors(),
|
|
65
|
-
Assert.hasAction("user_created")
|
|
66
|
-
]
|
|
67
|
-
});
|
|
135
|
+
**gateproof does not own your PRD’s intent or state.** If you choose to use `gateproof/prd`, your PRD must match a small capsule shape (`stories[]` with `id/title/gateFile/dependsOn?`). Otherwise, orchestrate gates however you want — gateproof only cares about executing gate files.
|
|
68
136
|
|
|
69
|
-
|
|
137
|
+
Stories execute in dependency order. The runner stops on first failure. Progress is not declared. It is proven.
|
|
138
|
+
|
|
139
|
+
## How it works
|
|
140
|
+
|
|
141
|
+
The PRD defines stories. Stories reference gate files. Gate files use gateproof's API. Gates can be enforced in CI before merge/deploy.
|
|
142
|
+
|
|
143
|
+
**The sequence:** PRD story → gate file → gate execution → story marked "done" only when gate passes.
|
|
144
|
+
|
|
145
|
+
**For agent iterations:** PRD → gate fails → agent fixes → gate re-runs → loop until pass.
|
|
146
|
+
|
|
147
|
+
Run your PRD:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
bun run prd.ts
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Run agent iteration loop:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
bash patterns/prd/agent-iteration-loop.sh
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Hardening `prd.ts` (recommended)
|
|
160
|
+
|
|
161
|
+
Treat `prd.ts` like code: typecheck + validate before push + enforce in CI.
|
|
162
|
+
|
|
163
|
+
- **Validate PRD**:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
bun run prd:validate
|
|
70
167
|
```
|
|
71
168
|
|
|
72
|
-
|
|
169
|
+
- **Pre-push (default for everyone on your team)**: add to your `prepush` script (Husky calls it).
|
|
73
170
|
|
|
74
171
|
```json
|
|
75
172
|
{
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"title": "User can sign up",
|
|
80
|
-
"gateFile": "./gates/user-signup.gate.ts",
|
|
81
|
-
"status": "pending"
|
|
82
|
-
}
|
|
83
|
-
]
|
|
173
|
+
"scripts": {
|
|
174
|
+
"prepush": "bun run typecheck && bun run prd:validate && bun test"
|
|
175
|
+
}
|
|
84
176
|
}
|
|
85
177
|
```
|
|
86
178
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Stories carry state. The PRD tracks which stories are pending, in progress, or done. gateproof does not manage this state. It only enforces: proceed only when gates pass.
|
|
90
|
-
|
|
91
|
-
## How it works
|
|
179
|
+
- **CI**: run the validator before running PRD/tests.
|
|
92
180
|
|
|
93
|
-
|
|
181
|
+
```yaml
|
|
182
|
+
- name: Validate PRD
|
|
183
|
+
run: bun run prd:validate
|
|
184
|
+
```
|
|
94
185
|
|
|
95
|
-
|
|
186
|
+
- **Monorepo**: validate any PRD file by path.
|
|
96
187
|
|
|
97
|
-
|
|
188
|
+
```bash
|
|
189
|
+
bun run scripts/prd-validate.ts packages/api/prd.ts
|
|
190
|
+
```
|
|
98
191
|
|
|
99
192
|
## Design notes
|
|
100
193
|
|
|
101
194
|
- [Effect and Schema: Gateproof's Foundation](docs/effect-and-schema.md)
|
|
102
195
|
|
|
196
|
+
## Writing good gates (agent-first)
|
|
197
|
+
|
|
198
|
+
Gates can fail loudly. They can also pass on silence if you write weak assertions.
|
|
199
|
+
|
|
200
|
+
- **Always assert at least one positive signal**: `Assert.hasAction(...)` and/or `Assert.hasStage(...)`. If your backend can be silent, add an explicit “evidence must exist” custom assertion.
|
|
201
|
+
- **Don’t rely on absence-only checks**: `Assert.noErrors()` alone can pass if you collect no logs.
|
|
202
|
+
- **Treat observability as part of the system**: your confidence is bounded by what you can observe.
|
|
203
|
+
|
|
204
|
+
## Limits / Non-goals
|
|
205
|
+
|
|
206
|
+
- **Not a planner or orchestrator**: gateproof executes gates; your PRD (or CI) decides what to run and in what context.
|
|
207
|
+
- **Not a truth oracle**: if your backend drops logs, a gate can be wrong. Gateproof can’t fix missing telemetry.
|
|
208
|
+
- **Enforcement is external**: gateproof returns results; CI/CD decides whether to block merge/deploy.
|
|
209
|
+
|
|
210
|
+
## Common objections (and answers)
|
|
211
|
+
|
|
212
|
+
- **"Isn't this just E2E tests?"** Similar goal, different anchor. Gates are evidence-first (logs/telemetry + explicit assertions), not DOM-only. The contract is: observe → act → assert → evidence.
|
|
213
|
+
|
|
214
|
+
- **"What about flaky telemetry?"** Gates don't fix missing telemetry. They make the dependency explicit. If your backend drops logs, a gate can be wrong — but you'll know immediately, not in production.
|
|
215
|
+
|
|
216
|
+
- **"Isn't this overhead?"** It can be. The pitch isn't "gate everything." It's "gate the few transitions that are expensive to get wrong." Start with one critical path.
|
|
217
|
+
|
|
218
|
+
- **"Will this lock us in?"** Gates are just TypeScript files. If you stop using gateproof, you keep the scripts and the intent. No vendor lock-in.
|
|
219
|
+
|
|
103
220
|
## Quick Start
|
|
104
221
|
|
|
105
222
|
The API is minimal: three concepts (Gate, Act, Assert). Here's a gate:
|
|
@@ -110,14 +227,14 @@ import { CloudflareProvider } from "gateproof/cloudflare";
|
|
|
110
227
|
|
|
111
228
|
const provider = CloudflareProvider({
|
|
112
229
|
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
|
|
113
|
-
apiToken: process.env.CLOUDFLARE_API_TOKEN
|
|
230
|
+
apiToken: process.env.CLOUDFLARE_API_TOKEN!,
|
|
114
231
|
});
|
|
115
232
|
|
|
116
233
|
const result = await Gate.run({
|
|
117
234
|
name: "api-health-check",
|
|
118
235
|
observe: provider.observe({ backend: "analytics", dataset: "worker_logs" }),
|
|
119
236
|
act: [Act.browser({ url: "https://my-worker.workers.dev" })],
|
|
120
|
-
assert: [Assert.noErrors(), Assert.hasAction("request_received")]
|
|
237
|
+
assert: [Assert.noErrors(), Assert.hasAction("request_received")],
|
|
121
238
|
});
|
|
122
239
|
|
|
123
240
|
if (result.status !== "success") process.exit(1);
|
|
@@ -163,6 +280,42 @@ Assert.custom("name", fn) // Custom: (logs) => boolean
|
|
|
163
280
|
}
|
|
164
281
|
```
|
|
165
282
|
|
|
283
|
+
## PRD Runner
|
|
284
|
+
|
|
285
|
+
gateproof provides a PRD runner that executes stories in dependency order:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { definePrd, runPrd } from "gateproof/prd";
|
|
289
|
+
|
|
290
|
+
const prd = definePrd({
|
|
291
|
+
stories: [
|
|
292
|
+
{
|
|
293
|
+
id: "story-1",
|
|
294
|
+
title: "First story",
|
|
295
|
+
gateFile: "./gates/story-1.gate.ts",
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
id: "story-2",
|
|
299
|
+
title: "Second story",
|
|
300
|
+
gateFile: "./gates/story-2.gate.ts",
|
|
301
|
+
dependsOn: ["story-1"],
|
|
302
|
+
},
|
|
303
|
+
] as const, // keep story IDs as literal types
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const result = await runPrd(prd);
|
|
307
|
+
if (!result.success) {
|
|
308
|
+
console.error(`Failed at: ${result.failedStory?.id}`);
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The runner:
|
|
314
|
+
- Validates dependencies (unknown IDs and cycles throw)
|
|
315
|
+
- Topologically sorts stories by `dependsOn`
|
|
316
|
+
- Executes gates in order
|
|
317
|
+
- **Stops on first failure**
|
|
318
|
+
|
|
166
319
|
## Plug Your Backend
|
|
167
320
|
|
|
168
321
|
gateproof works with any observability backend. Just implement the `Backend` interface:
|
|
@@ -202,18 +355,34 @@ See `patterns/` for complete examples:
|
|
|
202
355
|
- `patterns/cloudflare/` - Cloudflare-specific patterns
|
|
203
356
|
- `patterns/ci-cd/` - CI/CD integration
|
|
204
357
|
- `patterns/advanced/` - Advanced patterns
|
|
358
|
+
- `patterns/prd/` - PRD-as-code + agent iteration loop examples
|
|
359
|
+
- `patterns/agent-first/` - Spec interview → PRD stories (agent-first)
|
|
360
|
+
- `examples/hello-world-agent/` - Minimal agent with 5 tools + end-to-end gates
|
|
361
|
+
|
|
362
|
+
Run the hello-world agent example (requires `OPENCODE_ZEN_API_KEY` and network access to `opencode.ai`):
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
export OPENCODE_ZEN_API_KEY="your_key_here"
|
|
366
|
+
bun run examples/hello-world-agent/prd.ts
|
|
367
|
+
```
|
|
205
368
|
|
|
206
369
|
## CI/CD
|
|
207
370
|
|
|
208
371
|
gateproof enforces gates in CI/CD. See `patterns/ci-cd/github-actions.ts` for examples.
|
|
209
372
|
|
|
373
|
+
Run your PRD in CI:
|
|
374
|
+
|
|
375
|
+
```yaml
|
|
376
|
+
- name: Run PRD
|
|
377
|
+
run: bun run prd.ts
|
|
378
|
+
```
|
|
379
|
+
|
|
210
380
|
## Requirements
|
|
211
381
|
|
|
212
382
|
- Node.js 18+ or Bun
|
|
213
383
|
- `playwright` (optional, for Act.browser)
|
|
214
384
|
- Cloudflare credentials (for CloudflareProvider, or bring your own backend)
|
|
215
385
|
|
|
216
|
-
|
|
217
386
|
## License
|
|
218
387
|
|
|
219
388
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -63,4 +63,6 @@ export type { Provider } from "./provider";
|
|
|
63
63
|
export { createEmptyBackend, createEmptyObserveResource, runGateWithErrorHandling } from "./utils";
|
|
64
64
|
export { createTestObserveResource } from "./test-helpers";
|
|
65
65
|
export { createHttpObserveResource } from "./http-backend";
|
|
66
|
+
export type { GateResultV1, PrdReportV1, StoryResultV1, SerializableError } from "./report";
|
|
67
|
+
export { serializeError, toGateResultV1 } from "./report";
|
|
66
68
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwC,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAO,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAU,eAAe,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwC,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAO,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAU,eAAe,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;;;;;;AAYxC,qBAAa,SAAU,SAAQ,cAE7B;CAAG;;;;;;;;AAEL,qBAAa,eAAgB,SAAQ,oBAOpC;CAAG;AAEJ,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,eAAe,GAAG,eAAe,GAAG,wBAAwB,GAAG,kBAAkB,CAAC;AAE1H,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,eAAe,CAAC;IACzB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC5B;AA8ID,yBAAiB,IAAI,CAAC;IACpB,SAAgB,GAAG,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAEvD;IAED,SAAgB,SAAS,CACvB,IAAI,EAAE,QAAQ,GACb,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC,CAiGvD;CACF;AAuBD,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AACnG,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC5F,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Assert } from "./assert";
|
|
|
3
3
|
import { Schema } from "@effect/schema";
|
|
4
4
|
import { getActionExecutor } from "./action-executors";
|
|
5
5
|
import { DEFAULT_IDLE_MS, DEFAULT_MAX_MS, MAX_LOG_BUFFER, LOG_BUFFER_CAPACITY } from "./constants";
|
|
6
|
+
import { sortDeterministic, toGateResultV1 } from "./report";
|
|
6
7
|
export class GateError extends Schema.TaggedError()("GateError", {
|
|
7
8
|
cause: Schema.Unknown
|
|
8
9
|
}) {
|
|
@@ -29,10 +30,10 @@ function summarize(logs) {
|
|
|
29
30
|
errorTags.add(log.error.tag);
|
|
30
31
|
}
|
|
31
32
|
return {
|
|
32
|
-
requestIds: [...requestIds],
|
|
33
|
-
stagesSeen: [...stages],
|
|
34
|
-
actionsSeen: [...actions],
|
|
35
|
-
errorTags: [...errorTags]
|
|
33
|
+
requestIds: sortDeterministic([...requestIds]),
|
|
34
|
+
stagesSeen: sortDeterministic([...stages]),
|
|
35
|
+
actionsSeen: sortDeterministic([...actions]),
|
|
36
|
+
errorTags: sortDeterministic([...errorTags])
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
function makeLogTimeoutError(stop, cause) {
|
|
@@ -201,7 +202,9 @@ function printResult(report, result) {
|
|
|
201
202
|
}
|
|
202
203
|
}
|
|
203
204
|
else {
|
|
204
|
-
|
|
205
|
+
// Use serializable version for JSON output
|
|
206
|
+
const serializable = toGateResultV1(result);
|
|
207
|
+
console.log(JSON.stringify(serializable, null, 2));
|
|
205
208
|
}
|
|
206
209
|
}
|
|
207
210
|
export { Act } from "./act";
|
|
@@ -209,4 +212,5 @@ export { Assert } from "./assert";
|
|
|
209
212
|
export { createEmptyBackend, createEmptyObserveResource, runGateWithErrorHandling } from "./utils";
|
|
210
213
|
export { createTestObserveResource } from "./test-helpers";
|
|
211
214
|
export { createHttpObserveResource } from "./http-backend";
|
|
215
|
+
export { serializeError, toGateResultV1 } from "./report";
|
|
212
216
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAS,GAAG,EAAE,MAAM,EAAY,MAAM,EAAS,MAAM,QAAQ,CAAC;AAK7E,OAAO,EAAE,MAAM,EAA6C,MAAM,UAAU,CAAC;AAE7E,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAErB,MAAM,OAAO,SAAU,SAAQ,MAAM,CAAC,WAAW,EAAa,CAAC,WAAW,EAAE;IAC1E,KAAK,EAAE,MAAM,CAAC,OAAO;CACtB,CAAC;CAAG;AAEL,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,WAAW,EAAmB,CACxE,iBAAiB,EACjB;IACE,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;CACvC,CACF;CAAG;AA8BJ,SAAS,SAAS,CAAC,IAAW;IAC5B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,SAAS;YAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,GAAG,CAAC,KAAK;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,GAAG,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,GAAG,CAAC,KAAK,EAAE,GAAG;YAAE,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,OAAO;QACL,UAAU,EAAE,CAAC,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Prd } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Helper to define a PRD with type-safe story IDs.
|
|
4
|
+
* Preserves literal union types for StoryId.
|
|
5
|
+
*/
|
|
6
|
+
export declare function definePrd<TId extends string>(prd: Prd<TId>): Prd<TId>;
|
|
7
|
+
//# sourceMappingURL=define-prd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-prd.d.ts","sourceRoot":"","sources":["../../src/prd/define-prd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAEnC;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,SAAS,MAAM,EAC1C,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,GACZ,GAAG,CAAC,GAAG,CAAC,CAEV"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-prd.js","sourceRoot":"","sources":["../../src/prd/define-prd.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,SAAS,CACvB,GAAa;IAEb,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { Prd, Story, GateResult, StoryScope } from "./types";
|
|
2
|
+
export { definePrd } from "./define-prd";
|
|
3
|
+
export { runPrd, type RunPrdResult } from "./runner";
|
|
4
|
+
export { validateScope, getDiffStats, type ScopeViolation } from "./scope-check";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prd/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prd/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAqB,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAuB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Prd, Story } from "./types";
|
|
2
|
+
import type { PrdReportV1 } from "../report";
|
|
3
|
+
export interface RunPrdResult {
|
|
4
|
+
success: boolean;
|
|
5
|
+
failedStory?: Story;
|
|
6
|
+
error?: Error;
|
|
7
|
+
report?: PrdReportV1;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Runs a PRD by executing story gates in dependency order.
|
|
11
|
+
* Stops on first failure.
|
|
12
|
+
*
|
|
13
|
+
* @param options.reportPath - If provided, writes a structured JSON report to this path
|
|
14
|
+
* @param options.checkScope - If true, validates scope constraints against git diff
|
|
15
|
+
* @param options.baseRef - Git ref to compare against for scope checking (default: "HEAD" for local, "origin/main" for CI)
|
|
16
|
+
*/
|
|
17
|
+
export declare function runPrd<TId extends string>(prd: Prd<TId>, cwd?: string, options?: {
|
|
18
|
+
reportPath?: string;
|
|
19
|
+
checkScope?: boolean;
|
|
20
|
+
baseRef?: string;
|
|
21
|
+
}): Promise<RunPrdResult>;
|
|
22
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/prd/runner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAc,MAAM,SAAS,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAoC,MAAM,WAAW,CAAC;AAI/E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAkFD;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAAC,GAAG,SAAS,MAAM,EAC7C,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,EACb,GAAG,GAAE,MAAsB,EAC3B,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACb,GACL,OAAO,CAAC,YAAY,CAAC,CAyJvB"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { serializeError } from "../report";
|
|
4
|
+
import { validateScope, getDiffStats } from "./scope-check";
|
|
5
|
+
/**
|
|
6
|
+
* Validates that all story dependencies exist and there are no cycles.
|
|
7
|
+
*/
|
|
8
|
+
function validateDependencies(stories) {
|
|
9
|
+
const byId = new Map(stories.map((s) => [s.id, s]));
|
|
10
|
+
for (const story of stories) {
|
|
11
|
+
const deps = story.dependsOn ?? [];
|
|
12
|
+
for (const depId of deps) {
|
|
13
|
+
if (!byId.has(depId)) {
|
|
14
|
+
throw new Error(`Story "${story.id}" depends on unknown story "${depId}"`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Topologically sorts stories by their dependencies.
|
|
21
|
+
* Throws if there's a cycle or missing dependency.
|
|
22
|
+
*/
|
|
23
|
+
function orderStories(stories) {
|
|
24
|
+
validateDependencies(stories);
|
|
25
|
+
const byId = new Map(stories.map((s) => [s.id, s]));
|
|
26
|
+
const out = [];
|
|
27
|
+
const remaining = new Set(stories.map((s) => s.id));
|
|
28
|
+
const visiting = new Set();
|
|
29
|
+
function visit(id) {
|
|
30
|
+
if (visiting.has(id)) {
|
|
31
|
+
throw new Error(`PRD dependency cycle detected involving "${id}"`);
|
|
32
|
+
}
|
|
33
|
+
if (!remaining.has(id)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
visiting.add(id);
|
|
37
|
+
const story = byId.get(id);
|
|
38
|
+
if (!story) {
|
|
39
|
+
throw new Error(`Unknown story id: ${id}`);
|
|
40
|
+
}
|
|
41
|
+
const deps = story.dependsOn ?? [];
|
|
42
|
+
for (const depId of deps) {
|
|
43
|
+
visit(depId);
|
|
44
|
+
}
|
|
45
|
+
visiting.delete(id);
|
|
46
|
+
remaining.delete(id);
|
|
47
|
+
out.push(story);
|
|
48
|
+
}
|
|
49
|
+
while (remaining.size > 0) {
|
|
50
|
+
const nextId = Array.from(remaining)[0];
|
|
51
|
+
visit(nextId);
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Loads default forbidden paths from .gateproof/scope.defaults.json
|
|
57
|
+
*/
|
|
58
|
+
function loadDefaultForbidden(cwd) {
|
|
59
|
+
try {
|
|
60
|
+
const defaultsPath = resolve(cwd, ".gateproof/scope.defaults.json");
|
|
61
|
+
const content = readFileSync(defaultsPath, "utf-8");
|
|
62
|
+
const parsed = JSON.parse(content);
|
|
63
|
+
return parsed.forbiddenPaths ?? [];
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Runs a PRD by executing story gates in dependency order.
|
|
71
|
+
* Stops on first failure.
|
|
72
|
+
*
|
|
73
|
+
* @param options.reportPath - If provided, writes a structured JSON report to this path
|
|
74
|
+
* @param options.checkScope - If true, validates scope constraints against git diff
|
|
75
|
+
* @param options.baseRef - Git ref to compare against for scope checking (default: "HEAD" for local, "origin/main" for CI)
|
|
76
|
+
*/
|
|
77
|
+
export async function runPrd(prd, cwd = process.cwd(), options = {}) {
|
|
78
|
+
const ordered = orderStories(prd.stories);
|
|
79
|
+
const storyResults = [];
|
|
80
|
+
const startTime = Date.now();
|
|
81
|
+
const defaultForbidden = loadDefaultForbidden(cwd);
|
|
82
|
+
const baseRef = options.baseRef ?? (process.env.CI ? "origin/main" : "HEAD");
|
|
83
|
+
for (const story of ordered) {
|
|
84
|
+
const storyStartTime = Date.now();
|
|
85
|
+
let storyError;
|
|
86
|
+
try {
|
|
87
|
+
if (options.checkScope && story.scope) {
|
|
88
|
+
const diffStats = getDiffStats(baseRef);
|
|
89
|
+
const violations = validateScope(story, diffStats, defaultForbidden);
|
|
90
|
+
if (violations.length > 0) {
|
|
91
|
+
const violation = violations[0];
|
|
92
|
+
storyError = {
|
|
93
|
+
name: "ScopeViolation",
|
|
94
|
+
message: violation.message,
|
|
95
|
+
tag: violation.category,
|
|
96
|
+
};
|
|
97
|
+
storyResults.push({
|
|
98
|
+
id: story.id,
|
|
99
|
+
title: story.title,
|
|
100
|
+
gateFile: story.gateFile,
|
|
101
|
+
status: "failed",
|
|
102
|
+
durationMs: Date.now() - storyStartTime,
|
|
103
|
+
error: storyError,
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
failedStory: story,
|
|
108
|
+
error: new Error(violation.message),
|
|
109
|
+
report: {
|
|
110
|
+
version: "1",
|
|
111
|
+
success: false,
|
|
112
|
+
stories: storyResults,
|
|
113
|
+
failedStory: {
|
|
114
|
+
id: story.id,
|
|
115
|
+
title: story.title,
|
|
116
|
+
gateFile: story.gateFile,
|
|
117
|
+
},
|
|
118
|
+
totalDurationMs: Date.now() - startTime,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const gatePath = resolve(cwd, story.gateFile);
|
|
124
|
+
const mod = await import(`file://${gatePath}`);
|
|
125
|
+
const run = mod.run;
|
|
126
|
+
if (typeof run !== "function") {
|
|
127
|
+
throw new Error(`Gate file must export "run" function: ${story.gateFile}`);
|
|
128
|
+
}
|
|
129
|
+
console.log(`\n--- ${story.id}: ${story.title}`);
|
|
130
|
+
const result = (await run());
|
|
131
|
+
const durationMs = Date.now() - storyStartTime;
|
|
132
|
+
if (result.status !== "success") {
|
|
133
|
+
storyError = result.error ? serializeError(result.error) : {
|
|
134
|
+
name: "GateFailed",
|
|
135
|
+
message: `Gate failed with status: ${result.status}`,
|
|
136
|
+
};
|
|
137
|
+
storyResults.push({
|
|
138
|
+
id: story.id,
|
|
139
|
+
title: story.title,
|
|
140
|
+
gateFile: story.gateFile,
|
|
141
|
+
status: result.status,
|
|
142
|
+
durationMs,
|
|
143
|
+
error: storyError,
|
|
144
|
+
});
|
|
145
|
+
const report = {
|
|
146
|
+
version: "1",
|
|
147
|
+
success: false,
|
|
148
|
+
stories: storyResults,
|
|
149
|
+
failedStory: {
|
|
150
|
+
id: story.id,
|
|
151
|
+
title: story.title,
|
|
152
|
+
gateFile: story.gateFile,
|
|
153
|
+
},
|
|
154
|
+
totalDurationMs: Date.now() - startTime,
|
|
155
|
+
};
|
|
156
|
+
if (options.reportPath) {
|
|
157
|
+
const { writeFileSync } = await import("node:fs");
|
|
158
|
+
writeFileSync(options.reportPath, JSON.stringify(report, null, 2));
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
failedStory: story,
|
|
163
|
+
error: new Error(`Gate failed with status: ${result.status}`),
|
|
164
|
+
report,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
storyResults.push({
|
|
168
|
+
id: story.id,
|
|
169
|
+
title: story.title,
|
|
170
|
+
gateFile: story.gateFile,
|
|
171
|
+
status: "success",
|
|
172
|
+
durationMs,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
const durationMs = Date.now() - storyStartTime;
|
|
177
|
+
storyError = serializeError(error);
|
|
178
|
+
storyResults.push({
|
|
179
|
+
id: story.id,
|
|
180
|
+
title: story.title,
|
|
181
|
+
gateFile: story.gateFile,
|
|
182
|
+
status: "failed",
|
|
183
|
+
durationMs,
|
|
184
|
+
error: storyError,
|
|
185
|
+
});
|
|
186
|
+
const report = {
|
|
187
|
+
version: "1",
|
|
188
|
+
success: false,
|
|
189
|
+
stories: storyResults,
|
|
190
|
+
failedStory: {
|
|
191
|
+
id: story.id,
|
|
192
|
+
title: story.title,
|
|
193
|
+
gateFile: story.gateFile,
|
|
194
|
+
},
|
|
195
|
+
totalDurationMs: Date.now() - startTime,
|
|
196
|
+
};
|
|
197
|
+
if (options.reportPath) {
|
|
198
|
+
const { writeFileSync } = await import("node:fs");
|
|
199
|
+
writeFileSync(options.reportPath, JSON.stringify(report, null, 2));
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
success: false,
|
|
203
|
+
failedStory: story,
|
|
204
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
205
|
+
report,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const report = {
|
|
210
|
+
version: "1",
|
|
211
|
+
success: true,
|
|
212
|
+
stories: storyResults,
|
|
213
|
+
totalDurationMs: Date.now() - startTime,
|
|
214
|
+
};
|
|
215
|
+
if (options.reportPath) {
|
|
216
|
+
const { writeFileSync } = await import("node:fs");
|
|
217
|
+
writeFileSync(options.reportPath, JSON.stringify(report, null, 2));
|
|
218
|
+
}
|
|
219
|
+
return { success: true, report };
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/prd/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Story } from "./types";
|
|
2
|
+
export interface ScopeViolation {
|
|
3
|
+
category: "scope_violation";
|
|
4
|
+
message: string;
|
|
5
|
+
details: {
|
|
6
|
+
storyId: string;
|
|
7
|
+
violation: "forbidden_path" | "max_files_exceeded" | "max_lines_exceeded" | "default_forbidden";
|
|
8
|
+
path?: string;
|
|
9
|
+
actualFiles?: number;
|
|
10
|
+
maxFiles?: number;
|
|
11
|
+
actualLines?: number;
|
|
12
|
+
maxLines?: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface DiffStats {
|
|
16
|
+
changedFiles: string[];
|
|
17
|
+
totalLines: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Gets git diff stats against a base ref.
|
|
21
|
+
* For CI PRs, use origin/main. For local, use HEAD or a passed ref.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getDiffStats(baseRef?: string): DiffStats;
|
|
24
|
+
/**
|
|
25
|
+
* Validates that changed files match the story's scope constraints.
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateScope(story: Story, diffStats: DiffStats, defaultForbidden?: string[]): ScopeViolation[];
|
|
28
|
+
//# sourceMappingURL=scope-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-check.d.ts","sourceRoot":"","sources":["../../src/prd/scope-check.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAc,MAAM,SAAS,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,oBAAoB,GAAG,mBAAmB,CAAC;QAChG,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,MAAe,GAAG,SAAS,CA8BhE;AAiBD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,EACpB,gBAAgB,GAAE,MAAM,EAAO,GAC9B,cAAc,EAAE,CAyFlB"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Gets git diff stats against a base ref.
|
|
5
|
+
* For CI PRs, use origin/main. For local, use HEAD or a passed ref.
|
|
6
|
+
*/
|
|
7
|
+
export function getDiffStats(baseRef = "HEAD") {
|
|
8
|
+
try {
|
|
9
|
+
const changedFiles = execSync(`git diff --name-only ${baseRef}`, {
|
|
10
|
+
encoding: "utf-8",
|
|
11
|
+
cwd: process.cwd(),
|
|
12
|
+
})
|
|
13
|
+
.trim()
|
|
14
|
+
.split("\n")
|
|
15
|
+
.filter((f) => f.length > 0);
|
|
16
|
+
let totalLines = 0;
|
|
17
|
+
if (changedFiles.length > 0) {
|
|
18
|
+
const diffStat = execSync(`git diff --shortstat ${baseRef}`, {
|
|
19
|
+
encoding: "utf-8",
|
|
20
|
+
cwd: process.cwd(),
|
|
21
|
+
}).trim();
|
|
22
|
+
const match = diffStat.match(/(\d+)\s+files? changed/);
|
|
23
|
+
if (match) {
|
|
24
|
+
const linesMatch = diffStat.match(/(\d+)\s+insertions?/);
|
|
25
|
+
const deletionsMatch = diffStat.match(/(\d+)\s+deletions?/);
|
|
26
|
+
const insertions = linesMatch ? parseInt(linesMatch[1], 10) : 0;
|
|
27
|
+
const deletions = deletionsMatch ? parseInt(deletionsMatch[1], 10) : 0;
|
|
28
|
+
totalLines = insertions + deletions;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { changedFiles, totalLines };
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new Error(`Failed to get git diff stats: ${error instanceof Error ? error.message : String(error)}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Checks if a path matches any of the glob patterns.
|
|
39
|
+
* Simple prefix/suffix matching for now (not full glob).
|
|
40
|
+
*/
|
|
41
|
+
function matchesPattern(path, pattern) {
|
|
42
|
+
if (pattern.includes("**")) {
|
|
43
|
+
const prefix = pattern.replace(/\*\*/g, "");
|
|
44
|
+
return path.startsWith(prefix);
|
|
45
|
+
}
|
|
46
|
+
if (pattern.endsWith("*")) {
|
|
47
|
+
return path.startsWith(pattern.slice(0, -1));
|
|
48
|
+
}
|
|
49
|
+
return path === pattern;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validates that changed files match the story's scope constraints.
|
|
53
|
+
*/
|
|
54
|
+
export function validateScope(story, diffStats, defaultForbidden = []) {
|
|
55
|
+
const violations = [];
|
|
56
|
+
const scope = story.scope;
|
|
57
|
+
if (!scope) {
|
|
58
|
+
return violations;
|
|
59
|
+
}
|
|
60
|
+
const { changedFiles, totalLines } = diffStats;
|
|
61
|
+
for (const file of changedFiles) {
|
|
62
|
+
const filePath = resolve(process.cwd(), file);
|
|
63
|
+
if (scope.forbiddenPaths) {
|
|
64
|
+
for (const forbidden of scope.forbiddenPaths) {
|
|
65
|
+
if (matchesPattern(file, forbidden)) {
|
|
66
|
+
violations.push({
|
|
67
|
+
category: "scope_violation",
|
|
68
|
+
message: `Story "${story.id}" changed forbidden path: ${file}`,
|
|
69
|
+
details: {
|
|
70
|
+
storyId: story.id,
|
|
71
|
+
violation: "forbidden_path",
|
|
72
|
+
path: file,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const forbidden of defaultForbidden) {
|
|
79
|
+
if (matchesPattern(file, forbidden)) {
|
|
80
|
+
const isAllowed = scope.allowedPaths?.some((allowed) => matchesPattern(file, allowed));
|
|
81
|
+
if (!isAllowed) {
|
|
82
|
+
violations.push({
|
|
83
|
+
category: "scope_violation",
|
|
84
|
+
message: `Story "${story.id}" changed default-forbidden path: ${file}`,
|
|
85
|
+
details: {
|
|
86
|
+
storyId: story.id,
|
|
87
|
+
violation: "default_forbidden",
|
|
88
|
+
path: file,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (scope.allowedPaths && scope.allowedPaths.length > 0) {
|
|
95
|
+
const isAllowed = scope.allowedPaths.some((allowed) => matchesPattern(file, allowed));
|
|
96
|
+
if (!isAllowed) {
|
|
97
|
+
violations.push({
|
|
98
|
+
category: "scope_violation",
|
|
99
|
+
message: `Story "${story.id}" changed path outside allowed scope: ${file}`,
|
|
100
|
+
details: {
|
|
101
|
+
storyId: story.id,
|
|
102
|
+
violation: "forbidden_path",
|
|
103
|
+
path: file,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (scope.maxChangedFiles !== undefined && changedFiles.length > scope.maxChangedFiles) {
|
|
110
|
+
violations.push({
|
|
111
|
+
category: "scope_violation",
|
|
112
|
+
message: `Story "${story.id}" changed ${changedFiles.length} files, max allowed: ${scope.maxChangedFiles}`,
|
|
113
|
+
details: {
|
|
114
|
+
storyId: story.id,
|
|
115
|
+
violation: "max_files_exceeded",
|
|
116
|
+
actualFiles: changedFiles.length,
|
|
117
|
+
maxFiles: scope.maxChangedFiles,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (scope.maxChangedLines !== undefined && totalLines > scope.maxChangedLines) {
|
|
122
|
+
violations.push({
|
|
123
|
+
category: "scope_violation",
|
|
124
|
+
message: `Story "${story.id}" changed ${totalLines} lines, max allowed: ${scope.maxChangedLines}`,
|
|
125
|
+
details: {
|
|
126
|
+
storyId: story.id,
|
|
127
|
+
violation: "max_lines_exceeded",
|
|
128
|
+
actualLines: totalLines,
|
|
129
|
+
maxLines: scope.maxChangedLines,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return violations;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=scope-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-check.js","sourceRoot":"","sources":["../../src/prd/scope-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBpC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB,MAAM;IACnD,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,QAAQ,CAAC,wBAAwB,OAAO,EAAE,EAAE;YAC/D,QAAQ,EAAE,OAAO;YACjB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;SACnB,CAAC;aACC,IAAI,EAAE;aACN,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE/B,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,wBAAwB,OAAO,EAAE,EAAE;gBAC3D,QAAQ,EAAE,OAAO;gBACjB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;aACnB,CAAC,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACvD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;gBACzD,MAAM,cAAc,GAAG,QAAQ,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;gBAC5D,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChE,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACvE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;YACtC,CAAC;QACH,CAAC;QAED,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,iCAAiC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7G,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,IAAY,EAAE,OAAe;IACnD,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,IAAI,KAAK,OAAO,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAY,EACZ,SAAoB,EACpB,mBAA6B,EAAE;IAE/B,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAE1B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IAE/C,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;QAE9C,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;YACzB,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;gBAC7C,IAAI,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;oBACpC,UAAU,CAAC,IAAI,CAAC;wBACd,QAAQ,EAAE,iBAAiB;wBAC3B,OAAO,EAAE,UAAU,KAAK,CAAC,EAAE,6BAA6B,IAAI,EAAE;wBAC9D,OAAO,EAAE;4BACP,OAAO,EAAE,KAAK,CAAC,EAAE;4BACjB,SAAS,EAAE,gBAAgB;4BAC3B,IAAI,EAAE,IAAI;yBACX;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,gBAAgB,EAAE,CAAC;YACzC,IAAI,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;gBACpC,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;gBACvF,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,UAAU,CAAC,IAAI,CAAC;wBACd,QAAQ,EAAE,iBAAiB;wBAC3B,OAAO,EAAE,UAAU,KAAK,CAAC,EAAE,qCAAqC,IAAI,EAAE;wBACtE,OAAO,EAAE;4BACP,OAAO,EAAE,KAAK,CAAC,EAAE;4BACjB,SAAS,EAAE,mBAAmB;4BAC9B,IAAI,EAAE,IAAI;yBACX;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxD,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YACtF,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,UAAU,CAAC,IAAI,CAAC;oBACd,QAAQ,EAAE,iBAAiB;oBAC3B,OAAO,EAAE,UAAU,KAAK,CAAC,EAAE,yCAAyC,IAAI,EAAE;oBAC1E,OAAO,EAAE;wBACP,OAAO,EAAE,KAAK,CAAC,EAAE;wBACjB,SAAS,EAAE,gBAAgB;wBAC3B,IAAI,EAAE,IAAI;qBACX;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,GAAG,KAAK,CAAC,eAAe,EAAE,CAAC;QACvF,UAAU,CAAC,IAAI,CAAC;YACd,QAAQ,EAAE,iBAAiB;YAC3B,OAAO,EAAE,UAAU,KAAK,CAAC,EAAE,aAAa,YAAY,CAAC,MAAM,wBAAwB,KAAK,CAAC,eAAe,EAAE;YAC1G,OAAO,EAAE;gBACP,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,SAAS,EAAE,oBAAoB;gBAC/B,WAAW,EAAE,YAAY,CAAC,MAAM;gBAChC,QAAQ,EAAE,KAAK,CAAC,eAAe;aAChC;SACF,CAAC,CAAC;IACL,CAAC;IAED,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS,IAAI,UAAU,GAAG,KAAK,CAAC,eAAe,EAAE,CAAC;QAC9E,UAAU,CAAC,IAAI,CAAC;YACd,QAAQ,EAAE,iBAAiB;YAC3B,OAAO,EAAE,UAAU,KAAK,CAAC,EAAE,aAAa,UAAU,wBAAwB,KAAK,CAAC,eAAe,EAAE;YACjG,OAAO,EAAE;gBACP,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,SAAS,EAAE,oBAAoB;gBAC/B,WAAW,EAAE,UAAU;gBACvB,QAAQ,EAAE,KAAK,CAAC,eAAe;aAChC;SACF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface StoryScope {
|
|
2
|
+
allowedPaths?: string[];
|
|
3
|
+
forbiddenPaths?: string[];
|
|
4
|
+
maxChangedFiles?: number;
|
|
5
|
+
maxChangedLines?: number;
|
|
6
|
+
}
|
|
7
|
+
export type Story<TId extends string = string> = {
|
|
8
|
+
id: TId;
|
|
9
|
+
title: string;
|
|
10
|
+
gateFile: string;
|
|
11
|
+
dependsOn?: TId[];
|
|
12
|
+
scope?: StoryScope;
|
|
13
|
+
};
|
|
14
|
+
export type Prd<TId extends string = string> = {
|
|
15
|
+
stories: readonly Story<TId>[];
|
|
16
|
+
};
|
|
17
|
+
export type GateResult = {
|
|
18
|
+
status: "success" | "failed" | "timeout";
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/prd/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,KAAK,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,IAAI;IAC/C,EAAE,EAAE,GAAG,CAAC;IACR,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,IAAI;IAC7C,OAAO,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/prd/types.ts"],"names":[],"mappings":""}
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable, versioned report schemas for machine-readable gate outputs.
|
|
3
|
+
* All types are fully JSON-serializable (no Error objects, no functions).
|
|
4
|
+
*/
|
|
5
|
+
export interface SerializableError {
|
|
6
|
+
tag?: string;
|
|
7
|
+
name: string;
|
|
8
|
+
message: string;
|
|
9
|
+
stack?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface GateResultV1 {
|
|
12
|
+
version: "1";
|
|
13
|
+
status: "success" | "failed" | "timeout";
|
|
14
|
+
durationMs: number;
|
|
15
|
+
logs: unknown[];
|
|
16
|
+
evidence: {
|
|
17
|
+
requestIds: string[];
|
|
18
|
+
stagesSeen: string[];
|
|
19
|
+
actionsSeen: string[];
|
|
20
|
+
errorTags: string[];
|
|
21
|
+
};
|
|
22
|
+
error?: SerializableError;
|
|
23
|
+
}
|
|
24
|
+
export interface StoryResultV1 {
|
|
25
|
+
id: string;
|
|
26
|
+
title: string;
|
|
27
|
+
gateFile: string;
|
|
28
|
+
status: "success" | "failed" | "timeout";
|
|
29
|
+
durationMs: number;
|
|
30
|
+
error?: SerializableError;
|
|
31
|
+
}
|
|
32
|
+
export interface PrdReportV1 {
|
|
33
|
+
version: "1";
|
|
34
|
+
success: boolean;
|
|
35
|
+
stories: StoryResultV1[];
|
|
36
|
+
failedStory?: {
|
|
37
|
+
id: string;
|
|
38
|
+
title: string;
|
|
39
|
+
gateFile: string;
|
|
40
|
+
};
|
|
41
|
+
totalDurationMs: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Converts an Error (or Error-like object) into a SerializableError.
|
|
45
|
+
* Preserves Effect-tagged errors (_tag) when present.
|
|
46
|
+
*/
|
|
47
|
+
export declare function serializeError(error: unknown): SerializableError;
|
|
48
|
+
/**
|
|
49
|
+
* Sorts arrays deterministically (alphabetically) for stable output.
|
|
50
|
+
*/
|
|
51
|
+
export declare function sortDeterministic<T>(arr: T[]): T[];
|
|
52
|
+
/**
|
|
53
|
+
* Converts a GateResult to a fully serializable GateResultV1.
|
|
54
|
+
*/
|
|
55
|
+
export declare function toGateResultV1(result: {
|
|
56
|
+
status: "success" | "failed" | "timeout";
|
|
57
|
+
durationMs: number;
|
|
58
|
+
logs: unknown[];
|
|
59
|
+
evidence: {
|
|
60
|
+
requestIds: string[];
|
|
61
|
+
stagesSeen: string[];
|
|
62
|
+
actionsSeen: string[];
|
|
63
|
+
errorTags: string[];
|
|
64
|
+
};
|
|
65
|
+
error?: Error | unknown;
|
|
66
|
+
}): GateResultV1;
|
|
67
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,GAAG,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,WAAW,CAAC,EAAE;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAwBhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAElD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACrC,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;CACzB,GAAG,YAAY,CASf"}
|
package/dist/report.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable, versioned report schemas for machine-readable gate outputs.
|
|
3
|
+
* All types are fully JSON-serializable (no Error objects, no functions).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Converts an Error (or Error-like object) into a SerializableError.
|
|
7
|
+
* Preserves Effect-tagged errors (_tag) when present.
|
|
8
|
+
*/
|
|
9
|
+
export function serializeError(error) {
|
|
10
|
+
if (error instanceof Error) {
|
|
11
|
+
const errorWithTag = error;
|
|
12
|
+
return {
|
|
13
|
+
tag: errorWithTag._tag,
|
|
14
|
+
name: error.name || "Error",
|
|
15
|
+
message: error.message || String(error),
|
|
16
|
+
stack: error.stack,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (error && typeof error === "object" && "_tag" in error) {
|
|
20
|
+
const tagged = error;
|
|
21
|
+
return {
|
|
22
|
+
tag: tagged._tag,
|
|
23
|
+
name: tagged._tag,
|
|
24
|
+
message: tagged.message || String(error),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
name: "Error",
|
|
29
|
+
message: String(error),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sorts arrays deterministically (alphabetically) for stable output.
|
|
34
|
+
*/
|
|
35
|
+
export function sortDeterministic(arr) {
|
|
36
|
+
return [...arr].sort();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Converts a GateResult to a fully serializable GateResultV1.
|
|
40
|
+
*/
|
|
41
|
+
export function toGateResultV1(result) {
|
|
42
|
+
return {
|
|
43
|
+
version: "1",
|
|
44
|
+
status: result.status,
|
|
45
|
+
durationMs: result.durationMs,
|
|
46
|
+
logs: result.logs,
|
|
47
|
+
evidence: result.evidence,
|
|
48
|
+
error: result.error ? serializeError(result.error) : undefined,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA4CH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,MAAM,YAAY,GAAG,KAAkC,CAAC;QACxD,OAAO;YACL,GAAG,EAAE,YAAY,CAAC,IAAI;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,OAAO;YAC3B,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC;YACvC,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,KAAiE,CAAC;QACjF,OAAO;YACL,GAAG,EAAE,MAAM,CAAC,IAAI;YAChB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC;SACzC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;KACvB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAI,GAAQ;IAC3C,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAW9B;IACC,OAAO;QACL,OAAO,EAAE,GAAG;QACZ,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;KAC/D,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gateproof",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "E2E testing harness. Observe logs, run actions, assert results.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
"./cloudflare": {
|
|
14
14
|
"types": "./dist/cloudflare/index.d.ts",
|
|
15
15
|
"import": "./dist/cloudflare/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./prd": {
|
|
18
|
+
"types": "./dist/prd/index.d.ts",
|
|
19
|
+
"import": "./dist/prd/index.js"
|
|
16
20
|
}
|
|
17
21
|
},
|
|
18
22
|
"files": [
|
|
@@ -24,6 +28,7 @@
|
|
|
24
28
|
"build": "bun run build:tsc",
|
|
25
29
|
"build:tsc": "tsc -p tsconfig.build.json",
|
|
26
30
|
"typecheck": "tsc --noEmit",
|
|
31
|
+
"prd:validate": "bun run scripts/prd-validate.ts",
|
|
27
32
|
"test": "bun test",
|
|
28
33
|
"test:demo": "bun test test/demo.test.ts",
|
|
29
34
|
"test:production": "bun test test/demo.production.test.ts",
|
|
@@ -37,7 +42,7 @@
|
|
|
37
42
|
"gate:dev": "bun run gate:framework && bun run gate:demo && bun run gate:local",
|
|
38
43
|
"gate:all": "bun run gate:dev && bun run gate:production",
|
|
39
44
|
"demo:gate": "bun run gate:production",
|
|
40
|
-
"prepush": "bun run
|
|
45
|
+
"prepush": "bun run typecheck && bun run prd:validate && bun test",
|
|
41
46
|
"prepublishOnly": "bun run build && bun test"
|
|
42
47
|
},
|
|
43
48
|
"keywords": [
|