@davidorex/pi-context 0.26.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.
Files changed (126) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +195 -0
  3. package/dist/block-api.d.ts +328 -0
  4. package/dist/block-api.d.ts.map +1 -0
  5. package/dist/block-api.js +1167 -0
  6. package/dist/block-api.js.map +1 -0
  7. package/dist/block-validation.d.ts +33 -0
  8. package/dist/block-validation.d.ts.map +1 -0
  9. package/dist/block-validation.js +213 -0
  10. package/dist/block-validation.js.map +1 -0
  11. package/dist/context-dir.d.ts +93 -0
  12. package/dist/context-dir.d.ts.map +1 -0
  13. package/dist/context-dir.js +224 -0
  14. package/dist/context-dir.js.map +1 -0
  15. package/dist/context-sdk.d.ts +428 -0
  16. package/dist/context-sdk.d.ts.map +1 -0
  17. package/dist/context-sdk.js +1327 -0
  18. package/dist/context-sdk.js.map +1 -0
  19. package/dist/context.d.ts +497 -0
  20. package/dist/context.d.ts.map +1 -0
  21. package/dist/context.js +1060 -0
  22. package/dist/context.js.map +1 -0
  23. package/dist/dispatch-context.d.ts +112 -0
  24. package/dist/dispatch-context.d.ts.map +1 -0
  25. package/dist/dispatch-context.js +119 -0
  26. package/dist/dispatch-context.js.map +1 -0
  27. package/dist/execution-context.d.ts +138 -0
  28. package/dist/execution-context.d.ts.map +1 -0
  29. package/dist/execution-context.js +151 -0
  30. package/dist/execution-context.js.map +1 -0
  31. package/dist/index.d.ts +34 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +1655 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/lens-validator.d.ts +50 -0
  36. package/dist/lens-validator.d.ts.map +1 -0
  37. package/dist/lens-validator.js +46 -0
  38. package/dist/lens-validator.js.map +1 -0
  39. package/dist/lens-view.d.ts +75 -0
  40. package/dist/lens-view.d.ts.map +1 -0
  41. package/dist/lens-view.js +253 -0
  42. package/dist/lens-view.js.map +1 -0
  43. package/dist/rename-canonical-id.d.ts +64 -0
  44. package/dist/rename-canonical-id.d.ts.map +1 -0
  45. package/dist/rename-canonical-id.js +378 -0
  46. package/dist/rename-canonical-id.js.map +1 -0
  47. package/dist/roadmap-plan.d.ts +186 -0
  48. package/dist/roadmap-plan.d.ts.map +1 -0
  49. package/dist/roadmap-plan.js +534 -0
  50. package/dist/roadmap-plan.js.map +1 -0
  51. package/dist/samples-catalog.d.ts +48 -0
  52. package/dist/samples-catalog.d.ts.map +1 -0
  53. package/dist/samples-catalog.js +128 -0
  54. package/dist/samples-catalog.js.map +1 -0
  55. package/dist/schema-migrations.d.ts +82 -0
  56. package/dist/schema-migrations.d.ts.map +1 -0
  57. package/dist/schema-migrations.js +106 -0
  58. package/dist/schema-migrations.js.map +1 -0
  59. package/dist/schema-validator.d.ts +76 -0
  60. package/dist/schema-validator.d.ts.map +1 -0
  61. package/dist/schema-validator.js +219 -0
  62. package/dist/schema-validator.js.map +1 -0
  63. package/dist/schema-write.d.ts +122 -0
  64. package/dist/schema-write.d.ts.map +1 -0
  65. package/dist/schema-write.js +210 -0
  66. package/dist/schema-write.js.map +1 -0
  67. package/dist/status-vocab.d.ts +60 -0
  68. package/dist/status-vocab.d.ts.map +1 -0
  69. package/dist/status-vocab.js +109 -0
  70. package/dist/status-vocab.js.map +1 -0
  71. package/dist/test-helpers.d.ts +12 -0
  72. package/dist/test-helpers.d.ts.map +1 -0
  73. package/dist/test-helpers.js +28 -0
  74. package/dist/test-helpers.js.map +1 -0
  75. package/dist/topo.d.ts +19 -0
  76. package/dist/topo.d.ts.map +1 -0
  77. package/dist/topo.js +99 -0
  78. package/dist/topo.js.map +1 -0
  79. package/dist/update-check.d.ts +6 -0
  80. package/dist/update-check.d.ts.map +1 -0
  81. package/dist/update-check.js +82 -0
  82. package/dist/update-check.js.map +1 -0
  83. package/package.json +115 -0
  84. package/samples/blocks/context-contracts.json +3 -0
  85. package/samples/blocks/conventions.json +3 -0
  86. package/samples/blocks/decisions.json +3 -0
  87. package/samples/blocks/features.json +3 -0
  88. package/samples/blocks/framework-gaps.json +3 -0
  89. package/samples/blocks/issues.json +3 -0
  90. package/samples/blocks/layer-plans.json +3 -0
  91. package/samples/blocks/phase.json +3 -0
  92. package/samples/blocks/rationale.json +3 -0
  93. package/samples/blocks/requirements.json +3 -0
  94. package/samples/blocks/research.json +3 -0
  95. package/samples/blocks/spec-reviews.json +3 -0
  96. package/samples/blocks/story.json +3 -0
  97. package/samples/blocks/tasks.json +3 -0
  98. package/samples/blocks/verification.json +3 -0
  99. package/samples/conception.json +467 -0
  100. package/samples/schemas/context-contracts.schema.json +89 -0
  101. package/samples/schemas/conventions.schema.json +34 -0
  102. package/samples/schemas/decisions.schema.json +87 -0
  103. package/samples/schemas/features.schema.json +53 -0
  104. package/samples/schemas/framework-gaps.schema.json +64 -0
  105. package/samples/schemas/issues.schema.json +39 -0
  106. package/samples/schemas/layer-plans.schema.json +92 -0
  107. package/samples/schemas/phase.schema.json +118 -0
  108. package/samples/schemas/rationale.schema.json +24 -0
  109. package/samples/schemas/requirements.schema.json +34 -0
  110. package/samples/schemas/research.schema.json +134 -0
  111. package/samples/schemas/spec-reviews.schema.json +62 -0
  112. package/samples/schemas/story.schema.json +73 -0
  113. package/samples/schemas/tasks.schema.json +34 -0
  114. package/samples/schemas/verification.schema.json +37 -0
  115. package/schemas/bootstrap.schema.json +24 -0
  116. package/schemas/config.schema.json +193 -0
  117. package/schemas/layer.schema.json +9 -0
  118. package/schemas/priority.schema.json +9 -0
  119. package/schemas/relations.schema.json +31 -0
  120. package/schemas/severity.schema.json +9 -0
  121. package/schemas/source.schema.json +9 -0
  122. package/schemas/status.schema.json +9 -0
  123. package/schemas/verification-method.schema.json +9 -0
  124. package/skill-narrative.md +130 -0
  125. package/skills/pi-context/SKILL.md +684 -0
  126. package/skills/pi-context/references/bundled-resources.md +47 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Canonical schema-write surface — read / write / mutate the JSON Schemas
