stock-analysis-plugin 0.2.2__tar.gz → 0.2.5__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 (186) hide show
  1. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/.github/workflows/autofix.yml +2 -1
  2. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/.github/workflows/ci.yml +87 -32
  3. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/.github/workflows/publish.yml +19 -6
  4. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/AGENTS.md +6 -6
  5. stock_analysis_plugin-0.2.5/LICENSE +21 -0
  6. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/PKG-INFO +84 -17
  7. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/README.md +79 -15
  8. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/docs/hermes-integration.en.md +3 -3
  9. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/docs/hermes-integration.md +4 -4
  10. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/docs/openclaw-integration.md +4 -4
  11. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/docs/pi-integration.en.md +3 -3
  12. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/docs/pi-integration.md +3 -3
  13. stock_analysis_plugin-0.2.5/docs/research/issue-44-coverage-sources.md +122 -0
  14. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/dsh/README.md +2 -2
  15. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/dsh/index.ts +223 -16
  16. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/dsh/package.json +3 -3
  17. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/hermes/plugin.yaml +16 -0
  18. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/hermes/schemas.py +157 -6
  19. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/hermes/tools.py +93 -3
  20. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/openclaw/README.md +2 -2
  21. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/openclaw/index.ts +184 -26
  22. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/openclaw/openclaw.plugin.json +10 -1
  23. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/openclaw/package.json +1 -1
  24. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/package-lock.json +261 -143
  25. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/package.json +5 -5
  26. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/pi/index.ts +265 -11
  27. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/pyproject.toml +4 -2
  28. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/requirements-dev.txt +1 -1
  29. stock_analysis_plugin-0.2.5/ruff.toml +8 -0
  30. stock_analysis_plugin-0.2.5/scripts/ci-resolve-llm-host.mjs +29 -0
  31. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/scripts/setup-python.mjs +7 -9
  32. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/event-driven/SKILL.md +6 -0
  33. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/growth-quality/SKILL.md +6 -0
  34. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/hot-theme/SKILL.md +3 -2
  35. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/stock-analysis/SKILL.md +22 -0
  36. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/stock-screener/SKILL.md +19 -1
  37. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/strategy-backtest/SKILL.md +11 -5
  38. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/bottom_volume.yaml +5 -0
  39. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/box_oscillation.yaml +5 -0
  40. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/bull_trend.yaml +11 -3
  41. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/dragon_head.yaml +4 -2
  42. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/emotion_cycle.yaml +5 -0
  43. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/ma_crossover.yaml +10 -3
  44. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/rsi_oversold.yaml +5 -0
  45. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/shrink_pullback.yaml +7 -1
  46. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/strategies/examples/volume_breakout.yaml +7 -1
  47. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/conftest.py +25 -0
  48. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/host_smoke.mjs +52 -55
  49. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/test_hermes_llm.py +12 -13
  50. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/test_openclaw_e2e.ts +5 -2
  51. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/test_pi_llm.ts +8 -9
  52. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/test_provider_network.py +12 -0
  53. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_alert_rules.py +43 -0
  54. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_anomaly_detect.py +25 -0
  55. stock_analysis_plugin-0.2.5/tests/test_backtest.py +727 -0
  56. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_backtest_advanced.py +15 -0
  57. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_capabilities.py +1 -1
  58. stock_analysis_plugin-0.2.5/tests/test_data_cache.py +47 -0
  59. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_diagnostics.py +25 -0
  60. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_dsh_integration.ts +86 -5
  61. stock_analysis_plugin-0.2.5/tests/test_dsh_sdk_compat.ts +22 -0
  62. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_gather.py +75 -1
  63. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_hermes_integration.py +79 -0
  64. stock_analysis_plugin-0.2.5/tests/test_kline_adjustment.py +194 -0
  65. stock_analysis_plugin-0.2.5/tests/test_market_regime.py +148 -0
  66. stock_analysis_plugin-0.2.5/tests/test_market_review.py +229 -0
  67. stock_analysis_plugin-0.2.5/tests/test_name_resolver.py +135 -0
  68. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_openclaw_integration.ts +110 -14
  69. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_pi_integration.ts +49 -1
  70. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_report_renderer.py +66 -0
  71. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_risk_screening.py +32 -0
  72. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_screener.py +161 -0
  73. stock_analysis_plugin-0.2.5/tests/test_setup_python.mjs +21 -0
  74. stock_analysis_plugin-0.2.5/tests/test_stock_data.py +307 -0
  75. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_stock_data_failover.py +498 -68
  76. stock_analysis_plugin-0.2.5/tests/test_stock_data_margin.py +375 -0
  77. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_stock_data_short_term.py +14 -30
  78. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_technical.py +166 -0
  79. stock_analysis_plugin-0.2.5/tests/test_trading_calendar.py +300 -0
  80. stock_analysis_plugin-0.2.5/tests/test_value_data.py +974 -0
  81. stock_analysis_plugin-0.2.5/tests/test_volume_analysis.py +147 -0
  82. stock_analysis_plugin-0.2.5/tools/_cache.py +61 -0
  83. stock_analysis_plugin-0.2.5/tools/_subproc.py +95 -0
  84. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/alert_rules.py +19 -9
  85. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/anomaly_detect.py +24 -35
  86. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/backtest.py +180 -100
  87. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/capabilities.py +13 -5
  88. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/diagnostics.py +12 -6
  89. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/gather.py +13 -9
  90. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/import_parser.py +2 -5
  91. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/market_regime.py +27 -35
  92. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/market_review.py +56 -9
  93. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/name_resolver.py +2 -5
  94. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/pattern.py +2 -5
  95. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/position_context.py +2 -5
  96. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/report_renderer.py +10 -6
  97. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/requirements.txt +2 -1
  98. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/risk_screening.py +29 -23
  99. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/screener.py +80 -18
  100. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/search_intel.py +5 -13
  101. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/signal_tracker.py +2 -6
  102. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/stock_data.py +520 -169
  103. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/technical.py +136 -40
  104. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/trading_calendar.py +78 -18
  105. stock_analysis_plugin-0.2.5/tools/value_data.py +1368 -0
  106. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/volume_analysis.py +2 -5
  107. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/watchlist.py +2 -5
  108. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/watchlist_context.py +2 -5
  109. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tsconfig.json +8 -1
  110. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/typings/openclaw/index.d.ts +1 -0
  111. stock_analysis_plugin-0.2.2/ruff.toml +0 -6
  112. stock_analysis_plugin-0.2.2/tests/test_backtest.py +0 -211
  113. stock_analysis_plugin-0.2.2/tests/test_market_regime.py +0 -90
  114. stock_analysis_plugin-0.2.2/tests/test_market_review.py +0 -115
  115. stock_analysis_plugin-0.2.2/tests/test_stock_data.py +0 -95
  116. stock_analysis_plugin-0.2.2/tests/test_trading_calendar.py +0 -161
  117. stock_analysis_plugin-0.2.2/tools/_subproc.py +0 -46
  118. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/.github/release.yml +0 -0
  119. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/.gitignore +0 -0
  120. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/.npmignore +0 -0
  121. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/CLAUDE.md +0 -0
  122. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/dsh/cordis.patch.yml +0 -0
  123. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/hermes/__init__.py +0 -0
  124. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/openclaw/.npmignore +0 -0
  125. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/schemas/market_review_schema.json +0 -0
  126. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/schemas/report_schema.json +0 -0
  127. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/scripts/sync-version.sh +0 -0
  128. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/scripts/venv-python.mjs +0 -0
  129. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/bottom-volume/SKILL.md +0 -0
  130. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/bottom-volume/scripts/gather.py +0 -0
  131. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/box-oscillation/SKILL.md +0 -0
  132. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/box-oscillation/scripts/gather.py +0 -0
  133. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/bull-trend/SKILL.md +0 -0
  134. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/bull-trend/scripts/gather.py +0 -0
  135. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/chan-theory/SKILL.md +0 -0
  136. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/chan-theory/scripts/gather.py +0 -0
  137. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/dragon-head/SKILL.md +0 -0
  138. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/dragon-head/scripts/gather.py +0 -0
  139. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/emotion-cycle/SKILL.md +0 -0
  140. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/emotion-cycle/scripts/gather.py +0 -0
  141. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/event-driven/scripts/gather.py +0 -0
  142. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/expectation-repricing/SKILL.md +0 -0
  143. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/expectation-repricing/scripts/gather.py +0 -0
  144. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/growth-quality/scripts/gather.py +0 -0
  145. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/hot-theme/scripts/gather.py +0 -0
  146. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/ma-crossover/SKILL.md +0 -0
  147. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/ma-crossover/scripts/gather.py +0 -0
  148. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/market-review/SKILL.md +0 -0
  149. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/market-review/scripts/gather.py +0 -0
  150. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/one-yang-three-yin/SKILL.md +0 -0
  151. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/one-yang-three-yin/scripts/gather.py +0 -0
  152. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/shrink-pullback/SKILL.md +0 -0
  153. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/shrink-pullback/scripts/gather.py +0 -0
  154. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/stock-analysis/references/short-term-trading.md +0 -0
  155. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/stock-analysis/scripts/gather.py +0 -0
  156. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/stock-screener/scripts/gather.py +0 -0
  157. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/strategy-backtest/scripts/gather.py +0 -0
  158. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/volume-breakout/SKILL.md +0 -0
  159. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/volume-breakout/scripts/gather.py +0 -0
  160. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/wave-theory/SKILL.md +0 -0
  161. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/wave-theory/scripts/gather.py +0 -0
  162. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/skills/wisburg-research/SKILL.md +0 -0
  163. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/templates/_macros.j2 +0 -0
  164. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/templates/market_review/full.md.j2 +0 -0
  165. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/templates/stock_analysis/brief.md.j2 +0 -0
  166. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/templates/stock_analysis/full.md.j2 +0 -0
  167. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/__init__.py +0 -0
  168. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/_stubs/dsh-tools.ts +0 -0
  169. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/_stubs/openclaw-sdk.ts +0 -0
  170. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/_stubs/typebox.ts +0 -0
  171. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/dsh_tool_spy.mjs +0 -0
  172. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/test_dsh_e2e.ts +0 -0
  173. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/test_host_to_python.py +0 -0
  174. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/e2e/test_pi_e2e.ts +0 -0
  175. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_import_parser.py +0 -0
  176. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_pattern.py +0 -0
  177. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_position_context.py +0 -0
  178. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_search_intel.py +0 -0
  179. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_sentiment.py +0 -0
  180. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_signal_tracker.py +0 -0
  181. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_skill_workflows.py +0 -0
  182. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_subproc.py +0 -0
  183. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_watchlist.py +0 -0
  184. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tests/test_watchlist_context.py +0 -0
  185. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/tools/__init__.py +0 -0
  186. {stock_analysis_plugin-0.2.2 → stock_analysis_plugin-0.2.5}/typings/pi-agent/index.d.ts +0 -0
