@ismaelsoilet/synapsejs 1.8.0 → 1.11.1

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 (55) hide show
  1. package/README.md +98 -6
  2. package/bin/synapse.ts +291 -241
  3. package/package.json +2 -2
  4. package/src/client/components.tsx +459 -1
  5. package/src/client/context.tsx +23 -3
  6. package/src/client/error-boundary.tsx +59 -0
  7. package/src/client/hooks.ts +100 -1
  8. package/src/client/toast.tsx +219 -0
  9. package/src/client/upload.ts +153 -0
  10. package/src/client.ts +37 -2
  11. package/src/compiler/client-bundler.ts +94 -2
  12. package/src/compiler/context-bench.ts +9 -1
  13. package/src/compiler/contract.ts +31 -4
  14. package/src/compiler/db-schema-generator.ts +39 -8
  15. package/src/compiler/fields-parser.ts +28 -1
  16. package/src/compiler/impact-analyzer.ts +31 -1
  17. package/src/compiler/migration-runner.ts +10 -2
  18. package/src/compiler/optional-coverage.ts +137 -0
  19. package/src/compiler/oracle-runner.ts +18 -4
  20. package/src/compiler/scaffolder.ts +227 -9
  21. package/src/compiler/slice-discovery.ts +8 -1
  22. package/src/compiler/slice-splitter.ts +68 -6
  23. package/src/compiler/slice-templates.ts +234 -10
  24. package/src/compiler/typescript-api.ts +33 -0
  25. package/src/core/action-context.ts +101 -15
  26. package/src/core/config.ts +88 -10
  27. package/src/core/cron-parser.ts +167 -0
  28. package/src/core/database-client.ts +103 -6
  29. package/src/core/index.ts +5 -0
  30. package/src/core/jobs.ts +37 -0
  31. package/src/core/oauth-client.ts +322 -0
  32. package/src/core/path-guard.ts +105 -0
  33. package/src/core/postgres-client.ts +37 -0
  34. package/src/core/postgres-queue.ts +76 -9
  35. package/src/core/query-builder.ts +166 -34
  36. package/src/core/session-context.ts +45 -4
  37. package/src/core/session-token.ts +124 -8
  38. package/src/core/sqlite-client.ts +20 -0
  39. package/src/core/storage.ts +60 -19
  40. package/src/core/topics.ts +84 -0
  41. package/src/core/webhook-signature.ts +151 -0
  42. package/src/index.ts +2 -1
  43. package/src/mcp/server.ts +317 -218
  44. package/src/mcp/tools.ts +329 -0
  45. package/src/project-status.ts +433 -0
  46. package/src/runtime/client-entry.ts +11 -5
  47. package/src/runtime/network-guard.ts +3 -1
  48. package/src/runtime/queue-engine.ts +167 -5
  49. package/src/runtime/rate-limiter.ts +14 -4
  50. package/src/runtime/security-headers.ts +35 -0
  51. package/src/runtime/server.ts +1174 -236
  52. package/src/runtime/uploads.ts +199 -19
  53. package/src/version.ts +9 -2
  54. package/templates/starter/package.json +2 -2
  55. package/templates/starter/tsconfig.json +1 -0
package/bin/synapse.ts CHANGED
@@ -15,6 +15,7 @@
15
15
  * synapse split - Partition slices into shared/server/client modules (gated)
16
16
  * synapse test - Run all property-based testing (PBT) oracles
17
17
  * synapse new-slice - Scaffold a new atomic vertical slice
18
+ * synapse new-domain - Scaffold a domain layout, list slice and shared module
18
19
  * synapse info - Machine metadata and framework metrics
19
20
  */
20
21
 
@@ -22,25 +23,116 @@ import * as fs from 'fs';
22
23
  import * as path from 'path';
23
24
  import { runMachineVerifications } from '../src/compiler/agent-diagnostic-json';
24
25
  import { compressRepositoryAST } from '../src/compiler/ast-daemon-compressor';
25
- import { buildAllClientBundles } from '../src/compiler/client-bundler';
26
+ import { buildAllClientBundles, buildCssBundle } from '../src/compiler/client-bundler';
26
27
  import { renderContractJson, renderContractMarkdown } from '../src/compiler/contract';
