@smartmemory/compose 0.1.6-beta → 0.1.8-beta

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 (87) hide show
  1. package/README.md +32 -5
  2. package/bin/compose.js +353 -60
  3. package/bin/git-hooks/pre-push.template +26 -0
  4. package/contracts/feature-json.schema.json +115 -0
  5. package/contracts/roadmap-row.schema.json +23 -0
  6. package/contracts/vision-state.schema.json +64 -0
  7. package/dist/assets/{_baseUniq-D-avYfn5.js → _baseUniq-3jW4HAOf.js} +1 -1
  8. package/dist/assets/{arc-BC4dfQ-X.js → arc-DzzDimyd.js} +1 -1
  9. package/dist/assets/{architectureDiagram-Q4EWVU46-BZmFXnGI.js → architectureDiagram-Q4EWVU46-CtAgwORz.js} +1 -1
  10. package/dist/assets/{blockDiagram-DXYQGD6D-DlfWSuux.js → blockDiagram-DXYQGD6D-Bryby0c_.js} +1 -1
  11. package/dist/assets/{c4Diagram-AHTNJAMY-Y__uJrRx.js → c4Diagram-AHTNJAMY-C7N9RTJ8.js} +1 -1
  12. package/dist/assets/channel-DDkv7DUd.js +1 -0
  13. package/dist/assets/{chunk-4BX2VUAB-BfMePfTp.js → chunk-4BX2VUAB-wijkFgZY.js} +1 -1
  14. package/dist/assets/{chunk-4TB4RGXK-BdlMSdEA.js → chunk-4TB4RGXK-zdSZGRS2.js} +1 -1
  15. package/dist/assets/{chunk-55IACEB6-vrQHZTdv.js → chunk-55IACEB6-6zqzTZQQ.js} +1 -1
  16. package/dist/assets/{chunk-EDXVE4YY-B8wioVlW.js → chunk-EDXVE4YY-frd1Vwf-.js} +1 -1
  17. package/dist/assets/{chunk-FMBD7UC4-Cd6Hrux2.js → chunk-FMBD7UC4-CdkRK5Hx.js} +1 -1
  18. package/dist/assets/{chunk-OYMX7WX6-CfrhdQXY.js → chunk-OYMX7WX6-C6bMB0cf.js} +1 -1
  19. package/dist/assets/{chunk-QZHKN3VN-B9JQerOU.js → chunk-QZHKN3VN-4vsxN3jq.js} +1 -1
  20. package/dist/assets/{chunk-YZCP3GAM-DFN9X99H.js → chunk-YZCP3GAM-DbNARKip.js} +1 -1
  21. package/dist/assets/classDiagram-6PBFFD2Q-J6ZTeCbW.js +1 -0
  22. package/dist/assets/classDiagram-v2-HSJHXN6E-J6ZTeCbW.js +1 -0
  23. package/dist/assets/clone-5MVZ89iV.js +1 -0
  24. package/dist/assets/{cose-bilkent-S5V4N54A-BAn0ap_E.js → cose-bilkent-S5V4N54A-BpXeV7Vj.js} +1 -1
  25. package/dist/assets/{dagre-KV5264BT-DyxnVq1g.js → dagre-KV5264BT-DQLu_W8r.js} +1 -1
  26. package/dist/assets/{diagram-5BDNPKRD-XCrzqski.js → diagram-5BDNPKRD-skaOoe5A.js} +1 -1
  27. package/dist/assets/{diagram-G4DWMVQ6-MBCAXft_.js → diagram-G4DWMVQ6-DezlfFH4.js} +1 -1
  28. package/dist/assets/{diagram-MMDJMWI5-DbtB2yS6.js → diagram-MMDJMWI5-BUu-v-wT.js} +1 -1
  29. package/dist/assets/{diagram-TYMM5635-Bb5NzX61.js → diagram-TYMM5635-CziQ6LPs.js} +1 -1
  30. package/dist/assets/{erDiagram-SMLLAGMA-CpIeCOh2.js → erDiagram-SMLLAGMA-BsAyOVTI.js} +1 -1
  31. package/dist/assets/{flowDiagram-DWJPFMVM-CHyoKnhW.js → flowDiagram-DWJPFMVM-CbYWJOLq.js} +1 -1
  32. package/dist/assets/{ganttDiagram-T4ZO3ILL-DErKteO_.js → ganttDiagram-T4ZO3ILL-CAwgDkLl.js} +1 -1
  33. package/dist/assets/{gitGraphDiagram-UUTBAWPF-KFVAtj2F.js → gitGraphDiagram-UUTBAWPF-DK4RlkjO.js} +1 -1
  34. package/dist/assets/{graph-CRnO_ifT.js → graph-orv1XHGx.js} +1 -1
  35. package/dist/assets/{index-DkRKLuNr.js → index-Ceywghsu.js} +143 -143
  36. package/dist/assets/{infoDiagram-42DDH7IO-BZFnuSp5.js → infoDiagram-42DDH7IO-DQyA75sK.js} +1 -1
  37. package/dist/assets/{ishikawaDiagram-UXIWVN3A-4Xe2Szde.js → ishikawaDiagram-UXIWVN3A-C-F_5q4k.js} +1 -1
  38. package/dist/assets/{journeyDiagram-VCZTEJTY-CZRByfS-.js → journeyDiagram-VCZTEJTY-Bj8UIvK-.js} +1 -1
  39. package/dist/assets/{kanban-definition-6JOO6SKY-B95sk6Fk.js → kanban-definition-6JOO6SKY-DZYr8Dp1.js} +1 -1
  40. package/dist/assets/{layout-BqNQzxWT.js → layout-CBaTKjpX.js} +1 -1
  41. package/dist/assets/{linear-CUh7qb64.js → linear-j1sI_SiN.js} +1 -1
  42. package/dist/assets/{min-wXgOS3ig.js → min-DtJISjld.js} +1 -1
  43. package/dist/assets/{mindmap-definition-QFDTVHPH-DB6iaAbO.js → mindmap-definition-QFDTVHPH-Bulb64RS.js} +1 -1
  44. package/dist/assets/{pieDiagram-DEJITSTG-CHkZHrTW.js → pieDiagram-DEJITSTG-D11keQxr.js} +1 -1
  45. package/dist/assets/{quadrantDiagram-34T5L4WZ-DoTEO8e3.js → quadrantDiagram-34T5L4WZ-BEcWQiEG.js} +1 -1
  46. package/dist/assets/{requirementDiagram-MS252O5E-Dn8peXYp.js → requirementDiagram-MS252O5E-Cbp23uDf.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-XADWPNL6-DRXs6Ipb.js → sankeyDiagram-XADWPNL6-Dae1hMc5.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-FGHM5R23-wBBYZ0aq.js → sequenceDiagram-FGHM5R23-C16abORi.js} +1 -1
  49. package/dist/assets/{stateDiagram-FHFEXIEX-DPlBNGmf.js → stateDiagram-FHFEXIEX-CbEtfhbx.js} +1 -1
  50. package/dist/assets/stateDiagram-v2-QKLJ7IA2-CyY84hEA.js +1 -0
  51. package/dist/assets/{timeline-definition-GMOUNBTQ-CbbyTlHk.js → timeline-definition-GMOUNBTQ-BV7JTNMI.js} +1 -1
  52. package/dist/assets/{vennDiagram-DHZGUBPP-Bj4GaFfj.js → vennDiagram-DHZGUBPP-DBZiT48j.js} +1 -1
  53. package/dist/assets/{wardley-RL74JXVD-RtNzq8KU.js → wardley-RL74JXVD-Cc8uoiL3.js} +37 -37
  54. package/dist/assets/{wardleyDiagram-NUSXRM2D-CDfE3zSj.js → wardleyDiagram-NUSXRM2D-DEYcWGo5.js} +1 -1
  55. package/dist/assets/{xychartDiagram-5P7HB3ND-CZXHHYD5.js → xychartDiagram-5P7HB3ND-bFhLXv2b.js} +1 -1
  56. package/dist/index.html +1 -1
  57. package/lib/build.js +193 -19
  58. package/lib/completion-writer.js +8 -6
  59. package/lib/deps.js +17 -6
  60. package/lib/feature-code.js +29 -0
  61. package/lib/feature-events.js +3 -0
  62. package/lib/feature-validator.js +629 -0
  63. package/lib/feature-writer.js +35 -23
  64. package/lib/followup-writer.js +556 -0
  65. package/lib/journal-writer.js +1 -1
  66. package/lib/mcp-enforcement.js +173 -0
  67. package/lib/migrate-roadmap.js +4 -1
  68. package/lib/project-paths.js +36 -0
  69. package/lib/review-lenses.js +23 -8
  70. package/lib/review-normalize.js +42 -3
  71. package/lib/roadmap-drift.js +54 -0
  72. package/lib/roadmap-gen.js +297 -27
  73. package/lib/roadmap-preservers.js +353 -0
  74. package/lib/step-prompt.js +15 -0
  75. package/lib/triage.js +2 -1
  76. package/lib/version-check.js +110 -0
  77. package/package.json +1 -1
  78. package/server/compose-mcp-tools.js +34 -2
  79. package/server/compose-mcp.js +52 -1
  80. package/server/schema-validator.js +50 -9
  81. package/server/vision-routes.js +51 -2
  82. package/templates/ROADMAP.md +6 -0
  83. package/dist/assets/channel-LRG9kHqJ.js +0 -1
  84. package/dist/assets/classDiagram-6PBFFD2Q-BC9a6pDE.js +0 -1
  85. package/dist/assets/classDiagram-v2-HSJHXN6E-BC9a6pDE.js +0 -1
  86. package/dist/assets/clone-dRxgFrBv.js +0 -1
  87. package/dist/assets/stateDiagram-v2-QKLJ7IA2-BW0ezXb4.js +0 -1
