taskuary 0.3.2.6__tar.gz → 0.3.2.7__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 (246) hide show
  1. {taskuary-0.3.2.6/taskuary.egg-info → taskuary-0.3.2.7}/PKG-INFO +2 -2
  2. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/README.md +1 -1
  3. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/pyproject.toml +1 -1
  4. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/guard.py +1 -0
  5. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/server.py +17 -0
  6. taskuary-0.3.2.7/taskuary/update.py +179 -0
  7. taskuary-0.3.2.6/taskuary/web/assets/GeneralWorkspace-D46ydeAJ.css → taskuary-0.3.2.7/taskuary/web/assets/GeneralWorkspace-BpkuvgFU.css +1 -1
  8. taskuary-0.3.2.6/taskuary/web/assets/GeneralWorkspace-CCZEIxwO.js → taskuary-0.3.2.7/taskuary/web/assets/GeneralWorkspace-Cmu6KGGe.js +2 -2
  9. taskuary-0.3.2.7/taskuary/web/assets/SocialView-kma4W7JV.js +1 -0
  10. taskuary-0.3.2.6/taskuary/web/assets/index-gbbR3m6-.js → taskuary-0.3.2.7/taskuary/web/assets/index-rF2UKXaH.js +110 -110
  11. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/web/index.html +1 -1
  12. {taskuary-0.3.2.6 → taskuary-0.3.2.7/taskuary.egg-info}/PKG-INFO +2 -2
  13. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary.egg-info/SOURCES.txt +6 -4
  14. taskuary-0.3.2.7/tests/test_update.py +185 -0
  15. taskuary-0.3.2.6/taskuary/web/assets/SocialView-8UXis6mV.js +0 -1
  16. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/LICENSE +0 -0
  17. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/setup.cfg +0 -0
  18. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/__init__.py +0 -0
  19. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/agents.py +0 -0
  20. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/aisetup.py +0 -0
  21. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/artifacts.py +0 -0
  22. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/assistant.py +0 -0
  23. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/aws.py +0 -0
  24. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/azure.py +0 -0
  25. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/blackboard.py +0 -0
  26. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/browserview.py +0 -0
  27. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/calendar.py +0 -0
  28. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/categories.py +0 -0
  29. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/channels.py +0 -0
  30. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/ci.py +0 -0
  31. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/cli.py +0 -0
  32. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/climodels.py +0 -0
  33. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/clis.py +0 -0
  34. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/coder.py +0 -0
  35. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/compose.py +0 -0
  36. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/config.py +0 -0
  37. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/context.py +0 -0
  38. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/counsel.py +0 -0
  39. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/db.py +0 -0
  40. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/demo.py +0 -0
  41. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/desktop.py +0 -0
  42. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/devtools.py +0 -0
  43. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/digest.py +0 -0
  44. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/docsync.py +0 -0
  45. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/evalset.py +0 -0
  46. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/general.py +0 -0
  47. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/github.py +0 -0
  48. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/handbook.py +0 -0
  49. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/handraise.py +0 -0
  50. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/histgen.py +0 -0
  51. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/hooks.py +0 -0
  52. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/imapmail.py +0 -0
  53. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/imessage.py +0 -0
  54. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/ingest.py +0 -0
  55. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/intacct.py +0 -0
  56. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/interview.py +0 -0
  57. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/knowledge.py +0 -0
  58. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/learn.py +0 -0
  59. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/learnedgraph.py +0 -0
  60. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/llm.py +0 -0
  61. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/logs.py +0 -0
  62. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/mcp.py +0 -0
  63. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/messengers.py +0 -0
  64. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/msauth.py +0 -0
  65. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/mssql.py +0 -0
  66. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/outbound.py +0 -0
  67. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/outbox.py +0 -0
  68. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/ownwork.py +0 -0
  69. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/phone.py +0 -0
  70. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/playbooks.py +0 -0
  71. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/pm.py +0 -0
  72. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/policy.py +0 -0
  73. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/problems.py +0 -0
  74. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/promptmap.py +0 -0
  75. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/proof.py +0 -0
  76. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/proposals.py +0 -0
  77. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/quickbooks.py +0 -0
  78. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/rank.py +0 -0
  79. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/reports.py +0 -0
  80. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/research.py +0 -0
  81. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/reshape.py +0 -0
  82. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/responder.py +0 -0
  83. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/routing.py +0 -0
  84. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/scopes.py +0 -0
  85. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/selfclose.py +0 -0
  86. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/semantic.py +0 -0
  87. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/senders.py +0 -0
  88. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/setup.py +0 -0
  89. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/sharepoint.py +0 -0
  90. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/sheets.py +0 -0
  91. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/spawn.py +0 -0
  92. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/store.py +0 -0
  93. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/teller.py +0 -0
  94. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/templates/coder.md +0 -0
  95. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/templates/counsel.md +0 -0
  96. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/templates/digest.md +0 -0
  97. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/templates/learned.md +0 -0
  98. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/templates/playbook.md +0 -0
  99. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/templates/soul.md +0 -0
  100. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/templates/style.md +0 -0
  101. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/templates/triage.md +0 -0
  102. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/terminal.py +0 -0
  103. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/testing.py +0 -0
  104. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/toil.py +0 -0
  105. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/triage.py +0 -0
  106. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/verdicts.py +0 -0
  107. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/voice.py +0 -0
  108. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/wabridge.py +0 -0
  109. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/waitroom.py +0 -0
  110. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/web/assets/index-6GBZ9nXN.css +0 -0
  111. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/web/favicon.ico +0 -0
  112. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/web/favicon.png +0 -0
  113. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/webguard.py +0 -0
  114. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/whatsapp/bridge.mjs +0 -0
  115. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/whatsapp/package.json +0 -0
  116. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/whoami.py +0 -0
  117. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary/witness.py +0 -0
  118. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary.egg-info/dependency_links.txt +0 -0
  119. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary.egg-info/entry_points.txt +0 -0
  120. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary.egg-info/requires.txt +0 -0
  121. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/taskuary.egg-info/top_level.txt +0 -0
  122. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_agent_environment.py +0 -0
  123. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_agent_source.py +0 -0
  124. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_agent_wall.py +0 -0
  125. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_aisetup.py +0 -0
  126. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_answered_yourself.py +0 -0
  127. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_answers.py +0 -0
  128. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_api.py +0 -0
  129. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_assistant.py +0 -0
  130. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_assistant_verdicts.py +0 -0
  131. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_async_triage.py +0 -0
  132. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_audit_chain.py +0 -0
  133. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_aws_region.py +0 -0
  134. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_blackboard.py +0 -0
  135. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_browser_session.py +0 -0
  136. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_browserview.py +0 -0
  137. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_calendar.py +0 -0
  138. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_calendar_today.py +0 -0
  139. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_categories.py +0 -0
  140. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_cc_triage.py +0 -0
  141. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_chat_doors.py +0 -0
  142. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_chat_queue.py +0 -0
  143. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_climodels.py +0 -0
  144. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_clis.py +0 -0
  145. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_cloud.py +0 -0
  146. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_cloud_sources.py +0 -0
  147. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_compose.py +0 -0
  148. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_compose_sources.py +0 -0
  149. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_config.py +0 -0
  150. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_context.py +0 -0
  151. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_core.py +0 -0
  152. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_counsel.py +0 -0
  153. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_cwlogs_paging.py +0 -0
  154. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_demo.py +0 -0
  155. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_desktop.py +0 -0
  156. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_devtools.py +0 -0
  157. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_diff_review.py +0 -0
  158. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_digest_brief.py +0 -0
  159. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_docs_and_llm.py +0 -0
  160. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_docs_flow.py +0 -0
  161. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_duplicate_connectors.py +0 -0
  162. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_factory.py +0 -0
  163. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_feed_working.py +0 -0
  164. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_finished_chat_stays_finished.py +0 -0
  165. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_general.py +0 -0
  166. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_github_auto.py +0 -0
  167. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_guard.py +0 -0
  168. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_handbook.py +0 -0
  169. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_handbook_topics.py +0 -0
  170. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_handoff_channels.py +0 -0
  171. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_handraise.py +0 -0
  172. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_harvest.py +0 -0
  173. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_histgen.py +0 -0
  174. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_home_is_never_yours.py +0 -0
  175. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_imap_history.py +0 -0
  176. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_imapmail.py +0 -0
  177. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_imessage.py +0 -0
  178. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_intacct.py +0 -0
  179. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_kind_dispatch.py +0 -0
  180. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_knowledge.py +0 -0
  181. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_learnedgraph.py +0 -0
  182. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_local_file.py +0 -0
  183. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_mail_folders.py +0 -0
  184. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_mark_read.py +0 -0
  185. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_mcp.py +0 -0
  186. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_meeting_prep.py +0 -0
  187. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_message_thread.py +0 -0
  188. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_messengers.py +0 -0
  189. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_msauth.py +0 -0
  190. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_mssql.py +0 -0
  191. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_noop_ending.py +0 -0
  192. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_not_coding.py +0 -0
  193. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_note_retrieval.py +0 -0
  194. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_outbound_reports.py +0 -0
  195. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_own_rows_no_reply.py +0 -0
  196. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_playbooks.py +0 -0
  197. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_pm.py +0 -0
  198. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_poll_overlap.py +0 -0
  199. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_poll_sources.py +0 -0
  200. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_pr_comments.py +0 -0
  201. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_problems.py +0 -0
  202. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_promptmap_and_catalog.py +0 -0
  203. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_proof_ci_proposals.py +0 -0
  204. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_pypi_downloads.py +0 -0
  205. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_quickbooks.py +0 -0
  206. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_rank.py +0 -0
  207. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_reply_channels.py +0 -0
  208. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_reply_voice.py +0 -0
  209. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_report_alerts.py +0 -0
  210. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_report_triage.py +0 -0
  211. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_research.py +0 -0
  212. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_reviews.py +0 -0
  213. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_scopes.py +0 -0
  214. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_seed_fits_a_tty.py +0 -0
  215. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_seeded_reports.py +0 -0
  216. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_semantic.py +0 -0
  217. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_send_targets.py +0 -0
  218. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_setup.py +0 -0
  219. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_sheets_sharepoint.py +0 -0
  220. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_someone_else_replied.py +0 -0
  221. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_soul_interview.py +0 -0
  222. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_stay_open.py +0 -0
  223. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_stay_open_doors.py +0 -0
  224. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_store_app_cli.py +0 -0
  225. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_store_hotpaths.py +0 -0
  226. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_sync_clock.py +0 -0
  227. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_task_identity.py +0 -0
  228. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_teller.py +0 -0
  229. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_terminal.py +0 -0
  230. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_toil.py +0 -0
  231. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_triage_dataset.py +0 -0
  232. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_urgent_and_handoff.py +0 -0
  233. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_verdict_paths.py +0 -0
  234. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_verdict_sticks.py +0 -0
  235. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_vision.py +0 -0
  236. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_voice.py +0 -0
  237. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_wabridge.py +0 -0
  238. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_waitroom.py +0 -0
  239. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_watermark.py +0 -0
  240. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_web_entrypoint.py +0 -0
  241. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_webguard.py +0 -0
  242. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_whatsapp_documents.py +0 -0
  243. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_whatsapp_images.py +0 -0
  244. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_whoami.py +0 -0
  245. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_withdrawn.py +0 -0
  246. {taskuary-0.3.2.6 → taskuary-0.3.2.7}/tests/test_witness.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskuary
3
- Version: 0.3.2.6
3
+ Version: 0.3.2.7
4
4
  Summary: Automate your job - the local-first operating system for your work: AI triage in, coding agents out.
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/ldbumble/taskuary
@@ -64,7 +64,7 @@ and replies wait for your approval. Nothing sends or ships without you.
64
64
 
65
65
  ![The Taskuary Studio: work arrives, triage decides what needs action, and agents take seats to work it.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/hero.gif)
66
66
 
67
- Taskuary is early—currently **v0.3.2.6**—and moving fast. The funnel, review queue,
67
+ Taskuary is early—currently **v0.3.2.7**—and moving fast. The funnel, review queue,
68
68
  agent sessions, and reports pipeline are in daily use; breaking changes are still possible
69
69
  before 1.0.
70
70
 
@@ -13,7 +13,7 @@ and replies wait for your approval. Nothing sends or ships without you.
13
13
 
14
14
  ![The Taskuary Studio: work arrives, triage decides what needs action, and agents take seats to work it.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/hero.gif)
15
15
 
16
- Taskuary is early—currently **v0.3.2.6**—and moving fast. The funnel, review queue,
16
+ Taskuary is early—currently **v0.3.2.7**—and moving fast. The funnel, review queue,
17
17
  agent sessions, and reports pipeline are in daily use; breaking changes are still possible
