thinkstack-core 4.0.0__tar.gz → 4.1.0__tar.gz

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 (327) hide show
  1. {thinkstack_core-4.0.0/thinkstack_core.egg-info → thinkstack_core-4.1.0}/PKG-INFO +4 -3
  2. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/README.md +2 -2
  3. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/pyproject.toml +2 -2
  4. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s1_branch_merge.py +4 -4
  5. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s24_reasoning_plus_learning.py +4 -3
  6. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s3_sensitivity.py +1 -0
  7. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s7_mcp_hooks.py +12 -7
  8. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s7_parser.py +334 -18
  9. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_sync_bundle.py +2 -2
  10. thinkstack_core-4.1.0/tests/test_toon_integration.py +184 -0
  11. thinkstack_core-4.1.0/tests/test_toon_io.py +196 -0
  12. thinkstack_core-4.1.0/tests/test_toon_serialize.py +169 -0
  13. thinkstack_core-4.1.0/tests/test_toon_token.py +197 -0
  14. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/sync_bundle.py +35 -24
  15. thinkstack_core-4.1.0/thinkstack_core/compat.py +106 -0
  16. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/gcc.py +17 -15
  17. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/invariants.py +3 -1
  18. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/mcp/auth.py +10 -0
  19. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/mcp/server.py +66 -20
  20. thinkstack_core-4.1.0/thinkstack_core/parser/thinking.py +219 -0
  21. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/config.py +6 -16
  22. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/api.py +2 -1
  23. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/chain.py +14 -7
  24. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/deny_list.py +20 -26
  25. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/provenance.py +13 -23
  26. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/recorder.py +13 -26
  27. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/store.py +15 -36
  28. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/sensitivity.py +5 -6
  29. thinkstack_core-4.1.0/thinkstack_core/serialization/__init__.py +27 -0
  30. thinkstack_core-4.1.0/thinkstack_core/serialization/io.py +76 -0
  31. thinkstack_core-4.1.0/thinkstack_core/serialization/reporting.py +85 -0
  32. thinkstack_core-4.1.0/thinkstack_core/serialization/token_counter.py +57 -0
  33. thinkstack_core-4.1.0/thinkstack_core/serialization/toon.py +507 -0
  34. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/theta.py +4 -7
  35. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/topics.py +17 -10
  36. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0/thinkstack_core.egg-info}/PKG-INFO +4 -3
  37. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core.egg-info/SOURCES.txt +9 -0
  38. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core.egg-info/requires.txt +1 -0
  39. thinkstack_core-4.0.0/thinkstack_core/compat.py +0 -103
  40. thinkstack_core-4.0.0/thinkstack_core/parser/thinking.py +0 -112
  41. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/MANIFEST.in +0 -0
  42. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/setup.cfg +0 -0
  43. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_backend_factory.py +0 -0
  44. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_broadcast.py +0 -0
  45. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_claude_config_locations.py +0 -0
  46. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_cli_sync_all.py +0 -0
  47. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_cli_topics_concepts.py +0 -0
  48. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_cloud_auth.py +0 -0
  49. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_cloud_bridge.py +0 -0
  50. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_cloud_integration.py +0 -0
  51. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_cloud_sse.py +0 -0
  52. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_cloud_storage.py +0 -0
  53. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_cloud_sync.py +0 -0
  54. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_concept_catalog.py +0 -0
  55. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_doctor_ci.py +0 -0
  56. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_getting_started.py +0 -0
  57. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_github_app.py +0 -0
  58. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_github_pat.py +0 -0
  59. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_hidden_profile_benchmark.py +0 -0
  60. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_hook_entrypoint.py +0 -0
  61. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_mcp_client.py +0 -0
  62. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_rep_merge.py +0 -0
  63. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s0_gcc.py +0 -0
  64. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s10_jetbrains.py +0 -0
  65. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s10_vscode.py +0 -0
  66. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s11_codex.py +0 -0
  67. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s11_hooks_installer.py +0 -0
  68. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s12_github.py +0 -0
  69. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s12_gitlab.py +0 -0
  70. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s13_dashboard_api.py +0 -0
  71. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s13_forensic.py +0 -0
  72. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s14_audit_export.py +0 -0
  73. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s14_ciso_api.py +0 -0
  74. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s15_rep_network.py +0 -0
  75. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s16_alerts.py +0 -0
  76. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s17a_metrics.py +0 -0
  77. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s17b_observability.py +0 -0
  78. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s17b_sso.py +0 -0
  79. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s18_context_extraction.py +0 -0
  80. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s18_credibility.py +0 -0
  81. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s18_identity.py +0 -0
  82. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s19_learning_evolution.py +0 -0
  83. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s19_projects.py +0 -0
  84. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s19_reasoning_query.py +0 -0
  85. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s20_divergence.py +0 -0
  86. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s20_metrics.py +0 -0
  87. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s20_pii_guardrails.py +0 -0
  88. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s20_token_budget.py +0 -0
  89. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s20_wrapper_capture.py +0 -0
  90. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s21_cross_project.py +0 -0
  91. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s21_hitl.py +0 -0
  92. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s22_swe_bench.py +0 -0
  93. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s22_swe_bench_dry_run.py +0 -0
  94. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s22_sync.py +0 -0
  95. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s23_reasoning_plus.py +0 -0
  96. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s23_sync_remaining.py +0 -0
  97. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s25_delivery_time.py +0 -0
  98. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s25_serve.py +0 -0
  99. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s25_setup_detection.py +0 -0
  100. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s25_templates.py +0 -0
  101. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s26_daemon.py +0 -0
  102. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s26_git_hooks.py +0 -0
  103. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s26_proxy.py +0 -0
  104. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s26_watcher.py +0 -0
  105. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s27_cross_project.py +0 -0
  106. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s27_drift.py +0 -0
  107. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s27_query.py +0 -0
  108. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s27_templates.py +0 -0
  109. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s28_cli.py +0 -0
  110. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s28_disagreement.py +0 -0
  111. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s28_planner.py +0 -0
  112. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s28_roles.py +0 -0
  113. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s28_session.py +0 -0
  114. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s28_simulator.py +0 -0
  115. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s29_ci.py +0 -0
  116. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s29_cli.py +0 -0
  117. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s29_dashboard.py +0 -0
  118. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s29_github.py +0 -0
  119. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s2_context.py +0 -0
  120. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s30_audit.py +0 -0
  121. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s31_cloud.py +0 -0
  122. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s4_invariants.py +0 -0
  123. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s4_variance_lock.py +0 -0
  124. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s5_privacy_disclosure.py +0 -0
  125. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s5_rep_sis.py +0 -0
  126. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s6_debug.py +0 -0
  127. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s7_ollama_wrapper.py +0 -0
  128. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s7_proxy.py +0 -0
  129. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s7_wrappers.py +0 -0
  130. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s7ent_gateway.py +0 -0
  131. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s7ent_helm.py +0 -0
  132. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s8_aggphi.py +0 -0
  133. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s8_theta_synthesis.py +0 -0
  134. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_s9_gaps.py +0 -0
  135. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_setup_command.py +0 -0
  136. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_setup_targets.py +0 -0
  137. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_signing.py +0 -0
  138. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_storage_azure.py +0 -0
  139. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_sync_conflicts.py +0 -0
  140. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_sync_state.py +0 -0
  141. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/tests/test_topics.py +0 -0
  142. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/__init__.py +0 -0
  143. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/aggphi_textual.py +0 -0
  144. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/__init__.py +0 -0
  145. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/base.py +0 -0
  146. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/config.py +0 -0
  147. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/dispatcher.py +0 -0
  148. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/jira.py +0 -0
  149. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/linear.py +0 -0
  150. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/pagerduty.py +0 -0
  151. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/slack.py +0 -0
  152. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/alerts/teams.py +0 -0
  153. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/audit/__init__.py +0 -0
  154. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/audit/exporter.py +0 -0
  155. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/audit/privacy.py +0 -0
  156. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/audit/scrubber.py +0 -0
  157. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/audit/service.py +0 -0
  158. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/audit/signing.py +0 -0
  159. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/broadcast/__init__.py +0 -0
  160. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/broadcast/broadcaster.py +0 -0
  161. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/broadcast/watcher.py +0 -0
  162. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/capability.py +0 -0
  163. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/__init__.py +0 -0
  164. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/client_config.py +0 -0
  165. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/client_configs/.claude-opencode-fallback.json +0 -0
  166. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/client_configs/.claude-stdio.json +0 -0
  167. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/client_configs/.cursor-mcp.json +0 -0
  168. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/client_configs/.opencode-bridge.json +0 -0
  169. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/client_configs/.opencode.json +0 -0
  170. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/client_configs/.vscode-mcp.json +0 -0
  171. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/mcp_client.py +0 -0
  172. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/setup.py +0 -0
  173. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/sync.py +0 -0
  174. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/sync_conflicts.py +0 -0
  175. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/sync_state.py +0 -0
  176. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/team_sync.py +0 -0
  177. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/cloud/thinkstack-mcp-bridge.js +0 -0
  178. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/codex/__init__.py +0 -0
  179. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/codex/__main__.py +0 -0
  180. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/codex/capture.py +0 -0
  181. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/codex/proxy.py +0 -0
  182. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/concept_catalog.py +0 -0
  183. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/consolidation/__init__.py +0 -0
  184. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/consolidation/synthesizer.py +0 -0
  185. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/consolidation/workflow.py +0 -0
  186. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/daemon/__init__.py +0 -0
  187. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/daemon/supervisor.py +0 -0
  188. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/daemon/watcher.py +0 -0
  189. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/dashboard_api.py +0 -0
  190. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/deltaf.py +0 -0
  191. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/disclosure.py +0 -0
  192. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/divergence/__init__.py +0 -0
  193. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/divergence/detector.py +0 -0
  194. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/gateway/__init__.py +0 -0
  195. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/gateway/key_manager.py +0 -0
  196. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/gateway/metrics_webhook.py +0 -0
  197. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/gateway/policy.py +0 -0
  198. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/gateway/server.py +0 -0
  199. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/gateway/sso.py +0 -0
  200. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/github/__init__.py +0 -0
  201. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/github/app.py +0 -0
  202. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/github/comment_builder.py +0 -0
  203. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/github/pat.py +0 -0
  204. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/github/pr_parser.py +0 -0
  205. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/github/pr_reporter.py +0 -0
  206. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/gitlab/__init__.py +0 -0
  207. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hitl/__init__.py +0 -0
  208. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hitl/channels.py +0 -0
  209. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hitl/orchestrator.py +0 -0
  210. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hooks/__init__.py +0 -0
  211. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hooks/claude_code.py +0 -0
  212. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hooks/git_capture.py +0 -0
  213. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hooks/git_commit.py +0 -0
  214. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hooks/installer.py +0 -0
  215. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hooks/pre_commit.py +0 -0
  216. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/hooks/runner.py +0 -0
  217. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/identity/__init__.py +0 -0
  218. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/identity/agent.py +0 -0
  219. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/identity/providers.py +0 -0
  220. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/mcp/__init__.py +0 -0
  221. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/__init__.py +0 -0
  222. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/aggregate.py +0 -0
  223. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/calibrate.py +0 -0
  224. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/calibration.py +0 -0
  225. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/credibility.py +0 -0
  226. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/delivery_time.py +0 -0
  227. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/dhs.py +0 -0
  228. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/mcs.py +0 -0
  229. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/roi.py +0 -0
  230. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/session_writer.py +0 -0
  231. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/shadow_ai.py +0 -0
  232. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/metrics/sprint_writer.py +0 -0
  233. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/observability/__init__.py +0 -0
  234. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/observability/datadog.py +0 -0
  235. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/observability/formatter.py +0 -0
  236. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/observability/report.py +0 -0
  237. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/observability/servicenow.py +0 -0
  238. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/observability/splunk.py +0 -0
  239. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/observability/webhook.py +0 -0
  240. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/parser/__init__.py +0 -0
  241. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/parser/blocks.py +0 -0
  242. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/parser/inference.py +0 -0
  243. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/projects.py +0 -0
  244. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/prompt_artifact.py +0 -0
  245. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/__init__.py +0 -0
  246. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/routes/__init__.py +0 -0
  247. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/routes/anthropic.py +0 -0
  248. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/routes/azure_openai.py +0 -0
  249. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/routes/gemini.py +0 -0
  250. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/routes/groq.py +0 -0
  251. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/routes/ollama.py +0 -0
  252. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/routes/openai.py +0 -0
  253. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/proxy/server.py +0 -0
  254. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/query/__init__.py +0 -0
  255. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/query/grep.py +0 -0
  256. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/query/hybrid.py +0 -0
  257. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/query/semantic.py +0 -0
  258. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/rdp.py +0 -0
  259. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning/__init__.py +0 -0
  260. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning/entry.py +0 -0
  261. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning/store.py +0 -0
  262. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/__init__.py +0 -0
  263. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/augmenter.py +0 -0
  264. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/capture.py +0 -0
  265. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/context.py +0 -0
  266. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/__init__.py +0 -0
  267. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/analytics.py +0 -0
  268. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/composer.py +0 -0
  269. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/conflicts.py +0 -0
  270. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/context_collector.py +0 -0
  271. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/cross_project.py +0 -0
  272. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/embeddings.py +0 -0
  273. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/evolution.py +0 -0
  274. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/extractor.py +0 -0
  275. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/filter_five_layer.py +0 -0
  276. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/models.py +0 -0
  277. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/org_store.py +0 -0
  278. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/pii.py +0 -0
  279. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/promotion.py +0 -0
  280. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/relevance.py +0 -0
  281. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/state.py +0 -0
  282. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/learning/theta_learning_bridge.py +0 -0
  283. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/reasoning_plus/prompt.py +0 -0
  284. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/rep.py +0 -0
  285. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/rep_network/__init__.py +0 -0
  286. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/rep_network/merge.py +0 -0
  287. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/rep_network/node.py +0 -0
  288. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/rep_network/server.py +0 -0
  289. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/rep_network/sync.py +0 -0
  290. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/serve.py +0 -0
  291. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/session/__init__.py +0 -0
  292. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/session/disagreement.py +0 -0
  293. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/session/models.py +0 -0
  294. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/session/orchestrator.py +0 -0
  295. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/session/planner.py +0 -0
  296. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/session/simulator.py +0 -0
  297. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/signing.py +0 -0
  298. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/sis.py +0 -0
  299. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/skills/pr-reviewer/SKILL.md +0 -0
  300. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/skills/thinkstack-auto-sync/SKILL.md +0 -0
  301. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/skills/thinkstack-session-start/SKILL.md +0 -0
  302. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/storage.py +0 -0
  303. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/__init__.py +0 -0
  304. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/engine.py +0 -0
  305. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/go.py +0 -0
  306. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/infra.py +0 -0
  307. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/library/__init__.py +0 -0
  308. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/library/api_design.md +0 -0
  309. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/library/bug_fix.md +0 -0
  310. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/library/decision_record.md +0 -0
  311. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/library/engine.py +0 -0
  312. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/library/security_review.md +0 -0
  313. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/python.py +0 -0
  314. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/react.py +0 -0
  315. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/templates/typescript.py +0 -0
  316. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/theta_synthesis.py +0 -0
  317. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/variance.py +0 -0
  318. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/wrapper/__init__.py +0 -0
  319. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/wrapper/anthropic.py +0 -0
  320. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/wrapper/base.py +0 -0
  321. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/wrapper/bedrock.py +0 -0
  322. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/wrapper/gemini.py +0 -0
  323. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/wrapper/ollama.py +0 -0
  324. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core/wrapper/openai.py +0 -0
  325. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core.egg-info/dependency_links.txt +0 -0
  326. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core.egg-info/entry_points.txt +0 -0
  327. {thinkstack_core-4.0.0 → thinkstack_core-4.1.0}/thinkstack_core.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thinkstack-core
