toolang 0.2.0__tar.gz → 0.2.2__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 (204) hide show
  1. {toolang-0.2.0 → toolang-0.2.2}/PKG-INFO +1 -1
  2. {toolang-0.2.0 → toolang-0.2.2}/pyproject.toml +4 -4
  3. toolang-0.2.2/src/toolang/cli/__main__.py +8 -0
  4. toolang-0.2.2/src/toolang/cli/caps/__init__.py +5 -0
  5. toolang-0.2.2/src/toolang/cli/caps/__main__.py +8 -0
  6. toolang-0.2.0/src/toolang/cli/caps_main.py → toolang-0.2.2/src/toolang/cli/caps/app.py +3 -3
  7. toolang-0.2.0/src/toolang/cli/caps.py → toolang-0.2.2/src/toolang/cli/caps/commands.py +14 -14
  8. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/cli/progress.py +7 -0
  9. toolang-0.2.2/src/toolang/cli/toolang/__init__.py +0 -0
  10. toolang-0.2.2/src/toolang/cli/toolang/__main__.py +8 -0
  11. toolang-0.2.0/src/toolang/cli/main.py → toolang-0.2.2/src/toolang/cli/toolang/app.py +83 -55
  12. toolang-0.2.2/src/toolang/cli/toolang/caps.py +13 -0
  13. toolang-0.2.2/src/toolang/cli/toolang/fmt.py +129 -0
  14. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/cli/utils.py +26 -17
  15. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/config/log.py +21 -4
  16. toolang-0.2.2/src/toolang/program_format.py +851 -0
  17. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/up.py +11 -1
  18. {toolang-0.2.0 → toolang-0.2.2}/tests/test_cli.py +243 -12
  19. {toolang-0.2.0 → toolang-0.2.2}/tests/test_log_config.py +36 -0
  20. toolang-0.2.2/tests/test_program_format.py +359 -0
  21. {toolang-0.2.0 → toolang-0.2.2}/tests/test_run_queue_runner.py +46 -0
  22. {toolang-0.2.0 → toolang-0.2.2}/uv.lock +1 -1
  23. {toolang-0.2.0 → toolang-0.2.2}/.github/workflows/publish-pypi.yml +0 -0
  24. {toolang-0.2.0 → toolang-0.2.2}/.gitignore +0 -0
  25. {toolang-0.2.0 → toolang-0.2.2}/AGENTS.md +0 -0
  26. {toolang-0.2.0 → toolang-0.2.2}/LICENSE +0 -0
  27. {toolang-0.2.0 → toolang-0.2.2}/README.md +0 -0
  28. {toolang-0.2.0 → toolang-0.2.2}/docs/api.md +0 -0
  29. {toolang-0.2.0 → toolang-0.2.2}/docs/caps.md +0 -0
  30. {toolang-0.2.0 → toolang-0.2.2}/docs/chat.md +0 -0
  31. {toolang-0.2.0 → toolang-0.2.2}/docs/concepts.md +0 -0
  32. {toolang-0.2.0 → toolang-0.2.2}/docs/execution.md +0 -0
  33. {toolang-0.2.0 → toolang-0.2.2}/docs/ids.md +0 -0
  34. {toolang-0.2.0 → toolang-0.2.2}/docs/index.md +0 -0
  35. {toolang-0.2.0 → toolang-0.2.2}/docs/layout.md +0 -0
  36. {toolang-0.2.0 → toolang-0.2.2}/docs/models.md +0 -0
  37. {toolang-0.2.0 → toolang-0.2.2}/docs/plugins.md +0 -0
  38. {toolang-0.2.0 → toolang-0.2.2}/docs/prepared-lock.md +0 -0
  39. {toolang-0.2.0 → toolang-0.2.2}/docs/program.md +0 -0
  40. {toolang-0.2.0 → toolang-0.2.2}/docs/selectors.md +0 -0
  41. {toolang-0.2.0 → toolang-0.2.2}/docs/tasks.md +0 -0
  42. {toolang-0.2.0 → toolang-0.2.2}/docs/tools.md +0 -0
  43. {toolang-0.2.0 → toolang-0.2.2}/docs/webui-jobs.md +0 -0
  44. {toolang-0.2.0 → toolang-0.2.2}/examples/alice.too +0 -0
  45. {toolang-0.2.0 → toolang-0.2.2}/examples/invoke-playground.too +0 -0
  46. {toolang-0.2.0 → toolang-0.2.2}/examples/invoke.fixed-model.too +0 -0
  47. {toolang-0.2.0 → toolang-0.2.2}/examples/invoke.openrouter-smoke.too +0 -0
  48. {toolang-0.2.0 → toolang-0.2.2}/examples/invoke.priority.too +0 -0
  49. {toolang-0.2.0 → toolang-0.2.2}/examples/invoke.simulated-history.memory.too +0 -0
  50. {toolang-0.2.0 → toolang-0.2.2}/examples/invoke.simulated-history.none.too +0 -0
  51. {toolang-0.2.0 → toolang-0.2.2}/reference/README.md +0 -0
  52. {toolang-0.2.0 → toolang-0.2.2}/reference/build.py +0 -0
  53. {toolang-0.2.0 → toolang-0.2.2}/reference/config.toml +0 -0
  54. {toolang-0.2.0 → toolang-0.2.2}/reference/templates/index.html.jinja2 +0 -0
  55. {toolang-0.2.0 → toolang-0.2.2}/reference/templates/module.html.jinja2 +0 -0
  56. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/__init__.py +0 -0
  57. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/agents.py +0 -0
  58. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/__init__.py +0 -0
  59. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/error.py +0 -0
  60. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/examples/__init__.py +0 -0
  61. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/examples/tools.py +0 -0
  62. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/protocols/__init__.py +0 -0
  63. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/protocols/channel.py +0 -0
  64. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/protocols/loop.py +0 -0
  65. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/protocols/model.py +0 -0
  66. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/protocols/sandbox.py +0 -0
  67. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/protocols/tool.py +0 -0
  68. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/types/__init__.py +0 -0
  69. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/types/channel.py +0 -0
  70. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/types/message.py +0 -0
  71. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/types/model.py +0 -0
  72. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/types/run.py +0 -0
  73. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/types/sandbox.py +0 -0
  74. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/types/tool.py +0 -0
  75. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/utils/__init__.py +0 -0
  76. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/utils/channels.py +0 -0
  77. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/utils/function_tools.py +0 -0
  78. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/utils/tools.py +0 -0
  79. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/base/utils/typer_tools.py +0 -0
  80. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/caps.py +0 -0
  81. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/channels/__init__.py +0 -0
  82. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/channels/telegram.py +0 -0
  83. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/cli/__init__.py +0 -0
  84. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/cli/invoke.py +0 -0
  85. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/cli/logo.py +0 -0
  86. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/common/__init__.py +0 -0
  87. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/common/ids.py +0 -0
  88. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/common/progress.py +0 -0
  89. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/common/template.py +0 -0
  90. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/__init__.py +0 -0
  91. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/registry.py +0 -0
  92. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/__init__.py +0 -0
  93. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/_streaming.py +0 -0
  94. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/chat.py +0 -0
  95. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/inspect/__init__.py +0 -0
  96. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/inspect/_shared.py +0 -0
  97. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/inspect/agent.py +0 -0
  98. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/inspect/caps.py +0 -0
  99. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/inspect/execution.py +0 -0
  100. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/inspect/jobs.py +0 -0
  101. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/inspect/router.py +0 -0
  102. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/manage/__init__.py +0 -0
  103. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/manage/caps.py +0 -0
  104. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/manage/jobs.py +0 -0
  105. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/router/manage/router.py +0 -0
  106. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/runner/__init__.py +0 -0
  107. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/trigger/__init__.py +0 -0
  108. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/trigger/poll.py +0 -0
  109. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/trigger/pulse.py +0 -0
  110. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/components/trigger/watch.py +0 -0
  111. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/config/__init__.py +0 -0
  112. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/config/env.py +0 -0
  113. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/config/log_spec.py +0 -0
  114. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/config/plugins.py +0 -0
  115. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/config/web.py +0 -0
  116. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/__init__.py +0 -0
  117. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/assembly.py +0 -0
  118. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/binding.py +0 -0
  119. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/context.py +0 -0
  120. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/db.py +0 -0
  121. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/detail.py +0 -0
  122. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/effective.py +0 -0
  123. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/events.py +0 -0
  124. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/execute.py +0 -0
  125. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/input.py +0 -0
  126. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/model.py +0 -0
  127. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/model_call.py +0 -0
  128. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/prompts/__init__.py +0 -0
  129. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/prompts/context.default.md +0 -0
  130. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/prompts/instruct.default.md +0 -0
  131. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/records.py +0 -0
  132. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/response.py +0 -0
  133. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/runner.py +0 -0
  134. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/execution/stream.py +0 -0
  135. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/loops/__init__.py +0 -0
  136. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/loops/basic.py +0 -0
  137. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/__init__.py +0 -0
  138. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/adapters/__init__.py +0 -0
  139. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/adapters/chat_completions.py +0 -0
  140. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/adapters/responses.py +0 -0
  141. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/config.py +0 -0
  142. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/discovery.py +0 -0
  143. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/errors.py +0 -0
  144. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/providers/__init__.py +0 -0
  145. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/providers/custom.py +0 -0
  146. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/providers/deepseek.py +0 -0
  147. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/providers/google.py +0 -0
  148. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/providers/ollama.py +0 -0
  149. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/providers/openai.py +0 -0
  150. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/providers/openrouter.py +0 -0
  151. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/resolution.py +0 -0
  152. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/models/views.py +0 -0
  153. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/plugin.py +0 -0
  154. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/program.py +0 -0
  155. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/sandboxes/__init__.py +0 -0
  156. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/sandboxes/docker.py +0 -0
  157. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/sandboxes/none.py +0 -0
  158. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/selectors.py +0 -0
  159. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/state/__init__.py +0 -0
  160. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/state/durable.py +0 -0
  161. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/state/live.py +0 -0
  162. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/state/prepared.py +0 -0
  163. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/state/program.py +0 -0
  164. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/state/pulse.py +0 -0
  165. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/__init__.py +0 -0
  166. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/agent.default.too +0 -0
  167. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/chore.default.md +0 -0
  168. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/prompt.default.md +0 -0
  169. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/psyche.default.md +0 -0
  170. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/service.default.md +0 -0
  171. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/service.stdio.md +0 -0
  172. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/skill.default.md +0 -0
  173. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/templates/task.default.md +0 -0
  174. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/__init__.py +0 -0
  175. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/agent_chat.py +0 -0
  176. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/agent_state.py +0 -0
  177. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/filesystem.py +0 -0
  178. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/registry.py +0 -0
  179. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/service_use.py +0 -0
  180. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/shell.py +0 -0
  181. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/views.py +0 -0
  182. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/tools/web_search.py +0 -0
  183. {toolang-0.2.0 → toolang-0.2.2}/src/toolang/work.py +0 -0
  184. {toolang-0.2.0 → toolang-0.2.2}/syntax.too +0 -0
  185. {toolang-0.2.0 → toolang-0.2.2}/tests/fixtures/remote-prompt/rewrite.md +0 -0
  186. {toolang-0.2.0 → toolang-0.2.2}/tests/fixtures/remote-psyche/reviewer.md +0 -0
  187. {toolang-0.2.0 → toolang-0.2.2}/tests/fixtures/remote-service/github.md +0 -0
  188. {toolang-0.2.0 → toolang-0.2.2}/tests/fixtures/remote-skill/pdf-processing/SKILL.md +0 -0
  189. {toolang-0.2.0 → toolang-0.2.2}/tests/fixtures/remote-skill/pdf-processing/assets/template.md +0 -0
  190. {toolang-0.2.0 → toolang-0.2.2}/tests/fixtures/sample.too +0 -0
  191. {toolang-0.2.0 → toolang-0.2.2}/tests/fixtures/source_only.too +0 -0
  192. {toolang-0.2.0 → toolang-0.2.2}/tests/test_agent_state_tool.py +0 -0
  193. {toolang-0.2.0 → toolang-0.2.2}/tests/test_channels.py +0 -0
  194. {toolang-0.2.0 → toolang-0.2.2}/tests/test_execution_template.py +0 -0
  195. {toolang-0.2.0 → toolang-0.2.2}/tests/test_ids.py +0 -0
  196. {toolang-0.2.0 → toolang-0.2.2}/tests/test_models.py +0 -0
  197. {toolang-0.2.0 → toolang-0.2.2}/tests/test_plugin_tools.py +0 -0
  198. {toolang-0.2.0 → toolang-0.2.2}/tests/test_prepared.py +0 -0
  199. {toolang-0.2.0 → toolang-0.2.2}/tests/test_program.py +0 -0
  200. {toolang-0.2.0 → toolang-0.2.2}/tests/test_sandboxes.py +0 -0
  201. {toolang-0.2.0 → toolang-0.2.2}/tests/test_selectors.py +0 -0
  202. {toolang-0.2.0 → toolang-0.2.2}/tests/test_tools.py +0 -0
  203. {toolang-0.2.0 → toolang-0.2.2}/tests/test_typer_tools.py +0 -0
  204. {toolang-0.2.0 → toolang-0.2.2}/tests/test_work.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: toolang
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A programming language and runtime for agents
5
5
  Project-URL: Homepage, https://toolang.ai/
