@caiqueoak/flow 0.6.0 → 0.8.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 +65 -43
- package/dist/artifacts/backlog.d.mts +16 -0
- package/dist/artifacts/backlog.d.mts.map +1 -0
- package/dist/artifacts/backlog.mjs +193 -0
- package/dist/artifacts/backlog.mjs.map +1 -0
- package/dist/artifacts/document.d.mts +6 -0
- package/dist/artifacts/document.d.mts.map +1 -0
- package/dist/artifacts/document.mjs +39 -0
- package/dist/artifacts/document.mjs.map +1 -0
- package/dist/artifacts/engineering.d.mts +5 -0
- package/dist/artifacts/engineering.d.mts.map +1 -0
- package/dist/artifacts/engineering.mjs +27 -0
- package/dist/artifacts/engineering.mjs.map +1 -0
- package/dist/artifacts/gates.d.mts +7 -0
- package/dist/artifacts/gates.d.mts.map +1 -0
- package/dist/artifacts/gates.mjs +42 -0
- package/dist/artifacts/gates.mjs.map +1 -0
- package/dist/artifacts/implementation-plan.d.mts +11 -0
- package/dist/artifacts/implementation-plan.d.mts.map +1 -0
- package/dist/artifacts/implementation-plan.mjs +30 -0
- package/dist/artifacts/implementation-plan.mjs.map +1 -0
- package/dist/artifacts/prd.d.mts +4 -0
- package/dist/artifacts/prd.d.mts.map +1 -0
- package/dist/artifacts/prd.mjs +13 -0
- package/dist/artifacts/prd.mjs.map +1 -0
- package/dist/artifacts/review.d.mts +11 -0
- package/dist/artifacts/review.d.mts.map +1 -0
- package/dist/artifacts/review.mjs +27 -0
- package/dist/artifacts/review.mjs.map +1 -0
- package/dist/artifacts/spec.d.mts +14 -0
- package/dist/artifacts/spec.d.mts.map +1 -0
- package/dist/artifacts/spec.mjs +50 -0
- package/dist/artifacts/spec.mjs.map +1 -0
- package/dist/artifacts/state.d.mts +44 -0
- package/dist/artifacts/state.d.mts.map +1 -0
- package/dist/artifacts/state.mjs +60 -0
- package/dist/artifacts/state.mjs.map +1 -0
- package/dist/artifacts/tasks.d.mts +10 -0
- package/dist/artifacts/tasks.d.mts.map +1 -0
- package/dist/artifacts/tasks.mjs +107 -0
- package/dist/artifacts/tasks.mjs.map +1 -0
- package/dist/artifacts/work-items.d.mts +21 -0
- package/dist/artifacts/work-items.d.mts.map +1 -0
- package/dist/artifacts/work-items.mjs +81 -0
- package/dist/artifacts/work-items.mjs.map +1 -0
- package/dist/cli/command-registry.d.mts +498 -0
- package/dist/cli/command-registry.d.mts.map +1 -0
- package/dist/cli/command-registry.mjs +230 -0
- package/dist/cli/command-registry.mjs.map +1 -0
- package/dist/cli.d.mts +3 -0
- package/dist/cli.d.mts.map +1 -0
- package/dist/cli.mjs +48 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/commands/doctor.d.mts +21 -0
- package/dist/commands/doctor.d.mts.map +1 -0
- package/dist/commands/doctor.mjs +79 -0
- package/dist/commands/doctor.mjs.map +1 -0
- package/dist/commands/gates.d.mts +14 -0
- package/dist/commands/gates.d.mts.map +1 -0
- package/dist/commands/gates.mjs +136 -0
- package/dist/commands/gates.mjs.map +1 -0
- package/dist/commands/graph.d.mts +11 -0
- package/dist/commands/graph.d.mts.map +1 -0
- package/dist/commands/graph.mjs +78 -0
- package/dist/commands/graph.mjs.map +1 -0
- package/dist/commands/init.d.mts +6 -0
- package/dist/commands/init.d.mts.map +1 -0
- package/dist/commands/init.mjs +126 -0
- package/dist/commands/init.mjs.map +1 -0
- package/dist/commands/migrate.d.mts +27 -0
- package/dist/commands/migrate.d.mts.map +1 -0
- package/dist/commands/migrate.mjs +379 -0
- package/dist/commands/migrate.mjs.map +1 -0
- package/dist/commands/operations.d.mts +13 -0
- package/dist/commands/operations.d.mts.map +1 -0
- package/dist/commands/operations.mjs +340 -0
- package/dist/commands/operations.mjs.map +1 -0
- package/dist/commands/route.d.mts +12 -0
- package/dist/commands/route.d.mts.map +1 -0
- package/dist/commands/route.mjs +45 -0
- package/dist/commands/route.mjs.map +1 -0
- package/dist/commands/schemas.d.mts +5 -0
- package/dist/commands/schemas.d.mts.map +1 -0
- package/dist/commands/schemas.mjs +14 -0
- package/dist/commands/schemas.mjs.map +1 -0
- package/dist/commands/status.d.mts +4 -0
- package/dist/commands/status.d.mts.map +1 -0
- package/dist/commands/status.mjs +18 -0
- package/dist/commands/status.mjs.map +1 -0
- package/dist/commands/sync.d.mts +18 -0
- package/dist/commands/sync.d.mts.map +1 -0
- package/dist/commands/sync.mjs +29 -0
- package/dist/commands/sync.mjs.map +1 -0
- package/dist/commands/trace.d.mts +30 -0
- package/dist/commands/trace.d.mts.map +1 -0
- package/dist/commands/trace.mjs +111 -0
- package/dist/commands/trace.mjs.map +1 -0
- package/dist/commands/validate.d.mts +8 -0
- package/dist/commands/validate.d.mts.map +1 -0
- package/dist/commands/validate.mjs +82 -0
- package/dist/commands/validate.mjs.map +1 -0
- package/dist/domain/contracts.d.mts +203 -0
- package/dist/domain/contracts.d.mts.map +1 -0
- package/dist/domain/contracts.mjs +126 -0
- package/dist/domain/contracts.mjs.map +1 -0
- package/dist/domain/types.d.ts +45 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +2 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/entry.d.ts +3 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +4 -0
- package/dist/entry.js.map +1 -0
- package/dist/shared/cli-io.d.mts +15 -0
- package/dist/shared/cli-io.d.mts.map +1 -0
- package/dist/shared/cli-io.mjs +83 -0
- package/dist/shared/cli-io.mjs.map +1 -0
- package/dist/shared/profiles.d.mts +17 -0
- package/dist/shared/profiles.d.mts.map +1 -0
- package/dist/shared/profiles.mjs +25 -0
- package/dist/shared/profiles.mjs.map +1 -0
- package/dist/shared/project-config.d.mts +21 -0
- package/dist/shared/project-config.d.mts.map +1 -0
- package/dist/shared/project-config.mjs +41 -0
- package/dist/shared/project-config.mjs.map +1 -0
- package/dist/shared/project-path.d.mts +3 -0
- package/dist/shared/project-path.d.mts.map +1 -0
- package/dist/shared/project-path.mjs +9 -0
- package/dist/shared/project-path.mjs.map +1 -0
- package/dist/shared/skill-installer.d.mts +2 -0
- package/dist/shared/skill-installer.d.mts.map +1 -0
- package/dist/shared/skill-installer.mjs +33 -0
- package/dist/shared/skill-installer.mjs.map +1 -0
- package/package.json +16 -8
- package/schemas/backlog.schema.json +85 -0
- package/schemas/config.schema.json +29 -0
- package/schemas/gates.schema.json +17 -0
- package/schemas/review.schema.json +28 -0
- package/schemas/tasks.schema.json +66 -0
- package/skills/flow/SKILL.md +10 -11
- package/skills/flow/build/step-01-execute-task.md +3 -3
- package/skills/flow/discovery/bmad-comparison.md +5 -0
- package/skills/flow/discovery/step-01-project.md +8 -3
- package/skills/flow/engineering/profiles/readability-first.md +1 -0
- package/skills/flow/engineering/step-02-synthesize.md +2 -2
- package/skills/flow/invariants.md +4 -4
- package/skills/flow/planning/step-01-create-tasks.md +3 -0
- package/skills/flow/planning/step-01-plan-work-item.md +2 -2
- package/skills/flow/planning/step-02-prepare-plan.md +1 -1
- package/skills/flow/review/step-01-review-work-item.md +2 -2
- package/skills/flow/specification/step-01-deepen-spec.md +7 -0
- package/src/artifacts/backlog.mjs +0 -157
- package/src/artifacts/document.mjs +0 -30
- package/src/artifacts/engineering.mjs +0 -26
- package/src/artifacts/gates.mjs +0 -28
- package/src/artifacts/implementation-plan.mjs +0 -27
- package/src/artifacts/prd.mjs +0 -12
- package/src/artifacts/state.mjs +0 -63
- package/src/artifacts/tasks.mjs +0 -90
- package/src/cli.mjs +0 -62
- package/src/commands/gates.mjs +0 -71
- package/src/commands/graph.mjs +0 -92
- package/src/commands/init.mjs +0 -111
- package/src/commands/migrate.mjs +0 -224
- package/src/commands/route.mjs +0 -135
- package/src/commands/status.mjs +0 -35
- package/src/commands/trace.mjs +0 -58
- package/src/commands/validate.mjs +0 -197
- package/src/shared/cli-io.mjs +0 -86
- package/src/shared/profiles.mjs +0 -27
- package/src/shared/project-config.mjs +0 -39
- package/src/shared/project-path.mjs +0 -10
- package/src/shared/skill-installer.mjs +0 -34
package/README.md
CHANGED
|
@@ -1,75 +1,97 @@
|
|
|
1
1
|
# Flow
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Canonical work-items
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Each `_flow/work-items/W###-*/` directory is the sole source of truth. Creating a work-item writes versionable shells for `spec.md`, `tasks.yaml`, `implementation-plan.md`, and `review.yaml`. A spec may remain `outlined`; tasks require a `ready` spec and implementation requires an approved plan.
|
|
6
|
+
|
|
7
|
+
Run `flow sync` to materialize `_flow/generated/backlog.yaml` and `_flow/generated/graph.md`. Sync only reads canonical work-items and only writes `_flow/generated/`; it never alters a canonical source. Generated files are disposable and ignored by Git.
|
|
8
|
+
|
|
9
|
+
Complete a task with one commit whose exact subject is `type(domain): description [W###-T###]` and whose body contains matching `Flow-Work-Item` and `Flow-Task` trailers. Complete review with `flow work-item review-complete W### --domain domain`, which creates `chore(domain): complete review [W###]`. The review commit may contain only that item's `spec.md` and `review.yaml`; a deliberate review-time `spec.md` amendment belongs in the same commit.
|
|
10
|
+
|
|
11
|
+
CLI-first, repository-resumable delivery for coding agents. Flow keeps deterministic state, IDs, dependency routing, approvals, Git evidence, gates and migrations in the CLI while the agent owns product and engineering judgment.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
6
14
|
|
|
7
15
|
```bash
|
|
8
16
|
npm install --save-dev @caiqueoak/flow
|
|
9
17
|
npx --no-install flow init --runtime codex
|
|
18
|
+
npx --no-install flow doctor --quick --json
|
|
10
19
|
```
|
|
11
20
|
|
|
12
|
-
|
|
21
|
+
The project records the Flow package version that initialized or explicitly updated its artifacts. Flow never checks npm or upgrades a project automatically.
|
|
13
22
|
|
|
14
|
-
##
|
|
23
|
+
## Workflow
|
|
15
24
|
|
|
16
|
-
|
|
25
|
+
`doctor quick → discovery → PRD → engineering → outlined backlog → selected eligible item → ready spec → tasks and plan → approval → implementation → gates → implementation commit → evidence persistence → review`
|
|
17
26
|
|
|
18
|
-
The
|
|
27
|
+
The backlog contains every known work-item and its DAG, but deep specs are created on demand. `spec_maturity: outlined|ready` is independent of `state: pending|in_progress|completed`. Eligibility is derived from completed dependencies plus resolved external/decision blockers; then routing uses lower priority number and lower numeric ID.
|
|
19
28
|
|
|
20
|
-
|
|
29
|
+
Generated `backlog.yaml` and `graph.md` are disposable projections under `_flow/generated/`. Product truth lives in `docs/prd.md`, technical truth in `docs/engineering.md`, and work-item maturity/DAG in canonical work-item specs.
|
|
21
30
|
|
|
22
|
-
##
|
|
31
|
+
## CLI
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
Run `flow --help` or `flow <command> --help`. Help and parsing share one declarative command registry, so unknown flags and invalid combinations are rejected before writes.
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
Core read operations:
|
|
27
36
|
|
|
28
|
-
|
|
37
|
+
```bash
|
|
38
|
+
flow doctor --quick --json
|
|
39
|
+
flow status
|
|
40
|
+
flow route --json
|
|
41
|
+
flow validate [--work-item W015] [--gates]
|
|
42
|
+
flow trace W015-T003
|
|
43
|
+
flow gates list|run [--id ID|--task W015-T003|--work-item W015|--stage task|work-item-review|full|--all]
|
|
44
|
+
```
|
|
29
45
|
|
|
30
|
-
|
|
46
|
+
Structured writes:
|
|
31
47
|
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
```bash
|
|
49
|
+
flow work-item create --title "Customer search" --priority 2
|
|
50
|
+
flow work-item dependencies W015 --depends-on W003,W009
|
|
51
|
+
flow work-item blocker-add W015 --id vendor-approval --type external_action --description "Vendor approval"
|
|
52
|
+
flow work-item blocker-resolve W015 --id vendor-approval
|
|
53
|
+
flow work-item promote W015
|
|
54
|
+
flow task create W015 --title "Add query contract"
|
|
55
|
+
flow task start W015-T001
|
|
56
|
+
flow scope validate W015-T001 --files src/query.js,test/query.test.js
|
|
57
|
+
flow task commit W015-T001 --message "feat(search): add customer query [W015-T001]" --files src/query.js,test/query.test.js
|
|
58
|
+
flow approval record _flow/work-items/W015-customer-search/implementation-plan.md
|
|
59
|
+
```
|
|
40
60
|
|
|
41
|
-
|
|
61
|
+
## Git traceability
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
`W###-T###` is permanent task identity. A repository-mutating task creates exactly one coherent implementation commit. Its objective message contains the task ID for human visibility and its body contains the canonical machine evidence:
|
|
44
64
|
|
|
45
|
-
|
|
65
|
+
```text
|
|
66
|
+
Flow-Work-Item: W015
|
|
67
|
+
Flow-Task: W015-T003
|
|
68
|
+
```
|
|
46
69
|
|
|
47
|
-
|
|
48
|
-
| ---------------------------------------- | --------------------------------------------------------------------------- |
|
|
49
|
-
| `npx --no-install flow init` | Configure or add/refresh runtime integrations. |
|
|
50
|
-
| `npx --no-install flow migrate` | Atomic structural migration, followed by semantic reconciliation via /flow. |
|
|
51
|
-
| `npx --no-install flow status` | Progress and dependency/external blockers. |
|
|
52
|
-
| `npx --no-install flow validate` | Fast artifact integrity, approvals, DAGs and traceability checks. |
|
|
53
|
-
| `npx --no-install flow validate --gates` | Full validation, including configured deterministic project gates. |
|
|
54
|
-
| `npx --no-install flow route --json` | Next legal step and required context. |
|
|
55
|
-
| `npx --no-install flow graph` | Regenerate dependency graph. |
|
|
56
|
-
| `npx --no-install flow trace W015-T003` | Resolve a task's implementation commit. |
|
|
70
|
+
`flow trace W015-T003` resolves a unique reachable commit only when its subject and both trailers agree. SHA evidence is never stored in tasks.yaml. `flow trace W015` aggregates reachable implementation commits by `Flow-Work-Item`, including task, SHA, title and changed files.
|
|
57
71
|
|
|
58
|
-
|
|
72
|
+
## Gates and performance
|
|
59
73
|
|
|
60
|
-
|
|
74
|
+
`flow validate` performs cheap structural checks and does not run the project test suite. `--gates` is explicit. Gates declare stage (`task`, `work-item-review`, `full`), expected cost and optional task/work-item scope. JSON output includes duration, process and Git-read metrics. Engineering maps changed paths/contracts to the smallest safe test scope and falls back to broader checks when impact is unknown.
|
|
61
75
|
|
|
62
|
-
|
|
76
|
+
## Migration
|
|
63
77
|
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
```bash
|
|
79
|
+
flow doctor
|
|
80
|
+
flow migrate --plan --json
|
|
81
|
+
flow migrate --apply
|
|
67
82
|
```
|
|
68
83
|
|
|
69
|
-
|
|
84
|
+
Planning is read-only. Apply rechecks preconditions, transforms a staging copy, validates it, swaps only on success and preserves the prior `_flow` under `_flow-backups`. Structural migration never invents semantic decisions; ambiguous legacy truths route to assisted reconcile.
|
|
70
85
|
|
|
71
|
-
|
|
86
|
+
## Development
|
|
72
87
|
|
|
73
|
-
|
|
88
|
+
```bash
|
|
89
|
+
npm run typecheck
|
|
90
|
+
npm run lint
|
|
91
|
+
npm run format:check
|
|
92
|
+
npm test
|
|
93
|
+
npm run test:package
|
|
94
|
+
npm run pack:check
|
|
95
|
+
```
|
|
74
96
|
|
|
75
|
-
|
|
97
|
+
The npm binary points at ESM build output. Runtime sources remain JavaScript in this staged packaging migration and are not strict TypeScript-checked; a full source conversion is intentionally separate. The published package contains compiled source, skills and generated JSON Schemas.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class ArtifactValidationError extends Error {
|
|
2
|
+
constructor(message: any);
|
|
3
|
+
}
|
|
4
|
+
export declare function parseBacklog(text: any, { source }?: {
|
|
5
|
+
source?: string | undefined;
|
|
6
|
+
}): {
|
|
7
|
+
schema_version: number;
|
|
8
|
+
work_items: any;
|
|
9
|
+
};
|
|
10
|
+
export declare function validateAcyclic(items: any): void;
|
|
11
|
+
export declare function deriveExecutionStatus(item: any, byId: any): {
|
|
12
|
+
status: string;
|
|
13
|
+
reasons: any[];
|
|
14
|
+
};
|
|
15
|
+
export declare function topologicalOrder(items: any): any[];
|
|
16
|
+
//# sourceMappingURL=backlog.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backlog.d.mts","sourceRoot":"","sources":["../../src/artifacts/backlog.mjs"],"names":[],"mappings":"AAQA,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,YAAY,OAAO,KAAA,EAGlB;CACF;AAsBD,wBAAgB,YAAY,CAAC,IAAI,KAAA,EAAE,EAAE,MAAuB,EAAE;;CAAK;;;EAwFlE;AAED,wBAAgB,eAAe,CAAC,KAAK,KAAA,QAgBpC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,KAAA,EAAE,IAAI,KAAA;;;EAU/C;AAED,wBAAgB,gBAAgB,CAAC,KAAK,KAAA,SA6BrC"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { parseDocument } from 'yaml';
|
|
2
|
+
import { BACKLOG_SCHEMA_VERSION, LIFECYCLE_STATES, SPEC_MATURITIES, WORK_ITEM_ID as WORK_ITEM_ID_PATTERN } from '../domain/contracts.mjs';
|
|
3
|
+
export class ArtifactValidationError extends Error {
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'ArtifactValidationError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const KINDS = new Set(['feature', 'technical', 'maintenance']);
|
|
10
|
+
const STATES = new Set(LIFECYCLE_STATES);
|
|
11
|
+
const SPEC_MATURITY = new Set(SPEC_MATURITIES);
|
|
12
|
+
const WORK_ITEM_ID = WORK_ITEM_ID_PATTERN;
|
|
13
|
+
const WORK_ITEM_FOLDER = /^W\d{3,}-[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
14
|
+
function fail(message) {
|
|
15
|
+
throw new ArtifactValidationError(message);
|
|
16
|
+
}
|
|
17
|
+
function requireObject(value, label) {
|
|
18
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
19
|
+
fail(`${label} must be a mapping.`);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function requireString(value, label) {
|
|
23
|
+
if (typeof value !== 'string' || !value.trim())
|
|
24
|
+
fail(`${label} must be a non-empty string.`);
|
|
25
|
+
return value.trim();
|
|
26
|
+
}
|
|
27
|
+
export function parseBacklog(text, { source = 'backlog.yaml' } = {}) {
|
|
28
|
+
const document = parseDocument(text, { prettyErrors: false, uniqueKeys: true });
|
|
29
|
+
if (document.errors.length)
|
|
30
|
+
fail(`${source} is invalid: ${document.errors[0].message}`);
|
|
31
|
+
const backlog = requireObject(document.toJS(), source);
|
|
32
|
+
if (backlog.schema_version !== BACKLOG_SCHEMA_VERSION)
|
|
33
|
+
fail(`${source} schema_version must be ${BACKLOG_SCHEMA_VERSION}.`);
|
|
34
|
+
if (!Array.isArray(backlog.work_items))
|
|
35
|
+
fail(`${source} work_items must be a list.`);
|
|
36
|
+
const ids = new Set();
|
|
37
|
+
const items = backlog.work_items.map((raw, index) => {
|
|
38
|
+
const label = `work_items[${index}]`;
|
|
39
|
+
const item = requireObject(raw, label);
|
|
40
|
+
const id = requireString(item.id, `${label}.id`);
|
|
41
|
+
if (!WORK_ITEM_ID.test(id))
|
|
42
|
+
fail(`${label}.id must use W followed by a zero-padded numeric sequence, e.g. W015.`);
|
|
43
|
+
if (ids.has(id))
|
|
44
|
+
fail(`${source} contains duplicate work-item ID '${id}'.`);
|
|
45
|
+
ids.add(id);
|
|
46
|
+
const folder = requireString(item.folder ?? item.path, `${label}.folder`);
|
|
47
|
+
if (!WORK_ITEM_FOLDER.test(folder))
|
|
48
|
+
fail(`${label}.folder must use W###-kebab-case, e.g. W015-learner-web-application.`);
|
|
49
|
+
const numericId = id.slice(1);
|
|
50
|
+
if (!folder.startsWith(`W${numericId}-`))
|
|
51
|
+
fail(`${label}.folder must preserve the numeric sequence from ${id}.`);
|
|
52
|
+
if (!KINDS.has(item.kind))
|
|
53
|
+
fail(`${label}.kind must be feature, technical, or maintenance.`);
|
|
54
|
+
const title = requireString(item.title, `${label}.title`);
|
|
55
|
+
const state = item.state ?? item.status;
|
|
56
|
+
if (!STATES.has(state))
|
|
57
|
+
fail(`${label}.state must be pending, in_progress, or completed.`);
|
|
58
|
+
if (!Number.isInteger(item.priority) || item.priority < 1)
|
|
59
|
+
fail(`${label}.priority must be a positive integer.`);
|
|
60
|
+
const specMaturity = item.spec_maturity ?? (item.state === 'pending' ? 'outlined' : 'ready');
|
|
61
|
+
if (!SPEC_MATURITY.has(specMaturity))
|
|
62
|
+
fail(`${label}.spec_maturity must be outlined or ready.`);
|
|
63
|
+
if (state !== 'pending' && specMaturity !== 'ready')
|
|
64
|
+
fail(`${id}: in_progress or completed work must have spec_maturity ready.`);
|
|
65
|
+
if (!Array.isArray(item.depends_on ?? []))
|
|
66
|
+
fail(`${label}.depends_on must be a list.`);
|
|
67
|
+
if (!Array.isArray(item.blockers ?? []))
|
|
68
|
+
fail(`${label}.blockers must be a list when present.`);
|
|
69
|
+
const dependencies = [];
|
|
70
|
+
const seenDependencies = new Set();
|
|
71
|
+
for (const rawDependency of item.depends_on ?? []) {
|
|
72
|
+
const dependency = requireString(rawDependency, `${label}.depends_on entry`);
|
|
73
|
+
if (!WORK_ITEM_ID.test(dependency))
|
|
74
|
+
fail(`${label}.depends_on contains invalid work-item ID '${dependency}'.`);
|
|
75
|
+
if (dependency === id)
|
|
76
|
+
fail(`Work item '${id}' cannot depend on itself.`);
|
|
77
|
+
if (seenDependencies.has(dependency))
|
|
78
|
+
fail(`Work item '${id}' lists dependency '${dependency}' more than once.`);
|
|
79
|
+
seenDependencies.add(dependency);
|
|
80
|
+
dependencies.push(dependency);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
id,
|
|
84
|
+
folder,
|
|
85
|
+
kind: item.kind,
|
|
86
|
+
title,
|
|
87
|
+
state,
|
|
88
|
+
priority: item.priority,
|
|
89
|
+
spec_maturity: specMaturity,
|
|
90
|
+
depends_on: dependencies,
|
|
91
|
+
blockers: (item.blockers ?? []).map((blocker) => {
|
|
92
|
+
requireObject(blocker, `${id} blocker`);
|
|
93
|
+
if (!/^[a-z][a-z0-9-]*$/.test(blocker.id ?? ''))
|
|
94
|
+
fail(`${id} blocker.id must be stable kebab-case.`);
|
|
95
|
+
if (!['external_action', 'consequential_decision'].includes(blocker.type))
|
|
96
|
+
fail(`${id} blocker.type is invalid.`);
|
|
97
|
+
requireString(blocker.description, `${id} blocker.description`);
|
|
98
|
+
if (!['unresolved', 'resolved'].includes(blocker.status))
|
|
99
|
+
fail(`${id} blocker.status is invalid.`);
|
|
100
|
+
return blocker;
|
|
101
|
+
}),
|
|
102
|
+
...(item.objective ? { objective: requireString(item.objective, `${label}.objective`) } : {}),
|
|
103
|
+
boundaries: Array.isArray(item.boundaries) ? item.boundaries : [],
|
|
104
|
+
requirements: Array.isArray(item.requirements) ? item.requirements : [],
|
|
105
|
+
provides: Array.isArray(item.provides) ? item.provides : [],
|
|
106
|
+
consumes: Array.isArray(item.consumes) ? item.consumes : [],
|
|
107
|
+
dependency_rationale: item.dependency_rationale &&
|
|
108
|
+
typeof item.dependency_rationale === 'object' &&
|
|
109
|
+
!Array.isArray(item.dependency_rationale)
|
|
110
|
+
? item.dependency_rationale
|
|
111
|
+
: {}
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
const byId = new Map(items.map((item) => [item.id, item]));
|
|
115
|
+
for (const item of items) {
|
|
116
|
+
for (const dependency of item.depends_on) {
|
|
117
|
+
if (!byId.has(dependency))
|
|
118
|
+
fail(`Work item '${item.id}' depends on unknown work item '${dependency}'.`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
validateAcyclic(items);
|
|
122
|
+
if (items.filter((item) => item.state === 'in_progress').length > 1)
|
|
123
|
+
fail('Only one mutating work item may be in_progress.');
|
|
124
|
+
return { schema_version: BACKLOG_SCHEMA_VERSION, work_items: items };
|
|
125
|
+
}
|
|
126
|
+
export function validateAcyclic(items) {
|
|
127
|
+
const indegree = new Map(items.map((item) => [item.id, item.depends_on.length]));
|
|
128
|
+
const dependents = new Map(items.map((item) => [item.id, []]));
|
|
129
|
+
for (const item of items)
|
|
130
|
+
for (const dependency of item.depends_on)
|
|
131
|
+
dependents.get(dependency).push(item.id);
|
|
132
|
+
const queue = items.filter((item) => indegree.get(item.id) === 0).map((item) => item.id);
|
|
133
|
+
let visited = 0;
|
|
134
|
+
while (queue.length) {
|
|
135
|
+
const id = queue.shift();
|
|
136
|
+
visited += 1;
|
|
137
|
+
for (const dependent of dependents.get(id)) {
|
|
138
|
+
const next = indegree.get(dependent) - 1;
|
|
139
|
+
indegree.set(dependent, next);
|
|
140
|
+
if (next === 0)
|
|
141
|
+
queue.push(dependent);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (visited !== items.length)
|
|
145
|
+
fail('backlog.yaml work-item dependencies contain a cycle.');
|
|
146
|
+
}
|
|
147
|
+
export function deriveExecutionStatus(item, byId) {
|
|
148
|
+
if (item.state === 'completed')
|
|
149
|
+
return { status: 'completed', reasons: [] };
|
|
150
|
+
const incompleteDependencies = item.depends_on.filter((id) => byId.get(id)?.state !== 'completed');
|
|
151
|
+
const unresolvedBlockers = item.blockers.filter((blocker) => blocker.status === 'unresolved');
|
|
152
|
+
const reasons = [
|
|
153
|
+
...incompleteDependencies.map((id) => ({ type: 'dependency', ref: id })),
|
|
154
|
+
...unresolvedBlockers.map((blocker) => ({ type: 'blocker', ref: blocker.id, blocker_type: blocker.type }))
|
|
155
|
+
];
|
|
156
|
+
if (reasons.length)
|
|
157
|
+
return { status: 'blocked', reasons };
|
|
158
|
+
return { status: item.state === 'in_progress' ? 'in_progress' : 'eligible', reasons: [] };
|
|
159
|
+
}
|
|
160
|
+
export function topologicalOrder(items) {
|
|
161
|
+
const byId = new Map(items.map((item) => [item.id, item]));
|
|
162
|
+
const remaining = new Map(items.map((item) => [item.id, item.depends_on.length]));
|
|
163
|
+
const dependents = new Map(items.map((item) => [item.id, []]));
|
|
164
|
+
for (const item of items)
|
|
165
|
+
for (const dependency of item.depends_on)
|
|
166
|
+
dependents.get(dependency).push(item.id);
|
|
167
|
+
const compare = (a, b) => a.localeCompare(b);
|
|
168
|
+
for (const ids of dependents.values())
|
|
169
|
+
ids.sort(compare);
|
|
170
|
+
const ready = items
|
|
171
|
+
.filter((item) => item.depends_on.length === 0)
|
|
172
|
+
.map((item) => item.id)
|
|
173
|
+
.sort(compare);
|
|
174
|
+
const levels = new Map(ready.map((id) => [id, 0]));
|
|
175
|
+
const orderedIds = [];
|
|
176
|
+
while (ready.length) {
|
|
177
|
+
const id = ready.shift();
|
|
178
|
+
orderedIds.push(id);
|
|
179
|
+
for (const dependent of dependents.get(id)) {
|
|
180
|
+
levels.set(dependent, Math.max(levels.get(dependent) ?? 0, (levels.get(id) ?? 0) + 1));
|
|
181
|
+
const count = remaining.get(dependent) - 1;
|
|
182
|
+
remaining.set(dependent, count);
|
|
183
|
+
if (count === 0) {
|
|
184
|
+
ready.push(dependent);
|
|
185
|
+
ready.sort(compare);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return orderedIds
|
|
190
|
+
.map((id) => byId.get(id))
|
|
191
|
+
.sort((a, b) => levels.get(a.id) - levels.get(b.id) || compare(a.id, b.id));
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=backlog.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backlog.mjs","sourceRoot":"","sources":["../../src/artifacts/backlog.mjs"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.mts","sourceRoot":"","sources":["../../src/artifacts/document.mjs"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB,CAAC,IAAI,KAAA,OAEpC;AACD,wBAAgB,gBAAgB,CAAC,IAAI,KAAA,OAQpC;AACD,wBAAgB,gBAAgB,CAAC,IAAI,KAAA,EAAE,QAAQ,KAAA;;EAe9C"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { parseDocument } from 'yaml';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
export function documentRevision(text) {
|
|
4
|
+
return createHash('sha256').update(text).digest('hex');
|
|
5
|
+
}
|
|
6
|
+
export function documentMetadata(text) {
|
|
7
|
+
const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
8
|
+
if (!match)
|
|
9
|
+
throw new Error('Missing YAML frontmatter.');
|
|
10
|
+
const doc = parseDocument(match[1], { uniqueKeys: true });
|
|
11
|
+
if (doc.errors.length)
|
|
12
|
+
throw new Error(doc.errors[0].message);
|
|
13
|
+
const value = doc.toJS();
|
|
14
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
15
|
+
throw new Error('Frontmatter must be a mapping.');
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
export function validateDocument(text, headings) {
|
|
19
|
+
let metadata = {};
|
|
20
|
+
const errors = [];
|
|
21
|
+
try {
|
|
22
|
+
metadata = documentMetadata(text);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
errors.push(error.message);
|
|
26
|
+
}
|
|
27
|
+
if (metadata.schema_version !== 1)
|
|
28
|
+
errors.push('schema_version must be 1.');
|
|
29
|
+
if (!['draft', 'approved'].includes(metadata.status))
|
|
30
|
+
errors.push('status must be draft or approved.');
|
|
31
|
+
if (metadata.status === 'approved' && (!metadata.approved_at || Number.isNaN(Date.parse(metadata.approved_at))))
|
|
32
|
+
errors.push('approved_at must record the human approval timestamp.');
|
|
33
|
+
const actual = new Set(text.split(/\r?\n/).filter((line) => /^#{1,2} /.test(line)));
|
|
34
|
+
for (const heading of headings)
|
|
35
|
+
if (!actual.has(heading))
|
|
36
|
+
errors.push(`Missing ${heading}.`);
|
|
37
|
+
return { ...metadata, errors };
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=document.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.mjs","sourceRoot":"","sources":["../../src/artifacts/document.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,MAAM,UAAU,gBAAgB,CAAC,IAAI;IACnC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AACD,MAAM,UAAU,gBAAgB,CAAC,IAAI;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACnE,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACzB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACnH,OAAO,KAAK,CAAC;AACf,CAAC;AACD,MAAM,UAAU,gBAAgB,CAAC,IAAI,EAAE,QAAQ;IAC7C,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,IAAI,CAAC;QACH,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,QAAQ,CAAC,cAAc,KAAK,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAC5E,IAAI,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IACvG,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ,CAAC,WAAW,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;QAC7G,MAAM,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpF,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,WAAW,OAAO,GAAG,CAAC,CAAC;IAC7F,OAAO,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineering.d.mts","sourceRoot":"","sources":["../../src/artifacts/engineering.mjs"],"names":[],"mappings":"AAEA,eAAO,MAAM,oBAAoB,UAehC,CAAC;AACF,wBAAgB,2BAA2B,CAAC,IAAI,KAAA;;EAO/C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { validateDocument } from './document.mjs';
|
|
2
|
+
import { READABILITY_FIRST_PROFILE } from '../shared/profiles.mjs';
|
|
3
|
+
export const ENGINEERING_HEADINGS = [
|
|
4
|
+
'# Engineering',
|
|
5
|
+
'## System shape',
|
|
6
|
+
'## Modules and ownership',
|
|
7
|
+
'## Dependency direction and boundaries',
|
|
8
|
+
'## Vertical slices and code organization',
|
|
9
|
+
'## Naming and readability conventions',
|
|
10
|
+
'## Data ownership and persistence',
|
|
11
|
+
'## Error handling',
|
|
12
|
+
'## Testing and verification',
|
|
13
|
+
'## Dependencies and external services',
|
|
14
|
+
'## Security and operations',
|
|
15
|
+
'## Deterministic gates',
|
|
16
|
+
'## Deferred complexity',
|
|
17
|
+
'## Exceptions'
|
|
18
|
+
];
|
|
19
|
+
export function validateEngineeringDocument(text) {
|
|
20
|
+
const result = validateDocument(text, ENGINEERING_HEADINGS);
|
|
21
|
+
if (result.baseline?.profile !== READABILITY_FIRST_PROFILE.id)
|
|
22
|
+
result.errors.push('baseline.profile must be flow/readability-first@1.');
|
|
23
|
+
if (!['improve', 'preserve', 'not_applicable'].includes(result.baseline?.existing_code_policy))
|
|
24
|
+
result.errors.push('baseline.existing_code_policy is invalid.');
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=engineering.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineering.mjs","sourceRoot":"","sources":["../../src/artifacts/engineering.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,eAAe;IACf,iBAAiB;IACjB,0BAA0B;IAC1B,wCAAwC;IACxC,0CAA0C;IAC1C,uCAAuC;IACvC,mCAAmC;IACnC,mBAAmB;IACnB,6BAA6B;IAC7B,uCAAuC;IACvC,4BAA4B;IAC5B,wBAAwB;IACxB,wBAAwB;IACxB,eAAe;CAChB,CAAC;AACF,MAAM,UAAU,2BAA2B,CAAC,IAAI;IAC9C,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,QAAQ,EAAE,OAAO,KAAK,yBAAyB,CAAC,EAAE;QAC3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;IAC3E,IAAI,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,oBAAoB,CAAC;QAC5F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gates.d.mts","sourceRoot":"","sources":["../../src/artifacts/gates.mjs"],"names":[],"mappings":"AAMA,wBAAgB,UAAU,CAAC,IAAI,KAAA,EAAE,EAAE,MAAqB,EAAE;;CAAK;;;EAgC9D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { parseDocument } from 'yaml';
|
|
2
|
+
import { ArtifactValidationError } from './backlog.mjs';
|
|
3
|
+
import { GATES_SCHEMA_VERSION } from '../domain/contracts.mjs';
|
|
4
|
+
const KINDS = new Set(['command', 'builtin']);
|
|
5
|
+
export function parseGates(text, { source = 'gates.yaml' } = {}) {
|
|
6
|
+
const document = parseDocument(text, { prettyErrors: false, uniqueKeys: true });
|
|
7
|
+
if (document.errors.length)
|
|
8
|
+
throw new ArtifactValidationError(`${source} is invalid: ${document.errors[0].message}`);
|
|
9
|
+
const value = document.toJS();
|
|
10
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
11
|
+
throw new ArtifactValidationError(`${source} must be a mapping.`);
|
|
12
|
+
if (value.schema_version !== GATES_SCHEMA_VERSION)
|
|
13
|
+
throw new ArtifactValidationError(`${source} schema_version must be ${GATES_SCHEMA_VERSION}.`);
|
|
14
|
+
if (!Array.isArray(value.gates))
|
|
15
|
+
throw new ArtifactValidationError(`${source} gates must be a list.`);
|
|
16
|
+
const ids = new Set();
|
|
17
|
+
const gates = value.gates.map((gate, index) => {
|
|
18
|
+
if (!gate || typeof gate !== 'object' || Array.isArray(gate))
|
|
19
|
+
throw new ArtifactValidationError(`gates[${index}] must be a mapping.`);
|
|
20
|
+
if (typeof gate.id !== 'string' || !/^[a-z][a-z0-9-]*$/.test(gate.id))
|
|
21
|
+
throw new ArtifactValidationError(`gates[${index}].id must be lower kebab-case.`);
|
|
22
|
+
if (ids.has(gate.id))
|
|
23
|
+
throw new ArtifactValidationError(`duplicate gate '${gate.id}'.`);
|
|
24
|
+
ids.add(gate.id);
|
|
25
|
+
if (!KINDS.has(gate.kind))
|
|
26
|
+
throw new ArtifactValidationError(`${gate.id}.kind must be command or builtin.`);
|
|
27
|
+
if (gate.kind === 'command' && (!gate.command || typeof gate.command !== 'string'))
|
|
28
|
+
throw new ArtifactValidationError(`${gate.id} command gate requires command.`);
|
|
29
|
+
const stage = gate.stage ?? 'full';
|
|
30
|
+
if (!['task', 'work-item-review', 'full'].includes(stage))
|
|
31
|
+
throw new ArtifactValidationError(`${gate.id}.stage must be task, work-item-review or full.`);
|
|
32
|
+
const cost = gate.cost ?? 'medium';
|
|
33
|
+
if (!['low', 'medium', 'high'].includes(cost))
|
|
34
|
+
throw new ArtifactValidationError(`${gate.id}.cost must be low, medium or high.`);
|
|
35
|
+
const scope = gate.scope ?? {};
|
|
36
|
+
if (!scope || typeof scope !== 'object' || Array.isArray(scope))
|
|
37
|
+
throw new ArtifactValidationError(`${gate.id}.scope must be a mapping.`);
|
|
38
|
+
return { ...gate, stage, cost, scope, blocking: gate.blocking !== false };
|
|
39
|
+
});
|
|
40
|
+
return { schema_version: GATES_SCHEMA_VERSION, gates };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=gates.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gates.mjs","sourceRoot":"","sources":["../../src/artifacts/gates.mjs"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { documentRevision } from './document.mjs';
|
|
2
|
+
export declare const PLAN_HEADINGS: string[];
|
|
3
|
+
export declare function validateImplementationPlan(text: any, { workItem, engineeringText, specText, checkRevisions }: {
|
|
4
|
+
checkRevisions?: boolean | undefined;
|
|
5
|
+
engineeringText: any;
|
|
6
|
+
specText: any;
|
|
7
|
+
workItem: any;
|
|
8
|
+
}): {
|
|
9
|
+
errors: any[];
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=implementation-plan.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"implementation-plan.d.mts","sourceRoot":"","sources":["../../src/artifacts/implementation-plan.mjs"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,eAAO,MAAM,aAAa,UAazB,CAAC;AACF,wBAAgB,0BAA0B,CAAC,IAAI,KAAA,EAAE,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAqB,EAAE;;;;;CAAA;;EAU9G"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { documentRevision, validateDocument } from './document.mjs';
|
|
2
|
+
export { documentRevision } from './document.mjs';
|
|
3
|
+
export const PLAN_HEADINGS = [
|
|
4
|
+
'# Implementation Plan',
|
|
5
|
+
'## Outcome',
|
|
6
|
+
'## Current state',
|
|
7
|
+
'## Proposed changes',
|
|
8
|
+
'## Execution sequence',
|
|
9
|
+
'## Task mapping',
|
|
10
|
+
'## Data and control flow',
|
|
11
|
+
'## Engineering compliance',
|
|
12
|
+
'## Tests and validation',
|
|
13
|
+
'## Risks and rollback',
|
|
14
|
+
'## Deliberately excluded',
|
|
15
|
+
'## Human decisions required'
|
|
16
|
+
];
|
|
17
|
+
export function validateImplementationPlan(text, { workItem, engineeringText, specText, checkRevisions = true }) {
|
|
18
|
+
const result = validateDocument(text, PLAN_HEADINGS);
|
|
19
|
+
if (result.work_item !== workItem)
|
|
20
|
+
result.errors.push('Plan belongs to a different work item.');
|
|
21
|
+
for (const key of ['engineering_revision', 'spec_revision'])
|
|
22
|
+
if (!/^[a-f0-9]{64}$/.test(result[key] ?? ''))
|
|
23
|
+
result.errors.push(`${key} must be SHA256.`);
|
|
24
|
+
if (checkRevisions && result.engineering_revision !== documentRevision(engineeringText))
|
|
25
|
+
result.errors.push('Engineering revision is stale.');
|
|
26
|
+
if (checkRevisions && result.spec_revision !== documentRevision(specText))
|
|
27
|
+
result.errors.push('Spec revision is stale.');
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=implementation-plan.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"implementation-plan.mjs","sourceRoot":"","sources":["../../src/artifacts/implementation-plan.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,uBAAuB;IACvB,YAAY;IACZ,kBAAkB;IAClB,qBAAqB;IACrB,uBAAuB;IACvB,iBAAiB;IACjB,0BAA0B;IAC1B,2BAA2B;IAC3B,yBAAyB;IACzB,uBAAuB;IACvB,0BAA0B;IAC1B,6BAA6B;CAC9B,CAAC;AACF,MAAM,UAAU,0BAA0B,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,EAAE;IAC7G,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC,SAAS,KAAK,QAAQ;QAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAChG,KAAK,MAAM,GAAG,IAAI,CAAC,sBAAsB,EAAE,eAAe,CAAC;QACzD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,kBAAkB,CAAC,CAAC;IAC9F,IAAI,cAAc,IAAI,MAAM,CAAC,oBAAoB,KAAK,gBAAgB,CAAC,eAAe,CAAC;QACrF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IACvD,IAAI,cAAc,IAAI,MAAM,CAAC,aAAa,KAAK,gBAAgB,CAAC,QAAQ,CAAC;QACvE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prd.d.mts","sourceRoot":"","sources":["../../src/artifacts/prd.mjs"],"names":[],"mappings":"AACA,wBAAgB,mBAAmB,CAAC,IAAI,KAAA;;EAUvC"}
|