@@ -5,26 +5,43 @@ import Ajv from 'ajv';
5
5
  import addFormats from 'ajv-formats';
6
6
 
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
- const SCHEMA_PATH = resolve(__dirname, '../contracts/comp-obs-contract.schema.json');
8
+ const DEFAULT_SCHEMA_PATH = resolve(__dirname, '../contracts/comp-obs-contract.schema.json');
9
9
 
10
- let cached = null;
10
+ // Per-path cache. Each entry: { schema, ajv }.
11
+ const cache = new Map();
11
12
 
12
- function load() {
13
- if (cached) return cached;
14
- const schema = JSON.parse(readFileSync(SCHEMA_PATH, 'utf8'));
13
+ function load(schemaPath = DEFAULT_SCHEMA_PATH) {
14
+ if (cache.has(schemaPath)) return cache.get(schemaPath);
15
+ const schema = JSON.parse(readFileSync(schemaPath, 'utf8'));
15
16
  const ajv = new Ajv({ strict: false, allErrors: true });
16
17
  addFormats(ajv);
17
18
  ajv.addSchema(schema);
18
- cached = { schema, ajv };
19
- return cached;
19
+ const entry = { schema, ajv };
20
+ cache.set(schemaPath, entry);
21
+ return entry;
22
+ }
23
+
24
+ /**
25
+ * Load (and cache) a schema by absolute path. Returns `{ schema, ajv }`.
26
+ * Used by code that wants to compile arbitrary `$ref`s against the schema
27
+ * without going through the SchemaValidator class.
28
+ */
29
+ export function loadSchema(schemaPath) {
30
+ return load(schemaPath);
20
31
  }
21
32
 
22
33
  export class SchemaValidator {
23
- constructor() {
24
- const { schema, ajv } = load();
34
+ /**
35
+ * @param {string} [schemaPath] Absolute path to a JSON Schema file.
36
+ * Default is the comp-obs-contract schema (back-compat for existing
37
+ * callers that pass no args).
38
+ */
39
+ constructor(schemaPath = DEFAULT_SCHEMA_PATH) {
40
+ const { schema, ajv } = load(schemaPath);
25
41
  this.schema = schema;
26
42
  this.ajv = ajv;
27
43
  this._validators = new Map();
44
+ this._rootValidator = null;
28
45
  }
29
46
 
30
47
  _getValidator(defName) {
@@ -39,11 +56,35 @@ export class SchemaValidator {
39
56
  return v;
40
57
  }
41
58
 
59
+ /**
60
+ * Validate `obj` against `schema.definitions[defName]`. Used by the
61
+ * comp-obs-contract code paths.
62
+ */
42
63
  validate(defName, obj) {
43
64
  const v = this._getValidator(defName);
44
65
  const valid = v(obj);
45
66
  return { valid: !!valid, errors: valid ? [] : (v.errors || []) };
46
67
  }
68
+
69
+ /**
70
+ * Validate `obj` against the schema's root (no $defs/$ref indirection).
71
+ * Used by feature-json / vision-state / roadmap-row schemas, which are
72
+ * top-level shapes without nested definitions.
73
+ */
74
+ validateRoot(obj) {
75
+ if (!this._rootValidator) {
76
+ // ajv.getSchema by $id returns the root validator if the schema was
77
+ // added via addSchema (which load() does).
78
+ let v = this.schema.$id ? this.ajv.getSchema(this.schema.$id) : null;
79
+ if (!v) v = this.ajv.compile(this.schema);
80
+ this._rootValidator = v;
81
+ }
82
+ const v = this._rootValidator;
83
+ const valid = v(obj);
84
+ return { valid: !!valid, errors: valid ? [] : (v.errors || []) };
85
+ }
47
86
  }
48
87
 
88
+ // Back-compat export — points at the comp-obs schema version. Existing
89
+ // callers consuming SCHEMA_VERSION continue to work unchanged.
49
90
  export const SCHEMA_VERSION = load().schema.version;
@@ -338,7 +338,7 @@ export function attachVisionRoutes(app, { store, scheduleBroadcast, broadcastMes
338
338
  }
339
339
  });
340
340
 
341
- app.post('/api/vision/items/:id/lifecycle/complete', (req, res) => {
341
+ app.post('/api/vision/items/:id/lifecycle/complete', async (req, res) => {
342
342
  try {
343
343
  const item = store.items.get(req.params.id);
344
344
  if (!item?.lifecycle) return res.status(404).json({ error: 'No lifecycle on this item' });
@@ -360,7 +360,56 @@ export function attachVisionRoutes(app, { store, scheduleBroadcast, broadcastMes
360
360
  emitDriftAxes(broadcastMessage, store, item, projectRoot, now);
361
361
  // COMP-OBS-STATUS: emit status snapshot after lifecycle transition (complete)
362
362
  emitStatusSnapshot(broadcastMessage, store, item.lifecycle.featureCode, now);
363
- res.json({ completedAt: now });
363
+
364
+ // COMP-MCP-MIGRATION: reconcile cockpit complete with record_completion
365
+ // (commit-bound completion writer). Best-effort: failures emit a decision
366
+ // event but never roll back the lifecycle transition.
367
+ const featureCode = item.lifecycle.featureCode;
368
+ const completionResult = { partial: false };
369
+ if (featureCode) {
370
+ const { commit_sha, tests_pass, files_changed, notes } = req.body || {};
371
+ if (commit_sha) {
372
+ try {
373
+ const { recordCompletion } = await import('../lib/completion-writer.js');
374
+ await recordCompletion(projectRoot, {
375
+ feature_code: featureCode,
376
+ commit_sha,
377
+ tests_pass: tests_pass ?? true,
378
+ files_changed: files_changed ?? [],
379
+ notes: notes ?? `cockpit lifecycle: ${featureCode} complete`,
380
+ });
381
+ } catch (err) {
382
+ completionResult.partial = true;
383
+ const eventType = err.code === 'STATUS_FLIP_AFTER_COMPLETION_RECORDED'
384
+ ? 'cockpit_completion_partial_status_flip'
385
+ : 'cockpit_completion_failed';
386
+ completionResult.completion_failed = err.code || 'UNKNOWN';
387
+ completionResult.message = err.message;
388
+ try {
389
+ emitDecisionEvent(broadcastMessage, {
390
+ type: eventType,
391
+ featureCode,
392
+ timestamp: now,
393
+ error: { code: err.code, message: err.message },
394
+ });
395
+ } catch { /* decision event emit best-effort */ }
396
+ // eslint-disable-next-line no-console
397
+ console.warn(`[lifecycle/complete] record_completion ${eventType} for ${featureCode}: ${err.message}`);
398
+ }
399
+ } else {
400
+ // No SHA — emit a skip event so validate_feature can flag drift later
401
+ try {
402
+ emitDecisionEvent(broadcastMessage, {
403
+ type: 'cockpit_completion_skipped',
404
+ featureCode,
405
+ timestamp: now,
406
+ reason: 'no_commit_sha',
407
+ });
408
+ } catch { /* decision event emit best-effort */ }
409
+ }
410
+ }
411
+
412
+ res.json({ completedAt: now, ...completionResult });
364
413
  } catch (err) {
365
414
  const status = err.message.includes('not found') ? 404 : 400;
366
415
  res.status(status).json({ error: err.message });
@@ -5,6 +5,7 @@
5
5
 
6
6
  ---
7
7
 
8
+ <!-- preserved-section: roadmap-conventions -->
8
9
  ## Roadmap Conventions
9
10
 
10
11
  - **Status:** `PLANNED` | `IN_PROGRESS` | `PARTIAL` | `COMPLETE` | `SUPERSEDED` | `PARKED`
@@ -12,6 +13,8 @@
12
13
  - Items are numbered sequentially across all phases — never reuse a number.
13
14
  - Cross-reference stable IDs (e.g. `FEAT-1`, `Phase 2`) not section headings.
14
15
 
16
+ <!-- /preserved-section -->
17
+
15
18
  ---
16
19
 
17
20
  ## Phase 1: Foundation — PLANNED
@@ -37,6 +40,7 @@ Bootstrap: establish the core structure and first working milestone.
37
40
 
38
41
  ---
39
42
 
43
+ <!-- preserved-section: dogfooding-milestones -->
40
44
  ## Dogfooding Milestones
41
45
 
42
46
  | Milestone | Description | Status |
@@ -44,3 +48,5 @@ Bootstrap: establish the core structure and first working milestone.
44
48
  | D0: Bootstrap | Manual, out-of-band. | PLANNED |
45
49
  | D1: [First self-use milestone] | [Description] | PLANNED |
46
50
  | D2: [Second self-use milestone] | [Description] | PLANNED |
51
+
52
+ <!-- /preserved-section -->
@@ -1 +0,0 @@
1
- import{aq as o,ar as n}from"./index-DkRKLuNr.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-BdlMSdEA.js";import{_ as i}from"./index-DkRKLuNr.js";import"./chunk-FMBD7UC4-Cd6Hrux2.js";import"./chunk-YZCP3GAM-DFN9X99H.js";import"./chunk-55IACEB6-vrQHZTdv.js";import"./chunk-EDXVE4YY-B8wioVlW.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-BdlMSdEA.js";import{_ as i}from"./index-DkRKLuNr.js";import"./chunk-FMBD7UC4-Cd6Hrux2.js";import"./chunk-YZCP3GAM-DFN9X99H.js";import"./chunk-55IACEB6-vrQHZTdv.js";import"./chunk-EDXVE4YY-B8wioVlW.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1 +0,0 @@
1
- import{b as r}from"./graph-CRnO_ifT.js";var e=4;function a(o){return r(o,e)}export{a as c};
@@ -1 +0,0 @@
1
- import{s as t,b as r,a,S as s}from"./chunk-OYMX7WX6-CfrhdQXY.js";import{_ as i}from"./index-DkRKLuNr.js";import"./chunk-55IACEB6-vrQHZTdv.js";import"./chunk-EDXVE4YY-B8wioVlW.js";var l={parser:a,get db(){return new s(2)},renderer:r,styles:t,init:i(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},"init")};export{l as diagram};