@@ -18,7 +18,8 @@ jobs:
18
18
  cache: pip
19
19
 
20
20
  - name: Install ruff
21
- run: pip install "ruff>=0.4.0"
21
+ # Pinned — must match ci.yml and requirements-dev.txt.
22
+ run: pip install "ruff==0.15.20"
22
23
 
23
24
  - name: Ruff auto-fix (lint)
24
25
  run: ruff check --fix tools/ skills/ tests/ hermes/
@@ -7,9 +7,15 @@ on:
7
7
  branches: [main]
8
8
  workflow_call:
9
9
 
10
+ # One active run per branch/PR — new pushes cancel stale runs.
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
10
15
  jobs:
11
16
  lint:
12
17
  runs-on: ubuntu-latest
18
+ timeout-minutes: 10
13
19
  steps:
14
20
  - uses: actions/checkout@v4
15
21
 
@@ -18,7 +24,8 @@ jobs:
18
24
  python-version: "3.11"
19
25
 
20
26
  - name: Install Python lint tools
21
- run: pip install ruff>=0.4.0
27
+ # Pinned — must match requirements-dev.txt and autofix.yml.
28
+ run: pip install ruff==0.15.20
22
29
 
23
30
  - name: Ruff check
24
31
  run: ruff check tools/ skills/ tests/ hermes/
