aios-core 4.0.4 → 4.2.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 (107) hide show
  1. package/.aios-core/cli/commands/migrate/analyze.js +6 -6
  2. package/.aios-core/cli/commands/migrate/backup.js +2 -2
  3. package/.aios-core/cli/commands/migrate/execute.js +4 -4
  4. package/.aios-core/cli/commands/migrate/index.js +5 -5
  5. package/.aios-core/cli/commands/migrate/rollback.js +6 -6
  6. package/.aios-core/cli/commands/migrate/update-imports.js +2 -2
  7. package/.aios-core/cli/commands/migrate/validate.js +2 -2
  8. package/.aios-core/cli/commands/pro/index.js +52 -0
  9. package/.aios-core/cli/index.js +1 -1
  10. package/.aios-core/core/ids/registry-updater.js +29 -3
  11. package/.aios-core/core/migration/migration-config.yaml +2 -2
  12. package/.aios-core/core/migration/module-mapping.yaml +2 -2
  13. package/.aios-core/core/registry/README.md +2 -2
  14. package/.aios-core/core/synapse/context/context-builder.js +34 -0
  15. package/.aios-core/core/synapse/diagnostics/collectors/consistency-collector.js +168 -0
  16. package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +129 -0
  17. package/.aios-core/core/synapse/diagnostics/collectors/manifest-collector.js +82 -0
  18. package/.aios-core/core/synapse/diagnostics/collectors/output-analyzer.js +134 -0
  19. package/.aios-core/core/synapse/diagnostics/collectors/pipeline-collector.js +75 -0
  20. package/.aios-core/core/synapse/diagnostics/collectors/quality-collector.js +252 -0
  21. package/.aios-core/core/synapse/diagnostics/collectors/relevance-matrix.js +174 -0
  22. package/.aios-core/core/synapse/diagnostics/collectors/safe-read-json.js +31 -0
  23. package/.aios-core/core/synapse/diagnostics/collectors/session-collector.js +102 -0
  24. package/.aios-core/core/synapse/diagnostics/collectors/timing-collector.js +126 -0
  25. package/.aios-core/core/synapse/diagnostics/collectors/uap-collector.js +83 -0
  26. package/.aios-core/core/synapse/diagnostics/report-formatter.js +484 -0
  27. package/.aios-core/core/synapse/diagnostics/synapse-diagnostics.js +95 -0
  28. package/.aios-core/core/synapse/engine.js +73 -20
  29. package/.aios-core/core/synapse/runtime/hook-runtime.js +60 -0
  30. package/.aios-core/core-config.yaml +6 -0
  31. package/.aios-core/data/agent-config-requirements.yaml +2 -2
  32. package/.aios-core/data/aios-kb.md +4 -4
  33. package/.aios-core/data/entity-registry.yaml +210 -10
  34. package/.aios-core/data/registry-update-log.jsonl +52 -0
  35. package/.aios-core/development/agents/architect.md +10 -10
  36. package/.aios-core/development/agents/devops.md +93 -50
  37. package/.aios-core/development/agents/qa.md +94 -40
  38. package/.aios-core/development/agents/ux-design-expert.md +25 -25
  39. package/.aios-core/development/scripts/activation-runtime.js +63 -0
  40. package/.aios-core/development/scripts/generate-greeting.js +9 -8
  41. package/.aios-core/development/scripts/unified-activation-pipeline.js +102 -2
  42. package/.aios-core/development/tasks/{db-expansion-pack-integration.md → db-squad-integration.md} +5 -5
  43. package/.aios-core/development/tasks/{integrate-expansion-pack.md → integrate-squad.md} +2 -2
  44. package/.aios-core/development/tasks/next.md +3 -3
  45. package/.aios-core/development/tasks/pr-automation.md +2 -2
  46. package/.aios-core/development/tasks/publish-npm.md +257 -0
  47. package/.aios-core/development/tasks/release-management.md +4 -4
  48. package/.aios-core/development/tasks/setup-github.md +1 -1
  49. package/.aios-core/development/tasks/squad-creator-migrate.md +1 -1
  50. package/.aios-core/development/tasks/squad-creator-sync-ide-command.md +14 -14
  51. package/.aios-core/development/tasks/update-aios.md +1 -1
  52. package/.aios-core/development/tasks/validate-next-story.md +99 -2
  53. package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-QUICK-REFERENCE.md +1 -1
  54. package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-V2.1.md +5 -5
  55. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +21 -21
  56. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +25 -25
  57. package/.aios-core/docs/standards/OPEN-SOURCE-VS-SERVICE-DIFFERENCES.md +4 -4
  58. package/.aios-core/docs/standards/QUALITY-GATES-SPECIFICATION.md +3 -3
  59. package/.aios-core/docs/standards/STANDARDS-INDEX.md +13 -13
  60. package/.aios-core/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +1 -1
  61. package/.aios-core/framework-config.yaml +4 -0
  62. package/.aios-core/infrastructure/scripts/codex-skills-sync/index.js +182 -0
  63. package/.aios-core/infrastructure/scripts/codex-skills-sync/validate.js +172 -0
  64. package/.aios-core/infrastructure/scripts/ide-sync/README.md +14 -0
  65. package/.aios-core/infrastructure/scripts/ide-sync/index.js +6 -0
  66. package/.aios-core/infrastructure/scripts/tool-resolver.js +4 -4
  67. package/.aios-core/infrastructure/scripts/validate-paths.js +142 -0
  68. package/.aios-core/infrastructure/templates/aios-sync.yaml.template +11 -11
  69. package/.aios-core/infrastructure/templates/github-workflows/README.md +1 -1
  70. package/.aios-core/install-manifest.yaml +193 -109
  71. package/.aios-core/local-config.yaml.template +2 -0
  72. package/.aios-core/manifests/agents.csv +29 -1
  73. package/.aios-core/manifests/tasks.csv +80 -3
  74. package/.aios-core/product/README.md +2 -2
  75. package/.aios-core/product/data/integration-patterns.md +1 -1
  76. package/.aios-core/product/templates/ide-rules/cline-rules.md +1 -1
  77. package/.aios-core/product/templates/ide-rules/codex-rules.md +65 -0
  78. package/.aios-core/product/templates/ide-rules/copilot-rules.md +1 -1
  79. package/.aios-core/product/templates/ide-rules/roo-rules.md +1 -1
  80. package/.aios-core/user-guide.md +15 -14
  81. package/.aios-core/workflow-intelligence/engine/output-formatter.js +1 -1
  82. package/.claude/hooks/synapse-engine.js +9 -20
  83. package/README.md +14 -7
  84. package/bin/aios-init.js +255 -184
  85. package/bin/aios-minimal.js +2 -2
  86. package/bin/aios.js +4 -4
  87. package/package.json +6 -1
  88. package/packages/aios-pro-cli/bin/aios-pro.js +75 -2
  89. package/packages/aios-pro-cli/package.json +5 -1
  90. package/packages/aios-pro-cli/src/recover.js +100 -0
  91. package/packages/installer/src/__tests__/performance-benchmark.js +382 -0
  92. package/packages/installer/src/config/ide-configs.js +12 -1
  93. package/packages/installer/src/config/templates/core-config-template.js +2 -2
  94. package/packages/installer/src/installer/aios-core-installer.js +2 -2
  95. package/packages/installer/src/installer/file-hasher.js +97 -0
  96. package/packages/installer/src/installer/post-install-validator.js +41 -1
  97. package/packages/installer/src/pro/pro-scaffolder.js +335 -0
  98. package/packages/installer/src/utils/aios-colors.js +2 -2
  99. package/packages/installer/src/wizard/feedback.js +1 -1
  100. package/packages/installer/src/wizard/ide-config-generator.js +2 -2
  101. package/packages/installer/src/wizard/index.js +58 -19
  102. package/packages/installer/src/wizard/pro-setup.js +931 -0
  103. package/packages/installer/src/wizard/questions.js +20 -14
  104. package/packages/installer/src/wizard/validators.js +1 -1
  105. package/scripts/code-intel-health-check.js +343 -0
  106. package/scripts/package-synapse.js +323 -0
  107. package/scripts/validate-package-completeness.js +317 -0
