@smartmemory/compose 0.2.50-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 (118) 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 +310 -52
  5. package/dist/assets/App-CT0vXPgd.js +724 -0
  6. package/dist/assets/_baseUniq-CsOHc_iS.js +1 -0
  7. package/dist/assets/{arc-DeHak63Z.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-BsFJmPuS.js → c4Diagram-AHTNJAMY-nBIRLJTv.js} +1 -1
  12. package/dist/assets/channel-Dd4XaiYv.js +1 -0
  13. package/dist/assets/{chunk-4BX2VUAB-XO4S2_89.js → chunk-4BX2VUAB-CNmGyhrp.js} +1 -1
  14. package/dist/assets/chunk-4TB4RGXK-MLT7I7w4.js +206 -0
  15. package/dist/assets/{chunk-55IACEB6-CtFSLInj.js → chunk-55IACEB6-D8KuKVLa.js} +1 -1
  16. package/dist/assets/{chunk-2J33WTMH-AEu6HIoY.js → chunk-EDXVE4YY-TPlt1bS2.js} +1 -1
  17. package/dist/assets/{chunk-FMBD7UC4-BMGd_Y9a.js → chunk-FMBD7UC4-tYY8xcjr.js} +1 -1
  18. package/dist/assets/chunk-OYMX7WX6-yBPwT1AT.js +231 -0
  19. package/dist/assets/{chunk-QZHKN3VN-DHhUJ8RK.js → chunk-QZHKN3VN-B4Wfybww.js} +1 -1
  20. package/dist/assets/{chunk-ND2GUHAM-BlrOECEr.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-C3M0mZqk.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-AMDitV0b.js → erDiagram-SMLLAGMA-CtxJi57K.js} +1 -1
  31. package/dist/assets/{flowDiagram-I6XJVG4X-C0t2ZGQv.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-CCBwgjFs.js → ishikawaDiagram-UXIWVN3A-DWx-7BBy.js} +5 -5
  40. package/dist/assets/{journeyDiagram-JHISSGLW-zUJN38EU.js → journeyDiagram-VCZTEJTY-C42hXNha.js} +1 -1
  41. package/dist/assets/{kanban-definition-UN3LZRKU-BNxWi-8J.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-CRH9b4g7.js → linear-D158F7OT.js} +1 -1
  45. package/dist/assets/min-hESxN-c0.js +1 -0
  46. package/dist/assets/{mindmap-definition-RKZ34NQL-DolYwq7Y.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-DsXZ05jo.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-Bvnhw58e.js → timeline-definition-GMOUNBTQ-k_0vJQAK.js} +1 -1
  57. package/dist/assets/{vennDiagram-CIIHVFJN-5WnyjZqf.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-BCShes6B.js → xychartDiagram-5P7HB3ND-CynkZcUb.js} +1 -1
  61. package/dist/index.html +4 -4
  62. package/lib/build.js +272 -33
  63. package/lib/codex-preflight.js +151 -0
  64. package/lib/completion-writer.js +21 -1
  65. package/lib/feature-validator.js +5 -1
  66. package/lib/hooks-status.js +135 -0
  67. package/lib/install-agent-defs.js +22 -0
  68. package/lib/migrate-anon.js +277 -0
  69. package/lib/roadmap-parser.js +1 -1
  70. package/lib/test-bootstrap.js +165 -2
  71. package/lib/vocabulary-inject.js +103 -0
  72. package/package.json +2 -1
  73. package/pipelines/build-quick.stratum.yaml +433 -0
  74. package/pipelines/build.stratum.yaml +60 -3
  75. package/scripts/watch-server.sh +32 -0
  76. package/server/build-routes.js +89 -9
  77. package/server/build-stream-bridge.js +12 -0
  78. package/server/compose-mcp-tools.js +73 -1
  79. package/server/compose-mcp.js +27 -0
  80. package/server/feature-scaffold-routes.js +82 -0
  81. package/server/health-routes.js +261 -0
  82. package/server/qa-scope-routes.js +96 -0
  83. package/server/validate-routes.js +70 -0
  84. package/server/vision-routes.js +29 -0
  85. package/server/vision-server.js +21 -0
  86. package/dist/assets/App-Bxyif1yv.js +0 -706
  87. package/dist/assets/architectureDiagram-3BPJPVTR-C5Nkyl9y.js +0 -36
  88. package/dist/assets/blockDiagram-GPEHLZMM-BilnUBG2.js +0 -132
  89. package/dist/assets/channel-ZgbQ1k0u.js +0 -1
  90. package/dist/assets/chunk-727SXJPM-CZeBRpM9.js +0 -206
  91. package/dist/assets/chunk-AQP2D5EJ-_vmxcBc4.js +0 -231
  92. package/dist/assets/classDiagram-4FO5ZUOK-KXxOorUx.js +0 -1
  93. package/dist/assets/classDiagram-v2-Q7XG4LA2-KXxOorUx.js +0 -1
  94. package/dist/assets/dagre-BM42HDAG-DJlm4fEk.js +0 -4
  95. package/dist/assets/diagram-2AECGRRQ-BmcONQG5.js +0 -43
  96. package/dist/assets/diagram-5GNKFQAL-5JbWGIwd.js +0 -10
  97. package/dist/assets/diagram-KO2AKTUF-DAnIvyI0.js +0 -3
  98. package/dist/assets/diagram-LMA3HP47-Bmh7tvmI.js +0 -24
  99. package/dist/assets/diagram-OG6HWLK6-hnHVMNnk.js +0 -24
  100. package/dist/assets/ganttDiagram-6RSMTGT7-BPlM-BEN.js +0 -292
  101. package/dist/assets/gitGraphDiagram-PVQCEYII-Lv_YTxnb.js +0 -106
  102. package/dist/assets/graph-BBXaecIU.js +0 -331
  103. package/dist/assets/graph-CAnANduQ.js +0 -1
  104. package/dist/assets/index-BwLfbbOu.css +0 -1
  105. package/dist/assets/index-COq21Zym.js +0 -119
  106. package/dist/assets/infoDiagram-5YYISTIA-Dul1vdUm.js +0 -2
  107. package/dist/assets/katex-C5jXJg4s.js +0 -257
  108. package/dist/assets/layout-DGIYPm2g.js +0 -1
  109. package/dist/assets/mobile-Cag5dHlF.css +0 -1
  110. package/dist/assets/mobile-DwmxS_O4.js +0 -17
  111. package/dist/assets/pieDiagram-4H26LBE5-oxNfr2TX.js +0 -30
  112. package/dist/assets/quadrantDiagram-W4KKPZXB-BmZCvD-z.js +0 -7
  113. package/dist/assets/sankeyDiagram-5OEKKPKP-DsnYaawP.js +0 -40
  114. package/dist/assets/sequenceDiagram-3UESZ5HK-Dt5mu3g8.js +0 -162
  115. package/dist/assets/stateDiagram-AJRCARHV-BFR5ZINQ.js +0 -1
  116. package/dist/assets/stateDiagram-v2-BHNVJYJU-BDrQD8fR.js +0 -1
  117. package/dist/assets/wardley-L42UT6IY-CTxW4xow.js +0 -173
  118. package/dist/assets/wardleyDiagram-YWT4CUSO-K8Y1EOvb.js +0 -78