@@ -29,21 +36,30 @@ jobs:
29
36
  - uses: actions/setup-node@v4
30
37
  with:
31
38
  node-version: "20"
39
+ cache: "npm"
32
40
 
41
+ # --ignore-scripts: tsc doesn't need the postinstall-built Python venv.
33
42
  - name: Install Node dependencies
34
- run: npm install
43
+ run: npm ci --ignore-scripts
35
44
 
36
45
  - name: TypeScript type check
37
46
  run: npx tsc --noEmit
38
47
 
39
48
  test:
40
49
  runs-on: ubuntu-latest
50
+ timeout-minutes: 15
51
+ strategy:
52
+ fail-fast: false
53
+ matrix:
54
+ # 3.10 leg guards the declared floor — verified: full dep set installs
55
+ # and the suite passes on cpython 3.10.19.
56
+ python-version: ["3.11", "3.10"]
41
57
  steps:
42
58
  - uses: actions/checkout@v4
43
59
 
44
60
  - uses: actions/setup-python@v5
45
61
  with:
46
- python-version: "3.11"
62
+ python-version: ${{ matrix.python-version }}
47
63
  cache: pip
48
64
 
49
65
  - name: Install dependencies
@@ -57,7 +73,11 @@ jobs:
57
73
  network:
58
74
  # Real provider calls (akshare/yfinance) — flaky upstreams by nature, so