27
28
  import { generateDatabaseSchemaCatalog } from '../src/compiler/db-schema-generator';
28
29
  import { analyzeImpact } from '../src/compiler/impact-analyzer';
29
30
  import { rollbackSliceMigrations, runSliceMigrations } from '../src/compiler/migration-runner';
31
+ import { analyzeOptionalItemCoverage, unionCoverage } from '../src/compiler/optional-coverage';
30
32
  import { runSliceOracles } from '../src/compiler/oracle-runner';
31
- import { scaffoldCrud, scaffoldShared, scaffoldSlice } from '../src/compiler/scaffolder';
33
+ import { scaffoldCrud, scaffoldDomain, scaffoldShared, scaffoldSlice } from '../src/compiler/scaffolder';
32
34
  import { checkSchemaDrift } from '../src/compiler/schema-drift';
33
35
  import { findSliceFiles, resolveSlicesDir } from '../src/compiler/slice-discovery';
34
36
  import { artifactDirectory, splitSlice, verifySplit, writeSplitArtifacts } from '../src/compiler/slice-splitter';
35
37
  import { SLICE_TEMPLATES, type SliceTemplate } from '../src/compiler/slice-templates';
36
38
  import { buildStandalone } from '../src/compiler/standalone-builder';
39
+ import { assertCompilerApi } from '../src/compiler/typescript-api';
40
+ import { isInsideBase } from '../src/core/path-guard';
37
41
  import { SynapseMcpServer } from '../src/mcp/server';
42
+ import { projectStatus } from '../src/project-status';
38
43
  import { SynapseServer } from '../src/runtime/server';
44
+ import { SYNAPSE_VERSION } from '../src/version';
39
45
 
40
46
  const command = process.argv[2] || 'check';
41
47
  const root = process.cwd();
42
48
 
