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,247 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * SINAPSE Telemetry — STUB (opt-in, disabled by default)
5
+ * @story C.1 — Exit Codes, Auto-Doctor & Opt-in Telemetry
6
+ *
7
+ * IMPORTANT (contributors):
8
+ * This is a STUB implementation. It does NOT make real network requests.
9
+ * Calling `send(event)` when telemetry is enabled logs the payload at debug
10
+ * level and stops there.
11
+ *
12
+ * TODO(follow-up-story): wire a real HTTPS endpoint once the privacy policy
13
+ * at docs/TELEMETRY.md has been reviewed by legal and the endpoint URL is
14
+ * confirmed. Until then, NO real data leaves the user's machine.
15
+ *
16
+ * Contract (see Story C.1 ACs):
17
+ * AC 4 — Exported methods: enable(), disable(), isEnabled(), send(event).
18
+ * AC 5 — Disabled by default. `send()` is a no-op when disabled.
19
+ * AC 6 — `enable()` persists a flag to ~/.sinapse/config.json. CLI wrapper
20
+ * shows the confirmation message to the user.
21
+ * AC 7 — `SINAPSE_TELEMETRY=1` env var overrides the config file.
22
+ * AC 8 — Payload is anonymized: only { category, platform, version, timestamp }.
23
+ * NO user paths, NO usernames, NO file names, NO PII.
24
+ * AC 9 — send() logs at debug level only. No HTTP.
25
+ *
26
+ * Zero external deps (pure Node stdlib). Safe to require() anywhere.
27
+ */
28
+
29
+ const fs = require('fs');
30
+ const os = require('os');
31
+ const path = require('path');
32
+
33
+ // ─── Config file location ────────────────────────────────────────────────────
34
+ // Stored under ~/.sinapse/config.json so it is per-user (not per-project) and
35
+ // does not pollute the project directory.
36
+
37
+ function sinapseHome() {
38
+ return path.join(os.homedir(), '.sinapse');
39
+ }
40
+
41
+ function configPath() {
42
+ return path.join(sinapseHome(), 'config.json');
43
+ }
44
+
45
+ // ─── Predefined failure categories (AC 8) ────────────────────────────────────
46
+ // Adding a new category? Add it here AND in docs/TELEMETRY.md so the privacy
47
+ // policy stays in sync with the code.
48
+
49
+ const FAILURE_CATEGORIES = Object.freeze([
50
+ 'doctor-fail',
51
+ 'sync-ide-fail',
52
+ 'permission-error',
53
+ 'runtime-dir-fail',
54
+ 'unknown',
55
+ ]);
56
+
57
+ // ─── Allowed platforms (AC 8) ────────────────────────────────────────────────
58
+
59
+ const ALLOWED_PLATFORMS = Object.freeze(['win32', 'darwin', 'linux']);
60
+
61
+ /**
62
+ * Normalize process.platform to one of the allowed values. Any exotic platform
63
+ * (aix, freebsd, openbsd, sunos, ...) is coerced to 'linux' to avoid leaking a
64
+ * fingerprint. NEVER returns the raw platform string.
65
+ * @returns {'win32'|'darwin'|'linux'}
66
+ */
67
+ function normalizePlatform() {
68
+ const p = process.platform;
69
+ if (p === 'win32' || p === 'darwin' || p === 'linux') return p;
70
+ return 'linux';
71
+ }
72
+
73
+ // ─── Version reading ─────────────────────────────────────────────────────────
74
+
75
+ let _cachedVersion = null;
76
+ function readVersion() {
77
+ if (_cachedVersion) return _cachedVersion;
78
+ try {
79
+ const pkg = require(path.resolve(__dirname, '..', '..', '..', 'package.json'));
80
+ _cachedVersion = pkg && pkg.version ? String(pkg.version) : 'unknown';
81
+ } catch {
82
+ _cachedVersion = 'unknown';
83
+ }
84
+ return _cachedVersion;
85
+ }
86
+
87
+ // ─── Config file read / write ────────────────────────────────────────────────
88
+ // All filesystem calls are fail-safe: a corrupt or missing config.json MUST
89
+ // NEVER crash the caller. Telemetry is best-effort.
90
+
91
+ function readConfig() {
92
+ try {
93
+ const p = configPath();
94
+ if (!fs.existsSync(p)) return {};
95
+ const raw = fs.readFileSync(p, 'utf8');
96
+ const parsed = JSON.parse(raw);
97
+ return (parsed && typeof parsed === 'object') ? parsed : {};
98
+ } catch {
99
+ return {};
100
+ }
101
+ }
102
+
103
+ function writeConfig(cfg) {
104
+ try {
105
+ const home = sinapseHome();
106
+ if (!fs.existsSync(home)) {
107
+ fs.mkdirSync(home, { recursive: true });
108
+ }
109
+ fs.writeFileSync(configPath(), `${JSON.stringify(cfg, null, 2)}\n`, 'utf8');
110
+ return true;
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+
116
+ // ─── Public API ──────────────────────────────────────────────────────────────
117
+
118
+ /**
119
+ * AC 5 + AC 7 — Is telemetry currently enabled?
120
+ *
121
+ * Resolution order (highest priority first):
122
+ * 1. SINAPSE_TELEMETRY=1 env var → TRUE (overrides config file)
123
+ * 2. SINAPSE_TELEMETRY=0 env var → FALSE (explicit opt-out wins too)
124
+ * 3. ~/.sinapse/config.json { "telemetry": true|false }
125
+ * 4. Default → FALSE
126
+ *
127
+ * @returns {boolean}
128
+ */
129
+ function isEnabled() {
130
+ const envVar = process.env.SINAPSE_TELEMETRY;
131
+ if (envVar === '1' || envVar === 'true') return true;
132
+ if (envVar === '0' || envVar === 'false') return false;
133
+ const cfg = readConfig();
134
+ return cfg.telemetry === true;
135
+ }
136
+
137
+ /**
138
+ * AC 6 — Persist opt-in to config file. Returns true on success.
139
+ * Does NOT print any message (CLI layer owns the user-facing copy).
140
+ * @returns {boolean}
141
+ */
142
+ function enable() {
143
+ const cfg = readConfig();
144
+ cfg.telemetry = true;
145
+ return writeConfig(cfg);
146
+ }
147
+
148
+ /**
149
+ * Persist opt-out to config file. Returns true on success.
150
+ * @returns {boolean}
151
+ */
152
+ function disable() {
153
+ const cfg = readConfig();
154
+ cfg.telemetry = false;
155
+ return writeConfig(cfg);
156
+ }
157
+
158
+ /**
159
+ * AC 8 — Build an anonymized payload from a category.
160
+ * Only { category, platform, version, timestamp } is included.
161
+ * Unknown categories are coerced to 'unknown' to prevent category-sprawl and
162
+ * to keep the schema predictable for the (future) real endpoint.
163
+ *
164
+ * @param {string} category
165
+ * @returns {{category:string,platform:'win32'|'darwin'|'linux',version:string,timestamp:string}}
166
+ */
167
+ function buildPayload(category) {
168
+ const safeCategory = FAILURE_CATEGORIES.includes(category) ? category : 'unknown';
169
+ return {
170
+ category: safeCategory,
171
+ platform: normalizePlatform(),
172
+ version: readVersion(),
173
+ timestamp: new Date().toISOString(),
174
+ };
175
+ }
176
+
177
+ /**
178
+ * AC 5 + AC 9 — Send a telemetry event.
179
+ *
180
+ * When disabled → no-op (no network call, no log).
181
+ * When enabled → build anonymized payload, log at debug level, and return it.
182
+ *
183
+ * NOTE: This stub does NOT make any HTTP request. A follow-up story will add
184
+ * the real endpoint after legal review of docs/TELEMETRY.md.
185
+ *
186
+ * @param {{category?: string}} event
187
+ * @param {{logger?: object}} [opts] — inject a logger for tests; defaults to
188
+ * the shared SINAPSE logger if available, otherwise console.
189
+ * @returns {null|object} the payload that would have been sent, or null if disabled
190
+ */
191
+ function send(event = {}, opts = {}) {
192
+ if (!isEnabled()) return null;
193
+ const payload = buildPayload(event && event.category);
194
+ const logger = opts.logger || _getDefaultLogger();
195
+ try {
196
+ if (logger && typeof logger.debug === 'function') {
197
+ logger.debug('[telemetry stub]', JSON.stringify(payload));
198
+ }
199
+ } catch {
200
+ /* never throw from telemetry */
201
+ }
202
+ // TODO(follow-up-story): POST payload to real endpoint here.
203
+ return payload;
204
+ }
205
+
206
+ // ─── Default logger resolution ──────────────────────────────────────────────
207
+ // Try the shared SINAPSE logger first (so telemetry respects --debug/--quiet),
208
+ // but fall back to a console shim if it's unavailable (e.g. during very early
209
+ // bootstrap or in isolated tests).
210
+
211
+ let _defaultLogger = null;
212
+ function _getDefaultLogger() {
213
+ if (_defaultLogger) return _defaultLogger;
214
+ try {
215
+ const { getLogger } = require('../logger');
216
+ _defaultLogger = getLogger();
217
+ } catch {
218
+ _defaultLogger = {
219
+ debug: (...args) => { try { console.debug(...args); } catch { /* ignore */ } },
220
+ };
221
+ }
222
+ return _defaultLogger;
223
+ }
224
+
225
+ // Test helper — reset internal caches between tests. Not part of the public
226
+ // contract; do not use in production code.
227
+ function _reset() {
228
+ _cachedVersion = null;
229
+ _defaultLogger = null;
230
+ }
231
+
232
+ module.exports = {
233
+ // Public API (AC 4)
234
+ enable,
235
+ disable,
236
+ isEnabled,
237
+ send,
238
+ // Helpers exposed for tests + CLI command
239
+ buildPayload,
240
+ normalizePlatform,
241
+ readVersion,
242
+ configPath,
243
+ sinapseHome,
244
+ FAILURE_CATEGORIES,
245
+ ALLOWED_PLATFORMS,
246
+ _reset,
247
+ };