59
75
  # gated to same-repo PRs and pushes (forks skip it, like e2e-llm).
76
+ # continue-on-error: see publish.yml — a flaky upstream must not block the
77
+ # release path; failures still surface as annotations on the run.
78
+ continue-on-error: true
60
79
  runs-on: ubuntu-latest
80
+ timeout-minutes: 20
61
81
  if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
62
82
  steps:
63
83
  - uses: actions/checkout@v4
@@ -82,6 +102,7 @@ jobs:
82
102
  # structurally cannot see. Deterministic by design: no LLM, no secrets, and
83
103
  # the 4 round-trip tools are the non-network set (see tests/e2e/*.ts).
84
104
  runs-on: ${{ matrix.os }}
105
+ timeout-minutes: 15
85
106
  strategy:
86
107
  fail-fast: false
87
108
  matrix:
@@ -96,16 +117,20 @@ jobs:
96
117
  - uses: actions/setup-node@v4
97
118
  with:
98
119
  node-version: "20"
120
+ cache: "npm"
121
+
122
+ - name: Python setup failure check
123
+ run: node tests/test_setup_python.mjs
99
124
 
100
125
  # tests/conftest.py imports numpy/pandas at module load, so any pytest run
101
- # needs the tools' runtime deps in system python. npm install's postinstall
126
+ # needs the tools' runtime deps in system python. npm ci's postinstall
102
127
  # separately builds .venv (full requirements) — that's the python the
103
128
  # host↔python round-trips spawn.
104
129
  - name: Install dependencies
105
130
  run: |
106
131
  pip install -r tools/requirements.txt
107
132
  pip install -r requirements-dev.txt
108
- npm install
133
+ npm ci
109
134
 
110
135
  - name: TypeScript type check
111
136
  run: npx tsc --noEmit
@@ -119,6 +144,9 @@ jobs:
119
144
  - name: dsh plugin registration
120
145
  run: npx tsx tests/test_dsh_integration.ts
121
146
 
147
+ - name: dsh current SDK compatibility
148
+ run: npx tsx tests/test_dsh_sdk_compat.ts
149
+
122
150
  - name: Hermes plugin registration
123
151
  run: pytest tests/test_hermes_integration.py -v
124
152
 
@@ -135,9 +163,13 @@ jobs:
135
163
  run: npx tsx tests/e2e/test_dsh_e2e.ts
136
164
 
137
165
  e2e-llm:
138
- # Real DeepSeek call. Only runs when DEEPSEEK_API_KEY secret is present
166
+ # Real OpenAI-compatible call. API key is a secret; URL/model can also be variables.
139
167
  # (skipped on forks to prevent secret exposure).