@@ -0,0 +1,96 @@
1
+ /**
2
+ * qa-scope-routes.js — Read-only QA-scope REST API (COMP-PARITY-10).
3
+ *
4
+ * Route:
5
+ * GET /api/qa-scope?featureCode=<CODE> — surfaces `compose qa-scope <CODE>`
6
+ * (diff-to-route mapping from COMP-QA) as structured JSON for the cockpit's
7
+ * QA Scope view. Maps the feature's recorded filesChanged → affected /
8
+ * adjacent routes via lib/qa-scoping.js. Read-only, no side effects.
9
+ *
10
+ * Not auth-gated (mirrors GET /api/environment-health): it reads only
11
+ * feature.json + heuristic route mapping, no host paths leaked, no mutation.
12
+ *
13
+ * Degrade-never-fail: a bad feature code or unreadable feature.json returns a
14
+ * structured { found:false } / empty result, never a 500.
15
+ *
16
+ * Reuses (no logic fork):
17
+ * - lib/feature-json.js — readFeature(cwd, code)
18
+ * - lib/qa-scoping.js — mapFilesToRoutes(filesChanged,{cwd}), classifyRoutes(routes,[])
19
+ */
20
+ import { readFeature as defaultReadFeature } from '../lib/feature-json.js';
21
+ import {
22
+ mapFilesToRoutes as defaultMapFilesToRoutes,
23
+ classifyRoutes as defaultClassifyRoutes,
24
+ } from '../lib/qa-scoping.js';
25
+
26
+ /**
27
+ * @param {import('express').Express} app
28
+ * @param {object} [deps]
29
+ * @param {Function} [deps.readFeature] — (cwd, code) => FeatureJson|null
30
+ * @param {Function} [deps.mapFilesToRoutes] — (filesChanged, {cwd}) => {affectedRoutes,unmappedFiles,framework,docsOnly}
31
+ * @param {Function} [deps.classifyRoutes] — (routes, allKnown) => {affected,adjacent}
32
+ */
33
+ export function attachQaScopeRoutes(app, {
34
+ readFeature = defaultReadFeature,
35
+ mapFilesToRoutes = defaultMapFilesToRoutes,
36
+ classifyRoutes = defaultClassifyRoutes,
37
+ } = {}) {
38
+ app.get('/api/qa-scope', (req, res) => {
39
+ const featureCode = (req.query.featureCode || '').toString().trim();
40
+ if (!featureCode) {
41
+ return res.json({ found: false, error: 'featureCode required' });
42
+ }
43
+
44
+ const root = req.workspace?.root;
45
+ if (!root) {
46
+ return res.json({ found: false, error: 'no workspace root', featureCode });
47
+ }
48
+
49
+ let feature;
50
+ try {
51
+ feature = readFeature(root, featureCode);
52
+ } catch {
53
+ feature = null;
54
+ }
55
+ if (!feature) {
56
+ return res.json({ found: false, featureCode });
57
+ }
58
+
59
+ const filesChanged = feature.filesChanged ?? [];
60
+ if (filesChanged.length === 0) {
61
+ // Mirror the CLI's empty-diff guidance (bin/compose.js:2716-2719).
62
+ return res.json({
63
+ found: true,
64
+ featureCode,
65
+ filesChanged: [],
66
+ framework: 'unknown',
67
+ docsOnly: false,
68
+ affected: [],
69
+ adjacent: [],
70
+ unmappedFiles: [],
71
+ emptyDiff: true,
72
+ });
73
+ }
74
+
75
+ // Same pipeline as the CLI (bin/compose.js:2722-2724); allKnown=[] (v1: no registry).
76
+ let result, classified;
77
+ try {
78
+ result = mapFilesToRoutes(filesChanged, { cwd: root });
79
+ classified = classifyRoutes(result.affectedRoutes, []);
80
+ } catch (e) {
81
+ return res.json({ found: true, featureCode, error: e?.message || 'qa-scope failed' });
82
+ }
83
+
84
+ res.json({
85
+ found: true,
86
+ featureCode,
87
+ filesChanged,
88
+ framework: result.framework,
89
+ docsOnly: result.docsOnly,
90
+ affected: classified.affected,
91
+ adjacent: classified.adjacent,
92
+ unmappedFiles: result.unmappedFiles,
93
+ emptyDiff: false,
94
+ });
95
+ });
96
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * validate-routes.js — Read-only cross-artifact validation REST API (COMP-PARITY-6).
3
+ *
4
+ * Route:
5
+ * GET /api/validate?scope=feature|project&featureCode=<CODE>
6
+ * Surfaces `compose validate` (lib/feature-validator.js validateFeature/
7
+ * validateProject) as structured JSON for the cockpit Validate view.
8
+ * Read-only; local-only (no network xref resolution); degrades, never 500s.
9
+ *
10
+ * Deliberately NOT under an auth-allowlisted prefix (mirrors health-routes.js):
11
+ * non-allowlisted → default-deny in remote mode, open on localhost.
12
+ *
13
+ * Reuses (no logic fork): lib/feature-validator.js validateFeature/validateProject.
14
+ */
15
+ import {
16
+ validateFeature as defaultValidateFeature,
17
+ validateProject as defaultValidateProject,
18
+ } from '../lib/feature-validator.js';
19
+
20
+ const SEVERITIES = ['error', 'warning', 'info'];
21
+
22
+ /** Group a findings array into { error: n, warning: n, info: n }. */
23
+ export function summarizeFindings(findings = []) {
24
+ const by = { error: 0, warning: 0, info: 0 };
25
+ for (const f of findings) {
26
+ if (by[f?.severity] !== undefined) by[f.severity] += 1;
27
+ }
28
+ return by;
29
+ }
30
+
31
+ /**
32
+ * @param {import('express').Express} app
33
+ * @param {object} [deps]
34
+ * @param {Function} [deps.validateFeature] — injectable (default: lib validator)
35
+ * @param {Function} [deps.validateProject] — injectable (default: lib validator)
36
+ */
37
+ export function attachValidateRoutes(app, {
38
+ validateFeature = defaultValidateFeature,
39
+ validateProject = defaultValidateProject,
40
+ } = {}) {
41
+ app.get('/api/validate', async (req, res) => {
42
+ const root = req.workspace?.root;
43
+ if (!root) {
44
+ // No workspace to validate — a guarded failure, not a 500.
45
+ return res.json({ scope: null, findings: [], bySeverity: summarizeFindings([]), unavailable: true });
46
+ }
47
+ const scope = req.query.scope === 'feature' ? 'feature' : 'project';
48
+ const featureCode = typeof req.query.featureCode === 'string' ? req.query.featureCode : null;
49
+
50
+ if (scope === 'feature' && !featureCode) {
51
+ return res.status(400).json({ error: 'scope=feature requires featureCode' });
52
+ }
53
+
54
+ try {
55
+ const result = scope === 'feature'
56
+ ? await validateFeature(root, featureCode) // local-only; no `external`
57
+ : await validateProject(root, {}); // local-only; no `external`
58
+ const findings = Array.isArray(result.findings) ? result.findings : [];
59
+ // Pass the validator result through verbatim + add the severity rollup.
60
+ return res.json({ ...result, bySeverity: summarizeFindings(findings) });
61
+ } catch (err) {
62
+ // validateCode throws INVALID_INPUT on a malformed feature code → 400.
63
+ if (err && err.code === 'INVALID_INPUT') {
64
+ return res.status(400).json({ error: err.message });
65
+ }
66
+ // Any other failure degrades to a non-500 unavailable body.
67
+ return res.json({ scope, feature_code: featureCode, findings: [], bySeverity: summarizeFindings([]), unavailable: true, error: err?.message || 'validate failed' });
68
+ }
69
+ });
70
+ }
@@ -44,6 +44,8 @@ function getSchemaValidator() {
44
44
  import { randomUUID } from 'node:crypto';
45
45
  import { getTargetRoot, resolveProjectPath } from './project-root.js';
46
46
  import { resolveFeaturesPathFromConfig } from '../lib/project-paths.js';
47
+ import { getCompletions } from '../lib/completion-writer.js';
48
+ import { isFeatureCode } from '../lib/feature-code.js';
47
49
  import { anchorBoundary } from '../lib/checkpoint/checkpoint-writer.js';
48
50
  import { appendGateLogEntry, readGateLog, mapResolveOutcomeToSchema } from './gate-log-store.js';
49
51
  import { addOpenLoop, resolveOpenLoop, listOpenLoops } from './open-loops-store.js';
@@ -93,6 +95,33 @@ export function attachVisionRoutes(app, { store, scheduleBroadcast, broadcastMes
93
95
  const guardAuthEnabled = capabilities?.guardAuth === true;
94
96
  const guardAuth = (req, res, next) =>
95
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
+
96
125
  // GET /api/vision/items — full state (optional ?group= filter)
97
126
  app.get('/api/vision/items', (req, res) => {
98
127
  let state = store.getState();
@@ -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). */
@@ -85,6 +89,19 @@ export class VisionServer {
85
89
  broadcastMessage: (msg) => this.broadcastMessage(msg),
86
90
  });
87
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
+
88
105
  // ── Vision CRUD + lifecycle routes ─────────────────────────────────────
89
106
  attachVisionRoutes(app, {
90
107
  store: this.store,
@@ -152,6 +169,10 @@ export class VisionServer {
152
169
  // ── Build start/abort routes (sensitive) ───────────────────────────────
153
170
  attachBuildRoutes(app);
154
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
+
155
176
  // ── Build state hydration ─────────────────────────────────────────────
156
177
  app.get('/api/build/state', (_req, res) => {
157
178
  const buildPath = path.join(getDataDir(), 'active-build.json');