18
18
  before 1.0.
19
19
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "taskuary"
7
- version = "0.3.2.6"
7
+ version = "0.3.2.7"
8
8
  description = "Automate your job - the local-first operating system for your work: AI triage in, coding agents out."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -57,6 +57,7 @@ DENIED = (
57
57
  (r'POST|PUT|PATCH', r'^/api/settings', 'the settings decide what agents may do'),
58
58
  (r'POST|PUT|PATCH|DELETE', r'^/api/(policies|agents)', 'the rules and the agent profiles'),
59
59
  (r'POST|PUT|PATCH|DELETE', r'^/api/(docs?|playbooks)(/|$)', 'SOUL.md, the playbooks and the rest are the owner\'s word, not an agent\'s - propose, do not write'),
60
+ (r'POST', r'^/api/update$', 'replacing the program is the owner\'s decision'),
60
61
  )
61
62
  _DENIED = tuple((re.compile(f'^({m})$', re.I), re.compile(p), why) for m, p, why in DENIED)
62
63
 
@@ -197,6 +197,23 @@ _started = datetime.now().isoformat(sep=' ', timespec='seconds')
197
197
  @app.get('/api/version')
198
198
  def version(): return {'version': _ver, 'started': _started}
199
199
 
200
+ # ── update in place (update.py): Settings → Updates ─────────────────────────────────────
201
+ @app.get('/api/update')
202
+ def update_check(force: int = 0):
203
+ from . import update
204
+ return update.check(force=bool(force))
205
+
206
+ @app.post('/api/update')
207
+ def update_apply():
208
+ """Fetch the latest release and swap it in. The answer goes out first; the process ends a
209
+ moment later so the new build can start. Owner-only: guard.py refuses an agent token."""
210
+ from . import update
211
+ try: out = update.apply()
212
+ except Exception as e: raise HTTPException(422, str(e))
213
+ store.audit('app', 0, 'update', ACTOR, detail={k: v for k, v in out.items() if k != 'pip'})
214
+ if out.get('restarting'): update.exit_soon()
215
+ return out
216
+
200
217
  def _can_send(channel, has_message=True, gh_ok=None) -> bool:
201
218
  """Can an approved reply actually LEAVE on this channel? One answer for the whole app -
202
219
  outbound.can_reply - so the Approve button, triage and the coder wrap-up cannot
@@ -0,0 +1,179 @@
1
+ """Update in place, from Settings: check what the latest release is, fetch it, swap it in, come back.
2
+
3
+ Everything the owner has - connections, tokens, the database, the operator documents, the
4
+ playbooks - lives under ~/.taskuary (config.home()), never beside the program. So an update is
5
+ only ever a program swap: nothing in the data folder is touched, and the new build opens the same
6
+ database the old one closed. That is what makes "keep the connection and all the settings" free.
7
+
8
+ Three ways Taskuary can be installed, three roads:
9
+ exe Taskuary.exe (PyInstaller, taskuary.spec). A running exe cannot overwrite itself on
10
+ Windows, so the new one is downloaded beside it as Taskuary.new.exe and a tiny batch
11
+ script does the rest after we exit: wait for our PID to go, move the new file over
12
+ the old, start it with the same arguments, delete itself.
13
+ pip a wheel in a venv: `pip install -U taskuary`, then relaunch the same command line.
14
+ source a checkout (`pip install -e .`, the developer's machine): updating means `git pull`,
15
+ which is not ours to run in somebody's repository - say so instead.
16
+
17
+ The latest version is the GitHub release the publish workflow cuts on every tag, and the exe is
18
+ the asset it attaches at a fixed URL (releases/latest/download/Taskuary.exe). No token, no extra
19
+ service, and the same file a person would download by hand.
20
+ """
21
+ import os, re, sys, threading, time
22
+ from pathlib import Path
23
+
24
+ import requests
25
+ from loguru import logger
26
+
27
+ from . import __version__
28
+
29
+ REPO = 'ldbumble/taskuary'
30
+ LATEST_API = f'https://api.github.com/repos/{REPO}/releases/latest'
31
+ EXE_URL = f'https://github.com/{REPO}/releases/latest/download/Taskuary.exe'
32
+ TIMEOUT = 20
33
+ _cache = {'at': 0.0, 'result': None}
34
+ CACHE_S = 600 # GitHub allows 60 anonymous calls an hour; the header pill asks often
35
+
36
+
37
+ def how() -> str:
38
+ """'exe' | 'pip' | 'source' - which road an update takes on this install."""
39
+ if getattr(sys, 'frozen', False): return 'exe'
40
+ if (Path(__file__).parent.parent / 'pyproject.toml').is_file(): return 'source'
41
+ return 'pip'
42
+
43
+
44
+ def _parts(v: str) -> tuple:
45
+ return tuple(int(x) for x in re.findall(r'\d+', str(v or '')))
46
+
47
+
48
+ def newer(latest: str, current: str) -> bool:
49
+ """Is `latest` a later release than `current`? Dotted integers, any depth; a bad string is
50
+ never newer - an update button must not fire on a parse error."""
51
+ a, b = _parts(latest), _parts(current)
52
+ if not a or not b: return False
53
+ n = max(len(a), len(b))
54
+ return a + (0,) * (n - len(a)) > b + (0,) * (n - len(b))
55
+
56
+
57
+ def check(force: bool = False) -> dict:
58
+ """What is out there vs what is running. Cached ten minutes; a failure to reach GitHub is a
59
+ fact in the answer, not an exception - the card says 'could not check' and stays useful."""
60
+ if not force and _cache['result'] and time.time() - _cache['at'] < CACHE_S: return _cache['result']
61
+ out = {'current': __version__, 'how': how(), 'latest': None, 'newer': False, 'url': None, 'notes': None, 'error': None}
62
+ try:
63
+ r = requests.get(LATEST_API, timeout=TIMEOUT, headers={'Accept': 'application/vnd.github+json'})
64
+ r.raise_for_status()
65
+ j = r.json()
66
+ tag = str(j.get('tag_name') or '').lstrip('v')
67
+ out.update({'latest': tag or None, 'newer': newer(tag, __version__), 'notes': j.get('html_url'),
68
+ 'url': next((a.get('browser_download_url') for a in j.get('assets') or []
69
+ if str(a.get('name') or '').lower() == 'taskuary.exe'), EXE_URL)})
70
+ except Exception as e:
71
+ out['error'] = f'could not reach GitHub to check: {str(e)[:160]}'
72
+ _cache.update({'at': time.time(), 'result': out})
73
+ return out
74
+
75
+
76
+ # ── the exe road ────────────────────────────────────────────────────────────────────────
77
+ def _download(url: str, dest: Path, progress=None) -> int:
78
+ """Stream the new exe beside the old one. Size-checked against Content-Length and sniffed
79
+ for the PE header: a half-downloaded or HTML-error-page 'exe' must never be swapped in."""
80
+ with requests.get(url, stream=True, timeout=TIMEOUT, allow_redirects=True) as r:
81
+ r.raise_for_status()
82
+ total = int(r.headers.get('Content-Length') or 0)
83
+ got = 0
84
+ with open(dest, 'wb') as f:
85
+ for chunk in r.iter_content(1 << 20):
86
+ if not chunk: continue
87
+ f.write(chunk); got += len(chunk)
88
+ if progress: progress(got, total)
89
+ if total and got != total:
90
+ dest.unlink(missing_ok=True)
91
+ raise RuntimeError(f'download stopped short: {got:,} of {total:,} bytes')
92
+ with open(dest, 'rb') as f: head = f.read(2)
93
+ if head != b'MZ':
94
+ dest.unlink(missing_ok=True)
95
+ raise RuntimeError('what came down is not a Windows program - the release asset may be missing')
96
+ return got
97
+
98
+
99
+ def swap_script(exe: Path, new: Path, pid: int, args: list) -> str:
100
+ """The batch that finishes the job after this process has gone. Waits for the PID (the exe
101
+ is locked while it runs), moves the new file over the old (retrying - antivirus likes to hold
102
+ a fresh download for a second), starts the new build with the SAME arguments, removes itself."""
103
+ q = lambda s: '"' + str(s).replace('"', '""') + '"'
104
+ argstr = ' '.join(q(a) for a in args)
105
+ return '\r\n'.join([
106
+ '@echo off',
107
+ 'setlocal',
108
+ ':wait',
109
+ f'tasklist /FI "PID eq {pid}" 2>nul | find "{pid}" >nul',
110
+ 'if not errorlevel 1 (timeout /t 1 /nobreak >nul & goto wait)',
111
+ 'set /a tries=0',
112
+ ':swap',
113
+ f'move /Y {q(new)} {q(exe)} >nul 2>&1',
114
+ 'if errorlevel 1 (',
115
+ ' set /a tries+=1',
116
+ ' if %tries% geq 30 goto giveup',
117
+ ' timeout /t 1 /nobreak >nul',
118
+ ' goto swap',
119
+ ')',
120
+ f'start "" {q(exe)} {argstr}'.rstrip(),
121
+ 'del "%~f0"',
122
+ 'exit /b 0',
123
+ ':giveup',
124
+ f'start "" {q(exe)} {argstr}'.rstrip(),
125
+ 'del "%~f0"',
126
+ 'exit /b 1',
127
+ ]) + '\r\n'
128
+
129
+
130
+ def _apply_exe(url: str, progress=None) -> dict:
131
+ exe = Path(sys.executable).resolve()
132
+ new = exe.with_name('Taskuary.new.exe')
133
+ size = _download(url, new, progress)
134
+ script = exe.with_name('taskuary-update.cmd')
135
+ script.write_text(swap_script(exe, new, os.getpid(), sys.argv[1:]), encoding='utf-8')
136
+ from . import spawn
137
+ import subprocess
138
+ # detached: it must outlive us, and it must not die when our (nonexistent) console does
139
+ spawn.popen(['cmd', '/c', str(script)], cwd=str(exe.parent), close_fds=True,
140
+ creationflags=getattr(subprocess, 'DETACHED_PROCESS', 0) | getattr(subprocess, 'CREATE_NEW_PROCESS_GROUP', 0))
141
+ logger.info(f'update: {size:,} bytes downloaded to {new.name}; {script.name} takes over when this process exits')
142
+ return {'how': 'exe', 'downloaded': size, 'restarting': True}
143
+
144
+
145
+ # ── the pip road ────────────────────────────────────────────────────────────────────────
146
+ def _apply_pip(progress=None) -> dict:
147
+ from . import spawn
148
+ if progress: progress(0, 0)
149
+ r = spawn.run([sys.executable, '-m', 'pip', 'install', '-U', '--no-input', 'taskuary'],
150
+ capture_output=True, text=True, timeout=600)
151
+ if r.returncode != 0:
152
+ raise RuntimeError('pip could not update: ' + (r.stderr or r.stdout or '').strip()[-400:])
153
+ # relaunch the same command line, detached, once we are gone
154
+ import subprocess
155
+ kw = ({'creationflags': getattr(subprocess, 'DETACHED_PROCESS', 0) | getattr(subprocess, 'CREATE_NEW_PROCESS_GROUP', 0)}
156
+ if os.name == 'nt' else {'start_new_session': True})
157
+ spawn.popen([sys.executable, *sys.argv], close_fds=True, **kw)
158
+ return {'how': 'pip', 'restarting': True, 'pip': (r.stdout or '').strip()[-300:]}
159
+
160
+
161
+ def apply(progress=None) -> dict:
162
+ """Do it. Returns what happened; the caller ends the process (exit_soon) when 'restarting'."""
163
+ road = how()
164
+ if road == 'source':
165
+ raise RuntimeError('this is a source checkout - update it with `git pull` in the repository, then restart')
166
+ info = check(force=True)
167
+ if info.get('error'): raise RuntimeError(info['error'])
168
+ if not info.get('newer'): raise RuntimeError(f'already on the latest release ({__version__})')
169
+ return _apply_exe(info.get('url') or EXE_URL, progress) if road == 'exe' else _apply_pip(progress)
170
+
171
+
172
+ def exit_soon(delay: float = 1.5):
173
+ """Leave AFTER the HTTP answer has gone out. os._exit, not sys.exit: uvicorn runs in a
174
+ thread and pywebview owns the main one; a polite exit from a request handler goes nowhere."""
175
+ def _go():
176
+ time.sleep(delay)
177
+ logger.info('update: exiting so the new build can start')
178
+ os._exit(0)
179
+ threading.Thread(target=_go, daemon=True).start()
@@ -1 +1 @@
1
- .tq-aui-thread{height:100%;min-height:0;overflow:hidden;display:flex;flex-direction:column;background:#fbfaf7;color:#292824}.tq-aui-viewport{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;padding:18px;box-sizing:border-box;scrollbar-width:thin}.tq-aui-welcome{margin:auto auto 18px;max-width:560px;display:flex;align-items:flex-start;gap:10px;color:#667164}.tq-aui-welcome-title{color:#343832;font-weight:700;font-size:15px}.tq-aui-welcome-copy{color:#77766f;font-size:12.5px;margin-top:3px;line-height:1.45}.tq-aui-message{width:min(760px,92%);margin:0 auto 18px;display:grid;grid-template-columns:66px minmax(0,1fr);gap:10px;align-items:start}.tq-aui-role{padding-top:8px;color:#8b877e;font:600 9px/1.2 Cascadia Mono,Consolas,monospace;letter-spacing:.14em;text-transform:uppercase}.tq-aui-user-bubble{justify-self:start;max-width:88%;border:1px solid #dfdbd3;background:#f1eee8;border-radius:13px;padding:9px 13px;font-size:13px;line-height:1.48}.tq-aui-user-bubble p{margin:0;white-space:pre-wrap!important}.tq-aui-agent-body{min-width:0;padding:5px 3px}.tq-aui-report-action{width:min(760px,92%);margin:2px auto 14px;padding:10px 12px;border:1px dashed #d8d1c5;border-radius:11px;background:#f8f5ee;display:flex;align-items:center;gap:12px}.tq-aui-report-action>div{flex:1;min-width:0;display:flex;flex-direction:column}.tq-aui-report-action b{color:#4d514b;font-size:12px}.tq-aui-report-action span{color:#858078;font-size:10.5px}.tq-aui-progress{margin:0 0 8px;border:1px dashed #ddd7cd;border-radius:9px;color:#77766f;font-size:11.5px}.tq-aui-progress summary{cursor:pointer;padding:6px 9px;font-weight:650;color:#676b64}.tq-aui-progress>div{padding:0 9px 8px;white-space:pre-wrap;line-height:1.45}.tq-aui-tool{margin:0 0 7px;border:1px solid #ddd8cf;border-radius:9px;background:#faf8f4;overflow:hidden}.tq-aui-tool summary{min-height:31px;padding:5px 9px;display:flex;align-items:center;gap:7px;cursor:pointer;list-style:none;font-size:11.5px}.tq-aui-tool summary::-webkit-details-marker{display:none}.tq-aui-tool summary b{color:#4d514b}.tq-aui-tool summary span:not(.tq-aui-tool-dot){color:#858078;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tq-aui-tool summary em{margin-left:auto;color:#8d897f;font:9px/1.2 Cascadia Mono,Consolas,monospace;font-style:normal;text-transform:uppercase}.tq-aui-tool-dot{width:7px;height:7px;flex:0 0 7px;border-radius:50%;background:#78917a}.tq-aui-tool-running .tq-aui-tool-dot{background:#c99b42;animation:tqAuiPulse 1.2s ease-in-out infinite}.tq-aui-tool-error .tq-aui-tool-dot{background:#9a4e53}.tq-aui-tool pre{margin:0;padding:8px 10px;max-height:220px;overflow:auto;border-top:1px solid #e5e0d8;background:#22231f;color:#e8e4dc;font:10.5px/1.45 Cascadia Mono,Consolas,monospace;white-space:pre-wrap}@keyframes tqAuiPulse{50%{opacity:.3}}.tq-aui-footer{flex:0 0 auto;padding:10px 18px 8px;background:#fbfaf7;border-top:1px solid #e4e0d9}.tq-aui-composer{width:min(820px,100%);margin:0 auto;min-height:48px;display:flex;align-items:flex-end;gap:5px;padding:6px 7px;border:1px solid #d5d0c7;background:#fff;border-radius:13px;box-shadow:0 2px 8px #39352d0b}.tq-aui-input{flex:1;resize:none;border:0;outline:0;background:transparent;color:#292824;font:inherit;font-size:13px;line-height:1.45;padding:7px 5px;max-height:150px}.tq-aui-input::placeholder{color:#8f8b84}.tq-aui-send,.tq-aui-cancel{width:34px;height:34px;flex:0 0 34px;border:0;border-radius:9px;display:grid;place-items:center;cursor:pointer;color:#fff;background:#738275}.tq-aui-send:disabled{cursor:default;opacity:.4}.tq-aui-cancel{background:#9a6d65}.tq-aui-cancel:disabled{display:none}.tq-aui-hint{margin:5px auto 0;text-align:center;color:#a09b92;font:9px/1.2 Cascadia Mono,Consolas,monospace}.tq-aui-attachments{width:min(820px,100%);margin:0 auto 6px;display:flex;flex-wrap:wrap;gap:5px}@media (max-width: 700px){.tq-aui-viewport{padding-left:10px;padding-right:10px}.tq-aui-message{width:100%;grid-template-columns:1fr;gap:3px}.tq-aui-role{padding-top:0}.tq-aui-footer{padding-left:10px;padding-right:10px}}
1
+ .tq-aui-thread{height:100%;min-height:0;overflow:hidden;display:flex;flex-direction:column;background:#fbfaf7;color:#292824}.tq-aui-viewport{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;padding:18px;box-sizing:border-box;scrollbar-width:thin}.tq-aui-welcome{margin:auto auto 18px;max-width:560px;display:flex;align-items:flex-start;gap:10px;color:#667164}.tq-aui-welcome-title{color:#343832;font-weight:700;font-size:15px}.tq-aui-welcome-copy{color:#77766f;font-size:12.5px;margin-top:3px;line-height:1.45}.tq-aui-message{width:min(760px,92%);margin:0 auto 18px;display:grid;grid-template-columns:66px minmax(0,1fr);gap:10px;align-items:start}.tq-aui-role{padding-top:8px;color:#8b877e;font:600 9px/1.2 Cascadia Mono,Consolas,monospace;letter-spacing:.14em;text-transform:uppercase}.tq-aui-user-bubble{justify-self:start;max-width:88%;border:1px solid #dfdbd3;background:#f1eee8;border-radius:13px;padding:9px 13px;font-size:13px;line-height:1.48}.tq-aui-user-bubble p{margin:0;white-space:pre-wrap!important}.tq-aui-agent-body{min-width:0;padding:5px 3px}.tq-aui-report-action{width:min(760px,92%);margin:2px auto 14px;padding:10px 12px;border:1px dashed #d8d1c5;border-radius:11px;background:#f8f5ee;display:flex;align-items:center;gap:12px}.tq-aui-report-action>div{flex:1;min-width:0;display:flex;flex-direction:column}.tq-aui-report-action b{color:#4d514b;font-size:12px}.tq-aui-report-action span{color:#858078;font-size:10.5px}.tq-aui-progress{margin:0 0 8px;border:1px dashed #ddd7cd;border-radius:9px;color:#77766f;font-size:11.5px}.tq-aui-progress summary{cursor:pointer;padding:6px 9px;font-weight:650;color:#676b64}.tq-aui-progress>div{padding:0 9px 8px;white-space:pre-wrap;line-height:1.45}.tq-aui-tool{margin:0 0 7px;border:1px solid #ddd8cf;border-radius:9px;background:#faf8f4;overflow:hidden}.tq-aui-tool summary{min-height:31px;padding:5px 9px;display:flex;align-items:center;gap:7px;cursor:pointer;list-style:none;font-size:11.5px}.tq-aui-tool summary::-webkit-details-marker{display:none}.tq-aui-tool summary b{color:#4d514b}.tq-aui-tool summary span:not(.tq-aui-tool-dot){color:#858078;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tq-aui-tool summary em{margin-left:auto;color:#8d897f;font:9px/1.2 Cascadia Mono,Consolas,monospace;font-style:normal;text-transform:uppercase}.tq-aui-tool-dot{width:7px;height:7px;flex:0 0 7px;border-radius:50%;background:#78917a}.tq-aui-tool-running .tq-aui-tool-dot{background:#c99b42;animation:tqAuiPulse 1.2s ease-in-out infinite}.tq-aui-tool-error .tq-aui-tool-dot{background:#9a4e53}.tq-aui-tool pre{margin:0;padding:8px 10px;max-height:220px;overflow:auto;border-top:1px solid #e5e0d8;background:#22231f;color:#e8e4dc;font:10.5px/1.45 Cascadia Mono,Consolas,monospace;white-space:pre-wrap}@keyframes tqAuiPulse{50%{opacity:.3}}.tq-aui-footer{flex:0 0 auto;padding:10px 18px 8px;background:#fbfaf7;border-top:1px solid #e4e0d9}.tq-aui-composer{width:min(820px,100%);margin:0 auto;min-height:48px;display:flex;align-items:flex-end;gap:5px;padding:6px 7px;border:1px solid #d5d0c7;background:#fff;border-radius:13px;box-shadow:0 2px 8px #39352d0b}.tq-aui-input{flex:1;resize:none;border:0;outline:0;background:transparent;color:#292824;font:inherit;font-size:13px;line-height:1.45;padding:7px 5px;max-height:150px}.tq-aui-input::placeholder{color:#8f8b84}.tq-aui-send,.tq-aui-cancel{width:34px;height:34px;flex:0 0 34px;border:0;border-radius:9px;display:grid;place-items:center;cursor:pointer;color:#fff;background:#738275}.tq-aui-send:disabled{cursor:default;opacity:.4}.tq-aui-cancel{background:#9a6d65}.tq-aui-cancel:disabled{display:none}.tq-aui-hint{margin:5px auto 0;text-align:center;color:#a09b92;font:9px/1.2 Cascadia Mono,Consolas,monospace}.tq-aui-attachments{width:min(820px,100%);margin:0 auto 6px;display:flex;flex-wrap:wrap;gap:5px}@media (max-width: 700px){.tq-aui-viewport{padding-left:10px;padding-right:10px}.tq-aui-message{width:100%;grid-template-columns:1fr;gap:3px}.tq-aui-role{padding-top:0}.tq-aui-footer{padding-left:10px;padding-right:10px}}@media (max-width: 600px){.tq-aui-report-action{flex-direction:column;align-items:stretch;gap:10px}}