3
- Version: 4.0.0
3
+ Version: 4.1.0
4
4
  Summary: ThinkStack — AI reasoning capture, audit trail, and governance for agent-assisted development (core library)
5
5
  Author-email: Hemant Joshi <hemant@flotorch.ai>
6
6
  License: Apache-2.0
@@ -24,6 +24,7 @@ Requires-Dist: pytest>=8.0.0; extra == "dev"
24
24
  Requires-Dist: boto3>=1.34.0; extra == "dev"
25
25
  Requires-Dist: pyyaml>=6.0; extra == "dev"
26
26
  Requires-Dist: pdfminer.six>=20221105; extra == "dev"
27
+ Requires-Dist: tiktoken>=0.7.0; extra == "dev"
27
28
  Provides-Extra: wrapper
28
29
  Requires-Dist: anthropic>=0.40.0; extra == "wrapper"
29
30
  Requires-Dist: openai>=1.50.0; extra == "wrapper"
@@ -60,10 +61,10 @@ Requires-Dist: thinkstack-core[audit,cloud,embeddings,mcp,proxy,wrapper]; extra
60
61
 
61
62
  **Local-first AI agent governance.** ThinkStack gives multi-agent systems a shared on-disk audit trail, coordination vector, privacy controls, and LLM integration layer — all without a remote service.