6
6
  Project-URL: Documentation, https://toolang.ai/docs
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "toolang"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "A programming language and runtime for agents"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -54,9 +54,9 @@ Repository = "https://github.com/openhat-ai/toolang"
54
54
  Issues = "https://github.com/openhat-ai/toolang/issues"
55
55
 
56
56
  [project.scripts]
57
- toolang = "toolang.cli.main:main"
58
- too = "toolang.cli.main:main"
59
- caps = "toolang.cli.caps_main:main"
57
+ toolang = "toolang.cli.toolang.app:main"
58
+ too = "toolang.cli.toolang.app:main"
59
+ caps = "toolang.cli.caps.app:main"
60
60
 
61
61
  [project.entry-points."toolang.tool"]
62
62
  agent_chat = "toolang.tools.agent_chat:create_tool_set"
@@ -0,0 +1,8 @@
1
+ """Run the default Toolang CLI package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .toolang.app import main
6
+
7
+
8
+ raise SystemExit(main())
@@ -0,0 +1,5 @@
1
+ """Caps CLI command package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .commands import * # noqa: F403
@@ -0,0 +1,8 @@
1
+ """Run the standalone caps CLI package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .app import main
6
+
7
+
8
+ raise SystemExit(main())
@@ -14,9 +14,9 @@ from typing import Annotated
14
14
  import click
15
15
  import typer
16
16
 
17
- from ..config.log import configure_logging
18
- from .caps import CAP_KINDS, register_standalone_caps_commands
19
- from .utils import _OptionalPrefixAgentGroup, _toolang_root
17
+ from ...config.log import configure_logging
18
+ from .commands import CAP_KINDS, register_standalone_caps_commands
19
+ from ..utils import _OptionalPrefixAgentGroup, _toolang_root
20
20
 
21
21
  _CLI_PREFIX_AGENT: str | None = None
22
22
  CAP_TOP_LEVEL_COMMANDS = frozenset({"list", *CAP_KINDS})
@@ -12,8 +12,8 @@ import click
12
12
  import typer
13
13
  from typer.core import TyperGroup
14
14
 
15
- from ..base.error import ToolangError
16
- from .utils import (
15
+ from ...base.error import ToolangError
16
+ from ..utils import (
17
17
  _OptionalPrefixAgentCommand,
18
18
  _OptionalPrefixAgentGroup,
19
19
  _OptionalPrefixAgentListCommand,
@@ -27,12 +27,12 @@ from .utils import (
27
27
  )
28
28
 
29
29
  if TYPE_CHECKING:
30
- from .. import caps as cap_store
31
- from .. import templates
32
- from ..execution.records import UpdateKind
33
- from ..components.trigger import watch as watch_feature
34
- from ..state.prepared import PreparedEntry, PreparedState
35
- from .progress import CliProgress
30
+ from ... import caps as cap_store
31
+ from ... import templates
32
+ from ...execution.records import UpdateKind
33
+ from ...components.trigger import watch as watch_feature
34
+ from ...state.prepared import PreparedEntry, PreparedState
35
+ from ..progress import CliProgress
36
36
 
37
37
  CapKind = Literal["skill", "psyche", "prompt", "service"]
38
38
  EntryKind = Literal["psyche", "skill", "service", "prompt", "task", "chore"]
@@ -462,7 +462,7 @@ def _make_add_cap_command(kind: CapKind, title: str) -> Callable[..., None]:
462
462
  ctx: typer.Context,
463
463
  ref: str = typer.Argument(..., help=f"{title} ref"),
464
464
  ) -> None:
465
- from .progress import as_progress_sink
465
+ from ..progress import as_progress_sink
466
466
 
467
467
  visibility, agent_name = _target_visibility(ctx)
468
468
  selected_agent = _context_agent(ctx)
@@ -691,11 +691,11 @@ def _all_cap_entries(
691
691
  prepare: bool,
692
692
  kinds: set[EntryKind],
693
693
  ) -> tuple[PreparedEntry, ...]:
694
- from ..state.durable import scan_durable_state
694
+ from ...state.durable import scan_durable_state
695
695
 
696
696
  durable = _wrap_user_error(scan_durable_state, toolang_root, agent_name)
697
697
  if prepare and durable.program_source is not None:
698
- from .progress import as_progress_sink, make_cli_progress
698
+ from ..progress import as_progress_sink, make_cli_progress
699
699
 
700
700
  progress = make_cli_progress(
701
701
  prepare_summary_label="Resolved",
@@ -810,7 +810,7 @@ def _append_cap_update(
810
810
 
811
811
 
812
812
  def _make_cap_write_progress() -> CliProgress:
813
- from .progress import make_cli_progress
813
+ from ..progress import make_cli_progress
814
814
 
815
815
  return make_cli_progress(
816
816
  prepare_summary_label="Resolved",
@@ -828,8 +828,8 @@ def _refresh_and_append_cap_update(
828
828
  progress_total: int,
829
829
  progress: CliProgress | None = None,
830
830
  ) -> None:
831
- from ..state.durable import scan_durable_state
832
- from .progress import as_progress_sink
831
+ from ...state.durable import scan_durable_state
832
+ from ..progress import as_progress_sink
833
833
 
834
834
  durable = _wrap_user_error(scan_durable_state, toolang_root, agent_name)
835
835
  _wrap_user_error(
@@ -83,6 +83,7 @@ class CliProgress:
83
83
  for line in self._lines():
84
84
  print(line, file=self._stream)
85
85
  self._print_summary()
86
+ self._reset_terminal_style()
86
87
 
87
88
  def interrupt(self) -> None:
88
89
  with self._lock:
@@ -290,6 +291,12 @@ class CliProgress:
290
291
  for summary in summaries:
291
292
  self._console.print(Text(summary, style="dim"))
292
293
 
294
+ def _reset_terminal_style(self) -> None:
295
+ if not self._console.is_terminal:
296
+ return
297
+ self._stream.write("\x1b[0m")
298
+ self._stream.flush()
299
+
293
300
  def _live_text(self) -> Text:
294
301
  text = Text()
295
302
  agent_items = [item for item in self._items.values() if item.kind == "agent"]
File without changes
@@ -0,0 +1,8 @@
1
+ """Run the main Toolang CLI package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .app import main
6
+
7
+
8
+ raise SystemExit(main())
@@ -19,10 +19,9 @@ import click
19
19
  import typer
