sinapse-ai 9.4.0 → 9.5.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 (266) hide show
  1. package/.claude/CLAUDE.md +10 -4
  2. package/.claude/hooks/enforce-architecture-first.py +197 -197
  3. package/.claude/hooks/enforce-git-push-authority.sh +25 -4
  4. package/.claude/hooks/mind-clone-governance.py +193 -193
  5. package/.claude/hooks/read-protection.py +152 -152
  6. package/.claude/hooks/sql-governance.py +183 -183
  7. package/.claude/hooks/verify-packages.cjs +83 -0
  8. package/.claude/hooks/write-path-validation.py +195 -195
  9. package/.claude/rules/hook-governance.md +1 -0
  10. package/.claude/rules/mandatory-delegation.md +24 -0
  11. package/.claude/rules/project-intelligence.md +63 -0
  12. package/.claude/rules/response-format.md +4 -0
  13. package/.claude/rules/safe-collaboration.md +4 -2
  14. package/.claude/rules/security-data-protection.md +18 -0
  15. package/.claude/rules/squad-awareness.md +93 -67
  16. package/.claude/rules/token-economy.md +148 -0
  17. package/.codex/agents/analyst.md +90 -0
  18. package/.codex/agents/architect.md +78 -0
  19. package/.codex/agents/data-engineer.md +38 -0
  20. package/.codex/agents/developer.md +97 -0
  21. package/.codex/agents/devops.md +121 -0
  22. package/.codex/agents/product-lead.md +27 -0
  23. package/.codex/agents/project-lead.md +28 -0
  24. package/.codex/agents/quality-gate.md +89 -0
  25. package/.codex/agents/sprint-lead.md +28 -0
  26. package/.codex/agents/squad-creator.md +58 -0
  27. package/.codex/agents/ux-design-expert.md +28 -0
  28. package/.sinapse-ai/core/code-intel/registry-syncer.js +56 -3
  29. package/.sinapse-ai/core/doctor/checks/agent-memory.js +5 -1
  30. package/.sinapse-ai/core/doctor/checks/claude-md.js +4 -1
  31. package/.sinapse-ai/core/doctor/checks/code-intel.js +5 -1
  32. package/.sinapse-ai/core/doctor/checks/commands-count.js +4 -1
  33. package/.sinapse-ai/core/doctor/checks/constitution-consistency.js +4 -1
  34. package/.sinapse-ai/core/doctor/checks/core-config.js +4 -1
  35. package/.sinapse-ai/core/doctor/checks/entity-registry.js +6 -1
  36. package/.sinapse-ai/core/doctor/checks/git-hooks.js +5 -1
  37. package/.sinapse-ai/core/doctor/checks/graph-dashboard.js +4 -1
  38. package/.sinapse-ai/core/doctor/checks/hooks-claude-count.js +5 -1
  39. package/.sinapse-ai/core/doctor/checks/ide-sync.js +4 -1
  40. package/.sinapse-ai/core/doctor/checks/node-version.js +4 -1
  41. package/.sinapse-ai/core/doctor/checks/npm-packages.js +4 -1
  42. package/.sinapse-ai/core/doctor/checks/rules-files.js +4 -1
  43. package/.sinapse-ai/core/doctor/checks/settings-json.js +4 -1
  44. package/.sinapse-ai/core/doctor/checks/skills-count.js +4 -1
  45. package/.sinapse-ai/core/doctor/index.js +157 -50
  46. package/.sinapse-ai/core/ids/registry-updater.js +6 -1
  47. package/.sinapse-ai/core/logger/index.js +319 -0
  48. package/.sinapse-ai/core/orchestration/terminal-spawner.js +2 -2
  49. package/.sinapse-ai/core/telemetry/index.js +247 -0
  50. package/.sinapse-ai/data/entity-registry.yaml +1384 -944
  51. package/.sinapse-ai/development/agents/architect.md +5 -0
  52. package/.sinapse-ai/development/agents/data-engineer.md +38 -0
  53. package/.sinapse-ai/development/agents/developer.md +28 -0
  54. package/.sinapse-ai/development/agents/devops.md +4 -0
  55. package/.sinapse-ai/development/agents/product-lead.md +27 -0
  56. package/.sinapse-ai/development/agents/project-lead.md +28 -0
  57. package/.sinapse-ai/development/agents/quality-gate.md +4 -0
  58. package/.sinapse-ai/development/agents/sprint-lead/MEMORY.md +8 -0
  59. package/.sinapse-ai/development/agents/sprint-lead.md +28 -0
  60. package/.sinapse-ai/development/agents/squad-creator.md +58 -0
  61. package/.sinapse-ai/development/agents/ux-design-expert.md +28 -0
  62. package/.sinapse-ai/development/knowledge-base/agent-communication-protocol.md +127 -0
  63. package/.sinapse-ai/development/knowledge-base/database-scaling-patterns.md +374 -0
  64. package/.sinapse-ai/development/knowledge-base/environment-deployment-patterns.md +353 -0
  65. package/.sinapse-ai/development/knowledge-base/gotchas-patterns.md +224 -0
  66. package/.sinapse-ai/development/knowledge-base/infrastructure-decision-framework.md +221 -0
  67. package/.sinapse-ai/development/knowledge-base/security-pre-deploy-checklist.md +410 -0
  68. package/.sinapse-ai/development/knowledge-base/software-architecture-patterns.md +299 -0
  69. package/.sinapse-ai/development/knowledge-base/token-economy-guide.md +198 -0
  70. package/.sinapse-ai/development/scripts/populate-entity-registry.js +5 -1
  71. package/.sinapse-ai/development/skills/captcha-handler.md +82 -0
  72. package/.sinapse-ai/development/skills/chrome-brain.md +81 -0
  73. package/.sinapse-ai/development/skills/deploy-readiness.md +93 -0
  74. package/.sinapse-ai/development/skills/model-router.md +92 -0
  75. package/.sinapse-ai/development/skills/sinapse-methodology.md +175 -0
  76. package/.sinapse-ai/development/skills/story-fast-track.md +71 -0
  77. package/.sinapse-ai/development/tasks/dev-develop-story.md +10 -0
  78. package/.sinapse-ai/development/tasks/environment-promotion-pipeline.md +582 -0
  79. package/.sinapse-ai/development/tasks/generate-agent-handoff.md +223 -0
  80. package/.sinapse-ai/development/tasks/infrastructure-assessment.md +432 -0
  81. package/.sinapse-ai/development/tasks/load-testing-setup.md +611 -0
  82. package/.sinapse-ai/development/tasks/observability-blueprint.md +562 -0
  83. package/.sinapse-ai/development/templates/legal/breach-notification-tmpl.md +113 -0
  84. package/.sinapse-ai/development/templates/legal/privacy-policy-tmpl.md +93 -0
  85. package/.sinapse-ai/development/templates/legal/terms-of-service-tmpl.md +85 -0
  86. package/.sinapse-ai/development/templates/service-template/README.md.hbs +159 -159
  87. package/.sinapse-ai/development/templates/service-template/__tests__/index.test.ts.hbs +238 -238
  88. package/.sinapse-ai/development/templates/service-template/client.ts.hbs +404 -404
  89. package/.sinapse-ai/development/templates/service-template/errors.ts.hbs +183 -183
  90. package/.sinapse-ai/development/templates/service-template/index.ts.hbs +121 -121
  91. package/.sinapse-ai/development/templates/service-template/package.json.hbs +88 -88
  92. package/.sinapse-ai/development/templates/service-template/types.ts.hbs +146 -146
  93. package/.sinapse-ai/development/templates/squad-template/LICENSE +22 -22
  94. package/.sinapse-ai/development/workflows/story-development-cycle.yaml +40 -1
  95. package/.sinapse-ai/hooks/ids-post-commit.js +22 -0
  96. package/.sinapse-ai/infrastructure/contracts/compatibility/README.md +42 -0
  97. package/.sinapse-ai/infrastructure/contracts/compatibility/sinapse-current.yaml +35 -0
  98. package/.sinapse-ai/infrastructure/scripts/llm-routing/templates/claude-free-tracked.cmd +127 -127
  99. package/.sinapse-ai/infrastructure/scripts/llm-routing/templates/deepseek-proxy.cmd +71 -71
  100. package/.sinapse-ai/infrastructure/scripts/llm-routing/templates/deepseek-usage.cmd +51 -51
  101. package/.sinapse-ai/infrastructure/scripts/pr-review-ai.js +16 -13
  102. package/.sinapse-ai/infrastructure/scripts/setup-project-infra.js +128 -0
  103. package/.sinapse-ai/infrastructure/scripts/test-discovery.js +8 -3
  104. package/.sinapse-ai/infrastructure/scripts/validate-manifest-parity.js +380 -0
  105. package/.sinapse-ai/infrastructure/scripts/validate-parity.js +76 -25
  106. package/.sinapse-ai/infrastructure/templates/coderabbit.yaml.template +280 -280
  107. package/.sinapse-ai/infrastructure/templates/config/env.example +16 -0
  108. package/.sinapse-ai/infrastructure/templates/config/gitignore-additions.tmpl +59 -0
  109. package/.sinapse-ai/infrastructure/templates/github/CODEOWNERS.template +12 -0
  110. package/.sinapse-ai/infrastructure/templates/github/PULL_REQUEST_TEMPLATE.md +29 -0
  111. package/.sinapse-ai/infrastructure/templates/github/ci-template.yml +77 -0
  112. package/.sinapse-ai/infrastructure/templates/github/issue-templates/bug_report.md +34 -0
  113. package/.sinapse-ai/infrastructure/templates/github/issue-templates/feature_request.md +19 -0
  114. package/.sinapse-ai/infrastructure/templates/github-workflows/ci.yml.template +170 -170
  115. package/.sinapse-ai/infrastructure/templates/github-workflows/pr-automation.yml.template +331 -331
  116. package/.sinapse-ai/infrastructure/templates/github-workflows/release.yml.template +197 -197
  117. package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +19 -19
  118. package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-node.tmpl +86 -86
  119. package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-python.tmpl +146 -146
  120. package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-sinapse-base.tmpl +64 -64
  121. package/.sinapse-ai/infrastructure/templates/sinapse-sync.yaml.template +183 -183
  122. package/.sinapse-ai/install-manifest.yaml +275 -140
  123. package/.sinapse-ai/local-config.yaml.template +65 -65
  124. package/.sinapse-ai/monitor/hooks/lib/__init__.py +2 -2
  125. package/.sinapse-ai/monitor/hooks/lib/enrich.py +59 -59
  126. package/.sinapse-ai/monitor/hooks/lib/send_event.py +48 -48
  127. package/.sinapse-ai/monitor/hooks/notification.py +30 -30
  128. package/.sinapse-ai/monitor/hooks/post_tool_use.py +46 -46
  129. package/.sinapse-ai/monitor/hooks/pre_compact.py +30 -30
  130. package/.sinapse-ai/monitor/hooks/pre_tool_use.py +41 -41
  131. package/.sinapse-ai/monitor/hooks/stop.py +30 -30
  132. package/.sinapse-ai/monitor/hooks/subagent_stop.py +30 -30
  133. package/.sinapse-ai/monitor/hooks/user_prompt_submit.py +39 -39
  134. package/.sinapse-ai/product/templates/adr.hbs +126 -126
  135. package/.sinapse-ai/product/templates/dbdr.hbs +242 -242
  136. package/.sinapse-ai/product/templates/epic.hbs +213 -213
  137. package/.sinapse-ai/product/templates/pmdr.hbs +187 -187
  138. package/.sinapse-ai/product/templates/prd-v2.0.hbs +217 -217
  139. package/.sinapse-ai/product/templates/prd.hbs +202 -202
  140. package/.sinapse-ai/product/templates/story-tmpl.yaml +59 -0
  141. package/.sinapse-ai/product/templates/story.hbs +264 -264
  142. package/.sinapse-ai/product/templates/task.hbs +171 -171
  143. package/.sinapse-ai/product/templates/tmpl-comment-on-examples.sql +159 -159
  144. package/.sinapse-ai/product/templates/tmpl-migration-script.sql +92 -92
  145. package/.sinapse-ai/product/templates/tmpl-rls-granular-policies.sql +105 -105
  146. package/.sinapse-ai/product/templates/tmpl-rls-kiss-policy.sql +11 -11
  147. package/.sinapse-ai/product/templates/tmpl-rls-roles.sql +136 -136
  148. package/.sinapse-ai/product/templates/tmpl-rls-simple.sql +78 -78
  149. package/.sinapse-ai/product/templates/tmpl-rls-tenant.sql +153 -153
  150. package/.sinapse-ai/product/templates/tmpl-rollback-script.sql +78 -78
  151. package/.sinapse-ai/product/templates/tmpl-seed-data.sql +141 -141
  152. package/.sinapse-ai/product/templates/tmpl-smoke-test.sql +17 -17
  153. package/.sinapse-ai/product/templates/tmpl-staging-copy-merge.sql +140 -140
  154. package/.sinapse-ai/product/templates/tmpl-stored-proc.sql +141 -141
  155. package/.sinapse-ai/product/templates/tmpl-trigger.sql +153 -153
  156. package/.sinapse-ai/product/templates/tmpl-view-materialized.sql +134 -134
  157. package/.sinapse-ai/product/templates/tmpl-view.sql +178 -178
  158. package/.sinapse-ai/scripts/diagnostics/health-dashboard/package-lock.json +427 -355
  159. package/LICENSE +34 -34
  160. package/README.en.md +167 -20
  161. package/README.md +190 -22
  162. package/bin/cli.js +510 -196
  163. package/bin/postinstall.js +564 -0
  164. package/bin/sinapse-cli +283 -283
  165. package/bin/sinapse-graph.js +9 -0
  166. package/bin/sinapse-init.js +36 -4
  167. package/bin/sinapse-minimal.js +20 -9
  168. package/bin/sinapse.js +202 -122
  169. package/bin/utils/deprecation-warning.js +46 -0
  170. package/bin/utils/pre-push-safety.js +14 -0
  171. package/docs/TELEMETRY.md +131 -0
  172. package/docs/chrome-brain-upgrade-plan.md +624 -0
  173. package/docs/framework/orqx-plan.md +1 -1
  174. package/docs/installation/chrome-brain.md +17 -7
  175. package/docs/mega-upgrade-orchestration-plan.md +71 -0
  176. package/docs/pt/contributing.md +20 -0
  177. package/docs/research-synthesis-for-upgrade.md +511 -0
  178. package/docs/security-audit-report.md +306 -0
  179. package/package.json +20 -8
  180. package/packages/installer/src/config/configure-environment.js +19 -44
  181. package/packages/installer/src/detection/detect-project-type.js +181 -63
  182. package/packages/installer/src/installer/manifest-signature.js +32 -17
  183. package/packages/installer/src/wizard/i18n.js +12 -0
  184. package/packages/installer/src/wizard/ide-config-generator.js +8 -39
  185. package/packages/installer/src/wizard/index.js +119 -14
  186. package/packages/installer/src/wizard/questions.js +2 -3
  187. package/packages/installer/tests/integration/environment-configuration.test.js +7 -5
  188. package/packages/installer/tests/unit/detection/detect-project-type.test.js +138 -1
  189. package/packages/installer/tests/unit/doctor/doctor-orchestrator.test.js +3 -3
  190. package/packages/sinapse-install/bin/edmcp.js +0 -0
  191. package/packages/sinapse-install/bin/sinapse-install.js +0 -0
  192. package/packages/sinapse-pro-cli/bin/sinapse-pro.js +0 -0
  193. package/scripts/check-markdown-links.py +353 -353
  194. package/scripts/coverage-report-summary.js +169 -0
  195. package/scripts/generate-install-manifest.js +6 -2
  196. package/scripts/release-readiness.js +169 -0
  197. package/scripts/test-install-matrix-local.sh +153 -0
  198. package/scripts/validate-install-docs.js +394 -0
  199. package/scripts/validate-no-external-refs.js +376 -0
  200. package/scripts/validate-squad-orqx.js +302 -0
  201. package/scripts/validate-story-meta.js +263 -0
  202. package/squads/claude-code-mastery/CHANGELOG.md +1 -1
  203. package/squads/claude-code-mastery/README.md +2 -2
  204. package/squads/claude-code-mastery/squad.yaml +1 -1
  205. package/squads/squad-artdir/README.md +90 -0
  206. package/squads/squad-artdir/agents/accessibility-guardian.md +184 -0
  207. package/squads/squad-artdir/agents/artdir-orqx.md +145 -0
  208. package/squads/squad-artdir/agents/color-psychologist.md +166 -0
  209. package/squads/squad-artdir/agents/cro-persuasion.md +161 -0
  210. package/squads/squad-artdir/agents/design-system-architect.md +100 -0
  211. package/squads/squad-artdir/agents/ia-architect.md +169 -0
  212. package/squads/squad-artdir/agents/interaction-designer.md +162 -0
  213. package/squads/squad-artdir/agents/layout-engineer.md +163 -0
  214. package/squads/squad-artdir/agents/motion-architect.md +185 -0
  215. package/squads/squad-artdir/agents/platform-aesthetic-director.md +84 -0
  216. package/squads/squad-artdir/agents/premium-packaging-strategist.md +107 -0
  217. package/squads/squad-artdir/agents/product-surface-director.md +86 -0
  218. package/squads/squad-artdir/agents/type-systemist.md +138 -0
  219. package/squads/squad-artdir/agents/visual-strategist.md +127 -0
  220. package/squads/squad-artdir/checklists/seven-pillars-validation-checklist.md +172 -0
  221. package/squads/squad-artdir/knowledge-base/case-nyo-ia-reference.md +289 -0
  222. package/squads/squad-artdir/knowledge-base/deliverables-templates.md +457 -0
  223. package/squads/squad-artdir/knowledge-base/motion-technique-catalog.md +247 -0
  224. package/squads/squad-artdir/knowledge-base/premium-packaging-principles.md +133 -0
  225. package/squads/squad-artdir/knowledge-base/psychological-toolkit.md +229 -0
  226. package/squads/squad-artdir/knowledge-base/saas-art-direction-canon.md +242 -0
  227. package/squads/squad-artdir/knowledge-base/seven-pillars-framework.md +289 -0
  228. package/squads/squad-artdir/knowledge-base/ten-pillars-framework.md +221 -0
  229. package/squads/squad-artdir/package.json +20 -0
  230. package/squads/squad-artdir/squad.yaml +271 -0
  231. package/squads/squad-artdir/tasks/audit-conversion.md +97 -0
  232. package/squads/squad-artdir/tasks/audit-drift-multi-surface.md +55 -0
  233. package/squads/squad-artdir/tasks/consult-saas-canon.md +54 -0
  234. package/squads/squad-artdir/tasks/create-art-direction-brief.md +110 -0
  235. package/squads/squad-artdir/tasks/create-premium-packaging-brief.md +61 -0
  236. package/squads/squad-artdir/tasks/create-wireflow.md +84 -0
  237. package/squads/squad-artdir/tasks/design-color-system.md +81 -0
  238. package/squads/squad-artdir/tasks/design-product-surface.md +60 -0
  239. package/squads/squad-artdir/tasks/design-token-system.md +58 -0
  240. package/squads/squad-artdir/tasks/diagnose-visual-language.md +92 -0
  241. package/squads/squad-artdir/tasks/first-5-minutes-choreography.md +65 -0
  242. package/squads/squad-artdir/tasks/specify-motion-system.md +84 -0
  243. package/squads/squad-artdir/tasks/validate-against-pillars.md +143 -0
  244. package/squads/squad-artdir/templates/art-direction-brief-template.md +215 -0
  245. package/squads/squad-artdir/workflows/conversion-audit-cycle.yaml +78 -0
  246. package/squads/squad-artdir/workflows/full-art-direction-cycle.yaml +98 -0
  247. package/squads/squad-artdir/workflows/saas-platform-art-direction-cycle.yaml +174 -0
  248. package/squads/squad-brand/knowledge-base/ai-visual-generation-canon.md +234 -0
  249. package/squads/squad-brand/squad.yaml +20 -6
  250. package/squads/squad-claude/knowledge-base/context-window-optimization.md +1 -1
  251. package/squads/squad-claude/knowledge-base/swarm-orchestration-patterns.md +2 -2
  252. package/squads/squad-content/knowledge-base/ai-native-content-loop.md +220 -0
  253. package/squads/squad-content/knowledge-base/signal-intelligence-v2.md +234 -0
  254. package/squads/squad-content/knowledge-base/task-ownership-map.md +235 -0
  255. package/squads/squad-content/squad.yaml +187 -27
  256. package/squads/squad-copy/knowledge-base/ai-copy-human-loop-canon.md +235 -0
  257. package/squads/squad-copy/squad.yaml +19 -4
  258. package/squads/squad-design/knowledge-base/cross-surface-token-canon.md +209 -0
  259. package/squads/squad-design/squad.yaml +19 -4
  260. package/.sinapse-ai/core/registry/service-registry.json +0 -6346
  261. package/.sinapse-ai/data/registry-update-log.jsonl +0 -1323
  262. package/.sinapse-ai/manifests/agents.csv +0 -29
  263. package/.sinapse-ai/manifests/tasks.csv +0 -204
  264. package/.sinapse-ai/manifests/workers.csv +0 -196
  265. package/squads/squad-growth/tasks/calculate-sample-size.md +0 -121
  266. package/squads/squad-paidmedia/tasks/calculate-sample-size.md +0 -57