49
+ /**
50
+ * The flags each subcommand accepts. An unrecognised flag is refused on every
51
+ * command, with the same machine-readable failure code — a machine consumer must
52
+ * not be told "PASS" for a flag the command silently ignored.
53
+ */
54
+ const KNOWN_FLAGS: Record<string, string[]> = {
55
+ dev: ['--watch'],
56
+ start: ['--acknowledge-insecure'],
57
+ check: [],
58
+ migrate: [],
59
+ rollback: ['--steps'],
60
+ mcp: [],
61
+ skeleton: [],
62
+ 'db-schema': [],
63
+ 'db-drift': [],
64
+ impact: [],
65
+ split: [],
66
+ 'new-slice': ['--template', '--fields'],
67
+ 'new-shared': [],
68
+ 'new-domain': ['--fields'],
69
+ build: ['--standalone'],
70
+ contract: ['--markdown'],
71
+ test: ['--gate'],
72
+ new: [],
73
+ create: [],
74
+ init: [],
75
+ worker: [],
76
+ info: [],
77
+ coverage: []
78
+ };
79
+
80
+ /** Returns the first unrecognised flag, or null when every flag is declared. */
81
+ function unknownFlag(argv: string[]): string | null {
82
+ const known = KNOWN_FLAGS[command] ?? [];
83
+
84
+ for (const argument of argv.slice(3)) {
85
+ if (!argument.startsWith('--')) {
86
+ continue;
87
+ }
88
+
89
+ const name = argument.split('=')[0];
90
+
91
+ if (!known.includes(name)) {
92
+ return argument;
93
+ }
94
+ }
95
+
96
+ return null;
97
+ }
98
+
43
99
  async function main() {
100
+ const offendingFlag = unknownFlag(process.argv);
101
+
102
+ if (offendingFlag) {
103
+ process.stdout.write(
104
+ `${JSON.stringify(
105
+ {
106
+ status: 'FAIL',
107
+ code: 'UNKNOWN_FLAG',
108
+ operation: 'FLAG_VALIDATION',
109
+ message: `Flag desconhecida: ${offendingFlag}. Flags aceitas por '${command}': ${(KNOWN_FLAGS[command] ?? []).join(', ') || 'nenhuma'}.`
110
+ },
111
+ null,
112
+ 2
113
+ )}\n`
114
+ );
115
+ process.exit(1);
116
+ }
117
+
118
+ const compilerCommands = new Set(['check', 'split', 'skeleton', 'db-schema', 'impact', 'test', 'build']);
119
+
120
+ if (compilerCommands.has(command)) {
121
+ try {
122
+ assertCompilerApi();
123
+ } catch (error) {
124
+ process.stdout.write(
125
+ `${JSON.stringify({
126
+ status: 'FAIL',
127
+ operation: 'COMPILER_API_CHECK',
128
+ code: 'COMPILER_API_UNAVAILABLE',
129
+ message: error instanceof Error ? error.message : String(error)
130
+ })}\n`
131
+ );
132
+ process.exit(1);
133
+ }
134
+ }
135
+
44
136
  switch (command) {
45
137
  case 'dev': {
46
138
  const watch = process.argv.includes('--watch');
@@ -54,6 +146,7 @@ async function main() {
54
146
  }
55
147
 
56
148
  const port = parseInt(process.argv[3] || process.env.PORT || '3000', 10);
149
+ await buildCssBundle(root);
57
150
  const server = new SynapseServer(root, port);
58
151
  await server.discoverSlices();
59
152
  await server.start();
@@ -62,15 +155,36 @@ async function main() {
62
155
 
63
156
  case 'start': {
64
157
  const port = parseInt(process.argv[3] || process.env.PORT || '3000', 10);
65
- const isProduction = process.env.NODE_ENV === 'production';
158
+ const { isProductionLikeMode } = await import('../src/runtime/server');
159
+ const acknowledged =
160
+ process.argv.includes('--acknowledge-insecure') ||
161
+ process.env.SYNAPSE_ACKNOWLEDGE_INSECURE === 'true' ||
162
+ process.env.SYNAPSE_DEV_HEADERS === 'true';
66
163
 
67
- if (isProduction && !process.env.SYNAPSE_SESSION_SECRET) {
164
+ if (isProductionLikeMode() && !process.env.SYNAPSE_SESSION_SECRET && !acknowledged) {
165
+ process.stdout.write(
166
+ `${JSON.stringify(
167
+ {
168
+ status: 'FAIL',
169
+ operation: 'START',
170
+ code: 'MISSING_SESSION_SECRET',
171
+ message:
172
+ 'Modo de produção sem SYNAPSE_SESSION_SECRET: toda requisição resolveria para anônimo. Configure o segredo ou passe --acknowledge-insecure para assumir o risco explicitamente.'
173
+ },
174
+ null,
175
+ 2
176
+ )}\n`
177
+ );
178
+ process.exit(1);
179
+ }
180
+
181
+ if (!process.env.SYNAPSE_SESSION_SECRET && acknowledged) {
68
182
  console.warn(
69
- '⚠️ [AVISO DE SEGURANÇA] NODE_ENV=production ativo sem SYNAPSE_SESSION_SECRET configurado!\n' +
70
- ' Sessões de usuário permanecerão anônimas por padrão.'
183
+ '⚠️ [AVISO DE SEGURANÇA] Iniciando sem SYNAPSE_SESSION_SECRET: identidade e papéis vindos de headers do chamador (x-user-id, x-user-roles) NÃO serão confiados; requisições permanecem anônimas.'
71
184
  );
72
185
  }
73
186
 
187
+ await buildCssBundle(root);
74
188
  const server = new SynapseServer(root, port);
75
189
  await server.discoverSlices();
76
190
  await server.start();
@@ -79,13 +193,24 @@ async function main() {
79
193
  const gracefulShutdown = async (signal: string) => {
80
194
  if (shuttingDown) return;
81
195
  shuttingDown = true;
82
- console.log(`\n🛑 [SynapseJS] Recebido sinal ${signal}, iniciando encerramento gracioso...`);
83
196
  try {
84
- await server.stop();
85
- console.log('✅ [SynapseJS] Servidor e conexões de persistência encerrados com sucesso.');
197
+ const summary = await server.stop();
198
+ process.stdout.write(
199
+ `${JSON.stringify({
200
+ status: 'PASS',
201
+ operation: 'GRACEFUL_SHUTDOWN',
202
+ signal,
203
+ drainedRequests: summary.drained,
204
+ abortedRequests: summary.aborted,
205
+ jobsRequeued: summary.jobsRequeued,
206
+ jobsFailed: summary.jobsFailed
207
+ })}\n`
208
+ );
86
209
  process.exit(0);
87
210
  } catch (err) {
88
- console.error('❌ [SynapseJS] Erro durante encerramento gracioso:', err);
211
+ process.stderr.write(
212
+ `${JSON.stringify({ status: 'ERROR', operation: 'GRACEFUL_SHUTDOWN', error: String(err) })}\n`
213
+ );
89
214
  process.exit(1);
90
215
  }
91
216
  };
@@ -257,7 +382,9 @@ async function main() {
257
382
 
258
383
  const report = analyzeImpact(target, root);
259
384
  process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
260
- process.exit(0);
385
+ // A target that does not exist is a failure; a valid target with no
386
+ // dependents is not.
387
+ process.exit(report.status === 'PASS' ? 0 : 1);
261
388
  break;
262
389
  }
263
390
 
@@ -341,7 +468,7 @@ async function main() {
341
468
  const name = process.argv[4];
342
469
 
343
470
  if (!domain || !name) {
344
- process.stderr.write(
471
+ process.stdout.write(
345
472
  `${JSON.stringify({
346
473
  status: 'ERROR',
347
474
  message: 'Parâmetros obrigatórios ausentes. Uso: synapse new-slice <domain> <name>'
@@ -409,7 +536,7 @@ async function main() {
409
536
  const created = scaffoldSlice(domain, name, root, template, fieldsArg);
410
537
 
411
538
  if (!created.ok) {
412
- process.stderr.write(
539
+ process.stdout.write(
413
540
  `${JSON.stringify(
414
541
  {
415
542
  status: 'ERROR',
@@ -445,7 +572,7 @@ async function main() {
445
572
  case 'new-shared': {
446
573
  const name = process.argv[3];
447
574
  if (!name) {
448
- process.stderr.write(
575
+ process.stdout.write(
449
576
  `${JSON.stringify({
450
577
  status: 'ERROR',
451
578
  message: 'Nome do módulo compartilhado ausente. Uso: synapse new-shared <nome>'
@@ -458,7 +585,7 @@ async function main() {
458
585
  const created = scaffoldShared(name, root);
459
586
 
460
587
  if (!created.ok) {
461
- process.stderr.write(
588
+ process.stdout.write(
462
589
  `${JSON.stringify(
463
590
  {
464
591
  status: 'ERROR',
@@ -489,7 +616,56 @@ async function main() {
489
616
  break;
490
617
  }
491
618
 
619
+ case 'new-domain': {
620
+ const domain = process.argv[3];
621
+ if (!domain) {
622
+ process.stdout.write(
623
+ `${JSON.stringify({
624
+ status: 'ERROR',
625
+ message: 'Nome do domínio ausente. Uso: synapse new-domain <dominio> [--fields="..."]'
626
+ })}\n`
627
+ );
628
+ process.exit(1);
629
+ }
630
+
631
+ const root = process.env.SYNAPSE_ROOT || process.cwd();
632
+ const fields = process.argv.find((arg) => arg.startsWith('--fields='))?.slice('--fields='.length);
633
+ const created = scaffoldDomain(domain, root, fields);
634
+
635
+ if (!created.ok) {
636
+ process.stdout.write(
637
+ `${JSON.stringify(
638
+ {
639
+ status: 'ERROR',
640
+ operation: 'SCAFFOLD_DOMAIN',
641
+ code: created.error.code,
642
+ message: created.error.message
643
+ },
644
+ null,
645
+ 2
646
+ )}\n`
647
+ );
648
+ process.exit(1);
649
+ }
650
+
651
+ process.stdout.write(
652
+ `${JSON.stringify(
653
+ {
654
+ status: 'PASS',
655
+ operation: 'SCAFFOLD_DOMAIN',
656
+ domain,
657
+ createdFiles: created.value.map((f) => path.relative(root, f))
658
+ },
659
+ null,
660
+ 2
661
+ )}\n`
662
+ );
663
+ process.exit(0);
664
+ break;
665
+ }
666
+
492
667
  case 'build': {
668
+ await buildCssBundle(root);
493
669
  const isStandalone = process.argv.includes('--standalone');
494
670
 
495
671
  if (isStandalone) {
@@ -572,6 +748,52 @@ async function main() {
572
748
  break;
573
749
  }
574
750
 
751
+ case 'coverage': {
752
+ // Which optional contract items the committed slices exercise — across every
753
+ // shipped application, so the report covers the union.
754
+ const targets = [
755
+ root,
756
+ ...(fs.existsSync(path.join(root, 'examples'))
757
+ ? fs
758
+ .readdirSync(path.join(root, 'examples'), { withFileTypes: true })
759
+ .filter((entry) => entry.isDirectory())
760
+ .map((entry) => path.join(root, 'examples', entry.name))
761
+ : [])
762
+ ];
763
+
764
+ const reports = targets.map((target) => analyzeOptionalItemCoverage(target));
765
+ const resolvable = reports.filter((report) => report.status !== 'FAIL' || report.totalSlices > 0);
766
+
767
+ if (resolvable.length === 0) {
768
+ process.stdout.write(
769
+ `${JSON.stringify(reports[0] ?? { status: 'FAIL', operation: 'OPTIONAL_ITEM_COVERAGE' }, null, 2)}\n`
770
+ );
771
+ process.exit(1);
772
+ }
773
+
774
+ const union = unionCoverage(resolvable);
775
+
776
+ process.stdout.write(
777
+ `${JSON.stringify(
778
+ {
779
+ status: union.unexercised.length === 0 ? 'PASS' : 'FAIL',
780
+ operation: 'OPTIONAL_ITEM_COVERAGE',
781
+ applications: resolvable.map((report) => ({
782
+ appDir: report.appDir,
783
+ totalSlices: report.totalSlices,
784
+ items: report.items
785
+ })),
786
+ covered: union.covered,
787
+ unexercised: union.unexercised
788
+ },
789
+ null,
790
+ 2
791
+ )}\n`
792
+ );
793
+ process.exit(union.unexercised.length === 0 ? 0 : 1);
794
+ break;
795
+ }
796
+
575
797
  case 'contract': {
576
798
  // O framework se descreve numa chamada: e o que o agente le em vez de adivinhar.
577
799
  const asMarkdown = process.argv.includes('--markdown');
@@ -597,7 +819,7 @@ async function main() {
597
819
  case 'init': {
598
820
  const rawTarget = process.argv[3];
599
821
  if (!rawTarget) {
600
- process.stderr.write(
822
+ process.stdout.write(
601
823
  `${JSON.stringify({
602
824
  status: 'ERROR',
603
825
  message: 'Nome do projeto obrigatório. Uso: synapse new <project-name>'
@@ -607,15 +829,34 @@ async function main() {
607
829
  }
608
830
 
609
831
  const targetDir = path.resolve(root, rawTarget);
832
+
833
+ if (!isInsideBase(root, targetDir)) {
834
+ process.stdout.write(
835
+ `${JSON.stringify(
836
+ {
837
+ status: 'ERROR',
838
+ operation: 'CREATE_PROJECT',
839
+ code: 'INVALID_PATH_SEGMENT',
840
+ message: `O caminho '${rawTarget}' resolve para fora do diretório atual (${root}). Um projeto novo é criado dentro dele; use um nome simples ou um subdiretório.`
841
+ },
842
+ null,
843
+ 2
844
+ )}\n`
845
+ );
846
+ process.exit(1);
847
+ }
848
+
610
849
  const cleanProjectName = path
611
850
  .basename(targetDir)
612
851
  .toLowerCase()
613
852
  .replace(/[^a-z0-9-_]/g, '-');
614
853
 
615
854
  if (fs.existsSync(targetDir)) {
616
- process.stderr.write(
855
+ process.stdout.write(
617
856
  `${JSON.stringify({
618
857
  status: 'ERROR',
858
+ operation: 'CREATE_PROJECT',
859
+ code: 'TARGET_EXISTS',
619
860
  message: `O diretório '${rawTarget}' já existe em ${targetDir}.`
620
861
  })}\n`
621
862
  );
@@ -633,9 +874,11 @@ async function main() {
633
874
  const templateDir = candidates.find((dir) => fs.existsSync(dir));
634
875
 
635
876
  if (!templateDir) {
636
- process.stderr.write(
877
+ process.stdout.write(
637
878
  `${JSON.stringify({
638
879
  status: 'ERROR',
880
+ operation: 'CREATE_PROJECT',
881
+ code: 'TEMPLATE_NOT_FOUND',
639
882
  message: 'Template oficial starter não encontrado nos diretórios candidatos.'
640
883
  })}\n`
641
884
  );
@@ -660,9 +903,11 @@ async function main() {
660
903
  let content = fs.readFileSync(s, 'utf-8');
661
904
  if (entry.name === 'package.json') {
662
905
  content = content.replace('"starter-app"', `"${cleanProjectName}"`);
906
+ // The scaffold depends on the version this CLI ships, never on a frozen
907
+ // older pin: a new project must receive every fix since then.
663
908
  content = content.replace(
664
909
  /"(@ismaelsoilet\/)?synapsejs":\s*"[^"]+"/g,
665
- '"@ismaelsoilet/synapsejs": "^1.1.1"'
910
+ `"@ismaelsoilet/synapsejs": "^${SYNAPSE_VERSION}"`
666
911
  );
667
912
  }
668
913
  fs.writeFileSync(d, content, 'utf-8');
@@ -712,6 +957,7 @@ async function main() {
712
957
  typeof exportVal === 'object' &&
713
958
  'name' in (exportVal as Record<string, unknown>)
714
959
  ) {
960
+ // biome-ignore lint/suspicious/noExplicitAny: slice export boundary, validated by the shape check above
715
961
  queue.registerJob(exportVal as any);
716
962
  }
717
963
  }
@@ -724,9 +970,21 @@ async function main() {
724
970
  console.log('⚡ [SynapseJS Worker] Fila de background jobs ativa e processando...');
725
971
  let running = true;
726
972
  const shutdown = () => {
973
+ if (!running) return;
727
974
  running = false;
728
- console.log('\n🛑 [SynapseJS Worker] Encerrando worker...');
975
+ // Stop claiming first, then return whatever was running to the queue with its
976
+ // attempt counter already advanced by the interrupted claim.
977
+ queue.stopClaiming();
978
+ const interrupted = queue.interruptRunningJobs();
729
979
  queue.close();
980
+ process.stdout.write(
981
+ `${JSON.stringify({
982
+ status: 'PASS',
983
+ operation: 'WORKER_SHUTDOWN',
984
+ jobsRequeued: interrupted.requeued,
985
+ jobsFailed: interrupted.failed
986
+ })}\n`
987
+ );
730
988
  process.exit(0);
731
989
  };
732
990
  process.on('SIGINT', shutdown);
@@ -750,235 +1008,27 @@ async function main() {
750
1008
  }
751
1009
 
752
1010
  case 'info': {
1011
+ // One machine-readable source: version, adoption, tool inventory and feature
1012
+ // status all come from the same module the docs gate reads.
1013
+ process.stdout.write(`${JSON.stringify(projectStatus(), null, 2)}\n`);
1014
+ process.exit(0);
1015
+ break;
1016
+ }
1017
+
1018
+ default: {
753
1019
  process.stdout.write(
754
1020
  `${JSON.stringify(
755
1021
  {
756
- framework: 'SynapseJS',
757
- version: '1.6.0',
758
- runtime: 'Bun + Bun.serve',
759
- database: 'Embedded SQLite (WAL) and PostgreSQL, both verified',
760
- protocols: ['REST/HTTP', 'Isomorphic RPC', 'Model Context Protocol (MCP)'],
761
- features: [
762
- {
763
- feature: 'Vertical slices (N = 1) with Locality of Behavior',
764
- status: 'stable',
765
- evidence: 'bun test packages/synapse/test/locality.test.ts'
766
- },
767
- {
768
- feature: 'Result<T, E> control flow (no public throwing helper)',
769
- status: 'stable',
770
- evidence: 'bun test packages/synapse/test/machine-types.test.ts'
771
- },
772
- {
773
- feature: 'TypeBox JIT input contracts',
774
- status: 'stable',
775
- evidence: 'bun test packages/synapse/test/slice-contract.test.ts'
776
- },
777
- {
778
- feature: 'Declarative sliceSchema migrations, applied once per statement',
779
- status: 'stable',
780
- evidence: 'bun test packages/synapse/test/migration-runner.test.ts'
781
- },
782
- {
783
- feature: 'Domain errors map to HTTP status (401/403/404/409/422/500)',
784
- status: 'stable',
785
- evidence: 'bun test packages/synapse/test/runtime-server.test.ts'
786
- },
787
- {
788
- feature: 'React hydration from a client bundle the splitter produces',
789
- status: 'stable',
790
- evidence: 'bun test packages/synapse/test/runtime-server.test.ts'
791
- },
792
- {
793
- feature: 'Signed sessions (SYNAPSE_SESSION_SECRET) and static files from public/',
794
- status: 'stable',
795
- evidence: 'bun test packages/synapse/test/runtime-server.test.ts'
796
- },
797
- {
798
- feature: 'Login with Bun.password, signed token and cookie session (storeSession/clearSession)',
799
- status: 'stable',
800
- evidence:
801
- 'bun run --cwd apps/crm synapse test (login oracle: the server accepts the issued token) + bun test packages/synapse/test/session-cookie.test.ts'
802
- },
803
- {
804
- feature: 'Cross-slice atomicity through src/shared modules (db.transaction, rollback proven on SQLite)',
805
- status: 'stable',
806
- evidence: 'bun test packages/synapse/test/shared-modules.test.ts'
807
- },
808
- {
809
- feature: 'Slice boundary: a slice never imports another slice (SLICE_IMPORTS_SLICE)',
810
- status: 'stable',
811
- evidence: 'bun test packages/synapse/test/slice-splitter.test.ts'
812
- },
813
- {
814
- feature: 'Browser RPC transport that never throws (RPC_MALFORMED/RPC_UNREACHABLE as values)',
815
- status: 'stable',
816
- evidence: 'bun test packages/synapse/test/rpc-client.test.ts'
817
- },
818
- {
819
- feature: 'Pre-built client bundles with a manifest (synapse build)',
820
- status: 'stable',
821
- evidence: 'bun test packages/synapse/test/client-bundler.test.ts'
822
- },
823
- {
824
- feature: 'Uploads with session, size limit and traversal guard (/_synapse/files)',
825
- status: 'stable',
826
- evidence: 'bun test packages/synapse/test/uploads.test.ts'
827
- },
828
- {
829
- feature: 'Embedded SQLite engine (WAL, prepared-statement cache)',
830
- status: 'stable',
831
- evidence: 'bun test packages/synapse/test/sqlite-client.test.ts'
832
- },
833
- {
834
- feature: 'Zero-wiring routing, SSR shell and RPC dispatcher',
835
- status: 'stable',
836
- evidence: 'bun --cwd examples/enterprise-crm test:e2e'
837
- },
838
- {
839
- feature: 'Slice discovery resolution (never reports PASS with zero slices)',
840
- status: 'stable',
841
- evidence: 'bun test packages/synapse/test/slice-discovery.test.ts'
842
- },
843
- {
844
- feature: 'MCP stdio server (11 tools)',
845
- status: 'stable',
846
- evidence: 'bun test packages/synapse/test/mcp-server.test.ts'
847
- },
848
- {
849
- feature: 'AST skeletonizer to .codebase/repo-map.d.ts',
850
- status: 'stable',
851
- evidence: 'bun --cwd examples/enterprise-crm skeleton'
852
- },
853
- {
854
- feature: 'Centralized Database Schema Catalog (.codebase/db-schema.d.ts)',
855
- status: 'stable',
856
- evidence: 'bun test packages/synapse/test/db-schema-generator.test.ts'
857
- },
858
- {
859
- feature: 'Unified Object Storage (LocalStorage + AWS S3/R2 with SigV4)',
860
- status: 'stable',
861
- evidence: 'bun test packages/synapse/test/storage.test.ts'
862
- },
863
- {
864
- feature: 'Distributed PostgreSQL Queue (SKIP LOCKED, Full Jitter, DLQ)',
865
- status: 'stable',
866
- evidence: 'bun test packages/synapse/test/postgres-queue.test.ts'
867
- },
868
- {
869
- feature: 'Isomorphic slice splitter (shared/server/client modules)',
870
- status: 'stable',
871
- evidence: 'bun test packages/synapse/test/slice-splitter.test.ts'
872
- },
873
- {
874
- feature: 'Slice invariants executed by bun:test (per-invariant reporting)',
875
- status: 'stable',
876
- evidence: 'bun test packages/synapse/test/oracle-runner.test.ts'
877
- },
878
- {
879
- feature: 'Incremental diagnostics cache across processes',
880
- status: 'roadmap',
881
- evidence: 'removido na 0.4.0: medido mais lento que o check completo (2.5s vs 1.9s)'
882
- },
883
- {
884
- feature: 'PostgreSQL parity (migrations, DDL, action round-trip)',
885
- status: 'stable',
886
- evidence: 'bun run test:postgres (CI roda contra um serviço postgres:16)'
887
- },
888
- {
889
- feature: 'Context surface benchmark (files/tokens an agent must read)',
890
- status: 'stable',
891
- evidence: 'bun run bench'
892
- },
893
- {
894
- feature: 'Isolated SQLite Queue & Background Jobs (defineJob, exponential backoff)',
895
- status: 'stable',
896
- evidence: 'bun test packages/synapse/test/jobs-queue.test.ts'
897
- },
898
- {
899
- feature: 'Bidirectional DDL migrations with transactional rollback (synapse rollback)',
900
- status: 'stable',
901
- evidence: 'bun test packages/synapse/test/onda2.test.ts'
902
- },
903
- {
904
- feature: 'Vendor code-splitting and dynamic metadata (sliceMeta)',
905
- status: 'stable',
906
- evidence: 'bun test packages/synapse/test/onda1.test.ts'
907
- },
908
- {
909
- feature: 'Hierarchical domain layouts (_layout.tsx)',
910
- status: 'stable',
911
- evidence: 'bun test packages/synapse/test/onda1.test.ts'
912
- },
913
- {
914
- feature: 'Sliding-window rate limiting & streaming upload guard',
915
- status: 'stable',
916
- evidence: 'bun test packages/synapse/test/onda2.test.ts'
917
- },
918
- {
919
- feature: 'Distributed PostgreSQL Event Hub & Isomorphic i18n',
920
- status: 'stable',
921
- evidence: 'bun test packages/synapse/test/onda3.test.ts'
922
- },
923
- {
924
- feature: 'Token revocation, TOTP 2FA, image optimization & plugin hooks',
925
- status: 'stable',
926
- evidence: 'bun test packages/synapse/test/onda4.test.ts'
927
- },
928
- {
929
- feature: 'SSRF & Private Network Guard',
930
- status: 'stable',
931
- evidence: 'bun test packages/synapse/test/production-hardening.test.ts'
932
- },
933
- {
934
- feature: 'Bounded LRU SSR Cache & Query Normalization',
935
- status: 'stable',
936
- evidence: 'bun test packages/synapse/test/production-hardening.test.ts'
937
- },
938
- {
939
- feature: 'SQLite Queue Zombie Job Visibility Recovery',
940
- status: 'stable',
941
- evidence: 'bun test packages/synapse/test/production-hardening.test.ts'
942
- },
943
- {
944
- feature: 'HttpOnly Cookie Authentication via ActionContext',
945
- status: 'stable',
946
- evidence: 'bun test packages/synapse/test/production-hardening.test.ts'
947
- }
948
- ],
949
- commands: [
950
- 'new',
951
- 'dev',
952
- 'start',
953
- 'check',
954
- 'migrate',
955
- 'rollback',
956
- 'db-drift',
957
- 'impact',
958
- 'mcp',
959
- 'skeleton',
960
- 'db-schema',
961
- 'split',
962
- 'build',
963
- 'test',
964
- 'worker',
965
- 'new-slice',
966
- 'contract',
967
- 'info'
968
- ]
1022
+ status: 'FAIL',
1023
+ code: 'UNKNOWN_COMMAND',
1024
+ operation: 'COMMAND_VALIDATION',
1025
+ message: `Comando desconhecido: ${command}.`,
1026
+ commands: Object.keys(KNOWN_FLAGS)
969
1027
  },
970
1028
  null,
971
1029
  2
972
1030
  )}\n`
973
1031
  );
974
- process.exit(0);
975
- break;
976
- }
977
-
978
- default: {
979
- process.stderr.write(
980
- `Unknown command: ${command}\nAvailable: start, dev, check, migrate, rollback, mcp, skeleton, db-schema, db-drift, impact, split, build, test, worker, new, new-slice, contract, info\n`
981
- );
982
1032
  process.exit(1);
983
1033
  }
984
1034
  }