168
+ # continue-on-error: like `network` — non-deterministic output must not
169
+ # block the release path (see publish.yml).
170
+ continue-on-error: true
140
171
  runs-on: ubuntu-latest
172
+ timeout-minutes: 20
141
173
  if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }}
142
174
  steps:
143
175
  - uses: actions/checkout@v4
@@ -150,33 +182,43 @@ jobs:
150
182
  - uses: actions/setup-node@v4
151
183
  with:
152
184
  node-version: "20"
185
+ cache: "npm"
186
+
187
+ - name: Resolve model endpoint on runner
188
+ env:
189
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
190
+ run: node scripts/ci-resolve-llm-host.mjs
153
191
 
154
192
  - name: Install Python dependencies
155
193
  run: |
156
194
  pip install -r tools/requirements.txt
157
195
  pip install -r requirements-dev.txt
158
196
 
197
+ # Full npm ci (postinstall builds .venv) — the Pi LLM flow spawns tools
198
+ # through it.
159
199
  - name: Install Node dependencies
160
- run: npm install
200
+ run: npm ci
161
201
 
162
202
  - name: E2E — Hermes LLM flow
163
203
  env:
164
- DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
165
- DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-v4-flash' }}
204
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
205
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
206
+ OPENAI_MODEL: ${{ secrets.OPENAI_MODEL || vars.OPENAI_MODEL }}
166
207
  run: |
167
- if [ -z "$DEEPSEEK_API_KEY" ]; then
168
- echo "DEEPSEEK_API_KEY not configured — skipping LLM e2e"
208
+ if [ -z "$OPENAI_BASE_URL" ] || [ -z "$OPENAI_API_KEY" ] || [ -z "$OPENAI_MODEL" ]; then
209
+ echo "OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL are required — skipping LLM e2e"
169
210
  exit 0
170
211
  fi
171
212
  pytest tests/e2e/test_hermes_llm.py -m integration_llm -v
172
213
 
173
214
  - name: E2E — Pi LLM flow
174
215
  env:
175
- DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
176
- DEEPSEEK_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-v4-flash' }}
216
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
217
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
218
+ OPENAI_MODEL: ${{ secrets.OPENAI_MODEL || vars.OPENAI_MODEL }}
177
219
  run: |
178
- if [ -z "$DEEPSEEK_API_KEY" ]; then
179
- echo "DEEPSEEK_API_KEY not configured — skipping LLM e2e"
220
+ if [ -z "$OPENAI_BASE_URL" ] || [ -z "$OPENAI_API_KEY" ] || [ -z "$OPENAI_MODEL" ]; then
221
+ echo "OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL are required — skipping LLM e2e"
180
222
  exit 0
181
223
  fi
182
224
  npx tsx tests/e2e/test_pi_llm.ts
@@ -201,39 +243,42 @@ jobs:
201
243
  python-version: "3.11"
202
244
 
203
245
  - uses: actions/setup-node@v4
204
- # Node 24: openclaw requires >= 22.19, and pi 0.83's undici breaks on 20.x
205
- # (dsh also requires ^22.19 || >=24)
246
+ # OpenClaw 2026.9.6 requires Node >=24.16.
206
247
  with:
207
- node-version: "24"
248
+ node-version: "24.16.0"
249
+ cache: "npm"
250
+
251
+ - name: Resolve model endpoint on runner
252
+ env:
253
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
254
+ run: node scripts/ci-resolve-llm-host.mjs
208
255
 
209
256
  - name: Install Node dependencies (also builds repo .venv via postinstall)
210
- run: npm install
257
+ run: npm ci
211
258
 
212
259
  - name: Install host CLIs
213
- # Pinned: pi latest and openclaw latest (slim repack) drifted from the
214
- # validated CLIs — openclaw@latest installed no working bin, and pi's
215
- # `list` flags changed between releases. dsh is a developer preview
216
- # (rc line), so pin it too. `dsh plugin` forwards to pnpm.
260
+ # Pin the current host releases so failures are reproducible.
217
261
  run: |