@@ -0,0 +1,564 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SINAPSE Postinstall Orchestrator
5
+ * @story A.1 - Postinstall Script & Runtime Dirs
6
+ * @story B.1 - Minimalist Install Output Design
7
+ *
8
+ * Runs automatically after `npm install` (global or local) unless:
9
+ * - SINAPSE_SKIP_POSTINSTALL=1 is set (explicit opt-out)
10
+ * - A known CI env var is present (GITHUB_ACTIONS, CI=true, etc.)
11
+ * - npm was invoked with --ignore-scripts (native npm behavior, nothing to do here)
12
+ *
13
+ * Execution order (see Story A.1 AC 4):
14
+ * 1. env guard (SINAPSE_SKIP_POSTINSTALL / CI)
15
+ * 2. npm run sync:ide -- --ide claude-code
16
+ * 3. mkdir -p .sinapse/handoffs
17
+ * 4. mkdir -p .sinapse/scratchpad
18
+ * 5. sinapse doctor --quiet (exit code 2 = abort, 0/1 = OK)
19
+ * 6. Minimalist summary (Story B.1): 6-8 lines, friendly PT-BR copy.
20
+ *
21
+ * Output modes (Story B.1):
22
+ * default ≤ 8 lines. Minimal, non-technical, Portuguese.
23
+ * --verbose Full legacy detailed output (step lines, doctor details).
24
+ * --json Single JSON object: { status, version, agents, squads, warnings, errors }.
25
+ *
26
+ * Exit codes:
27
+ * 0 success OR non-critical warning (framework operational)
28
+ * 2 critical failure (sync:ide failed, or doctor exit >= 2)
29
+ *
30
+ * Note: exit 1 is NOT used. npm treats any non-zero postinstall exit as
31
+ * `command failed`, which scares users when the install is actually operational.
32
+ * Partial installs (doctor WARN, permission fallback) print the "Instalação
33
+ * parcial" message and exit 0 so `npm install` completes cleanly. Callers that
34
+ * want strict behavior should parse `--json` output and check `status: warn`.
35
+ */
36
+
37
+ 'use strict';
38
+
39
+ const fs = require('fs');
40
+ const os = require('os');
41
+ const path = require('path');
42
+ const { spawnSync } = require('child_process');
43
+
44
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
45
+
46
+ // ANSI colors (intentionally minimal — no chalk dep at postinstall time)
47
+ const c = {
48
+ reset: '\x1b[0m',
49
+ dim: '\x1b[2m',
50
+ bold: '\x1b[1m',
51
+ red: '\x1b[31m',
52
+ green: '\x1b[32m',
53
+ yellow: '\x1b[33m',
54
+ cyan: '\x1b[36m',
55
+ };
56
+
57
+ // ─── Flag detection ──────────────────────────────────────────────────────────
58
+ // Postinstall runs under npm, so CLI args come via:
59
+ // - process.argv (rare: node bin/postinstall.js --verbose)
60
+ // - npm_config_loglevel (npm install --verbose sets this to "verbose")
61
+ // - env opt-ins for testing: SINAPSE_VERBOSE=1, SINAPSE_JSON=1
62
+ //
63
+ // In --json mode ALL human-readable output is suppressed and a single JSON
64
+ // object is emitted on exit. In --verbose mode the legacy detailed lines are
65
+ // shown. Default mode prints only the 6-8 line minimalist summary.
66
+
67
+ function detectFlags(argv = process.argv.slice(2), env = process.env) {
68
+ const has = (name) => argv.includes(name);
69
+ const npmLogLevel = (env.npm_config_loglevel || '').toLowerCase();
70
+ const verbose =
71
+ has('--verbose')
72
+ || has('-v')
73
+ || env.SINAPSE_VERBOSE === '1'
74
+ || npmLogLevel === 'verbose'
75
+ || npmLogLevel === 'silly';
76
+ const json = has('--json') || env.SINAPSE_JSON === '1';
77
+ const quiet = has('--quiet') || has('-q') || env.SINAPSE_QUIET === '1';
78
+ return { verbose, json, quiet };
79
+ }
80
+
81
+ // ─── Dynamic counts (Story B.1 AC 1, AC 7) ───────────────────────────────────
82
+ // Source of truth is the real filesystem, not the manifest (manifest can drift
83
+ // — see Story A.4 G5). We count the actual agent definitions and squad dirs.
84
+
85
+ /**
86
+ * Count real agent definitions under .sinapse-ai/development/agents/*.md.
87
+ * Fails open (returns 0) on any filesystem error.
88
+ */
89
+ function countAgents() {
90
+ try {
91
+ const dir = path.join(PROJECT_ROOT, '.sinapse-ai', 'development', 'agents');
92
+ if (!fs.existsSync(dir)) return 0;
93
+ return fs
94
+ .readdirSync(dir, { withFileTypes: true })
95
+ .filter((d) => d.isFile() && d.name.endsWith('.md') && !d.name.startsWith('_'))
96
+ .length;
97
+ } catch {
98
+ return 0;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Count real squad directories under squads/* (skip dotfiles and .gitkeep).
104
+ * A squad is any subdirectory of squads/.
105
+ */
106
+ function countSquads() {
107
+ try {
108
+ const dir = path.join(PROJECT_ROOT, 'squads');
109
+ if (!fs.existsSync(dir)) return 0;
110
+ return fs
111
+ .readdirSync(dir, { withFileTypes: true })
112
+ .filter((d) => d.isDirectory() && !d.name.startsWith('.'))
113
+ .length;
114
+ } catch {
115
+ return 0;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Read the installed package version. Fails open with "unknown".
121
+ */
122
+ function readVersion() {
123
+ try {
124
+ return require(path.join(PROJECT_ROOT, 'package.json')).version || 'unknown';
125
+ } catch {
126
+ return 'unknown';
127
+ }
128
+ }
129
+
130
+ // ─── First-run detection (Story B.1 AC 5) ────────────────────────────────────
131
+ // The ~/.sinapse/.first-run-done flag is created on successful first install.
132
+ // On subsequent installs the welcome line is suppressed. Flag creation failures
133
+ // are non-fatal (welcome shows again on next install — acceptable degradation).
134
+
135
+ // NOTE: resolved dynamically so tests can redirect HOME/USERPROFILE between runs.
136
+ function sinapseHome() {
137
+ return path.join(os.homedir(), '.sinapse');
138
+ }
139
+ function firstRunFlag() {
140
+ return path.join(sinapseHome(), '.first-run-done');
141
+ }
142
+
143
+ function isFirstRun() {
144
+ try {
145
+ return !fs.existsSync(firstRunFlag());
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+
151
+ function markFirstRunDone() {
152
+ try {
153
+ const home = sinapseHome();
154
+ if (!fs.existsSync(home)) {
155
+ fs.mkdirSync(home, { recursive: true });
156
+ }
157
+ const flag = firstRunFlag();
158
+ if (!fs.existsSync(flag)) {
159
+ fs.writeFileSync(flag, `${new Date().toISOString()}\n`, 'utf8');
160
+ }
161
+ return true;
162
+ } catch {
163
+ return false; // silent — welcome will show again next install
164
+ }
165
+ }
166
+
167
+ // ─── Output sinks (flag-aware) ───────────────────────────────────────────────
168
+ // In --json mode, every human-readable call accumulates into jsonState instead
169
+ // of writing to stdout. In --verbose mode, step lines are shown. In default
170
+ // mode, only the final summary is printed.
171
+
172
+ const jsonState = {
173
+ status: 'success',
174
+ version: null,
175
+ agents: 0,
176
+ squads: 0,
177
+ warnings: [],
178
+ errors: [],
179
+ };
180
+
181
+ let FLAGS = { verbose: false, json: false, quiet: false };
182
+
183
+ function plain(s) {
184
+ // Strip ANSI for --json mode (we still want semantic text, no escape codes).
185
+ return String(s).replace(/\x1b\[[0-9;]*m/g, ''); // eslint-disable-line no-control-regex
186
+ }
187
+
188
+ function verboseLog(msg) {
189
+ if (FLAGS.json) return;
190
+ if (!FLAGS.verbose) return;
191
+ process.stdout.write(`${msg}\n`);
192
+ }
193
+
194
+ function warn(msg) {
195
+ if (FLAGS.json) {
196
+ jsonState.warnings.push(plain(msg));
197
+ if (jsonState.status === 'success') jsonState.status = 'warn';
198
+ return;
199
+ }
200
+ if (FLAGS.verbose) {
201
+ process.stdout.write(`${c.yellow}${msg}${c.reset}\n`);
202
+ }
203
+ }
204
+
205
+ function error(msg) {
206
+ if (FLAGS.json) {
207
+ jsonState.errors.push(plain(msg));
208
+ jsonState.status = 'error';
209
+ return;
210
+ }
211
+ // Errors are always shown (even in default minimal mode) because they
212
+ // indicate the install is broken and the user needs to know.
213
+ process.stderr.write(`${c.red}${msg}${c.reset}\n`);
214
+ }
215
+
216
+ /**
217
+ * Return true if we should skip postinstall entirely.
218
+ * Respects SINAPSE_SKIP_POSTINSTALL=1 and common CI signals.
219
+ */
220
+ function shouldSkip() {
221
+ if (process.env.SINAPSE_SKIP_POSTINSTALL === '1') {
222
+ return { skip: true, reason: 'SINAPSE_SKIP_POSTINSTALL=1' };
223
+ }
224
+ // Auto-skip on CI unless user explicitly opts in with SINAPSE_FORCE_POSTINSTALL=1.
225
+ // Rationale (Story A.1 Risks): CI pipelines should not have runtime side effects.
226
+ if (process.env.SINAPSE_FORCE_POSTINSTALL === '1') {
227
+ return { skip: false };
228
+ }
229
+ const ciSignals = ['CI', 'GITHUB_ACTIONS', 'GITLAB_CI', 'CIRCLECI', 'TRAVIS', 'JENKINS_URL'];
230
+ for (const key of ciSignals) {
231
+ if (process.env[key]) {
232
+ return { skip: true, reason: `CI detected (${key})` };
233
+ }
234
+ }
235
+ return { skip: false };
236
+ }
237
+
238
+ /**
239
+ * Ensure the project root looks like a real SINAPSE install before we touch anything.
240
+ * Returns false if we should bail out silently (e.g. running from a partial copy).
241
+ */
242
+ function isValidInstallRoot() {
243
+ try {
244
+ return fs.existsSync(path.join(PROJECT_ROOT, '.sinapse-ai'));
245
+ } catch {
246
+ return false;
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Spawn a child process and return the raw result. Does NOT throw on non-zero exit.
252
+ * In --json/default mode, child stdio is piped (swallowed) to preserve the minimal
253
+ * output contract. In --verbose mode it is inherited so users see full details.
254
+ */
255
+ function run(command, args, opts = {}) {
256
+ const stdio = FLAGS.verbose ? 'inherit' : 'pipe';
257
+ const result = spawnSync(command, args, {
258
+ cwd: PROJECT_ROOT,
259
+ stdio,
260
+ shell: process.platform === 'win32',
261
+ ...opts,
262
+ });
263
+ return result;
264
+ }
265
+
266
+ /**
267
+ * Step 1: sync:ide --ide claude-code.
268
+ * Copies agent definitions to .claude/commands/SINAPSE/agents/ so Claude Code can resolve @developer, etc.
269
+ */
270
+ function stepSyncIde() {
271
+ verboseLog(`${c.cyan}›${c.reset} Sincronizando agents para Claude Code...`);
272
+ const result = run('npm', ['run', 'sync:ide', '--silent', '--', '--ide', 'claude-code', '--quiet']);
273
+ if (result.error) {
274
+ error(`sync:ide falhou ao iniciar: ${result.error.message}`);
275
+ return { ok: false, critical: true };
276
+ }
277
+ if (result.status !== 0) {
278
+ error(`sync:ide saiu com código ${result.status}`);
279
+ return { ok: false, critical: true };
280
+ }
281
+ verboseLog(`${c.green}✓${c.reset} Agents sincronizados`);
282
+ return { ok: true, critical: false };
283
+ }
284
+
285
+ /**
286
+ * Step 2 + 3: create runtime directories (.sinapse/handoffs and .sinapse/scratchpad).
287
+ * Idempotent — no-op if directories already exist.
288
+ * Permission errors are non-critical (warn, continue).
289
+ */
290
+ function stepCreateRuntimeDirs() {
291
+ const dirs = [
292
+ path.join(PROJECT_ROOT, '.sinapse', 'handoffs'),
293
+ path.join(PROJECT_ROOT, '.sinapse', 'scratchpad'),
294
+ ];
295
+ let softFailures = 0;
296
+ for (const dir of dirs) {
297
+ try {
298
+ fs.mkdirSync(dir, { recursive: true });
299
+ } catch (err) {
300
+ if (err.code === 'EACCES' || err.code === 'EPERM') {
301
+ warn(`Sem permissão para criar ${path.relative(PROJECT_ROOT, dir)} — SINAPSE vai tentar criar no primeiro uso.`);
302
+ softFailures += 1;
303
+ continue;
304
+ }
305
+ error(`Falha ao criar ${dir}: ${err.message}`);
306
+ return { ok: false, critical: true };
307
+ }
308
+ }
309
+ if (softFailures === 0) {
310
+ verboseLog(`${c.green}✓${c.reset} Diretórios de runtime prontos (.sinapse/handoffs, .sinapse/scratchpad)`);
311
+ }
312
+ return { ok: softFailures === 0, critical: false };
313
+ }
314
+
315
+ /**
316
+ * Step 4: sinapse doctor --quiet.
317
+ * Exit code semantics (per Story A.1 Dev Notes + Story A.3):
318
+ * 0 = PASS (ok)
319
+ * 1 = WARN only (ok, no abort)
320
+ * 2 = FAIL (critical — abort postinstall with non-zero exit)
321
+ */
322
+ function stepDoctor() {
323
+ verboseLog(`${c.cyan}›${c.reset} Verificando saúde da instalação...`);
324
+ const doctorBin = path.join(PROJECT_ROOT, 'bin', 'sinapse.js');
325
+ if (!fs.existsSync(doctorBin)) {
326
+ warn('bin/sinapse.js não encontrado — pulando doctor check');
327
+ return { ok: true, critical: false };
328
+ }
329
+ const result = run(process.execPath, [doctorBin, 'doctor', '--quiet']);
330
+ if (result.error) {
331
+ warn(`doctor falhou ao iniciar: ${result.error.message} — não-crítico`);
332
+ return { ok: false, critical: false };
333
+ }
334
+ if (result.status === 0) {
335
+ verboseLog(`${c.green}✓${c.reset} Saúde da instalação: PASS`);
336
+ return { ok: true, critical: false };
337
+ }
338
+ if (result.status === 1) {
339
+ warn("Saúde da instalação: WARN — rode 'sinapse doctor' para detalhes");
340
+ return { ok: false, critical: false };
341
+ }
342
+ // Exit code 2 or anything higher is treated as critical per Story A.1 Dev Notes.
343
+ error(`Saúde da instalação: FAIL (exit ${result.status}) — rode 'sinapse doctor' para detalhes`);
344
+ return { ok: false, critical: true };
345
+ }
346
+
347
+ /**
348
+ * Story B.1 — render the minimalist summary.
349
+ *
350
+ * Default output (≤ 8 lines — the blank lines count):
351
+ *
352
+ * [Bem-vindo ao SINAPSE! 🎉] ← only on first run
353
+ * SINAPSE {version} instalado ✓
354
+ * {N} agents · {M} squads prontos
355
+ *
356
+ * Teste: sinapse doctor
357
+ * Começar: @sinapse no Claude Code
358
+ *
359
+ * Docs: https://sinapse.club
360
+ *
361
+ * In --verbose mode the caller has already printed detailed step output, so we
362
+ * still render the minimal summary at the end as a recap.
363
+ *
364
+ * In --json mode this function populates jsonState and is a no-op on stdout;
365
+ * the caller will flush jsonState at process exit.
366
+ *
367
+ * @param {{ firstRun?: boolean }} [opts]
368
+ * @returns {{ lineCount: number, lines: string[] }}
369
+ */
370
+ function renderFinalSummary(opts = {}) {
371
+ const version = readVersion();
372
+ const agents = countAgents();
373
+ const squads = countSquads();
374
+ const firstRun = Boolean(opts.firstRun);
375
+
376
+ // Populate JSON state even if we'll never print human output.
377
+ jsonState.version = version;
378
+ jsonState.agents = agents;
379
+ jsonState.squads = squads;
380
+ jsonState.firstRun = firstRun;
381
+
382
+ if (FLAGS.json) {
383
+ return { lineCount: 0, lines: [] };
384
+ }
385
+ if (FLAGS.quiet) {
386
+ return { lineCount: 0, lines: [] };
387
+ }
388
+
389
+ // Pluralization: Portuguese "agent(s)" / "squad(s)". 1 is singular.
390
+ const agentsWord = agents === 1 ? 'agent' : 'agents';
391
+ const squadsWord = squads === 1 ? 'squad' : 'squads';
392
+ const prontosWord = squads === 1 && agents === 1 ? 'pronto' : 'prontos';
393
+
394
+ const lines = [];
395
+ if (firstRun) {
396
+ lines.push(`${c.bold}Bem-vindo ao SINAPSE!${c.reset} 🎉`);
397
+ }
398
+ lines.push(`${c.bold}SINAPSE ${version}${c.reset} instalado ${c.green}✓${c.reset}`);
399
+ lines.push(`${c.dim}${agents} ${agentsWord} · ${squads} ${squadsWord} ${prontosWord}${c.reset}`);
400
+ lines.push('');
401
+ lines.push(`Teste: ${c.cyan}sinapse doctor${c.reset}`);
402
+ lines.push(`Começar: ${c.cyan}@sinapse${c.reset} no Claude Code`);
403
+ lines.push('');
404
+ lines.push(`Docs: ${c.dim}https://sinapse.club${c.reset}`);
405
+
406
+ for (const line of lines) {
407
+ process.stdout.write(`${line}\n`);
408
+ }
409
+
410
+ return { lineCount: lines.length, lines };
411
+ }
412
+
413
+ /**
414
+ * Story C.1 AC 3 — Partial install user message.
415
+ *
416
+ * When postinstall exits with code 1 (warnings) or 2 (failure), show a single
417
+ * non-technical one-liner so the user knows SOMETHING is off and where to look.
418
+ * Suppressed in --quiet and --json modes (exit code alone signals the failure).
419
+ */
420
+ function renderPartialInstallMessage() {
421
+ if (FLAGS.json) return;
422
+ if (FLAGS.quiet) return;
423
+ const msg = `${c.yellow}Instalação parcial — rode 'sinapse doctor' pra ver o quê${c.reset}`;
424
+ try {
425
+ process.stdout.write(`${msg}\n`);
426
+ } catch {
427
+ /* ignore */
428
+ }
429
+ }
430
+
431
+ /**
432
+ * Flush the JSON state (single-object output). Safe to call multiple times.
433
+ */
434
+ let _jsonFlushed = false;
435
+ function flushJson() {
436
+ if (!FLAGS.json || _jsonFlushed) return;
437
+ _jsonFlushed = true;
438
+ try {
439
+ process.stdout.write(`${JSON.stringify(jsonState)}\n`);
440
+ } catch {
441
+ /* ignore */
442
+ }
443
+ }
444
+
445
+ function main(argvOverride) {
446
+ // Reset module-level state so repeated calls (from tests) are isolated.
447
+ FLAGS = detectFlags(argvOverride || process.argv.slice(2));
448
+ jsonState.status = 'success';
449
+ jsonState.version = null;
450
+ jsonState.agents = 0;
451
+ jsonState.squads = 0;
452
+ jsonState.warnings = [];
453
+ jsonState.errors = [];
454
+ jsonState.firstRun = false;
455
+ _jsonFlushed = false;
456
+
457
+ const skip = shouldSkip();
458
+ if (skip.skip) {
459
+ verboseLog(`Postinstall skipped (${skip.reason})`);
460
+ if (FLAGS.json) {
461
+ jsonState.status = 'skipped';
462
+ jsonState.skipReason = skip.reason;
463
+ flushJson();
464
+ }
465
+ return 0;
466
+ }
467
+
468
+ if (!isValidInstallRoot()) {
469
+ // Silently bail — package may be partially copied or invoked from an unexpected context.
470
+ if (FLAGS.json) {
471
+ jsonState.status = 'skipped';
472
+ jsonState.skipReason = 'not-sinapse-root';
473
+ flushJson();
474
+ }
475
+ return 0;
476
+ }
477
+
478
+ verboseLog(`${c.dim}SINAPSE postinstall — configurando ambiente...${c.reset}`);
479
+
480
+ const syncIde = stepSyncIde();
481
+ if (syncIde.critical) {
482
+ renderPartialInstallMessage();
483
+ if (FLAGS.json) flushJson();
484
+ return 2;
485
+ }
486
+
487
+ const runtimeDirs = stepCreateRuntimeDirs();
488
+ if (runtimeDirs.critical) {
489
+ renderPartialInstallMessage();
490
+ if (FLAGS.json) flushJson();
491
+ return 2;
492
+ }
493
+
494
+ const doctor = stepDoctor();
495
+ if (doctor.critical) {
496
+ renderPartialInstallMessage();
497
+ if (FLAGS.json) flushJson();
498
+ return 2;
499
+ }
500
+
501
+ // Capture first-run BEFORE creating the flag file so the welcome line shows
502
+ // on this install only.
503
+ const firstRun = isFirstRun();
504
+
505
+ // Render the minimalist summary (Story B.1 AC 1, AC 4, AC 7).
506
+ renderFinalSummary({ firstRun });
507
+
508
+ // Mark first-run AFTER the summary so a crash during rendering does not
509
+ // suppress the welcome line on the next attempt.
510
+ if (firstRun) {
511
+ markFirstRunDone();
512
+ }
513
+
514
+ // Non-critical warnings: show user the "partial install" message but exit 0
515
+ // so `npm install` does not report `command failed`. Critical failures have
516
+ // already returned 2 above. The `--json` output still carries `status: warn`
517
+ // for pipelines that want to act on it. [Story 10.39]
518
+ if (!syncIde.ok || !runtimeDirs.ok || !doctor.ok) {
519
+ renderPartialInstallMessage();
520
+ if (FLAGS.json) {
521
+ if (jsonState.status === 'success') jsonState.status = 'warn';
522
+ flushJson();
523
+ }
524
+ return 0;
525
+ }
526
+
527
+ if (FLAGS.json) flushJson();
528
+ return 0;
529
+ }
530
+
531
+ // Export for unit tests; only run if invoked directly.
532
+ module.exports = {
533
+ main,
534
+ detectFlags,
535
+ shouldSkip,
536
+ isValidInstallRoot,
537
+ stepSyncIde,
538
+ stepCreateRuntimeDirs,
539
+ stepDoctor,
540
+ renderFinalSummary,
541
+ renderPartialInstallMessage,
542
+ countAgents,
543
+ countSquads,
544
+ readVersion,
545
+ isFirstRun,
546
+ markFirstRunDone,
547
+ flushJson,
548
+ sinapseHome,
549
+ firstRunFlag,
550
+ _getJsonState: () => jsonState,
551
+ _getFlags: () => FLAGS,
552
+ _setFlags: (f) => { FLAGS = { ...FLAGS, ...f }; },
553
+ };
554
+
555
+ if (require.main === module) {
556
+ try {
557
+ const code = main();
558
+ process.exit(code);
559
+ } catch (err) {
560
+ error(`Postinstall falhou inesperadamente: ${err && err.stack ? err.stack : err}`);
561
+ // Non-critical — don't block the install on unexpected errors.
562
+ process.exit(0);
563
+ }
564
+ }