62
63
 
63
- > **Latest release:** `thinkstack-core` and `thinkstack-cli` **3.0.2** — Local-first AI governance split into a core SDK (`thinkstack-core`) and a CLI (`thinkstack-cli`). Install or upgrade with `pip install -U thinkstack-cli`.
64
+ > **Latest release:** `thinkstack-core` and `thinkstack-cli` **4.0.0** — Multi-model reasoning parsers + TOON default serialization + RACP spec paper. Install or upgrade with `pip install -U thinkstack-cli`.
64
65
 
65
66
  ```bash
66
- pip install -U thinkstack-cli>=3.0.1
67
+ pip install -U thinkstack-cli>=4.0.0
67
68
  thinkstack init
68
69
  thinkstack setup # connects to Claude Code, Cursor, or Antigravity
69
70
  thinkstack debug timeline
@@ -2,10 +2,10 @@
2
2
 
3
3
  **Local-first AI agent governance.** ThinkStack gives multi-agent systems a shared on-disk audit trail, coordination vector, privacy controls, and LLM integration layer — all without a remote service.
4
4
 
5
- > **Latest release:** `thinkstack-core` and `thinkstack-cli` **3.0.2** — Local-first AI governance split into a core SDK (`thinkstack-core`) and a CLI (`thinkstack-cli`). Install or upgrade with `pip install -U thinkstack-cli`.
5
+ > **Latest release:** `thinkstack-core` and `thinkstack-cli` **4.0.0** — Multi-model reasoning parsers + TOON default serialization + RACP spec paper. Install or upgrade with `pip install -U thinkstack-cli`.
6
6
 
7
7
  ```bash