218
- npm i -g @earendil-works/pi-coding-agent@0.83.0
219
- npm i -g openclaw@2026.6.33
220
- npm i -g @deepseek-ai/dsh@0.1.0-rc.7
262
+ npm i -g @earendil-works/pi-coding-agent@0.99.0
263
+ npm i -g openclaw@2026.9.6
264
+ npm i -g @deepseek-ai/dsh@0.2.0-rc.2
221
265
  npm i -g pnpm@10
222
266
 
223
267
  - name: Real-host smoke QA (${{ matrix.host }})
224
268
  env:
225
- SMOKE_LLM_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
226
- SMOKE_LLM_BASE_URL: https://api.deepseek.com
227
- SMOKE_LLM_MODEL: ${{ vars.DEEPSEEK_MODEL || 'deepseek-v4-flash' }}
269
+ OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL || vars.OPENAI_BASE_URL }}
270
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
271
+ OPENAI_MODEL: ${{ secrets.OPENAI_MODEL || vars.OPENAI_MODEL }}
228
272
  run: |
229
- if [ -z "$SMOKE_LLM_API_KEY" ]; then
230
- echo "SMOKE_LLM_API_KEY not configured — failing (this check is blocking by design)"
273
+ if [ -z "$OPENAI_BASE_URL" ] || [ -z "$OPENAI_API_KEY" ] || [ -z "$OPENAI_MODEL" ]; then
274
+ echo "OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL are required (blocking check)"
231
275
  exit 1
232
276
  fi
233
277
  node tests/e2e/host_smoke.mjs ${{ matrix.host }}
234
278
 
235
279
  build:
236
280
  runs-on: ubuntu-latest
281
+ timeout-minutes: 10
237
282
  needs: [lint, test, compat]
238
283
  steps:
239
284
  - uses: actions/checkout@v4
@@ -241,9 +286,19 @@ jobs:
241
286
  - uses: actions/setup-node@v4
242
287
  with:
243
288
  node-version: "20"
289
+ cache: "npm"
244
290
 
291
+ # --ignore-scripts: packing/bundling doesn't need the Python venv
292
+ # (esbuild's binary arrives via optionalDependencies, not postinstall).
245
293
  - name: Install Node dependencies
246
- run: npm install
294
+ run: npm ci --ignore-scripts
295
+
296
+ # Bundle both compiled hosts here so esbuild breakage surfaces in CI
297
+ # instead of at tag-publish time.
298
+ - name: Build host bundles
299
+ run: |
300
+ npm run build:openclaw
301
+ npm run build:dsh
247
302
 
248
303
  - name: Verify pack contents
249
304
  run: npm pack --dry-run
@@ -6,6 +6,9 @@ on:
6
6
  - "v*"
7
7
 
8
8
  jobs:
9
+ # ci is a whole-workflow reusable call — a caller cannot `needs` individual
10
+ # jobs inside it, so the flaky jobs (network, e2e-llm) carry job-level
11
+ # `continue-on-error: true` in ci.yml to keep them off the release path.
9
12
  ci:
10
13
  uses: ./.github/workflows/ci.yml
11
14
  secrets: inherit
@@ -29,8 +32,9 @@ jobs:
29
32
  - name: Sync version from tag
30
33
  run: bash scripts/sync-version.sh
31
34
 
35
+ # --ignore-scripts: publishing only packs and uploads — no Python venv.
32
36
  - name: Install dependencies
33
- run: npm install
37
+ run: npm ci --ignore-scripts
34
38
 
35
39
  - name: Build and verify
36
40
  run: npm pack --dry-run
@@ -95,8 +99,9 @@ jobs:
95
99
  - name: Sync version from tag
96
100
  run: bash scripts/sync-version.sh
97
101
 
102
+ # --ignore-scripts: publishing only packs and uploads — no Python venv.
98
103
  - name: Install dependencies
99
- run: npm install
104
+ run: npm ci --ignore-scripts
100
105
 
101
106
  - name: Build compiled plugin entry (dist/index.js)
102
107
  run: npm run build:openclaw
@@ -111,6 +116,7 @@ jobs:
111
116
  fi
112
117
  done
113
118
  rm -f openclaw/scripts/sync-version.sh
119
+ cp LICENSE openclaw/LICENSE
114
120
 
115
121
  # Guard against regression of the issue behind
