@smartmemory/compose 0.2.49-beta → 0.2.51-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 (148) hide show
  1. package/.claude/skills/compose/SKILL.md +24 -1
  2. package/.claude/skills/compose/references/hermes-tools.md +80 -0
  3. package/README.md +1 -1
  4. package/bin/compose.js +340 -70
  5. package/dist/assets/App-CT0vXPgd.js +724 -0
  6. package/dist/assets/_baseUniq-CsOHc_iS.js +1 -0
  7. package/dist/assets/{arc-B1TqAC_R.js → arc-BXht3LyE.js} +1 -1
  8. package/dist/assets/architectureDiagram-Q4EWVU46-BV1r86-w.js +36 -0
  9. package/dist/assets/blockDiagram-DXYQGD6D-BgcMJjAR.js +132 -0
  10. package/dist/assets/{browser-DW2JlJCC.js → browser-CnKiSnlr.js} +6 -6
  11. package/dist/assets/{c4Diagram-AAUBKEIU-Dc6swoQo.js → c4Diagram-AHTNJAMY-nBIRLJTv.js} +1 -1
  12. package/dist/assets/channel-Dd4XaiYv.js +1 -0
  13. package/dist/assets/{chunk-4BX2VUAB-CdqXgd68.js → chunk-4BX2VUAB-CNmGyhrp.js} +1 -1
  14. package/dist/assets/chunk-4TB4RGXK-MLT7I7w4.js +206 -0
  15. package/dist/assets/{chunk-55IACEB6-D7VauOmU.js → chunk-55IACEB6-D8KuKVLa.js} +1 -1
  16. package/dist/assets/{chunk-2J33WTMH-6HKDSnOw.js → chunk-EDXVE4YY-TPlt1bS2.js} +1 -1
  17. package/dist/assets/{chunk-FMBD7UC4-C1Z5m8DP.js → chunk-FMBD7UC4-tYY8xcjr.js} +1 -1
  18. package/dist/assets/chunk-OYMX7WX6-yBPwT1AT.js +231 -0
  19. package/dist/assets/{chunk-QZHKN3VN-DY9GU2uD.js → chunk-QZHKN3VN-B4Wfybww.js} +1 -1
  20. package/dist/assets/{chunk-ND2GUHAM-DmqZMEQe.js → chunk-YZCP3GAM-DE6_5aqh.js} +1 -1
  21. package/dist/assets/classDiagram-6PBFFD2Q-DshSQDF9.js +1 -0
  22. package/dist/assets/classDiagram-v2-HSJHXN6E-DshSQDF9.js +1 -0
  23. package/dist/assets/clone-CBsbNGAa.js +1 -0
  24. package/dist/assets/{cose-bilkent-S5V4N54A-B34g9xzV.js → cose-bilkent-S5V4N54A-DzzRyJtB.js} +1 -1
  25. package/dist/assets/dagre-KV5264BT-CTcTVGdU.js +4 -0
  26. package/dist/assets/diagram-5BDNPKRD-qR6mc8kJ.js +10 -0
  27. package/dist/assets/diagram-G4DWMVQ6-CUcGXyNb.js +24 -0
  28. package/dist/assets/diagram-MMDJMWI5-B68cPonH.js +43 -0
  29. package/dist/assets/diagram-TYMM5635-q8Id8eFG.js +24 -0
  30. package/dist/assets/{erDiagram-TEJ5UH35-C05_Iqmb.js → erDiagram-SMLLAGMA-CtxJi57K.js} +1 -1
  31. package/dist/assets/{flowDiagram-I6XJVG4X-lXpnb-Ch.js → flowDiagram-DWJPFMVM-BzzO4JYU.js} +1 -1
  32. package/dist/assets/ganttDiagram-T4ZO3ILL-Dn0wIyhR.js +292 -0
  33. package/dist/assets/gitGraphDiagram-UUTBAWPF-tnNFXfMM.js +106 -0
  34. package/dist/assets/graph-DZe55uk8.js +331 -0
  35. package/dist/assets/graph-Tq_bs_r0.js +1 -0
  36. package/dist/assets/index-8UhRLbGq.js +123 -0
  37. package/dist/assets/index-CRqB9els.css +1 -0
  38. package/dist/assets/infoDiagram-42DDH7IO-BXLvLeS0.js +2 -0
  39. package/dist/assets/{ishikawaDiagram-YF4QCWOH-CgdsWdgu.js → ishikawaDiagram-UXIWVN3A-DWx-7BBy.js} +5 -5
  40. package/dist/assets/{journeyDiagram-JHISSGLW-CyvHmE3z.js → journeyDiagram-VCZTEJTY-C42hXNha.js} +1 -1
  41. package/dist/assets/{kanban-definition-UN3LZRKU-Bqjdyv0T.js → kanban-definition-6JOO6SKY-CEq930ew.js} +1 -1
  42. package/dist/assets/katex-DkKDou_j.js +257 -0
  43. package/dist/assets/layout-qtUgN9BC.js +1 -0
  44. package/dist/assets/{linear-DecnRXf0.js → linear-D158F7OT.js} +1 -1
  45. package/dist/assets/min-hESxN-c0.js +1 -0
  46. package/dist/assets/{mindmap-definition-RKZ34NQL-DM1x9vNY.js → mindmap-definition-QFDTVHPH-d9SSh2nG.js} +7 -7
  47. package/dist/assets/mobile-1gVCT0OK.css +1 -0
  48. package/dist/assets/mobile-Chw8RWyH.js +17 -0
  49. package/dist/assets/pieDiagram-DEJITSTG-gglmeMav.js +30 -0
  50. package/dist/assets/quadrantDiagram-34T5L4WZ-CqFC_htU.js +7 -0
  51. package/dist/assets/{requirementDiagram-4Y6WPE33-DD-Gg_y5.js → requirementDiagram-MS252O5E-B1ZFIotK.js} +1 -1
  52. package/dist/assets/sankeyDiagram-XADWPNL6-BvItvZt5.js +10 -0
  53. package/dist/assets/sequenceDiagram-FGHM5R23-CAIn5Z3U.js +157 -0
  54. package/dist/assets/stateDiagram-FHFEXIEX-CyJrGzib.js +1 -0
  55. package/dist/assets/stateDiagram-v2-QKLJ7IA2-DprhF_Ho.js +1 -0
  56. package/dist/assets/{timeline-definition-PNZ67QCA-BPm2AEQj.js → timeline-definition-GMOUNBTQ-k_0vJQAK.js} +1 -1
  57. package/dist/assets/{vennDiagram-CIIHVFJN-DQCDWwlj.js → vennDiagram-DHZGUBPP-TZAW60b0.js} +4 -4
  58. package/dist/assets/wardley-RL74JXVD-DzQEoG6X.js +162 -0
  59. package/dist/assets/wardleyDiagram-NUSXRM2D-BAoVVIjZ.js +20 -0
  60. package/dist/assets/{xychartDiagram-2RQKCTM6-Ba05SXXF.js → xychartDiagram-5P7HB3ND-CynkZcUb.js} +1 -1
  61. package/dist/index.html +4 -4
  62. package/lib/build-all.js +2 -1
  63. package/lib/build.js +363 -38
  64. package/lib/checkpoint/checkpoint-writer.js +3 -2
  65. package/lib/codex-preflight.js +151 -0
  66. package/lib/completion-writer.js +59 -15
  67. package/lib/feature-json.js +14 -3
  68. package/lib/feature-validator.js +27 -10
  69. package/lib/feature-write-guard.js +5 -7
  70. package/lib/feature-writer.js +3 -3
  71. package/lib/followup-writer.js +2 -2
  72. package/lib/get-roadmap.js +2 -2
  73. package/lib/gsd.js +2 -1
  74. package/lib/hooks-status.js +135 -0
  75. package/lib/ideabox.js +3 -2
  76. package/lib/install-agent-defs.js +22 -0
  77. package/lib/journal-writer.js +3 -3
  78. package/lib/migrate-anon.js +277 -0
  79. package/lib/migrate-roadmap.js +2 -3
  80. package/lib/paths-core.js +47 -0
  81. package/lib/project-paths.js +46 -37
  82. package/lib/roadmap-gen.js +3 -4
  83. package/lib/roadmap-graph/collect.js +5 -5
  84. package/lib/roadmap-graph/index.js +2 -2
  85. package/lib/roadmap-parser.js +1 -1
  86. package/lib/state-migrations.js +3 -3
  87. package/lib/test-bootstrap.js +165 -2
  88. package/lib/tracker/local-provider.js +2 -2
  89. package/lib/triage.js +7 -5
  90. package/lib/vocabulary-inject.js +103 -0
  91. package/lib/xref-push.js +4 -4
  92. package/lib/xref-sync.js +4 -4
  93. package/package.json +2 -1
  94. package/pipelines/build-quick.stratum.yaml +433 -0
  95. package/pipelines/build.stratum.yaml +60 -3
  96. package/scripts/watch-server.sh +32 -0
  97. package/server/build-routes.js +89 -9
  98. package/server/build-stream-bridge.js +12 -0
  99. package/server/compose-mcp-tools.js +73 -1
  100. package/server/compose-mcp.js +27 -0
  101. package/server/design-routes.js +9 -4
  102. package/server/drift-axes.js +5 -3
  103. package/server/feature-scaffold-routes.js +82 -0
  104. package/server/feature-scan.js +8 -2
  105. package/server/file-watcher.js +13 -7
  106. package/server/health-routes.js +261 -0
  107. package/server/ideabox-routes.js +12 -11
  108. package/server/project-root.js +7 -4
  109. package/server/qa-scope-routes.js +96 -0
  110. package/server/session-routes.js +2 -2
  111. package/server/stratum-sync.js +85 -9
  112. package/server/validate-routes.js +70 -0
  113. package/server/vision-routes.js +46 -2
  114. package/server/vision-server.js +25 -3
  115. package/server/vision-utils.js +23 -4
  116. package/dist/assets/App-DOerhoDp.js +0 -706
  117. package/dist/assets/architectureDiagram-3BPJPVTR-C4hfxNOw.js +0 -36
  118. package/dist/assets/blockDiagram-GPEHLZMM-DRqkGncy.js +0 -132
  119. package/dist/assets/channel-KsY1x-7s.js +0 -1
  120. package/dist/assets/chunk-727SXJPM-CeKpXDif.js +0 -206
  121. package/dist/assets/chunk-AQP2D5EJ-y2XL-YHV.js +0 -231
  122. package/dist/assets/classDiagram-4FO5ZUOK-zDEDoVPk.js +0 -1
  123. package/dist/assets/classDiagram-v2-Q7XG4LA2-zDEDoVPk.js +0 -1
  124. package/dist/assets/dagre-BM42HDAG-klZ_GOcw.js +0 -4
  125. package/dist/assets/diagram-2AECGRRQ-D0FmM6Wf.js +0 -43
  126. package/dist/assets/diagram-5GNKFQAL-DYuhby6q.js +0 -10
  127. package/dist/assets/diagram-KO2AKTUF-CCtQZgal.js +0 -3
  128. package/dist/assets/diagram-LMA3HP47-Cd1OqEln.js +0 -24
  129. package/dist/assets/diagram-OG6HWLK6-CiJrhoxo.js +0 -24
  130. package/dist/assets/ganttDiagram-6RSMTGT7-EPbL_2Hr.js +0 -292
  131. package/dist/assets/gitGraphDiagram-PVQCEYII-COCoF_vW.js +0 -106
  132. package/dist/assets/graph-BBXaecIU.js +0 -331
  133. package/dist/assets/graph-CAnANduQ.js +0 -1
  134. package/dist/assets/index-BwLfbbOu.css +0 -1
  135. package/dist/assets/index-DlgxA8dX.js +0 -123
  136. package/dist/assets/infoDiagram-5YYISTIA-B1sJw6j5.js +0 -2
  137. package/dist/assets/katex-C5jXJg4s.js +0 -257
  138. package/dist/assets/layout-DGIYPm2g.js +0 -1
  139. package/dist/assets/mobile-Cag5dHlF.css +0 -1
  140. package/dist/assets/mobile-DwmxS_O4.js +0 -17
  141. package/dist/assets/pieDiagram-4H26LBE5-CRtmCvwV.js +0 -30
  142. package/dist/assets/quadrantDiagram-W4KKPZXB-CsBLWg27.js +0 -7
  143. package/dist/assets/sankeyDiagram-5OEKKPKP-BPdMN8UU.js +0 -40
  144. package/dist/assets/sequenceDiagram-3UESZ5HK-D4AENdze.js +0 -162
  145. package/dist/assets/stateDiagram-AJRCARHV-DDplpCf_.js +0 -1
  146. package/dist/assets/stateDiagram-v2-BHNVJYJU-J4t9AVzF.js +0 -1
  147. package/dist/assets/wardley-L42UT6IY-WERqOmJt.js +0 -173
  148. package/dist/assets/wardleyDiagram-YWT4CUSO-5teUSOiI.js +0 -78