3
+ * that live alongside project blocks under `<contextDir>/schemas/`.
4
+ *
5
+ * Closes structurally:
6
+ * - FGAP-011 (canonical schema-write surface): every schema mutation that
7
+ * would otherwise reach `.project/schemas/*.schema.json` via direct fs
8
+ * edits now has a single typed entry point. Direct fs writes remain
9
+ * possible but are now a parallel ungated path that should be retired
10
+ * in any future schema mutation per the F-006-bypass-pattern discipline.
11
+ *
12
+ * Contract:
13
+ * - All schemas pass through AJV draft-07 meta-schema validation before
14
+ * they touch disk. Malformed schemas throw `ValidationError` with the
15
+ * meta-violation details; the file is not created or modified.
16
+ * - Atomic on-disk semantics — writes go to a `<file>.schema-write-<pid>.tmp`
17
+ * sibling and are renamed into place. A failed write leaves the prior
18
+ * schema byte-identical.
19
+ * - Schema files land at `<resolveContextDir(cwd)>/schemas/<schemaName>.schema.json`,
20
+ * routed through `schemaPath` (context-dir) so write resolution is identical
21
+ * to read resolution — pointer-canonical, `config.root` is NOT a path input
22
+ * (FGAP-079 / DEC-0045). Previously based on a config.root-honoring
23
+ * path-builder, which diverged from the pointer-canonical read side.
24
+ *
25
+ * Out-of-scope for step 3:
26
+ * - Schema $id + version + $ref + migration registry (FGAP-006, step 4)
27
+ * - Schema diff / change-log tooling
28
+ * - Cross-package opinionated mutators (e.g. add-author-fields shorthand)
29
+ */
30
+ import type { DispatchContext } from "./dispatch-context.js";
31
+ import { ValidationError } from "./schema-validator.js";
32
+ /**
33
+ * Read a schema from `<contextDir>/schemas/<schemaName>.schema.json` and
34
+ * return the parsed object. Returns `null` when the file does not exist —
35
+ * absence is a normal pre-write state, not an error. Throws when the file
36
+ * exists but is unreadable or contains invalid JSON.
37
+ *
38
+ * Note: this reader does NOT meta-validate. Callers that need a guarantee
39
+ * the file holds a valid schema should pipe the result through
40
+ * `validateSchemaAgainstMeta` themselves; `updateSchema` already does.
41
+ */
42
+ export declare function readSchema(cwd: string, schemaName: string): object | null;
43
+ /**
44
+ * Atomically write `schema` to `<contextDir>/schemas/<schemaName>.schema.json`
45
+ * after validating it against the JSON Schema draft-07 meta-schema.
46
+ *
47
+ * Failure modes:
48
+ * - Malformed schema → `ValidationError` (file not created or modified).
49
+ * - Filesystem failure during write → `Error` with file context; tmp file
50
+ * cleanup is best-effort, prior schema (if any) is left byte-identical
51
+ * because the rename never happened.
52
+ *
53
+ * Overwrites any existing schema at the target path; callers that need
54
+ * mutate-in-place semantics should use `updateSchema`.
55
+ */
56
+ export declare function writeSchema(cwd: string, schemaName: string, schema: object): void;
57
+ /**
58
+ * Op-correct create-or-replace of a whole schema body, layered over
59
+ * `writeSchema` (FGAP-077 — the Pi-tool / CLI-facing schema-write op).
60
+ *
61
+ * Where `writeSchema` is an unconditional create-or-overwrite, this surface
62
+ * adds an explicit operation discriminator so a caller's intent (create a NEW
63
+ * schema vs. replace an EXISTING one) is enforced rather than silently
64
+ * coerced:
65
+ * - `operation: "create"` requires the schema to be ABSENT — a collision
66
+ * with an existing schema throws (use `replace` to overwrite).
67
+ * - `operation: "replace"` requires the schema to be PRESENT — a missing
68
+ * target throws (use `create` to initialize).
69
+ * - any other operation string throws before any disk read.
70
+ *
71
+ * The presence check reuses `readSchema` (returns `null` when absent) and the
72
+ * single private `schemaWritePath` helper so there is one path source. The
73
+ * actual write delegates to `writeSchema`, which meta-validates against the
74
+ * draft-07 meta-schema and writes atomically (tmp + rename); this surface adds
75
+ * no second validation or write path.
76
+ *
77
+ * Migration boundary (DECIDED, FGAP-077): this op writes the schema JSON and
78
+ * meta-validates the schema body. It does NOT migrate existing block items
79
+ * forward when a `replace` changes the schema's `version`. A breaking
80
+ * evolution is handled at READ time by `validateBlockWithMigration`, which
81
+ * throws a version mismatch until a code-level `MigrationFn` is registered via
82
+ * `createRegistry().register(...)` — and there is no Pi-tool surface for
83
+ * registering a `MigrationFn`. This surface does not (and must not) emit an
84
+ * "items exist at old version" warning: that would require reading block files
85
+ * to assess data-layer impact from inside the schema-write layer, inverting
86
+ * the read-time / write-time layering.
87
+ *
88
+ * `ctx` is accepted and IGNORED: schema files carry no author-attestation
89
+ * fields, so there is nothing to stamp. The parameter is present for call-site
90
+ * parity with the attestation-aware block-write / config-write surfaces
91
+ * (mirrors `amendConfigEntry`'s ctx-forwarding parameter, which forwards to
92
+ * `writeConfig`; here there is no author-bearing target to forward to).
93
+ *
94
+ * `opts.dryRun` runs the SAME meta-validator `writeSchema` uses against the
95
+ * supplied body and returns `{ written: false }` without touching disk —
96
+ * keeping ONE validation path (no re-implemented validation for the preview).
97
+ */
98
+ export declare function writeSchemaChecked(cwd: string, schemaName: string, schema: object, operation: "create" | "replace", ctx?: DispatchContext, opts?: {
99
+ dryRun?: boolean;
100
+ }): {
101
+ written: boolean;
102
+ operation: "create" | "replace";
103
+ schemaPath: string;
104
+ };
105
+ /**
106
+ * Read the current schema at `<contextDir>/schemas/<schemaName>.schema.json`,
107
+ * pass it to `mutator`, meta-validate the result, and atomically write it
108
+ * back. Throws if:
109
+ * - the schema does not exist (`Error` — caller must initialize first)
110
+ * - the on-disk schema parses as JSON but the mutator output fails meta
111
+ * validation (`ValidationError`)
112
+ * - the filesystem write fails (`Error`, prior schema unchanged)
113
+ *
114
+ * `mutator` receives a deep-readable reference to the parsed schema; it is
115
+ * the caller's responsibility to return a fresh object rather than mutate
116
+ * in place — callers that mutate in place still work because the result is
117
+ * what writeSchema sees, but the convention is "mutator returns the new
118
+ * schema" so the call site reads as a transform.
119
+ */
120
+ export declare function updateSchema(cwd: string, schemaName: string, mutator: (current: object) => object): void;
121
+ export { ValidationError };
122
+ //# sourceMappingURL=schema-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-write.d.ts","sourceRoot":"","sources":["../src/schema-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAA6B,MAAM,uBAAuB,CAAC;AAgBnF;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBzE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAuBjF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,kBAAkB,CACjC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,GAAG,SAAS,EAC/B,GAAG,CAAC,EAAE,eAAe,EACrB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAgC3E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAoBxG;AAID,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Canonical schema-write surface — read / write / mutate the JSON Schemas
3
+ * that live alongside project blocks under `<contextDir>/schemas/`.
4
+ *
5
+ * Closes structurally:
6
+ * - FGAP-011 (canonical schema-write surface): every schema mutation that
7
+ * would otherwise reach `.project/schemas/*.schema.json` via direct fs
8
+ * edits now has a single typed entry point. Direct fs writes remain
9
+ * possible but are now a parallel ungated path that should be retired
10
+ * in any future schema mutation per the F-006-bypass-pattern discipline.
11
+ *
12
+ * Contract:
13
+ * - All schemas pass through AJV draft-07 meta-schema validation before
14
+ * they touch disk. Malformed schemas throw `ValidationError` with the
15
+ * meta-violation details; the file is not created or modified.
16
+ * - Atomic on-disk semantics — writes go to a `<file>.schema-write-<pid>.tmp`
17
+ * sibling and are renamed into place. A failed write leaves the prior
18
+ * schema byte-identical.
19
+ * - Schema files land at `<resolveContextDir(cwd)>/schemas/<schemaName>.schema.json`,
20
+ * routed through `schemaPath` (context-dir) so write resolution is identical
21
+ * to read resolution — pointer-canonical, `config.root` is NOT a path input
22
+ * (FGAP-079 / DEC-0045). Previously based on a config.root-honoring
23
+ * path-builder, which diverged from the pointer-canonical read side.
24
+ *
25
+ * Out-of-scope for step 3:
26
+ * - Schema $id + version + $ref + migration registry (FGAP-006, step 4)
27
+ * - Schema diff / change-log tooling
28
+ * - Cross-package opinionated mutators (e.g. add-author-fields shorthand)
29
+ */
30
+ import fs from "node:fs";
31
+ import path from "node:path";
32
+ import { schemaPath } from "./context-dir.js";
33
+ import { ValidationError, validateSchemaAgainstMeta } from "./schema-validator.js";
34
+ /**
35
+ * `<resolveContextDir(cwd)>/schemas/<schemaName>.schema.json` — canonical schema
36
+ * path, routed through `schemaPath` (context-dir) so write resolution is
37
+ * BYTE-IDENTICAL to read resolution (FGAP-079 / DEC-0045). Previously this was
38
+ * based on a config.root-honoring path-builder, which diverged from the
39
+ * pointer-canonical read side (`schemaPath` / `validateBlockWithMigration`) under
40
+ * a non-default `config.root` — schemas would be written where reads/validation
41
+ * could not find them. Delegating to `schemaPath` collapses the two paths to one
42
+ * source AND inherits its `assertSubstrateName` guard (path-traversal rejection).
43
+ */
44
+ function schemaWritePath(cwd, schemaName) {
45
+ return schemaPath(cwd, schemaName);
46
+ }
47
+ /**
48
+ * Read a schema from `<contextDir>/schemas/<schemaName>.schema.json` and
49
+ * return the parsed object. Returns `null` when the file does not exist —
50
+ * absence is a normal pre-write state, not an error. Throws when the file
51
+ * exists but is unreadable or contains invalid JSON.
52
+ *
53
+ * Note: this reader does NOT meta-validate. Callers that need a guarantee
54
+ * the file holds a valid schema should pipe the result through
55
+ * `validateSchemaAgainstMeta` themselves; `updateSchema` already does.
56
+ */
57
+ export function readSchema(cwd, schemaName) {
58
+ const p = schemaWritePath(cwd, schemaName);
59
+ if (!fs.existsSync(p))
60
+ return null;
61
+ let raw;
62
+ try {
63
+ raw = fs.readFileSync(p, "utf-8");
64
+ }
65
+ catch (err) {
66
+ throw new Error(`readSchema: failed to read ${p}: ${err instanceof Error ? err.message : String(err)}`);
67
+ }
68
+ try {
69
+ return JSON.parse(raw);
70
+ }
71
+ catch (err) {
72
+ throw new Error(`readSchema: invalid JSON in ${p}: ${err instanceof Error ? err.message : String(err)}`);
73
+ }
74
+ }
75
+ /**
76
+ * Atomically write `schema` to `<contextDir>/schemas/<schemaName>.schema.json`
77
+ * after validating it against the JSON Schema draft-07 meta-schema.
78
+ *
79
+ * Failure modes:
80
+ * - Malformed schema → `ValidationError` (file not created or modified).
81
+ * - Filesystem failure during write → `Error` with file context; tmp file
82
+ * cleanup is best-effort, prior schema (if any) is left byte-identical
83
+ * because the rename never happened.
84
+ *
85
+ * Overwrites any existing schema at the target path; callers that need
86
+ * mutate-in-place semantics should use `updateSchema`.
87
+ */
88
+ export function writeSchema(cwd, schemaName, schema) {
89
+ const p = schemaWritePath(cwd, schemaName);
90
+ // (1) Meta-schema validation BEFORE any disk activity.
91
+ validateSchemaAgainstMeta(schema, `schema '${schemaName}'`);
92
+ // (2) Ensure the schemas/ directory exists.
93
+ fs.mkdirSync(path.dirname(p), { recursive: true });
94
+ // (3) Atomic write: tmp + rename.
95
+ const tmpPath = `${p}.schema-write-${process.pid}.tmp`;
96
+ try {
97
+ fs.writeFileSync(tmpPath, `${JSON.stringify(schema, null, 2)}\n`, "utf-8");
98
+ fs.renameSync(tmpPath, p);
99
+ }
100
+ catch (err) {
101
+ try {
102
+ fs.unlinkSync(tmpPath);
103
+ }
104
+ catch {
105
+ /* best-effort cleanup — surface the original error below */
106
+ }
107
+ const msg = err instanceof Error ? err.message : String(err);
108
+ throw new Error(`writeSchema: failed to write ${p}: ${msg}`);
109
+ }
110
+ }
111
+ /**
112
+ * Op-correct create-or-replace of a whole schema body, layered over
113
+ * `writeSchema` (FGAP-077 — the Pi-tool / CLI-facing schema-write op).
114
+ *
115
+ * Where `writeSchema` is an unconditional create-or-overwrite, this surface
116
+ * adds an explicit operation discriminator so a caller's intent (create a NEW
117
+ * schema vs. replace an EXISTING one) is enforced rather than silently
118
+ * coerced:
119
+ * - `operation: "create"` requires the schema to be ABSENT — a collision
120
+ * with an existing schema throws (use `replace` to overwrite).
121
+ * - `operation: "replace"` requires the schema to be PRESENT — a missing
122
+ * target throws (use `create` to initialize).
123
+ * - any other operation string throws before any disk read.
124
+ *
125
+ * The presence check reuses `readSchema` (returns `null` when absent) and the
126
+ * single private `schemaWritePath` helper so there is one path source. The
127
+ * actual write delegates to `writeSchema`, which meta-validates against the
128
+ * draft-07 meta-schema and writes atomically (tmp + rename); this surface adds
129
+ * no second validation or write path.
130
+ *
131
+ * Migration boundary (DECIDED, FGAP-077): this op writes the schema JSON and
132
+ * meta-validates the schema body. It does NOT migrate existing block items
133
+ * forward when a `replace` changes the schema's `version`. A breaking
134
+ * evolution is handled at READ time by `validateBlockWithMigration`, which
135
+ * throws a version mismatch until a code-level `MigrationFn` is registered via
136
+ * `createRegistry().register(...)` — and there is no Pi-tool surface for
137
+ * registering a `MigrationFn`. This surface does not (and must not) emit an
138
+ * "items exist at old version" warning: that would require reading block files
139
+ * to assess data-layer impact from inside the schema-write layer, inverting
140
+ * the read-time / write-time layering.
141
+ *
142
+ * `ctx` is accepted and IGNORED: schema files carry no author-attestation
143
+ * fields, so there is nothing to stamp. The parameter is present for call-site
144
+ * parity with the attestation-aware block-write / config-write surfaces
145
+ * (mirrors `amendConfigEntry`'s ctx-forwarding parameter, which forwards to
146
+ * `writeConfig`; here there is no author-bearing target to forward to).
147
+ *
148
+ * `opts.dryRun` runs the SAME meta-validator `writeSchema` uses against the
149
+ * supplied body and returns `{ written: false }` without touching disk —
150
+ * keeping ONE validation path (no re-implemented validation for the preview).
151
+ */
152
+ export function writeSchemaChecked(cwd, schemaName, schema, operation, ctx, opts) {
153
+ void ctx; // accepted for call-site parity; schema files carry no author fields.
154
+ const target = schemaWritePath(cwd, schemaName);
155
+ // (1) Operation discriminator — reject unknown ops before any disk read.
156
+ if (operation !== "create" && operation !== "replace") {
157
+ throw new Error(`writeSchemaChecked: unknown operation '${operation}' — expected create | replace`);
158
+ }
159
+ // (2) Presence guard — readSchema returns null when the file is absent.
160
+ const existing = readSchema(cwd, schemaName);
161
+ if (operation === "create" && existing !== null) {
162
+ throw new Error(`writeSchemaChecked: create collision — schema '${schemaName}' already exists at ${target}; use operation 'replace' to overwrite`);
163
+ }
164
+ if (operation === "replace" && existing === null) {
165
+ throw new Error(`writeSchemaChecked: replace target missing — schema '${schemaName}' does not exist at ${target}; use operation 'create'`);
166
+ }
167
+ // (3) Dry-run: meta-validate via the SAME validator writeSchema uses, no write.
168
+ if (opts?.dryRun) {
169
+ validateSchemaAgainstMeta(schema, `schema '${schemaName}' (dry-run)`);
170
+ return { written: false, operation, schemaPath: target };
171
+ }
172
+ // (4) Commit: writeSchema re-meta-validates + writes atomically (tmp + rename).
173
+ writeSchema(cwd, schemaName, schema);
174
+ return { written: true, operation, schemaPath: target };
175
+ }
176
+ /**
177
+ * Read the current schema at `<contextDir>/schemas/<schemaName>.schema.json`,
178
+ * pass it to `mutator`, meta-validate the result, and atomically write it
179
+ * back. Throws if:
180
+ * - the schema does not exist (`Error` — caller must initialize first)
181
+ * - the on-disk schema parses as JSON but the mutator output fails meta
182
+ * validation (`ValidationError`)
183
+ * - the filesystem write fails (`Error`, prior schema unchanged)
184
+ *
185
+ * `mutator` receives a deep-readable reference to the parsed schema; it is
186
+ * the caller's responsibility to return a fresh object rather than mutate
187
+ * in place — callers that mutate in place still work because the result is
188
+ * what writeSchema sees, but the convention is "mutator returns the new
189
+ * schema" so the call site reads as a transform.
190
+ */
191
+ export function updateSchema(cwd, schemaName, mutator) {
192
+ const current = readSchema(cwd, schemaName);
193
+ if (current === null) {
194
+ throw new Error(`updateSchema: schema '${schemaName}' does not exist at ${schemaWritePath(cwd, schemaName)}; use writeSchema to create it`);
195
+ }
196
+ const next = mutator(current);
197
+ // validateSchemaAgainstMeta will throw ValidationError on a malformed result;
198
+ // we deliberately let that propagate so the caller sees the meta details.
199
+ validateSchemaAgainstMeta(next, `schema '${schemaName}' (post-mutator)`);
200
+ // Reuse writeSchema for the atomic write — it re-validates, which is a
201
+ // belt-and-braces double-check rather than wasted work, since the second
202
+ // validation is fast on the same AJV instance and guarantees disk state
203
+ // matches a meta-valid schema even if a future refactor moves the
204
+ // pre-write check.
205
+ writeSchema(cwd, schemaName, next);
206
+ }
207
+ // Re-export ValidationError so consumers don't need a dual import to catch
208
+ // the only error subclass thrown from the meta-validation path.
209
+ export { ValidationError };
210
+ //# sourceMappingURL=schema-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-write.js","sourceRoot":"","sources":["../src/schema-write.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Status-vocabulary primitives — pure helpers mapping per-schema status enum
3
+ * values to a normalized StatusBucket, plus the config-override resolver.
4
+ *
5
+ * Extracted here (from roadmap-plan.ts) so both roadmap-plan AND context-sdk
6
+ * can consume the vocabulary without forming a module import cycle. This
7
+ * mirrors the topo.ts extraction precedent: context-sdk's currentState +
8
+ * validateContext (status-consistency invariants) and roadmap-plan's
9
+ * rollupPhaseStatus both bucket statuses; routing both through one
10
+ * substrate-light module (it imports only loadContext from
11
+ * context, which depends on neither roadmap-plan nor context-sdk)
12
+ * keeps the dependency graph acyclic.
13
+ *
14
+ * StatusBucket itself is declared in context.ts (the substrate type
15
+ * surface) and imported/re-exported here; it is NOT redeclared.
16
+ */
17
+ import { type StatusBucket } from "./context.js";
18
+ export type { StatusBucket } from "./context.js";
19
+ /**
20
+ * Hardcoded baseline mapping from per-schema status enum values to
21
+ * StatusBucket. Per-project overrides land via config.status_buckets and
22
+ * shadow these defaults at lookup time (resolveStatusVocabulary spreads
23
+ * the user map over the defaults so user keys win on collision).
24
+ *
25
+ * Mappings cover the going-forward conception vocabulary — the status enums
26
+ * of packages/pi-context/samples/schemas/ (the DEC-0037 15-kind canon, all
27
+ * also live in this repo's .project/ registered block_kinds). Per DEC-0036
28
+ * (registry/ is retiring in favor of samples/→.context) these defaults track
29
+ * the conception, NOT the retired registry-only vocab (audit pass/fail/warn/
30
+ * skip, project inception/planning/development/maintenance, decisions
31
+ * revisit/tentative) — a substrate needing such vocab declares it via
32
+ * config.status_buckets (DEC-0025 override surface), never here.
33
+ * - decisions.status: open | enacted | superseded
34
+ * - framework-gaps.status: identified | accepted | in-progress | closed | wontfix
35
+ * - tasks.status: planned | in-progress | completed | blocked | cancelled
36
+ * - features.status: proposed | approved | in-progress | in-review | complete | blocked | cancelled
37
+ * - story.status: proposed | ready | in-progress | in-review | complete | blocked
38
+ * - research.status: planned | in-progress | complete | stale | superseded | revised
39
+ * - requirements.status: proposed | accepted | deferred | implemented | verified
40
+ * - verification.status: passed | failed | partial | skipped
41
+ * - spec-reviews.status: not-started | in-progress | complete | abandoned
42
+ * - layer-plans.status: draft | proposed | decided | in-progress | complete | abandoned
43
+ * - issues.status: open | resolved | deferred
44
+ * - phase.status: planned | in-progress | completed
45
+ *
46
+ * status-vocab.test.ts guards completeness: every samples/schemas status enum
47
+ * value must resolve here (only the intended terminal-not-complete set may map
48
+ * to "unknown"). Values still bucket to "unknown" without throwing — caller
49
+ * decides whether unknown statuses are warning-worthy (validateRoadmaps emits
50
+ * roadmap_status_unknown_value when relevant).
51
+ */
52
+ export declare const STATUS_VOCABULARY_DEFAULTS: Record<string, StatusBucket>;
53
+ /**
54
+ * Resolve the active status-vocabulary map for `cwd` — defaults shadowed
55
+ * by config.status_buckets entries. Pure: builds a fresh map per call;
56
+ * callers caching for hot paths (rollupPhaseStatus over many phases)
57
+ * should pass the resolved map in directly.
58
+ */
59
+ export declare function resolveStatusVocabulary(cwd: string): Record<string, StatusBucket>;
60
+ //# sourceMappingURL=status-vocab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-vocab.d.ts","sourceRoot":"","sources":["../src/status-vocab.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAE9D,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CA+CnE,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAGjF"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Status-vocabulary primitives — pure helpers mapping per-schema status enum
3
+ * values to a normalized StatusBucket, plus the config-override resolver.
4
+ *
5
+ * Extracted here (from roadmap-plan.ts) so both roadmap-plan AND context-sdk
6
+ * can consume the vocabulary without forming a module import cycle. This
7
+ * mirrors the topo.ts extraction precedent: context-sdk's currentState +
8
+ * validateContext (status-consistency invariants) and roadmap-plan's
9
+ * rollupPhaseStatus both bucket statuses; routing both through one
10
+ * substrate-light module (it imports only loadContext from
11
+ * context, which depends on neither roadmap-plan nor context-sdk)
12
+ * keeps the dependency graph acyclic.
13
+ *
14
+ * StatusBucket itself is declared in context.ts (the substrate type
15
+ * surface) and imported/re-exported here; it is NOT redeclared.
16
+ */
17
+ import { loadContext } from "./context.js";
18
+ /**
19
+ * Hardcoded baseline mapping from per-schema status enum values to
20
+ * StatusBucket. Per-project overrides land via config.status_buckets and
21
+ * shadow these defaults at lookup time (resolveStatusVocabulary spreads
22
+ * the user map over the defaults so user keys win on collision).
23
+ *
24
+ * Mappings cover the going-forward conception vocabulary — the status enums
25
+ * of packages/pi-context/samples/schemas/ (the DEC-0037 15-kind canon, all
26
+ * also live in this repo's .project/ registered block_kinds). Per DEC-0036
27
+ * (registry/ is retiring in favor of samples/→.context) these defaults track
28
+ * the conception, NOT the retired registry-only vocab (audit pass/fail/warn/
29
+ * skip, project inception/planning/development/maintenance, decisions
30
+ * revisit/tentative) — a substrate needing such vocab declares it via
31
+ * config.status_buckets (DEC-0025 override surface), never here.
32
+ * - decisions.status: open | enacted | superseded
33
+ * - framework-gaps.status: identified | accepted | in-progress | closed | wontfix
34
+ * - tasks.status: planned | in-progress | completed | blocked | cancelled
35
+ * - features.status: proposed | approved | in-progress | in-review | complete | blocked | cancelled
36
+ * - story.status: proposed | ready | in-progress | in-review | complete | blocked
37
+ * - research.status: planned | in-progress | complete | stale | superseded | revised
38
+ * - requirements.status: proposed | accepted | deferred | implemented | verified
39
+ * - verification.status: passed | failed | partial | skipped
40
+ * - spec-reviews.status: not-started | in-progress | complete | abandoned
41
+ * - layer-plans.status: draft | proposed | decided | in-progress | complete | abandoned
42
+ * - issues.status: open | resolved | deferred
43
+ * - phase.status: planned | in-progress | completed
44
+ *
45
+ * status-vocab.test.ts guards completeness: every samples/schemas status enum
46
+ * value must resolve here (only the intended terminal-not-complete set may map
47
+ * to "unknown"). Values still bucket to "unknown" without throwing — caller
48
+ * decides whether unknown statuses are warning-worthy (validateRoadmaps emits
49
+ * roadmap_status_unknown_value when relevant).
50
+ */
51
+ export const STATUS_VOCABULARY_DEFAULTS = {
52
+ // → complete
53
+ resolved: "complete",
54
+ completed: "complete",
55
+ complete: "complete",
56
+ done: "complete",
57
+ enacted: "complete",
58
+ implemented: "complete",
59
+ passed: "complete",
60
+ archived: "complete",
61
+ closed: "complete", // framework-gaps: gap resolved/done
62
+ verified: "complete", // requirements: terminal-done, beyond "implemented"
63
+ // → in_progress
64
+ in_progress: "in_progress",
65
+ "in-progress": "in_progress",
66
+ active: "in_progress",
67
+ accepted: "in_progress",
68
+ "in-review": "in_progress", // features/story: under review, still active (not yet complete)
69
+ revised: "in_progress", // research: transient state during re-investigation
70
+ partial: "in_progress", // verification: incomplete — NOT a clean pass, must not assert complete
71
+ // → blocked
72
+ blocked: "blocked",
73
+ paused: "blocked",
74
+ failed: "blocked",
75
+ // → todo
76
+ open: "todo",
77
+ todo: "todo",
78
+ planned: "todo",
79
+ proposed: "todo",
80
+ draft: "todo",
81
+ identified: "todo",
82
+ "not-started": "todo",
83
+ pending: "todo",
84
+ approved: "todo", // features: approved to build, not yet started
85
+ ready: "todo", // story/features: refined + ready to pick up, not started
86
+ decided: "todo", // layer-plans: plan decided to execute, before in-progress
87
+ // superseded / cancelled / deferred / abandoned / wontfix / skipped / stale
88
+ // bucket to unknown — terminal-but-not-complete states that don't fit the
89
+ // linear progress narrative. Roadmap/plan rollups treat them as "doesn't
90
+ // count toward progress" rather than as complete or todo.
91
+ superseded: "unknown",
92
+ cancelled: "unknown",
93
+ deferred: "unknown",
94
+ abandoned: "unknown", // layer-plans/spec-reviews: work stopped, not completed
95
+ wontfix: "unknown", // framework-gaps: decided not to address
96
+ skipped: "unknown", // verification: waived/not run — must not assert complete
97
+ stale: "unknown", // research: grounding no longer authoritative (degraded-complete)
98
+ };
99
+ /**
100
+ * Resolve the active status-vocabulary map for `cwd` — defaults shadowed
101
+ * by config.status_buckets entries. Pure: builds a fresh map per call;
102
+ * callers caching for hot paths (rollupPhaseStatus over many phases)
103
+ * should pass the resolved map in directly.
104
+ */
105
+ export function resolveStatusVocabulary(cwd) {
106
+ const ctx = loadContext(cwd);
107
+ return { ...STATUS_VOCABULARY_DEFAULTS, ...(ctx.config?.status_buckets ?? {}) };
108
+ }
109
+ //# sourceMappingURL=status-vocab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-vocab.js","sourceRoot":"","sources":["../src/status-vocab.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,WAAW,EAAqB,MAAM,cAAc,CAAC;AAI9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAiC;IACvE,aAAa;IACb,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,UAAU;IACrB,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,UAAU;IACnB,WAAW,EAAE,UAAU;IACvB,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,UAAU,EAAE,oCAAoC;IACxD,QAAQ,EAAE,UAAU,EAAE,oDAAoD;IAC1E,gBAAgB;IAChB,WAAW,EAAE,aAAa;IAC1B,aAAa,EAAE,aAAa;IAC5B,MAAM,EAAE,aAAa;IACrB,QAAQ,EAAE,aAAa;IACvB,WAAW,EAAE,aAAa,EAAE,gEAAgE;IAC5F,OAAO,EAAE,aAAa,EAAE,oDAAoD;IAC5E,OAAO,EAAE,aAAa,EAAE,wEAAwE;IAChG,YAAY;IACZ,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;IACjB,SAAS;IACT,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,MAAM;IACf,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,MAAM;IACb,UAAU,EAAE,MAAM;IAClB,aAAa,EAAE,MAAM;IACrB,OAAO,EAAE,MAAM;IACf,QAAQ,EAAE,MAAM,EAAE,+CAA+C;IACjE,KAAK,EAAE,MAAM,EAAE,0DAA0D;IACzE,OAAO,EAAE,MAAM,EAAE,2DAA2D;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,yEAAyE;IACzE,0DAA0D;IAC1D,UAAU,EAAE,SAAS;IACrB,SAAS,EAAE,SAAS;IACpB,QAAQ,EAAE,SAAS;IACnB,SAAS,EAAE,SAAS,EAAE,wDAAwD;IAC9E,OAAO,EAAE,SAAS,EAAE,yCAAyC;IAC7D,OAAO,EAAE,SAAS,EAAE,0DAA0D;IAC9E,KAAK,EAAE,SAAS,EAAE,kEAAkE;CACpF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAW;IAClD,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,EAAE,GAAG,0BAA0B,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,IAAI,EAAE,CAAC,EAAE,CAAC;AACjF,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared test helpers for pi-project tests — mock factories for ctx and pi.
3
+ */
4
+ /**
5
+ * Create a mock extension context for testing.
6
+ */
7
+ export declare function mockCtx(cwd: string): any;
8
+ /**
9
+ * Create a mock pi API for testing.
10
+ */
11
+ export declare function mockPi(): any;
12
+ //# sourceMappingURL=test-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAS7B,GAAG,CACR;AAED;;GAEG;AACH,wBAAgB,MAAM,IAKhB,GAAG,CACR"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Shared test helpers for pi-project tests — mock factories for ctx and pi.
3
+ */
4
+ /**
5
+ * Create a mock extension context for testing.
6
+ */
7
+ export function mockCtx(cwd) {
8
+ return {
9
+ cwd,
10
+ hasUI: false,
11
+ ui: {
12
+ setWidget: () => { },
13
+ notify: () => { },
14
+ setStatus: () => { },
15
+ },
16
+ };
17
+ }
18
+ /**
19
+ * Create a mock pi API for testing.
20
+ */
21
+ export function mockPi() {
22
+ const messages = [];
23
+ return {
24
+ sendMessage: (msg, opts) => messages.push({ msg, opts }),
25
+ _messages: messages,
26
+ };
27
+ }
28
+ //# sourceMappingURL=test-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW;IAClC,OAAO;QACN,GAAG;QACH,KAAK,EAAE,KAAK;QACZ,EAAE,EAAE;YACH,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;YACnB,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;YAChB,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;SACnB;KACM,CAAC;AACV,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM;IACrB,MAAM,QAAQ,GAAU,EAAE,CAAC;IAC3B,OAAO;QACN,WAAW,EAAE,CAAC,GAAQ,EAAE,IAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QAClE,SAAS,EAAE,QAAQ;KACZ,CAAC;AACV,CAAC"}
package/dist/topo.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Generic topological sort + cycle detection — a pure utility with no
3
+ * substrate dependency. Extracted here (from roadmap-plan.ts) so both
4
+ * roadmap-plan and context-sdk can consume it without forming a module
5
+ * import cycle (context-sdk.currentState + roadmap-plan both topo-order).
6
+ *
7
+ * Returns:
8
+ * order — dependency-respecting id order (Kahn's algorithm; stable,
9
+ * preserves input order within a stratum).
10
+ * cycles — array of cycle paths, each a string[] starting and ending
11
+ * with the same id. Empty when the graph is acyclic.
12
+ *
13
+ * Callers choose whether cycles are fatal.
14
+ */
15
+ export declare function topoSort<T>(nodes: T[], idOf: (n: T) => string, deps: (n: T) => string[]): {
16
+ order: string[];
17
+ cycles: string[][];
18
+ };
19
+ //# sourceMappingURL=topo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topo.d.ts","sourceRoot":"","sources":["../src/topo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACzB,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,EACtB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,EAAE,GACtB;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAA;CAAE,CAkFzC"}