@@ -0,0 +1,484 @@
1
+ /**
2
+ * Report Formatter — Generates structured markdown diagnostic report.
3
+ *
4
+ * Takes collector results and produces a human-readable report
5
+ * with sections for each diagnostic area.
6
+ *
7
+ * @module core/synapse/diagnostics/report-formatter
8
+ * @version 1.0.0
9
+ * @created Story SYN-13
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ /**
15
+ * Format a complete diagnostic report from collector results.
16
+ *
17
+ * @param {object} data - Collected diagnostic data
18
+ * @param {object} data.hook - Hook collector results
19
+ * @param {object} data.session - Session collector results
20
+ * @param {object} data.manifest - Manifest collector results
21
+ * @param {object} data.pipeline - Pipeline collector results
22
+ * @param {object} data.uap - UAP collector results
23
+ * @returns {string} Formatted markdown report
24
+ */
25
+ function formatReport(data) {
26
+ if (!data || typeof data !== 'object') {
27
+ return '# SYNAPSE Diagnostic Report\n**Error:** No diagnostic data provided.\n';
28
+ }
29
+
30
+ const lines = [];
31
+ const timestamp = new Date().toISOString();
32
+
33
+ // Header
34
+ lines.push('# SYNAPSE Diagnostic Report');
35
+ lines.push(`**Timestamp:** ${timestamp}`);
36
+
37
+ if (data.pipeline) {
38
+ const bracket = data.pipeline.bracket || 'UNKNOWN';
39
+ const contextPercent = typeof data.pipeline.contextPercent === 'number'
40
+ ? data.pipeline.contextPercent.toFixed(1)
41
+ : '?';
42
+ lines.push(`**Bracket:** ${bracket} (${contextPercent}% context remaining)`);
43
+ }
44
+
45
+ const agentId = _extractAgentId(data);
46
+ if (agentId) {
47
+ const quality = data.session?.raw?.bridgeData?.activation_quality || 'unknown';
48
+ lines.push(`**Agent:** @${agentId} (activation_quality: ${quality})`);
49
+ }
50
+
51
+ lines.push('');
52
+
53
+ // Section 1: Hook Status
54
+ lines.push('## 1. Hook Status');
55
+ if (data.hook && data.hook.checks) {
56
+ lines.push('| Check | Status | Detail |');
57
+ lines.push('|-------|--------|--------|');
58
+ for (const check of data.hook.checks) {
59
+ lines.push(`| ${check.name} | ${check.status} | ${check.detail} |`);
60
+ }
61
+ } else {
62
+ lines.push('*No hook data collected*');
63
+ }
64
+ lines.push('');
65
+
66
+ // Section 2: Session Status
67
+ lines.push('## 2. Session Status');
68
+ if (data.session && data.session.fields) {
69
+ lines.push('| Field | Expected | Actual | Status |');
70
+ lines.push('|-------|----------|--------|--------|');
71
+ for (const field of data.session.fields) {
72
+ lines.push(`| ${field.field} | ${field.expected} | ${field.actual} | ${field.status} |`);
73
+ }
74
+ } else {
75
+ lines.push('*No session data collected*');
76
+ }
77
+ lines.push('');
78
+
79
+ // Section 3: Manifest Integrity
80
+ lines.push('## 3. Manifest Integrity');
81
+ if (data.manifest && data.manifest.entries) {
82
+ lines.push('| Domain | In Manifest | File Exists | Status |');
83
+ lines.push('|--------|-------------|-------------|--------|');
84
+ for (const entry of data.manifest.entries) {
85
+ lines.push(`| ${entry.domain} | ${entry.inManifest} | ${entry.fileExists ? 'yes' : 'no'} | ${entry.status} |`);
86
+ }
87
+
88
+ if (data.manifest.orphanedFiles && data.manifest.orphanedFiles.length > 0) {
89
+ lines.push('');
90
+ lines.push(`**Orphaned files** (in .synapse/ but not in manifest): ${data.manifest.orphanedFiles.join(', ')}`);
91
+ }
92
+ } else {
93
+ lines.push('*No manifest data collected*');
94
+ }
95
+ lines.push('');
96
+
97
+ // Section 4: Pipeline Simulation
98
+ lines.push(`## 4. Pipeline Simulation (${data.pipeline?.bracket || 'UNKNOWN'} bracket)`);
99
+ if (data.pipeline && data.pipeline.layers) {
100
+ lines.push('| Layer | Expected | Status |');
101
+ lines.push('|-------|----------|--------|');
102
+ for (const layer of data.pipeline.layers) {
103
+ lines.push(`| ${layer.layer} | ${layer.expected} | ${layer.status} |`);
104
+ }
105
+ } else {
106
+ lines.push('*No pipeline data collected*');
107
+ }
108
+ lines.push('');
109
+
110
+ // Section 5: UAP Bridge
111
+ lines.push('## 5. UAP Bridge');
112
+ if (data.uap && data.uap.checks) {
113
+ lines.push('| Check | Status | Detail |');
114
+ lines.push('|-------|--------|--------|');
115
+ for (const check of data.uap.checks) {
116
+ lines.push(`| ${check.name} | ${check.status} | ${check.detail} |`);
117
+ }
118
+ } else {
119
+ lines.push('*No UAP bridge data collected*');
120
+ }
121
+ lines.push('');
122
+
123
+ // Section 6: Memory Bridge
124
+ lines.push('## 6. Memory Bridge');
125
+ lines.push('| Check | Status | Detail |');
126
+ lines.push('|-------|--------|--------|');
127
+
128
+ // Memory bridge is Pro-only, so always report current state
129
+ lines.push('| Pro available | INFO | Check `pro/` submodule |');
130
+ lines.push(`| Bracket requires hints | ${_bracketNeedsMemory(data.pipeline?.bracket) ? 'YES' : 'NO'} | ${data.pipeline?.bracket || 'UNKNOWN'} bracket |`);
131
+ lines.push('');
132
+
133
+ // Section 7: Gaps & Recommendations
134
+ lines.push('## 7. Gaps & Recommendations');
135
+ const gaps = _collectGaps(data);
136
+
137
+ if (gaps.length === 0) {
138
+ lines.push('| # | Severity | Gap | Recommendation |');
139
+ lines.push('|---|----------|-----|----------------|');
140
+ lines.push('| - | - | None found | Pipeline operating correctly |');
141
+ } else {
142
+ lines.push('| # | Severity | Gap | Recommendation |');
143
+ lines.push('|---|----------|-----|----------------|');
144
+ for (let i = 0; i < gaps.length; i++) {
145
+ lines.push(`| ${i + 1} | ${gaps[i].severity} | ${gaps[i].gap} | ${gaps[i].recommendation} |`);
146
+ }
147
+ }
148
+ lines.push('');
149
+
150
+ // Section 8: Timing Analysis (SYN-14)
151
+ _formatTimingSection(lines, data.timing);
152
+
153
+ // Section 9: Context Quality Analysis (SYN-14)
154
+ _formatQualitySection(lines, data.quality);
155
+
156
+ // Section 10: Consistency Checks (SYN-14)
157
+ _formatConsistencySection(lines, data.consistency);
158
+
159
+ // Section 11: Output Quality (SYN-14)
160
+ _formatOutputSection(lines, data.outputAnalysis);
161
+
162
+ // Section 12: Relevance Matrix (SYN-14)
163
+ _formatRelevanceSection(lines, data.relevance);
164
+
165
+ return lines.join('\n');
166
+ }
167
+
168
+ /**
169
+ * Extract agent ID from collected data.
170
+ * @param {object} data
171
+ * @returns {string|null}
172
+ */
173
+ function _extractAgentId(data) {
174
+ if (data.session?.raw?.bridgeData?.id) return data.session.raw.bridgeData.id;
175
+ if (data.session?.raw?.session?.active_agent?.id) return data.session.raw.session.active_agent.id;
176
+ return null;
177
+ }
178
+
179
+ /**
180
+ * Check if a bracket requires memory hints.
181
+ * @param {string} bracket
182
+ * @returns {boolean}
183
+ */
184
+ function _bracketNeedsMemory(bracket) {
185
+ return bracket === 'DEPLETED' || bracket === 'CRITICAL';
186
+ }
187
+
188
+ /**
189
+ * Collect gaps from all collector results.
190
+ * @param {object} data
191
+ * @returns {Array<{ severity: string, gap: string, recommendation: string }>}
192
+ */
193
+ function _collectGaps(data) {
194
+ const gaps = [];
195
+
196
+ // Check hook failures
197
+ const hookChecks = data.hook?.checks || [];
198
+ for (const check of hookChecks) {
199
+ if (check.status === 'FAIL') {
200
+ gaps.push({
201
+ severity: 'HIGH',
202
+ gap: `Hook: ${check.name} — ${check.detail}`,
203
+ recommendation: 'Run `npx aios-core install` to reinstall hooks',
204
+ });
205
+ }
206
+ }
207
+
208
+ // Check session issues
209
+ const sessionFields = data.session?.fields || [];
210
+ for (const field of sessionFields) {
211
+ if (field.status === 'FAIL') {
212
+ gaps.push({
213
+ severity: 'HIGH',
214
+ gap: `Session: ${field.field} — ${field.actual}`,
215
+ recommendation: 'Activate an agent with @agent to create session',
216
+ });
217
+ }
218
+ }
219
+
220
+ // Check manifest failures
221
+ const manifestEntries = data.manifest?.entries || [];
222
+ for (const entry of manifestEntries) {
223
+ if (entry.status === 'FAIL') {
224
+ gaps.push({
225
+ severity: 'MEDIUM',
226
+ gap: `Manifest: domain "${entry.domain}" file missing`,
227
+ recommendation: `Create .synapse/${entry.domain} domain file`,
228
+ });
229
+ }
230
+ }
231
+
232
+ // Check UAP bridge failures
233
+ const uapChecks = data.uap?.checks || [];
234
+ for (const check of uapChecks) {
235
+ if (check.status === 'FAIL') {
236
+ gaps.push({
237
+ severity: 'HIGH',
238
+ gap: `UAP Bridge: ${check.name} — ${check.detail}`,
239
+ recommendation: 'Activate an agent to trigger UAP bridge write',
240
+ });
241
+ }
242
+ }
243
+
244
+ // SYN-14 fix: Include gaps from new collectors (consistency, quality, relevance)
245
+
246
+ // Consistency check failures
247
+ const consistencyChecks = data.consistency?.checks || [];
248
+ for (const check of consistencyChecks) {
249
+ if (check.status === 'FAIL') {
250
+ gaps.push({
251
+ severity: 'MEDIUM',
252
+ gap: `Consistency: ${check.name} — ${check.detail}`,
253
+ recommendation: 'Re-activate agent to refresh metrics alignment',
254
+ });
255
+ }
256
+ }
257
+
258
+ // Quality grade below threshold
259
+ if (data.quality?.overall?.grade === 'F') {
260
+ gaps.push({
261
+ severity: 'HIGH',
262
+ gap: `Context quality: ${data.quality.overall.score}/100 (${data.quality.overall.grade})`,
263
+ recommendation: 'Re-activate agent to refresh UAP metrics',
264
+ });
265
+ }
266
+
267
+ // Relevance critical gaps
268
+ const relevanceGaps = data.relevance?.gaps || [];
269
+ for (const g of relevanceGaps) {
270
+ if (g.importance === 'critical') {
271
+ gaps.push({
272
+ severity: 'HIGH',
273
+ gap: `Relevance: ${g.component} (${g.importance}) missing`,
274
+ recommendation: 'Ensure critical context component is available for active agent',
275
+ });
276
+ }
277
+ }
278
+
279
+ // Sort by severity (HIGH first)
280
+ const severityOrder = { HIGH: 0, MEDIUM: 1, LOW: 2 };
281
+ gaps.sort((a, b) => {
282
+ const orderA = severityOrder[a.severity] !== undefined ? severityOrder[a.severity] : 3;
283
+ const orderB = severityOrder[b.severity] !== undefined ? severityOrder[b.severity] : 3;
284
+ return orderA - orderB;
285
+ });
286
+
287
+ return gaps;
288
+ }
289
+
290
+ /**
291
+ * Section 8: Timing Analysis.
292
+ * @param {string[]} lines
293
+ * @param {object} timing
294
+ */
295
+ function _formatTimingSection(lines, timing) {
296
+ lines.push('## 8. Timing Analysis');
297
+ if (!timing || timing.error) {
298
+ lines.push('*No timing data available*');
299
+ lines.push('');
300
+ return;
301
+ }
302
+
303
+ // UAP Timing
304
+ if (timing.uap && timing.uap.available) {
305
+ const staleTag = timing.uap.stale ? ' **[STALE]**' : '';
306
+ lines.push(`### UAP Activation Pipeline (${timing.uap.totalDuration}ms total, quality: ${timing.uap.quality})${staleTag}`);
307
+ lines.push('| Loader | Duration | Status | Tier |');
308
+ lines.push('|--------|----------|--------|------|');
309
+ for (const loader of timing.uap.loaders) {
310
+ lines.push(`| ${loader.name} | ${loader.duration}ms | ${loader.status} | ${loader.tier} |`);
311
+ }
312
+ lines.push(`| **Total** | **${timing.uap.totalDuration}ms** | | |`);
313
+ } else {
314
+ lines.push('### UAP Activation Pipeline');
315
+ lines.push('*No UAP timing data — activate an agent first*');
316
+ }
317
+ lines.push('');
318
+
319
+ // Hook Timing
320
+ if (timing.hook && timing.hook.available) {
321
+ const staleTag = timing.hook.stale ? ' **[STALE]**' : '';
322
+ const bootInfo = timing.hook.hookBootMs ? ` boot: ${Math.round(timing.hook.hookBootMs)}ms,` : '';
323
+ lines.push(`### SYNAPSE Hook Pipeline (${timing.hook.totalDuration}ms total,${bootInfo} ${timing.hook.bracket} bracket)${staleTag}`);
324
+ lines.push('| Layer | Duration | Status | Rules |');
325
+ lines.push('|-------|----------|--------|-------|');
326
+ for (const layer of timing.hook.layers) {
327
+ lines.push(`| ${layer.name} | ${layer.duration}ms | ${layer.status} | ${layer.rules} |`);
328
+ }
329
+ const totalRules = timing.hook.layers.reduce((sum, l) => sum + (l.rules || 0), 0);
330
+ lines.push(`| **Total** | **${timing.hook.totalDuration}ms** | | **${totalRules}** |`);
331
+ } else {
332
+ lines.push('### SYNAPSE Hook Pipeline');
333
+ lines.push('*No Hook timing data — send a prompt first*');
334
+ }
335
+ lines.push('');
336
+
337
+ // Combined
338
+ lines.push(`**Combined pipeline time:** ${timing.combined ? timing.combined.totalMs : 0}ms`);
339
+ lines.push('');
340
+ }
341
+
342
+ /**
343
+ * Section 9: Context Quality Analysis.
344
+ * @param {string[]} lines
345
+ * @param {object} quality
346
+ */
347
+ function _formatQualitySection(lines, quality) {
348
+ lines.push('## 9. Context Quality Analysis');
349
+ if (!quality || quality.error) {
350
+ lines.push('*No quality data available*');
351
+ lines.push('');
352
+ return;
353
+ }
354
+
355
+ const overall = quality.overall || { score: 0, grade: 'F', label: 'UNKNOWN' };
356
+ lines.push(`**Overall: ${overall.score}/100 (${overall.grade} — ${overall.label})**`);
357
+
358
+ const uapScore = quality.uap ? quality.uap.score : 0;
359
+ const hookScore = quality.hook ? quality.hook.score : 0;
360
+ const uapStale = quality.uap && quality.uap.stale ? ' [STALE]' : '';
361
+ const hookStale = quality.hook && quality.hook.stale ? ' [STALE]' : '';
362
+ lines.push(`UAP: ${uapScore}/100${uapStale} | Hook: ${hookScore}/100${hookStale}`);
363
+ lines.push('');
364
+
365
+ // UAP Loaders
366
+ if (quality.uap && quality.uap.loaders && quality.uap.loaders.length > 0) {
367
+ lines.push('### UAP Loaders');
368
+ lines.push('| Loader | Score | Criticality | Impact |');
369
+ lines.push('|--------|-------|-------------|--------|');
370
+ for (const loader of quality.uap.loaders) {
371
+ lines.push(`| ${loader.name} | ${loader.score}/${loader.maxScore} | ${loader.criticality} | ${loader.impact} |`);
372
+ }
373
+ lines.push('');
374
+ }
375
+
376
+ // Hook Layers
377
+ if (quality.hook && quality.hook.layers && quality.hook.layers.length > 0) {
378
+ lines.push('### Hook Layers');
379
+ lines.push('| Layer | Score | Criticality | Rules | Impact |');
380
+ lines.push('|-------|-------|-------------|-------|--------|');
381
+ for (const layer of quality.hook.layers) {
382
+ lines.push(`| ${layer.name} | ${layer.score}/${layer.maxScore} | ${layer.criticality} | ${layer.rules || '-'} | ${layer.impact} |`);
383
+ }
384
+ lines.push('');
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Section 10: Consistency Checks.
390
+ * @param {string[]} lines
391
+ * @param {object} consistency
392
+ */
393
+ function _formatConsistencySection(lines, consistency) {
394
+ lines.push('## 10. Consistency Checks');
395
+ if (!consistency || consistency.error || !consistency.available) {
396
+ lines.push('*No consistency data available*');
397
+ lines.push('');
398
+ return;
399
+ }
400
+
401
+ lines.push(`**Score:** ${consistency.score}/${consistency.maxScore}`);
402
+ lines.push('');
403
+ lines.push('| Check | Status | Detail |');
404
+ lines.push('|-------|--------|--------|');
405
+ for (const check of consistency.checks) {
406
+ lines.push(`| ${check.name} | ${check.status} | ${check.detail} |`);
407
+ }
408
+ lines.push('');
409
+ }
410
+
411
+ /**
412
+ * Section 11: Output Quality.
413
+ * @param {string[]} lines
414
+ * @param {object} outputAnalysis
415
+ */
416
+ function _formatOutputSection(lines, outputAnalysis) {
417
+ lines.push('## 11. Output Quality');
418
+ if (!outputAnalysis || outputAnalysis.error || !outputAnalysis.available) {
419
+ lines.push('*No output analysis data available*');
420
+ lines.push('');
421
+ return;
422
+ }
423
+
424
+ const s = outputAnalysis.summary;
425
+ lines.push(`**UAP:** ${s.uapHealthy}/${s.uapTotal} healthy | **Hook:** ${s.hookHealthy}/${s.hookTotal} healthy`);
426
+ lines.push('');
427
+
428
+ if (outputAnalysis.uapAnalysis && outputAnalysis.uapAnalysis.length > 0) {
429
+ lines.push('### UAP Loaders');
430
+ lines.push('| Loader | Status | Quality | Detail |');
431
+ lines.push('|--------|--------|---------|--------|');
432
+ for (const a of outputAnalysis.uapAnalysis) {
433
+ lines.push(`| ${a.name} | ${a.status} | ${a.quality} | ${a.detail} |`);
434
+ }
435
+ lines.push('');
436
+ }
437
+
438
+ if (outputAnalysis.hookAnalysis && outputAnalysis.hookAnalysis.length > 0) {
439
+ lines.push('### Hook Layers');
440
+ lines.push('| Layer | Status | Rules | Quality | Detail |');
441
+ lines.push('|-------|--------|-------|---------|--------|');
442
+ for (const a of outputAnalysis.hookAnalysis) {
443
+ lines.push(`| ${a.name} | ${a.status} | ${a.rules} | ${a.quality} | ${a.detail} |`);
444
+ }
445
+ lines.push('');
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Section 12: Relevance Matrix.
451
+ * @param {string[]} lines
452
+ * @param {object} relevance
453
+ */
454
+ function _formatRelevanceSection(lines, relevance) {
455
+ lines.push('## 12. Relevance Matrix');
456
+ if (!relevance || relevance.error || !relevance.available) {
457
+ lines.push('*No relevance data available*');
458
+ lines.push('');
459
+ return;
460
+ }
461
+
462
+ lines.push(`**Agent:** @${relevance.agentId} | **Relevance Score:** ${relevance.score}/100`);
463
+ lines.push('');
464
+
465
+ if (relevance.matrix && relevance.matrix.length > 0) {
466
+ lines.push('| Component | Importance | Status | Gap |');
467
+ lines.push('|-----------|------------|--------|-----|');
468
+ for (const item of relevance.matrix) {
469
+ const gapFlag = item.gap ? 'YES' : '-';
470
+ lines.push(`| ${item.component} | ${item.importance} | ${item.status} | ${gapFlag} |`);
471
+ }
472
+ lines.push('');
473
+ }
474
+
475
+ if (relevance.gaps && relevance.gaps.length > 0) {
476
+ lines.push('### Critical Gaps');
477
+ for (const gap of relevance.gaps) {
478
+ lines.push(`- **${gap.component}** (${gap.importance}): missing or failed`);
479
+ }
480
+ lines.push('');
481
+ }
482
+ }
483
+
484
+ module.exports = { formatReport };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * SYNAPSE Diagnostics Orchestrator
3
+ *
4
+ * Coordinates all collectors and generates a comprehensive diagnostic report
5
+ * comparing expected vs. actual SYNAPSE pipeline state.
6
+ *
7
+ * Usage:
8
+ * const { runDiagnostics } = require('.../synapse-diagnostics');
9
+ * const report = runDiagnostics('/path/to/project');
10
+ *
11
+ * @module core/synapse/diagnostics/synapse-diagnostics
12
+ * @version 1.0.0
13
+ * @created Story SYN-13
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ const path = require('path');
19
+ const { collectHookStatus } = require('./collectors/hook-collector');
20
+ const { collectSessionStatus } = require('./collectors/session-collector');
21
+ const { collectManifestIntegrity } = require('./collectors/manifest-collector');
22
+ const { collectPipelineSimulation } = require('./collectors/pipeline-collector');
23
+ const { collectUapBridgeStatus } = require('./collectors/uap-collector');
24
+ const { formatReport } = require('./report-formatter');
25
+ const { parseManifest } = require('../domain/domain-loader');
26
+
27
+ /**
28
+ * Safely execute a collector, returning an error object on failure.
29
+ * Diagnostics must be resilient — a broken collector should not crash the entire run.
30
+ * @param {string} name - Collector name for error reporting
31
+ * @param {Function} fn - Collector function to execute
32
+ * @returns {*} Collector result or { error: true, collector, message, checks, fields, entries }
33
+ */
34
+ function _safeCollect(name, fn) {
35
+ try {
36
+ return fn();
37
+ } catch (error) {
38
+ return { error: true, collector: name, message: error.message, checks: [], fields: [], entries: [] };
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Run all collectors and return raw results.
44
+ * Shared orchestration logic used by both runDiagnostics and runDiagnosticsRaw.
45
+ * @param {string} projectRoot - Absolute path to project root
46
+ * @param {object} options - Diagnostic options
47
+ * @returns {{ hook, session, manifest, pipeline, uap }} Collector results
48
+ */
49
+ function _collectAll(projectRoot, options) {
50
+ if (!projectRoot || typeof projectRoot !== 'string') {
51
+ throw new Error('projectRoot is required and must be a string');
52
+ }
53
+
54
+ const synapsePath = path.join(projectRoot, '.synapse');
55
+ const manifestPath = path.join(synapsePath, 'manifest');
56
+
57
+ const hook = _safeCollect('hook', () => collectHookStatus(projectRoot));
58
+ const session = _safeCollect('session', () => collectSessionStatus(projectRoot, options.sessionId));
59
+ const manifest = _safeCollect('manifest', () => collectManifestIntegrity(projectRoot));
60
+ const parsedManifest = _safeCollect('parsedManifest', () => parseManifest(manifestPath));
61
+
62
+ const promptCount = session?.raw?.session?.prompt_count || 0;
63
+ const activeAgentId = session?.raw?.bridgeData?.id || session?.raw?.session?.active_agent?.id || null;
64
+
65
+ const pipeline = _safeCollect('pipeline', () => collectPipelineSimulation(promptCount, activeAgentId, parsedManifest));
66
+ const uap = _safeCollect('uap', () => collectUapBridgeStatus(projectRoot));
67
+
68
+ return { hook, session, manifest, pipeline, uap };
69
+ }
70
+
71
+ /**
72
+ * Run full SYNAPSE diagnostics and return formatted markdown report.
73
+ *
74
+ * @param {string} projectRoot - Absolute path to project root
75
+ * @param {object} [options] - Diagnostic options
76
+ * @param {string} [options.sessionId] - Session UUID for session-specific checks
77
+ * @returns {string} Formatted markdown diagnostic report
78
+ */
79
+ function runDiagnostics(projectRoot, options = {}) {
80
+ const data = _collectAll(projectRoot, options);
81
+ return formatReport(data);
82
+ }
83
+
84
+ /**
85
+ * Run diagnostics and return raw collector data (for programmatic use).
86
+ *
87
+ * @param {string} projectRoot - Absolute path to project root
88
+ * @param {object} [options] - Diagnostic options
89
+ * @returns {object} Raw collector results
90
+ */
91
+ function runDiagnosticsRaw(projectRoot, options = {}) {
92
+ return _collectAll(projectRoot, options);
93
+ }
94
+
95
+ module.exports = { runDiagnostics, runDiagnosticsRaw };