@@ -42,7 +42,10 @@ function getSchemaValidator() {
42
42
  }
43
43
 
44
44
  import { randomUUID } from 'node:crypto';
45
- import { getTargetRoot, resolveProjectPath, loadProjectConfig } from './project-root.js';
45
+ import { getTargetRoot, resolveProjectPath } from './project-root.js';
46
+ import { resolveFeaturesPathFromConfig } from '../lib/project-paths.js';
47
+ import { getCompletions } from '../lib/completion-writer.js';
48
+ import { isFeatureCode } from '../lib/feature-code.js';
46
49
  import { anchorBoundary } from '../lib/checkpoint/checkpoint-writer.js';
47
50
  import { appendGateLogEntry, readGateLog, mapResolveOutcomeToSchema } from './gate-log-store.js';
48
51
  import { addOpenLoop, resolveOpenLoop, listOpenLoops } from './open-loops-store.js';
@@ -55,6 +58,20 @@ import { requireSensitiveOrPaired as requireSensitiveToken } from './security.js
55
58
 
56
59
  const PROJECT_ROOT = getTargetRoot();
57
60
 
61
+ /**
62
+ * Read the compose.json config for an ARBITRARY workspace root (not the bound
63
+ * target). The alternate-root lifecycle branch must resolve `paths.features`
64
+ * against that root's own config, not the process-global cache
65
+ * (COMP-PATHS-EXTERNAL, Decision 1 / Codex finding 3).
66
+ */
67
+ function loadComposeConfig(root) {
68
+ try {
69
+ return JSON.parse(fs.readFileSync(path.join(root, '.compose', 'compose.json'), 'utf-8'));
70
+ } catch {
71
+ return {};
72
+ }
73
+ }
74
+
58
75
  /**
59
76
  * Attach vision CRUD and lifecycle REST routes to an Express app.
60
77
  *
@@ -78,6 +95,33 @@ export function attachVisionRoutes(app, { store, scheduleBroadcast, broadcastMes
78
95
  const guardAuthEnabled = capabilities?.guardAuth === true;
79
96
  const guardAuth = (req, res, next) =>
80
97
  guardAuthEnabled ? requireSensitiveToken(req, res, next) : next();
98
+
99
+ // PARITY-5: GET /api/completions — read-only recorded-completion log for a
100
+ // feature. Reads are open (not guardAuth-wrapped); wraps the same
101
+ // getCompletions() the CLI uses so the cockpit and CLI agree byte-for-byte.
102
+ app.get('/api/completions', (req, res) => {
103
+ try {
104
+ const opts = {};
105
+ const fc = req.query.featureCode;
106
+ if (typeof fc === 'string' && fc) {
107
+ // This route is open (no auth) and feature_code is join()'d into a
108
+ // filesystem path downstream (feature-json.js#readFeature). Reject
109
+ // anything that isn't a canonical feature code so `../`-style traversal
110
+ // can't read feature.json outside the features dir.
111
+ if (!isFeatureCode(fc)) {
112
+ return res.status(400).json({ error: 'invalid featureCode' });
113
+ }
114
+ opts.feature_code = fc;
115
+ }
116
+ const rawLimit = parseInt(req.query.limit, 10);
117
+ if (Number.isFinite(rawLimit)) opts.limit = rawLimit;
118
+ const result = getCompletions(getTargetRoot(), opts);
119
+ res.json(result);
120
+ } catch (err) {
121
+ res.status(400).json({ error: err.message || String(err) });
122
+ }
123
+ });
124
+
81
125
  // GET /api/vision/items — full state (optional ?group= filter)
82
126
  app.get('/api/vision/items', (req, res) => {
83
127
  let state = store.getState();
@@ -167,7 +211,7 @@ export function attachVisionRoutes(app, { store, scheduleBroadcast, broadcastMes
167
211
 
168
212
  // ── Lifecycle endpoints (simplified — no state machine) ──────────────
169
213
  const featuresPath = projectRoot !== PROJECT_ROOT
170
- ? path.join(projectRoot, loadProjectConfig().paths?.features || 'docs/features')
214
+ ? resolveFeaturesPathFromConfig(projectRoot, loadComposeConfig(projectRoot))
171
215
  : resolveProjectPath('features');
172
216
 
173
217
  // Phase graph + SKIPPABLE + TERMINAL are owned by lifecycle-guard.js (single
@@ -27,11 +27,15 @@ import { attachSessionRoutes } from './session-routes.js';
27
27
  import { attachActivityRoutes } from './activity-routes.js';
28
28
  import { SettingsStore } from './settings-store.js';
29
29
  import { attachSettingsRoutes } from './settings-routes.js';
30
+ import { attachHealthRoutes } from './health-routes.js';
31
+ import { attachValidateRoutes } from './validate-routes.js';
32
+ import { attachQaScopeRoutes } from './qa-scope-routes.js';
30
33
  import { attachDesignRoutes } from './design-routes.js';
31
34
  import { DesignSessionManager } from './design-session.js';
32
35
  import { attachPipelineRoutes } from './pipeline-routes.js';
33
36
  import { attachIdeaboxRoutes } from './ideabox-routes.js';
34
37
  import { attachBuildRoutes } from './build-routes.js';
38
+ import { attachFeatureScaffoldRoutes } from './feature-scaffold-routes.js';
35
39
  import { attachJournalRoutes } from './journal-routes.js';
36
40
  import { CoalescingBuffer } from './coalescing-buffer.js';
37
41
  /** Settings defaults (previously derived from contracts/lifecycle.json). */