116
122
  # https://github.com/Weaxs/stock-analysis-plugin/issues/3 — a TS entry
@@ -124,11 +130,14 @@ jobs:
124
130
  npm pack --dry-run 2>&1 | tee pack-dry-run.txt
125
131
  grep -q "dist/index.js" pack-dry-run.txt \
126
132
  || { echo "::error::dist/index.js missing from openclaw npm tarball — build ran but files whitelist excludes dist/"; exit 1; }
133
+ grep -q "LICENSE" pack-dry-run.txt \
134
+ || { echo "::error::LICENSE missing from openclaw npm tarball"; exit 1; }
127
135
  test -f dist/index.js \
128
136
  || { echo "::error::openclaw/dist/index.js missing on disk — clawhub publish would ship no compiled entry"; exit 1; }
129
137
 
130
138
  - name: Install clawhub CLI
131
- run: npm i -g clawhub
139
+ # Pinned — an unpinned clawhub@latest broke a release before; bump deliberately.
140
+ run: npm i -g clawhub@0.23.3
132
141
 
133
142
  - name: npm publish
134
143
  working-directory: openclaw
@@ -142,10 +151,10 @@ jobs:
142
151
  CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
143
152
 
144
153
  - name: Publish to ClawHub (dry-run)
145
- run: clawhub package publish ./openclaw --dry-run
154
+ run: clawhub package publish ./openclaw --family bundle-plugin --dry-run
146
155
 
147
156
  - name: Publish to ClawHub
148
- run: clawhub package publish ./openclaw
157
+ run: clawhub package publish ./openclaw --family bundle-plugin
149
158
 
150
159
  - name: Publish unscoped variant to npm
151
160
  # Same payload under the unscoped name. Runs after ClawHub so the
@@ -174,8 +183,9 @@ jobs:
174
183
  - name: Sync version from tag
175
184
  run: bash scripts/sync-version.sh
176
185
 
186
+ # --ignore-scripts: publishing only packs and uploads — no Python venv.
177
187
  - name: Install dependencies
178
- run: npm install
188
+ run: npm ci --ignore-scripts
179
189
 
180
190
  - name: Build compiled plugin entry (dist/index.js)
181
191
  run: npm run build:dsh
@@ -190,6 +200,7 @@ jobs:
190
200
  fi
191
201
  done
192
202
  rm -f dsh/scripts/sync-version.sh
203
+ cp LICENSE dsh/LICENSE
193
204
 
194
205
  # Same regression guard as the OpenClaw job: the dsh profile loader
195
206
  # imports built JS, so dist must survive the `files` whitelist, and the
@@ -202,6 +213,8 @@ jobs:
202
213
  || { echo "::error::dist/index.js missing from dsh npm tarball — build ran but files whitelist excludes dist/"; exit 1; }
203
214
  grep -q "cordis.patch.yml" pack-dry-run.txt \
204
215
  || { echo "::error::cordis.patch.yml missing from dsh npm tarball — dsh bundle manifest would dangle"; exit 1; }
216
+ grep -q "LICENSE" pack-dry-run.txt \
217
+ || { echo "::error::LICENSE missing from dsh npm tarball"; exit 1; }
205
218
 
206
219
  - name: npm publish
207
220
  working-directory: dsh
@@ -7,13 +7,13 @@ A multi-host agent plugin for stock analysis, screening, and strategy backtestin
7
7
  The architecture is **one Python core, four thin host adapters**:
8
8
 
9
9
  - `tools/*.py` — the shared CLI tools. **This is the single source of truth** for all behavior. Every tool prints JSON to stdout.
10
- - `pi/index.ts` — Pi extension. `pi.registerTool` ×48, each spawns a `tools/*.py` CLI.
10
+ - `pi/index.ts` — Pi extension. `pi.registerTool` ×57, each spawns a `tools/*.py` CLI.
11
11
  - `hermes/` — Hermes plugin (`plugin.yaml` + `register(ctx)` in `__init__.py`; `tools.py` handlers → subprocess to the same CLIs). Discovered via the `hermes_agent.plugins` entry point.