20
20
  from typer.core import TyperCommand, TyperGroup
21
21
 
22
- from .. import agents
23
- from ..config.log import LoggingPlan, configure_logging, configure_logging_plan, resolve_agent_logging
24
- from .caps import CAP_KINDS, register_toolang_caps_commands
25
- from .utils import (
22
+ from ... import agents
23
+ from ...config.log import LoggingPlan, configure_logging, configure_logging_plan, resolve_agent_logging
24
+ from ..utils import (
26
25
  _PrefixAgentWorkGroup,
27
26
  _RequiredPrefixAgentCommand,
28
27
  _RunAgentCommand,
@@ -39,22 +38,23 @@ from .utils import (
39
38
  _required_prefix_agent,
40
39
  _required_runtime_agent,
41
40
  _runtime_environ_for_agent,
42
- _runtime_components,
43
41
  _runtime_value,
44
42
  _toolang_root,
45
43
  _ui_base_url,
46
44
  _wait_for_started_status,
47
45
  _wrap_user_error,
48
46
  )
47
+ from .caps import CAP_KINDS, register_caps_commands
48
+ from .fmt import register_fmt_command
49
49
 
50
50
  if TYPE_CHECKING:
51
- from .. import caps as cap_store
52
- from .. import templates
53
- from .. import up as agent_up
54
- from ..execution.records import UpdateKind
55
- from ..state.prepared import PreparedLock, PreparedState
56
- from . import invoke as cli_invoke
57
- from .progress import CliProgress
51
+ from ... import caps as cap_store
52
+ from ... import templates
53
+ from ... import up as agent_up
54
+ from ...execution.records import UpdateKind
55
+ from ...state.prepared import PreparedLock, PreparedState
56
+ from .. import invoke as cli_invoke
57
+ from ..progress import CliProgress
58
58
 
59
59
 
60
60
  class _LazyModule:
@@ -105,6 +105,7 @@ TOP_LEVEL_COMMANDS = frozenset(
105
105
  "remove",
106
106
  "list",
107
107
  "info",
108
+ "fmt",
108
109
  "model",
109
110
  "tool",
110
111
  "channel",
@@ -399,6 +400,7 @@ def info_agent(
399
400
  ("Home", str(agents.agent_home(root, agent_name))),
400
401
  ("Caps", _info_caps_summary(root, agent_name)),
401
402
  ("Jobs", _info_jobs_summary(root, agent_name)),
403
+ ("Tools", _info_tools_summary(root, agent_name)),
402
404
  ("Models", _info_models_summary(root, agent_name, runtime_state=runtime_state, running=status.status != "stopped")),
403
405
  ("Status", status_value),
404
406
  ]
@@ -408,16 +410,12 @@ def info_agent(
408
410
  return
409
411
  if status.sandbox:
410
412
  rows.append(("Sandbox", status.sandbox))
411
- if status.status == "running":
412
- loops_text = _runtime_components(runtime_state)
413
- if loops_text is not None:
414
- rows.append(("Components", loops_text))
415
413
  message = _runtime_value(runtime_state.get("message"))
416
414
  pid_text = agents.runtime_pid_label(runtime_state)
417
415
  if pid_text is not None and status.status != "stopped":
418
416
  rows.append(("PID", pid_text))
419
- if status.api_url:
420
- rows.append(("API", status.api_url))
417
+ if status.endpoint:
418
+ rows.append(("API", status.endpoint))
421
419
  if status.webui_url:
422
420
  rows.append(("WebUI", status.webui_url))
423
421
  if status.status == "running" and started_at != "-":
@@ -491,7 +489,7 @@ def run_agent(
491
489
  typer.Option("--sandbox-child", hidden=True),
492
490
  ] = False,
493
491
  ) -> None:
494
- from .progress import as_progress_sink, make_cli_progress
492
+ from ..progress import as_progress_sink, make_cli_progress
495
493
 
496
494
  selector = _required_runtime_agent(ctx, agent)
497
495
  normalized_components = _normalize_component_option(components)
@@ -563,7 +561,7 @@ def _resolve_runtime_startup(
563
561
  background: bool,
564
562
  progress: CliProgress | None,
565
563
  ) -> _RuntimeStartup:
566
- from .progress import as_progress_sink
564
+ from ..progress import as_progress_sink
567
565
 
568
566
  run_root = target.toolang_root
569
567
  agent_name = target.agent_name
@@ -666,7 +664,7 @@ def start_agent(
666
664
  typer.Option("--endpoint-host", help="Endpoint host name.", hidden=True),
667
665
  ] = None,
668
666
  ) -> None:
669
- from .progress import as_progress_sink, make_cli_progress
667
+ from ..progress import as_progress_sink, make_cli_progress
670
668
 
671
669
  selector = _required_runtime_agent(ctx, agent)
672
670
  parsed_selector = _wrap_user_error(agents.parse_agent_selector, selector)
@@ -709,7 +707,7 @@ def start_agent(
709
707
  command = [
710
708
  sys.executable,
711
709
  "-m",
712
- "toolang.cli.main",
710
+ "toolang.cli.toolang",
713
711
  *agent_up.build_run_argv(launch.startup),
714
712
  ]
715
713
  with log_path.open("ab") as stream:
@@ -801,7 +799,7 @@ def _info_caps_summary(toolang_root: Path, agent_name: str) -> str:
801
799
 
802
800
 
803
801
  def _prepared_info_cap_counts(toolang_root: Path, agent_name: str) -> dict[str, int] | None:
804
- from ..state.prepared import load_private_lock, load_shared_lock
802
+ from ...state.prepared import load_private_lock, load_shared_lock
805
803
 
806
804
  try:
807
805
  shared_lock = load_shared_lock(toolang_root)
@@ -834,7 +832,7 @@ def _prepared_lock_info_cap_counts(
834
832
 
835
833
 
836
834
  def _prepare_info_cap_counts(toolang_root: Path, agent_name: str) -> dict[str, int]:
837
- from .progress import as_progress_sink, make_cli_progress
835
+ from ..progress import as_progress_sink, make_cli_progress
838
836
 
839
837
  progress = make_cli_progress(show_materialize_summary=True)
840
838
  try:
@@ -853,7 +851,7 @@ def _prepare_info_cap_counts(toolang_root: Path, agent_name: str) -> dict[str, i
853
851
 
854
852
 
855
853
  def _info_jobs_summary(toolang_root: Path, agent_name: str) -> str:
856
- from .. import work
854
+ from ... import work
857
855
 
858
856
  chore_count = len(work.list_chores(toolang_root, agent_name))
859
857
  task_count = len(work.list_tasks(toolang_root, agent_name))
@@ -873,19 +871,46 @@ def _info_models_summary(
873
871
  if running:
874
872
  raw_models = runtime_state.get("models")
875
873
  if isinstance(raw_models, list):
876
- runtime_models = tuple(
874
+ selectors = tuple(
877
875
  str(item).strip()
878
876
  for item in raw_models
879
877
  if isinstance(item, str) and item.strip()
880
878
  )
881
- if runtime_models:
882
- return ", ".join(runtime_models)
883
- configured = agent_up.load_default_models(toolang_root, agent_name)
884
- if configured:
885
- return ", ".join(configured)
886
- from ..models.resolution import DEFAULT_MODEL_SELECTOR
879
+ if selectors:
880
+ return _model_count_summary(
881
+ toolang_root,
882
+ agent_name,
883
+ environ=dict(os.environ),
884
+ selectors=selectors,
885
+ )
886
+ selectors = agent_up.load_default_models(toolang_root, agent_name)
887
+ return _model_count_summary(
888
+ toolang_root,
889
+ agent_name,
890
+ environ=dict(os.environ),
891
+ selectors=selectors,
892
+ )
893
+
887
894
 
888
- return DEFAULT_MODEL_SELECTOR
895
+ def _info_tools_summary(toolang_root: Path, agent_name: str) -> str:
896
+ rows = _tool_rows(toolang_root, dict(os.environ), agent_name=agent_name)
897
+ set_count = len({namespace for namespace, _tool, _description in rows})
898
+ return f"{len(rows)} {'tool' if len(rows) == 1 else 'tools'}, {set_count} {'set' if set_count == 1 else 'sets'}"
899
+
900
+
901
+ def _model_count_summary(
902
+ toolang_root: Path,
903
+ agent_name: str,
904
+ *,
905
+ environ: dict[str, str],
906
+ selectors: Sequence[str] = (),
907
+ ) -> str:
908
+ rows = _model_rows(toolang_root, environ, agent_name=agent_name, model_selectors=selectors)
909
+ provider_count = len({provider for _model, provider, _details in rows})
910
+ return (
911
+ f"{len(rows)} {'model' if len(rows) == 1 else 'models'}, "
912
+ f"{provider_count} {'provider' if provider_count == 1 else 'providers'}"
913
+ )
889
914
 
890
915
 
891
916
  model_app = typer.Typer(
@@ -936,8 +961,8 @@ def list_models(
936
961
  ),
937
962
  ] = None,
938
963
  ) -> None:
939
- from ..models.errors import NO_AVAILABLE_MODELS_MESSAGE
940
- from ..models.resolution import split_model_selectors
964
+ from ...models.errors import NO_AVAILABLE_MODELS_MESSAGE
965
+ from ...models.resolution import split_model_selectors
941
966
 
942
967
  environ = dict(os.environ)
943
968
  root = _toolang_root(None)
@@ -970,7 +995,7 @@ def list_model_providers() -> None:
970
995
 
971
996
  @model_app.command("adapters", help="List available model API adapters.")
972
997
  def list_model_adapters() -> None:
973
- from ..models.views import available_model_adapters
998
+ from ...models.views import available_model_adapters
974
999
 
975
1000
  rows = [(name,) for name in available_model_adapters()]
976
1001
  _echo_table(("ADAPTER",), rows)
@@ -988,7 +1013,7 @@ def list_tools(
988
1013
  ),
989
1014
  ] = None,
990
1015
  ) -> None:
991
- from ..tools.registry import split_tool_selectors
1016
+ from ...tools.registry import split_tool_selectors
992
1017
 
993
1018
  environ = dict(os.environ)
994
1019
  root = _toolang_root(None)
@@ -1030,13 +1055,14 @@ def _model_rows(
1030
1055
  root: Path,
1031
1056
  environ: dict[str, str],
1032
1057
  *,
1058
+ agent_name: str = "",
1033
1059
  model_selectors: Sequence[str] = (),
1034
1060
  ) -> list[tuple[str, str, str]]:
1035
- from ..models.config import load_model_aliases
1036
- from ..models.views import model_list_rows
1061
+ from ...models.config import load_model_aliases
1062
+ from ...models.views import model_list_rows
1037
1063
 
1038
- providers = agent_up.load_model_providers(root, "")
1039
- aliases = load_model_aliases(root, "")
1064
+ providers = agent_up.load_model_providers(root, agent_name)
1065
+ aliases = load_model_aliases(root, agent_name)
1040
1066
  return model_list_rows(
1041
1067
  providers=providers,
1042
1068
  aliases=aliases,
@@ -1046,8 +1072,8 @@ def _model_rows(
1046
1072
 
1047
1073
 
1048
1074
  def _model_provider_rows(root: Path, environ: dict[str, str]) -> list[tuple[str, str, str]]:
1049
- from ..models.config import load_model_aliases, load_model_provider_configs
1050
- from ..models.views import model_provider_rows
1075
+ from ...models.config import load_model_aliases, load_model_provider_configs
1076
+ from ...models.views import model_provider_rows
1051
1077
 
1052
1078
  provider_configs = load_model_provider_configs(root, "")
1053
1079
  providers = agent_up.load_model_providers(root, "")
@@ -1064,12 +1090,13 @@ def _tool_rows(
1064
1090
  root: Path,
1065
1091
  environ: dict[str, str],
1066
1092
  *,
1093
+ agent_name: str = "",
1067
1094
  tool_selectors: Sequence[str] = (),
1068
1095
  ) -> list[tuple[str, str, str]]:
1069
- from ..config.plugins import load_tool_plugin_config
1070
- from ..tools.views import tool_list_rows
1096
+ from ...config.plugins import load_tool_plugin_config
1097
+ from ...tools.views import tool_list_rows
1071
1098
 
1072
- config = load_tool_plugin_config(root, "", environ=environ)
1099
+ config = load_tool_plugin_config(root, agent_name, environ=environ)
1073
1100
  tools = agent_up.load_tool_plugins(config=config)
1074
1101
  sources = _plugin_source_by_name("toolang.tool")
1075
1102
  return tool_list_rows(
@@ -1209,7 +1236,7 @@ def _make_work_list_command(kind: WorkKind, title: str) -> Callable[..., None]:
1209
1236
  typer.Option("--all", help="Include archived items."),
1210
1237
  ] = False,
1211
1238
  ) -> None:
1212
- from .. import work
1239
+ from ... import work
1213
1240
 
1214
1241
  agent_name = _required_prefix_agent(ctx, command_name=kind)
1215
1242
  root = _context_root(ctx)
@@ -1253,7 +1280,7 @@ def _make_new_work_command(kind: WorkKind, title: str) -> Callable[..., None]:
1253
1280
  def new_work(
1254
1281
  ctx: typer.Context,
1255
1282
  ) -> None:
1256
- from .. import work
1283
+ from ... import work
1257
1284
 
1258
1285
  agent_name = _required_prefix_agent(ctx, command_name=kind)
1259
1286
  text = click.edit(
@@ -1281,7 +1308,7 @@ def _make_edit_work_command(kind: WorkKind, title: str) -> Callable[..., None]:
1281
1308
  ctx: typer.Context,
1282
1309
  id: str = typer.Argument(..., help=f"{title} id", metavar="ID"),
1283
1310
  ) -> None:
1284
- from .. import work
1311
+ from ... import work
1285
1312
 
1286
1313
  job_id = id
1287
1314
  agent_name = _required_prefix_agent(ctx, command_name=kind)
@@ -1316,7 +1343,7 @@ def _make_pause_work_command(kind: WorkKind, title: str) -> Callable[..., None]:
1316
1343
  ctx: typer.Context,
1317
1344
  id: str = typer.Argument(..., help=f"{title} id", metavar="ID"),
1318
1345
  ) -> None:
1319
- from .. import work
1346
+ from ... import work
1320
1347
 
1321
1348
  job_id = id
1322
1349
  agent_name = _required_prefix_agent(ctx, command_name=kind)
@@ -1339,7 +1366,7 @@ def _make_resume_work_command(kind: WorkKind, title: str) -> Callable[..., None]
1339
1366
  ctx: typer.Context,
1340
1367
  id: str = typer.Argument(..., help=f"{title} id", metavar="ID"),
1341
1368
  ) -> None:
1342
- from .. import work
1369
+ from ... import work
1343
1370
 
1344
1371
  job_id = id
1345
1372
  agent_name = _required_prefix_agent(ctx, command_name=kind)
@@ -1362,7 +1389,7 @@ def _make_archive_work_command(kind: WorkKind, title: str) -> Callable[..., None
1362
1389
  ctx: typer.Context,
1363
1390
  id: str = typer.Argument(..., help=f"{title} id", metavar="ID"),
1364
1391
  ) -> None:
1365
- from .. import work
1392
+ from ... import work
1366
1393
 
1367
1394
  job_id = id
1368
1395
  agent_name = _required_prefix_agent(ctx, command_name=kind)
@@ -1389,7 +1416,7 @@ def _make_restore_work_command(kind: WorkKind, title: str) -> Callable[..., None
1389
1416
  typer.Option("--inactive", help="Restore as inactive instead of active."),
1390
1417
  ] = False,
1391
1418
  ) -> None:
1392
- from .. import work
1419
+ from ... import work
1393
1420
 
1394
1421
  job_id = id
1395
1422
  agent_name = _required_prefix_agent(ctx, command_name=kind)
@@ -1414,7 +1441,7 @@ def _make_delete_work_command(kind: WorkKind, title: str) -> Callable[..., None]
1414
1441
  ctx: typer.Context,
1415
1442
  id: str = typer.Argument(..., help=f"{title} id", metavar="ID"),
1416
1443
  ) -> None:
1417
- from .. import work
1444
+ from ... import work
1418
1445
 
1419
1446
  job_id = id
1420
1447
  agent_name = _required_prefix_agent(ctx, command_name=kind)
@@ -1457,7 +1484,8 @@ app.add_typer(model_app, name="model", no_args_is_help=True, rich_help_panel=RUN
1457
1484
  app.add_typer(tool_app, name="tool", no_args_is_help=True, rich_help_panel=RUNTIME_COMMAND_PANEL)
1458
1485
  app.add_typer(channel_app, name="channel", no_args_is_help=True, rich_help_panel=RUNTIME_COMMAND_PANEL)
1459
1486
  app.add_typer(sandbox_app, name="sandbox", no_args_is_help=True, rich_help_panel=RUNTIME_COMMAND_PANEL)
1460
- register_toolang_caps_commands(app, rich_help_panel=CAPS_COMMAND_PANEL)
1487
+ register_fmt_command(app)
1488
+ register_caps_commands(app, rich_help_panel=CAPS_COMMAND_PANEL)
1461
1489
  register_work_commands()
1462
1490
 
1463
1491
 
@@ -0,0 +1,13 @@
1
+ """Caps commands mounted under the main toolang CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+
7
+ from ..caps.commands import CAP_KINDS, register_toolang_caps_commands as _register_toolang_caps_commands
8
+
9
+ __all__ = ["CAP_KINDS", "register_caps_commands"]
10
+
11
+
12
+ def register_caps_commands(app: typer.Typer, *, rich_help_panel: str | None = None) -> None:
13
+ _register_toolang_caps_commands(app, rich_help_panel=rich_help_panel)
@@ -0,0 +1,129 @@
1
+ """Hidden formatter command for Toolang source files."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable
6
+ from pathlib import Path
7
+ import sys
8
+ from typing import Annotated
9
+
10
+ import click
11
+ import typer
12
+
13
+
14
+ def register_fmt_command(app: typer.Typer) -> None:
15
+ app.command("fmt", help="Format .too files.", hidden=True, no_args_is_help=True)(fmt)
16
+
17
+
18
+ def fmt(
19
+ paths: Annotated[
20
+ list[Path] | None,
21
+ typer.Argument(help="File or directory paths to format."),
22
+ ] = None,
23
+ check: Annotated[
24
+ bool,
25
+ typer.Option("--check", help="Exit non-zero if any file is not formatted."),
26
+ ] = False,
27
+ tab_size: Annotated[
28
+ int,
29
+ typer.Option("--tab-size", help="Number of spaces per indentation level."),
30
+ ] = 2,
31
+ stdin_filepath: Annotated[
32
+ Path | None,
33
+ typer.Option(
34
+ "--stdin-filepath",
35
+ help="Path label for stdin.",
36
+ ),
37
+ ] = None,
38
+ ) -> None:
39
+ from ...program_format import ToolangFormatError, format_source
40
+
41
+ if tab_size < 1:
42
+ raise click.ClickException("--tab-size must be at least 1")
43
+
44
+ def format_too_source(source: str) -> str:
45
+ return format_source(source, tab_size=tab_size)
46
+
47
+ path_args = paths or []
48
+ if any(str(path) == "-" for path in path_args) and len(path_args) > 1:
49
+ raise click.ClickException("'-' cannot be combined with other path arguments")
50
+
51
+ stdin_path_arg = _stdin_path_arg(path_args)
52
+ if stdin_filepath is not None or stdin_path_arg is not None:
53
+ if path_args and stdin_path_arg is None:
54
+ raise click.ClickException("--stdin-filepath can only be combined with '-'")
55
+ if check:
56
+ raise click.ClickException("--check cannot be combined with stdin formatting")
57
+ label = stdin_filepath or stdin_path_arg or Path("<stdin>")
58
+ _format_stdin(label, format_source=format_too_source, error_type=ToolangFormatError)
59
+ return
60
+
61
+ source_paths = _collect_format_paths(path_args)
62
+ changed: list[Path] = []
63
+ for source_path in source_paths:
64
+ try:
65
+ source = source_path.read_text(encoding="utf-8")
66
+ except OSError as exc:
67
+ raise click.ClickException(f"{source_path}: {exc}") from exc
68
+ try:
69
+ formatted = format_too_source(source)
70
+ except ToolangFormatError as exc:
71
+ raise click.ClickException(f"{source_path}: {exc}") from exc
72
+ if formatted == source:
73
+ continue
74
+ changed.append(source_path)
75
+ if check:
76
+ continue
77
+ try:
78
+ source_path.write_text(formatted, encoding="utf-8")
79
+ except OSError as exc:
80
+ raise click.ClickException(f"{source_path}: {exc}") from exc
81
+
82
+ if check and changed:
83
+ for source_path in changed:
84
+ typer.echo(f"would reformat {source_path}")
85
+ raise typer.Exit(1)
86
+ if changed:
87
+ for source_path in changed:
88
+ typer.echo(f"formatted {source_path}")
89
+
90
+
91
+ def _format_stdin(
92
+ stdin_filepath: Path,
93
+ *,
94
+ format_source: Callable[[str], str],
95
+ error_type: type[Exception],
96
+ ) -> None:
97
+ try:
98
+ formatted = format_source(sys.stdin.read())
99
+ except error_type as exc:
100
+ raise click.ClickException(f"{stdin_filepath}: {exc}") from exc
101
+ sys.stdout.write(formatted)
102
+
103
+
104
+ def _stdin_path_arg(paths: list[Path]) -> Path | None:
105
+ if len(paths) == 1 and str(paths[0]) == "-":
106
+ return Path("<stdin>")
107
+ return None
108
+
109
+
110
+ def _collect_format_paths(paths: list[Path]) -> list[Path]:
111
+ collected: list[Path] = []
112
+ seen: set[Path] = set()
113
+ for path in paths:
114
+ candidate = path.expanduser()
115
+ if candidate.is_dir():
116
+ candidates = sorted(item for item in candidate.rglob("*.too") if item.is_file())
117
+ elif candidate.is_file():
118
+ if candidate.suffix != ".too":
119
+ raise click.ClickException(f"not a .too file: {candidate}")
120
+ candidates = [candidate]
121
+ else:
122
+ raise click.ClickException(f"path not found: {candidate}")
123
+ for source_path in candidates:
124
+ resolved = source_path.resolve()
125
+ if resolved in seen:
126
+ continue
127
+ seen.add(resolved)
128
+ collected.append(source_path)
129
+ return collected