8
- pip install -U thinkstack-cli>=3.0.1
8
+ pip install -U thinkstack-cli>=4.0.0
9
9
  thinkstack init
10
10
  thinkstack setup # connects to Claude Code, Cursor, or Antigravity
11
11
  thinkstack debug timeline
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "thinkstack-core"
3
- version = "4.0.0"
3
+ version = "4.1.0"
4
4
  description = "ThinkStack — AI reasoning capture, audit trail, and governance for agent-assisted development (core library)"
5
5
  readme = "README.md"
6
6
  license = { text = "Apache-2.0" }
@@ -26,7 +26,7 @@ dependencies = []
26
26
  thinkstack-hook = "thinkstack_core.hooks.runner:cli"
27
27
 
28
28
  [project.optional-dependencies]
29
- dev = ["pytest>=8.0.0", "boto3>=1.34.0", "pyyaml>=6.0", "pdfminer.six>=20221105"]
29
+ dev = ["pytest>=8.0.0", "boto3>=1.34.0", "pyyaml>=6.0", "pdfminer.six>=20221105", "tiktoken>=0.7.0"]
30
30
  wrapper = [
31
31
  "anthropic>=0.40.0",
32
32
  "openai>=1.50.0",
@@ -20,14 +20,14 @@ def test_commit_ids_are_deterministic_and_monotonic(tmp_path: Path) -> None:
20
20
  commits_dir = gcc_dir / "commits"
21
21
 
22
22
  # Expect two commits with deterministic, hex-encoded IDs starting from 1
23
- files = sorted(p.name for p in commits_dir.glob("*.json"))
24
- assert files == ["00000001.json", "00000002.json"]
23
+ files = sorted(p.name for p in commits_dir.glob("*.toon"))
24
+ assert files == ["00000001.toon", "00000002.toon"]
25
25
 
26
26
  # Re-open repo and commit once more: ID should continue monotonically
27
27
  repo2 = GCCRepository.at(tmp_path)
28
28
  repo2.commit("c3")
29
- files = sorted(p.name for p in commits_dir.glob("*.json"))
30
- assert files == ["00000001.json", "00000002.json", "00000003.json"]
29
+ files = sorted(p.name for p in commits_dir.glob("*.toon"))
30
+ assert files == ["00000001.toon", "00000002.toon", "00000003.toon"]
31
31
 
32
32
 
33
33
  def test_branch_and_history(tmp_path: Path) -> None:
@@ -31,6 +31,7 @@ from thinkstack_core.reasoning_plus.learning import (
31
31
  ReasoningCall,
32
32
  workspace_state_hash,
33
33
  )
34
+ from thinkstack_core.serialization import loads as toon_loads
34
35
 
35
36
 
36
37
  # ---------------------------------------------------------------------------
@@ -433,7 +434,7 @@ class TestReasoningPlusLearning:
433
434
  )
434
435
  learnings = drpl.get_relevant_learnings("fix parse_date bug")
435
436
  assert len(learnings) >= 1
436
- assert "utils.py" in learnings[0].content or "parse_date" in learnings[0].content
437
+ assert "parse_date" in learnings[0].content
437
438
 
438
439
  def test_compose_user_prompt(self, drpl):
439
440
  learnings = [Learning(content="Check foo.py first")]
@@ -574,7 +575,7 @@ class TestMCPLearningTools:
574
575
  repo = self._make_repo(temp_repo)
575
576
  self._seed_learning(repo)
576
577
  text = _dispatch_tool(repo, "thinkstack_reasoning_plus_learning_query", {"context": "fix parse_date bug"})