12
- - `openclaw/` — OpenClaw plugin (`openclaw.plugin.json` manifest + `index.ts` `definePluginEntry` + `registerTool` ×48). Bundled with esbuild.
13
- - `dsh/` — dsh bundle (`package.json` `dsh.bundle` + `cordis.patch.yml` + `index.ts` cordis `apply(ctx)` with `defineTool` ×48 via `@deepseek-ai/dsh-tools`; skills via `ctx.skills.register`). Bundled with esbuild, `@deepseek-ai/*` external (peer deps).
12
+ - `openclaw/` — OpenClaw plugin (`openclaw.plugin.json` manifest + `index.ts` `definePluginEntry` + `registerTool` ×57). Bundled with esbuild.
13
+ - `dsh/` — dsh bundle (`package.json` `dsh.bundle` + `cordis.patch.yml` + `index.ts` cordis `apply(ctx)` with `defineTool` ×57 via `@deepseek-ai/dsh-tools`; skills via `ctx.skills.register`). Bundled with esbuild, `@deepseek-ai/*` external (peer deps).
14
14
  - `skills/*/SKILL.md` — 20 workflow / strategy-methodology skills shared by all four hosts.
15
15
 
16
- > **The invariant that matters most:** the four adapters expose the *same* 48 tools over the *same* Python CLIs. A change to a tool's name, parameters, or JSON output shape must be applied to **all four adapters and the relevant SKILL.md together** — never just one.
16
+ > **The invariant that matters most:** the four adapters expose the *same* 57 tools over the *same* Python CLIs. A change to a tool's name, parameters, or JSON output shape must be applied to **all four adapters and the relevant SKILL.md together** — never just one.
17
17
 
18
18
  ---
19
19
 
@@ -132,7 +132,7 @@ This is the #1 regression surface (issues #2 / #7; the `compat` CI job exists sp
132
132
  - **Output is JSON on stdout, always.** Host adapters parse `result.stdout`. Human-readable prose goes to stderr, never stdout.
133
133
  - **Errors are data**: print a JSON object with an `error` key (and exit non-zero) rather than an uncaught traceback, so adapters can surface a clean message.
134
134
  - **argparse CLI per script**, subcommands per capability (`stock_data.py kline|quote|news|...`). See the README "独立 CLI 使用" section for the established shape.
135
- - **Keep `tools/` py3.9-compatible** (`ruff.toml` targets `py39`; OpenClaw hosts only guarantee Python ≥ 3.9) even though the Hermes wheel declares `requires-python >= 3.10`. No 3.10+-only syntax in `tools/`.
135
+ - **Keep `tools/` py3.10-compatible** (`ruff.toml` targets `py310`; the Python floor is 3.10 everywhere — Hermes wheel `requires-python >= 3.10`, OpenClaw hosts). PEP 604 annotations (`X | None`) and other 3.10 syntax are allowed; nothing 3.11+-only.
136
136
  - **Line length 120**, ruff rules `E,F,W,I,UP,B,SIM` (E501 ignored).
137
137
  - Adding a runtime dependency means adding it to `tools/requirements.txt` (the postinstall-built `.venv`) **and** considering the Hermes wheel's `dependencies` in `pyproject.toml`. Follow ponytail rung 5 — don't add a dependency for a one-call problem.
138
138
 
@@ -222,7 +222,7 @@ Versions live in **five** manifests that must stay in lockstep: `pyproject.toml`
222
222
 
223
223
  ## Adding a New Tool
224
224
 
225
- 1. Implement the CLI in the appropriate `tools/*.py` (argparse subcommand, JSON stdout, py3.9-compatible).
225
+ 1. Implement the CLI in the appropriate `tools/*.py` (argparse subcommand, JSON stdout, py3.10-compatible).
226
226
  2. Add a failing pytest first (`tests/test_<module>.py`), then make it pass (see `tdd`).
227
227
  3. Register it in all four adapters: `pi/index.ts`, `openclaw/index.ts`, `dsh/index.ts`, `hermes/tools.py` + `hermes/schemas.py` — same name, same params.
228
228
  4. Wire it into the relevant `skills/*/SKILL.md` workflow if an agent should call it.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Weaxs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.