@@ -55,7 +59,8 @@ const SETTINGS_DEFAULTS = {
55
59
  policyModes: ['gate', 'flag', 'skip'],
56
60
  };
57
61
 
58
- import { getTargetRoot, getDataDir } from './project-root.js';
62
+ import { getTargetRoot, getDataDir, resolveProjectPath } from './project-root.js';
63
+ import { relForDisplay } from '../lib/project-paths.js';
59
64
 
60
65
  export class VisionServer {
61
66
  constructor(store, sessionManager = null, { config } = {}) {
@@ -84,6 +89,19 @@ export class VisionServer {
84
89
  broadcastMessage: (msg) => this.broadcastMessage(msg),
85
90
  });
86
91
 
92
+ // ── Environment-health route (COMP-PARITY-3) ──────────────────────────
93
+ // Read-only GET /api/environment-health; resolves its own compose package
94
+ // root + composeBin/Node defaults, reads hooks off req.workspace.
95
+ attachHealthRoutes(app);
96
+
97
+ // ── Cross-artifact validation findings (COMP-PARITY-6) ─────────────────
98
+ // Read-only GET /api/validate; reads workspace off req.workspace.
99
+ attachValidateRoutes(app);
100
+
101
+ // ── QA-scope affected-routes panel (COMP-PARITY-10) ────────────────────
102
+ // Read-only GET /api/qa-scope?featureCode=…; reads off req.workspace.
103
+ attachQaScopeRoutes(app);
104
+
87
105
  // ── Vision CRUD + lifecycle routes ─────────────────────────────────────
88
106
  attachVisionRoutes(app, {
89
107
  store: this.store,
@@ -151,6 +169,10 @@ export class VisionServer {
151
169
  // ── Build start/abort routes (sensitive) ───────────────────────────────
152
170
  attachBuildRoutes(app);
153
171
 
172
+ // ── Feature scaffolding (COMP-PARITY-9, sensitive) ─────────────────────
173
+ // POST /api/features/scaffold — writes feature.json + a ROADMAP row.
174
+ attachFeatureScaffoldRoutes(app, { getProjectRoot: () => getTargetRoot() });
175
+
154
176
  // ── Build state hydration ─────────────────────────────────────────────
155
177
  app.get('/api/build/state', (_req, res) => {
156
178
  const buildPath = path.join(getDataDir(), 'active-build.json');
@@ -264,7 +286,7 @@ export class VisionServer {
264
286
  const projectsRoot = process.env.CC_PROJECTS_ROOT ||
265
287
  path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude', 'projects');
266
288
  const sessionsFile = this.sessionManager?.sessionsFile || path.join(getDataDir(), 'sessions.json');
267
- const featureRoot = path.join(getTargetRoot(), 'docs', 'features');
289
+ const featureRoot = resolveProjectPath('features');
268
290
 
269
291
  const findItemIdByFeatureCode = (fc) => {
270
292
  for (const it of this.store.items.values()) {
@@ -457,7 +479,7 @@ export class VisionServer {
457
479
  /** Resolve a file path to matching tracker items */
458
480
  resolveItems(filePath) {
459
481
  const rel = filePath.startsWith(getTargetRoot())
460
- ? filePath.slice(getTargetRoot().length + 1)
482
+ ? relForDisplay(getTargetRoot(), filePath)
461
483
  : filePath.replace(/^\.\//, '');
462
484
  const matches = [];
463
485
  const matchType = new Map();
@@ -10,10 +10,25 @@ import fs from 'node:fs';
10
10
  import path from 'node:path';
11
11
  import { fileURLToPath } from 'node:url';
12
12
 
13
- import { getTargetRoot, loadProjectConfig } from './project-root.js';
13
+ import { getTargetRoot } from './project-root.js';
14
+ import { resolveJournalPathFromConfig, relForDisplay } from '../lib/project-paths.js';
14
15
 
15
16
  const PROJECT_ROOT = getTargetRoot();
16
17
 
18
+ /**
19
+ * Read the compose.json config for an ARBITRARY workspace root (not the bound
20
+ * target). Routes/agents that serve an alternate `projectRoot` must resolve
21
+ * artifact paths against that root's own config, not the process-global cache
22
+ * (COMP-PATHS-EXTERNAL, Decision 1 / Codex finding 3).
23
+ */
24
+ function loadComposeConfig(root) {
25
+ try {
26
+ return JSON.parse(fs.readFileSync(path.join(root, '.compose', 'compose.json'), 'utf-8'));
27
+ } catch {
28
+ return {};
29
+ }
30
+ }
31
+
17
32
  // ---------------------------------------------------------------------------
18
33
  // Error detection
19
34
  // ---------------------------------------------------------------------------
@@ -71,8 +86,12 @@ export function detectError(tool, input, responseText) {
71
86
  * @param {string} [projectRoot] — defaults to PROJECT_ROOT
72
87
  */
73
88
  export function spawnJournalAgent(session, transcriptPath, projectRoot = PROJECT_ROOT) {
74
- const config = loadProjectConfig();
75
- const journalRel = config.paths?.journal || 'docs/journal';
89
+ // Resolve the journal path against the PASSED projectRoot's own config not
90
+ // the process-global cached config of the bound target (COMP-PATHS-EXTERNAL).
91
+ const journalAbs = resolveJournalPathFromConfig(projectRoot, loadComposeConfig(projectRoot));
92
+ // Display path for the agent prompt: clean relative when in-root (the agent
93
+ // runs with cwd: projectRoot), absolute when the journal escapes the root.
94
+ const journalRel = relForDisplay(projectRoot, journalAbs);
76
95
 
77
96
  const itemSummaries = Object.entries(session.items || {})
78
97
  .map(([_id, data]) => `- ${data.title}: ${data.writes} writes, ${data.reads} reads. ${(data.summaries || []).map(s => s.summary || '').filter(Boolean).join('. ')}`)
@@ -88,7 +107,7 @@ export function spawnJournalAgent(session, transcriptPath, projectRoot = PROJECT
88
107
  const today = new Date().toISOString().slice(0, 10);
89
108
  let sessionNum = 0;
90
109
  try {
91
- const entries = fs.readdirSync(path.join(projectRoot, journalRel));
110
+ const entries = fs.readdirSync(journalAbs);
92
111
  for (const f of entries) {
93
112
  const m = f.match(new RegExp(`^${today}-session-(\\d+)`));
94
113
  if (m) sessionNum = Math.max(sessionNum, parseInt(m[1]) + 1);