577
- data = json.loads(text)
578
+ data = toon_loads(text)
578
579
  assert data["count"] >= 1
579
580
  assert "parse_date" in data["learnings"][0]["content"]
580
581
 
@@ -590,7 +591,7 @@ class TestMCPLearningTools:
590
591
  "thinkstack_reasoning_plus_learning_feedback",
591
592
  {"learning_id": learning.id, "outcome": "success"},
592
593
  )
593
- data = json.loads(text)
594
+ data = toon_loads(text)
594
595
  assert data["confidence"] > 0.8
595
596
 
596
597
  def test_learning_purge(self, temp_repo):
@@ -200,6 +200,7 @@ class TestSensitivityStore:
200
200
  store.add(SensitivityEvent("n1", "schema_version", "", 0.9, "PUBLIC"))
201
201
  store.add(SensitivityEvent("n2", "schema_version", "", 0.7, "PROTECTED"))
202
202
  store.add(SensitivityEvent("n3", "pii_fields", "", 0.6, "PRIVATE"))
203
+ import json
203
204
  index = json.loads((tmp_path / "sens" / "index.json").read_text())
204
205
  assert len(index["schema_version"]) == 2
205
206
  assert len(index["pii_fields"]) == 1
@@ -15,6 +15,7 @@ Tests:
15
15
  from __future__ import annotations
16
16
 
17
17
  import json
18
+ from thinkstack_core.serialization import loads as toon_loads
18
19
  import sys
19
20
  import io
20
21
  from pathlib import Path
@@ -287,13 +288,17 @@ class TestMCPServer(unittest.TestCase):
287
288
  resp = responses[0]
288
289
  self.assertIn("result", resp)
289
290
  tools = resp["result"]["tools"]
290
- # 19 original tools + 3 S21 + 1 S23 sync status = 23
291
- self.assertEqual(len(tools), 23)
291
+ # 23 new tools + 23 legacy devtorch_* aliases = 46
292
+ self.assertEqual(len(tools), 46)
292
293
  names = {t["name"] for t in tools}
293
294
  self.assertIn("thinkstack_commit", names)
295
+ self.assertIn("devtorch_commit", names)
294
296
  self.assertIn("thinkstack_sensitivity_add", names)
297
+ self.assertIn("devtorch_sensitivity_add", names)
295
298
  self.assertIn("thinkstack_context", names)
299
+ self.assertIn("devtorch_context", names)
296
300
  self.assertIn("thinkstack_theta_read", names)
301
+ self.assertIn("devtorch_theta_read", names)
297
302
  self.assertIn("thinkstack_reasoning_plus_config", names)
298
303
  self.assertIn("thinkstack_reasoning_plus_set", names)
299
304
  self.assertIn("thinkstack_reasoning_plus_learning_query", names)
@@ -384,7 +389,7 @@ class TestMCPServer(unittest.TestCase):
384
389
  }
385
390
  responses = self._call_jsonrpc(mock_repo, req)
386
391
  text = responses[0]["result"]["content"][0]["text"]
387
- parsed = json.loads(text)
392
+ parsed = toon_loads(text)
388
393
  self.assertIn("auth", parsed)
389
394
  self.assertIn("api", parsed)
390
395
 
@@ -409,7 +414,7 @@ class TestMCPServer(unittest.TestCase):
409
414
  }
410
415
  responses = self._call_jsonrpc(mock_repo, req)
411
416
  text = responses[0]["result"]["content"][0]["text"]
412
- parsed = json.loads(text)
417
+ parsed = toon_loads(text)
413
418
  self.assertIn("auth", parsed)
414
419
  self.assertIn("schema", parsed)
415
420
  self.assertNotIn("api", parsed)
@@ -453,7 +458,7 @@ class TestMCPServer(unittest.TestCase):
453
458
  }
454
459
  responses = self._call_jsonrpc(repo, req)
455
460
  text = responses[0]["result"]["content"][0]["text"]
456
- parsed = json.loads(text)
461
+ parsed = toon_loads(text)
457
462
  self.assertIn("source", parsed)
458
463
  self.assertIn("config", parsed)
459
464
  self.assertIn("enabled", parsed["config"])
@@ -476,8 +481,8 @@ class TestMCPServer(unittest.TestCase):
476
481
  }
477
482
  responses = self._call_jsonrpc(repo, req)
478
483
  text = responses[0]["result"]["content"][0]["text"]
479
- self.assertIn("\"enabled\": false", text)
480
- settings = json.loads((repo.gcc_dir / "settings.json").read_text())
484
+ self.assertIn("enabled: false", text)
485
+ settings = toon_loads((repo.gcc_dir / "settings.toon").read_text()) if (repo.gcc_dir / "settings.toon").exists() else json.loads((repo.gcc_dir / "settings.json").read_text())
481
486
  self.assertFalse(settings["reasoning_plus"]["enabled"])
482
487
  self.assertEqual(settings["reasoning_plus"]["smart_top_n"], 5)
483
488
 
@@ -6,13 +6,15 @@ Tests for the S7 parser layer (thinkstack_core.parser).
6
6
  Coverage
7
7
  --------
8
8
  * extract_racp_blocks — both block types, only commits, only sensitivities,
9
- malformed XML, no blocks, attribute-order variation
9
+ malformed XML, no blocks, attribute-order variation
10
10
  * strip_racp_blocks — blocks removed, surrounding text preserved,
11
- paired tags, mixed content
12
- * extract_thinking_blocks — Anthropic format, OpenAI format, empty / missing
11
+ paired tags, mixed content
12
+ * extract_thinking_blocks — Anthropic format, OpenAI format, Gemini format,
13
+ DeepSeek/generic, generic XML/bracket tags,
14
+ precedence order, nested tags, empty / missing
13
15
  * thinking_to_commit_message — normal, empty, long text, whitespace collapse
14
16
  * infer_sensitivity — schema keywords, auth keywords, empty text,
15
- max_concepts limit, multi-match
17
+ max_concepts limit, multi-match
16
18
  * extract_decision_summary — normal sentence, markdown-heavy, very long,
17
19
  empty, code-fence stripping
18
20
  """
@@ -104,14 +106,10 @@ class TestExtractRacpBlocks:
104
106
  def test_malformed_tag_skipped_gracefully(self):
105
107
  """Malformed XML must not raise; valid blocks in same text are still extracted."""
106
108
  text = (
107
- # malformed: unquoted attribute value
108
109
  '<thinkstack:commit message=not-quoted confidence="0.9"/>\n'
109
- # valid block follows
110
110
  '<thinkstack:commit message="valid block" confidence="0.8"/>\n'
111
111
  )
112
- # Should not raise
113
112
  commits, sensitivities = extract_racp_blocks(text)
114
- # The valid block should be parsed
115
113
  valid = [c for c in commits if c.message == "valid block"]
116
114
  assert len(valid) == 1
117
115
 
@@ -356,6 +354,7 @@ class TestExtractThinkingBlocks:
356
354
  assert blocks == []
357
355
 
358
356
  def test_anthropic_thinking_block_empty_text_skipped(self):
357
+ """Empty thinking text should be skipped."""
359
358
  response = {
360
359
  "content": [
361
360
  {"type": "thinking", "thinking": ""},
@@ -363,7 +362,6 @@ class TestExtractThinkingBlocks:
363
362
  ]
364
363
  }
365
364
  blocks = extract_thinking_blocks(response)
366
- # Empty thinking text should be skipped
367
365
  assert len(blocks) == 1
368
366
  assert blocks[0].text == "Non-empty thought."
369
367
 
@@ -384,6 +382,332 @@ class TestExtractThinkingBlocks:
384
382
  blocks = extract_thinking_blocks(response)
385
383
  assert blocks == []
386
384
 
385
+ def test_gemini_format(self):
386
+ response = {
387
+ "candidates": [
388
+ {
389
+ "content": {
390
+ "parts": [
391
+ {"text": "I need to check the API limits first.", "thought": True},
392
+ {"text": "The answer is 42."},
393
+ ]
394
+ }
395
+ }
396
+ ]
397
+ }
398
+ blocks = extract_thinking_blocks(response)
399
+ assert len(blocks) == 1
400
+ assert blocks[0].text == "I need to check the API limits first."
401
+ assert blocks[0].source == "gemini_thought"
402
+
403
+ def test_gemini_format_multiple_thoughts(self):
404
+ response = {
405
+ "candidates": [
406
+ {
407
+ "content": {
408
+ "parts": [
409
+ {"text": "Thought one.", "thought": True},
410
+ {"text": "Thought two.", "thought": True},
411
+ {"text": "Final answer."},
412
+ ]
413
+ }
414
+ }
415
+ ]
416
+ }
417
+ blocks = extract_thinking_blocks(response)
418
+ assert len(blocks) == 2
419
+ assert blocks[0].text == "Thought one."
420
+ assert blocks[1].text == "Thought two."
421
+
422
+ def test_gemini_format_no_thoughts(self):
423
+ response = {
424
+ "candidates": [
425
+ {
426
+ "content": {
427
+ "parts": [
428
+ {"text": "Direct answer without thinking."},
429
+ ]
430
+ }
431
+ }
432
+ ]
433
+ }
434
+ blocks = extract_thinking_blocks(response)
435
+ assert blocks == []
436
+
437
+ def test_deepseek_reasoning_content(self):
438
+ """DeepSeek / generic servers using reasoning_content field."""
439
+ response = {
440
+ "choices": [
441
+ {
442
+ "message": {
443
+ "role": "assistant",
444
+ "content": "The answer.",
445
+ "reasoning_content": "DeepSeek reasoning goes here.",
446
+ }
447
+ }
448
+ ]
449
+ }
450
+ blocks = extract_thinking_blocks(response)
451
+ assert len(blocks) == 1
452
+ assert blocks[0].text == "DeepSeek reasoning goes here."
453
+ assert blocks[0].source == "reasoning_content"
454
+
455
+ def test_generic_reasoning_field_fallback(self):
456
+ """Some servers use 'reasoning' instead of 'reasoning_content'."""
457
+ response = {
458
+ "choices": [
459
+ {
460
+ "message": {
461
+ "role": "assistant",
462
+ "content": "Final answer.",
463
+ "reasoning": "Alternative field name.",
464
+ }
465
+ }
466
+ ]
467
+ }
468
+ blocks = extract_thinking_blocks(response)
469
+ assert len(blocks) == 1
470
+ assert blocks[0].text == "Alternative field name."
471
+ assert blocks[0].source == "reasoning"
472
+
473
+ def test_generic_chain_of_thought_field(self):
474
+ response = {
475
+ "choices": [
476
+ {
477
+ "message": {
478
+ "role": "assistant",
479
+ "content": "Final answer.",
480
+ "chain_of_thought": "Step-by-step reasoning.",
481
+ }
482
+ }
483
+ ]
484
+ }
485
+ blocks = extract_thinking_blocks(response)
486
+ assert len(blocks) == 1
487
+ assert blocks[0].text == "Step-by-step reasoning."
488
+ assert blocks[0].source == "chain_of_thought"
489
+
490
+ def test_precedence_api_native_wins_over_generic_tags(self):
491
+ """API-native reasoning_content takes priority over generic tags in text."""
492
+ response = {
493
+ "choices": [
494
+ {
495
+ "message": {
496
+ "role": "assistant",
497
+ "content": "<thinking>Should not be captured.</thinking>\nFinal answer.",
498
+ "reasoning_content": "API-native reasoning wins.",
499
+ }
500
+ }
501
+ ]
502
+ }
503
+ blocks = extract_thinking_blocks(response)
504
+ assert len(blocks) == 1
505
+ assert blocks[0].text == "API-native reasoning wins."
506
+ assert blocks[0].source == "reasoning_content"
507
+
508
+ def test_generic_tag_thinking_in_output_text(self):
509
+ """<thinking> tags in response text when no API-native fields present."""
510
+ response = {
511
+ "choices": [
512
+ {
513
+ "message": {
514
+ "role": "assistant",
515
+ "content": "<thinking>This is my reasoning.</thinking>\nFinal answer."
516
+ }
517
+ }
518
+ ]
519
+ }
520
+ blocks = extract_thinking_blocks(response)
521
+ assert len(blocks) == 1
522
+ assert blocks[0].text == "This is my reasoning."
523
+ assert blocks[0].source == "tag_thinking"
524
+
525
+ def test_generic_tag_reasoning_in_output_text(self):
526
+ response = {
527
+ "choices": [
528
+ {
529
+ "message": {
530
+ "role": "assistant",
531
+ "content": "<reasoning>Step-by-step logic.</reasoning>\nOutput."
532
+ }
533
+ }
534
+ ]
535
+ }
536
+ blocks = extract_thinking_blocks(response)
537
+ assert len(blocks) == 1
538
+ assert blocks[0].text == "Step-by-step logic."
539
+ assert blocks[0].source == "tag_reasoning"
540
+
541
+ def test_generic_bracket_thinking_in_output_text(self):
542
+ response = {
543
+ "choices": [
544
+ {
545
+ "message": {
546
+ "role": "assistant",
547
+ "content": "[thinking]Bracket reasoning.[/thinking]\nFinal."
548
+ }
549
+ }
550
+ ]
551
+ }
552
+ blocks = extract_thinking_blocks(response)
553
+ assert len(blocks) == 1
554
+ assert blocks[0].text == "Bracket reasoning."
555
+ assert blocks[0].source == "bracket_thinking"
556
+
557
+ def test_generic_html_comment_with_reasoning_marker(self):
558
+ response = {
559
+ "choices": [
560
+ {
561
+ "message": {
562
+ "role": "assistant",
563
+ "content": "<!-- think: Reasoning inside HTML comment -->\nFinal answer."
564
+ }
565
+ }
566
+ ]
567
+ }
568
+ blocks = extract_thinking_blocks(response)
569
+ assert len(blocks) == 1
570
+ assert "Reasoning inside HTML comment" in blocks[0].text
571
+ assert blocks[0].source == "html_comment"
572
+
573
+ def test_generic_html_comment_with_reasoning_marker_lowercase(self):
574
+ response = {
575
+ "choices": [
576
+ {
577
+ "message": {
578
+ "role": "assistant",
579
+ "content": "<!-- reasoning Step-by-step logic. -->\nFinal."
580
+ }
581
+ }
582
+ ]
583
+ }
584
+ blocks = extract_thinking_blocks(response)
585
+ assert len(blocks) == 1
586
+ assert "Step-by-step logic." in blocks[0].text
587
+ assert blocks[0].source == "html_comment"
588
+
589
+ def test_generic_html_comment_false_positive_not_captured(self):
590
+ """Plain HTML comments without a reasoning marker must NOT be captured."""
591
+ response = {
592
+ "choices": [
593
+ {
594
+ "message": {
595
+ "role": "assistant",
596
+ "content": "<!-- generated by tool -->\nFinal answer here."
597
+ }
598
+ }
599
+ ]
600
+ }
601
+ blocks = extract_thinking_blocks(response)
602
+ assert blocks == []
603
+
604
+ def test_generic_html_comment_false_positive_pii_disclaimer(self):
605
+ response = {
606
+ "choices": [
607
+ {
608
+ "message": {
609
+ "role": "assistant",
610
+ "content": "<!-- TODO: fix security issue -->\nThe answer is 42."
611
+ }
612
+ }
613
+ ]
614
+ }
615
+ blocks = extract_thinking_blocks(response)
616
+ assert blocks == []
617
+
618
+ def test_no_matching_generic_tag_returns_empty(self):
619
+ response = {
620
+ "choices": [
621
+ {
622
+ "message": {
623
+ "role": "assistant",
624
+ "content": "Just a normal response with no tags."
625
+ }
626
+ }
627
+ ]
628
+ }
629
+ blocks = extract_thinking_blocks(response)
630
+ assert blocks == []
631
+
632
+ def test_nested_tags_first_closing_wins(self):
633
+ """Nested/overlapping tags: first matching closing tag captures content."""
634
+ response = {
635
+ "choices": [
636
+ {
637
+ "message": {
638
+ "role": "assistant",
639
+ "content": "<thinking>Outer <reasoning>inner</reasoning> still outer</thinking>\nAnswer."
640
+ }
641
+ }
642
+ ]
643
+ }
644
+ blocks = extract_thinking_blocks(response)
645
+ assert len(blocks) == 1
646
+ assert "Outer" in blocks[0].text
647
+ assert blocks[0].source == "tag_thinking"
648
+
649
+ def test_multi_format_dedup_first_pattern_wins(self):
650
+ """When both <thinking> and [thinking] coexist, only first pattern used."""
651
+ response = {
652
+ "choices": [
653
+ {
654
+ "message": {
655
+ "role": "assistant",
656
+ "content": "<thinking>XML thinking.</thinking>\n[thinking]Bracket thinking.[/thinking]"
657
+ }
658
+ }
659
+ ]
660
+ }
661
+ blocks = extract_thinking_blocks(response)
662
+ assert len(blocks) == 1
663
+ assert blocks[0].source == "tag_thinking"
664
+
665
+ def test_multiple_thinking_tags_same_pattern_all_captured(self):
666
+ """Multiple occurrences of the SAME tag convention are all captured."""
667
+ response = {
668
+ "choices": [
669
+ {
670
+ "message": {
671
+ "role": "assistant",
672
+ "content": "<thinking>First thought.</thinking>\n<thinking>Second thought.</thinking>\nAnswer."
673
+ }
674
+ }
675
+ ]
676
+ }
677
+ blocks = extract_thinking_blocks(response)
678
+ assert len(blocks) == 2
679
+ assert blocks[0].text == "First thought."
680
+ assert blocks[1].text == "Second thought."
681
+
682
+ def test_backward_compatibility_anthropic_still_works(self):
683
+ """Existing Anthropic-only tests must still pass."""
684
+ response = {
685
+ "content": [
686
+ {"type": "thinking", "thinking": "Thinking content."},
687
+ {"type": "text", "text": "Answer."},
688
+ ]
689
+ }
690
+ blocks = extract_thinking_blocks(response)
691
+ assert len(blocks) == 1
692
+ assert blocks[0].source == "thinking_content"
693
+
694
+ def test_backward_compatibility_openai_still_works(self):
695
+ """Existing OpenAI-only tests must still pass."""
696
+ response = {
697
+ "choices": [
698
+ {
699
+ "message": {
700
+ "role": "assistant",
701
+ "content": "Answer.",
702
+ "reasoning_content": "OpenAI reasoning.",
703
+ }
704
+ }
705
+ ]
706
+ }
707
+ blocks = extract_thinking_blocks(response)
708
+ assert len(blocks) == 1
709
+ assert blocks[0].source == "reasoning_content"
710
+
387
711
 
388
712
  # ===========================================================================
389
713
  # thinking_to_commit_message
@@ -401,10 +725,9 @@ class TestThinkingToCommitMessage:
401
725
  assert result == "auto: (no thinking content)"
402
726
 
403
727
  def test_truncation_at_max_chars(self):
404
- long_text = "word " * 100 # 500 chars
728
+ long_text = "word " * 100
405
729
  blocks = [ThinkingBlock(text=long_text)]
406
730
  result = thinking_to_commit_message(blocks, max_chars=50)
407
- # "auto: " is 6 chars, the rest is <= 50 chars of content
408
731
  content = result[len("auto: "):]
409
732
  assert len(content) <= 50
410
733
 
@@ -470,7 +793,6 @@ class TestInferSensitivity:
470
793
  text = "Update the environment configuration to point to the new endpoint."
471
794
  results = infer_sensitivity(text)
472
795
  concepts = [r.concept for r in results]
473
- # Should match at least one of 'configuration' or 'api_interface'
474
796
  assert any(c in concepts for c in ("configuration", "api_interface"))
475
797
 
476
798
  def test_empty_text(self):
@@ -487,7 +809,6 @@ class TestInferSensitivity:
487
809
  assert results == []
488
810
 
489
811
  def test_max_concepts_limit(self):
490
- # This text deliberately contains keywords for multiple concepts.
491
812
  text = (
492
813
  "The database migration affects the JWT auth token and the "
493
814
  "deploy pipeline and the cache layer."
@@ -534,7 +855,6 @@ class TestExtractDecisionSummary:
534
855
  )
535
856
  result = extract_decision_summary(text)
536
857
  assert result.startswith("auto: ")
537
- # Markdown markers should be stripped
538
858
  assert "##" not in result
539
859
  assert "**" not in result
540
860
  assert "_" not in result
@@ -545,9 +865,7 @@ class TestExtractDecisionSummary:
545
865
  "The above code prints hello."
546
866
  )
547
867
  result = extract_decision_summary(text)
548
- # Python syntax from inside the fence must be gone
549
868
  assert "print('hello')" not in result
550
- # The plain-English sentence following the fence should be captured
551
869
  assert "prints hello" in result or result.startswith("auto: ")
552
870
 
553
871
  def test_very_long_text_truncated(self):
@@ -575,7 +893,6 @@ class TestExtractDecisionSummary:
575
893
  "We chose the first option."
576
894
  )
577
895
  result = extract_decision_summary(text)
578
- # Bullet markers should not appear
579
896
  assert "- " not in result
580
897
 
581
898
  def test_numbered_list_stripped(self):
@@ -591,5 +908,4 @@ class TestExtractDecisionSummary:
591
908
  text = "This is\na sentence\nspread over lines."
592
909
  result = extract_decision_summary(text)
593
910
  assert result.startswith("auto: ")
594
- # Should contain the content (collapsed)
595
911
  assert "\n" not in result
@@ -193,8 +193,8 @@ class TestMergePull:
193
193
  result = merge_pull(gcc_dir, remote_delta, conflict_log)
194
194
  assert result["counts"]["commits"] == 2
195
195
  assert result["conflicts"] == []
196
- assert (gcc_dir / "commits" / "c001.json").exists()
197
- assert (gcc_dir / "commits" / "c002.json").exists()
196
+ assert (gcc_dir / "commits" / "c001.toon").exists()
197
+ assert (gcc_dir / "commits" / "c002.toon").exists()
198
198
 
199
199
  def test_merge_pull_detects_commit_id_collision(
200
200
  self, gcc_dir: Path, conflict_log: _MockConflictLog