taskuary 0.3.9.2__tar.gz → 0.3.9.4__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.
- {taskuary-0.3.9.2/taskuary.egg-info → taskuary-0.3.9.4}/PKG-INFO +3 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/README.md +2 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/pyproject.toml +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/advisor.py +193 -42
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/agents.py +12 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/aisetup.py +4 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/alchemy.py +2 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/asks.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/assistant.py +19 -14
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/batch.py +131 -5
- taskuary-0.3.9.4/taskuary/buttons.json +52 -0
- taskuary-0.3.9.4/taskuary/buttons.py +42 -0
- taskuary-0.3.9.4/taskuary/capabilities.py +82 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/channels.py +8 -6
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/chatgptauth.py +15 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/ci.py +4 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cli.py +3 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/compose.py +83 -31
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/concierge.py +244 -181
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/connectorcatalog.json +12 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/counsel.py +20 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/db.py +3 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/demo.py +134 -45
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/evalset.py +3 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/firstrun.py +201 -37
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/funnel.py +72 -107
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/funnel_presentation.py +109 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/funnel_selection.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/general.py +13 -6
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/guard.py +1 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/handbook.py +5 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/histgen.py +3 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/images.py +2 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/imapmail.py +3 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/ingest.py +42 -12
- taskuary-0.3.9.4/taskuary/lanes.json +278 -0
- taskuary-0.3.9.4/taskuary/lanes.py +97 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/llm.py +7 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/lookups.py +5 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/markets.py +6 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/messengers.py +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/operations.py +4 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/outbound.py +34 -11
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/outbox.py +5 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/outcomes.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_unread.py +6 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/proposals.py +27 -42
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/remind.py +3 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/remote_assistant.py +52 -71
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/reports.py +61 -24
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/research.py +12 -8
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/responder.py +45 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/scopes.py +2 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/selfclose.py +6 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/server.py +86 -48
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/settings_defaults.json +1 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/settings_schema.json +29 -23
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/setup.py +40 -26
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/since.py +6 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/slots.py +17 -22
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/store.py +22 -3
- taskuary-0.3.9.4/taskuary/templates/counsel.md +108 -0
- taskuary-0.3.9.4/taskuary/templates/history/counsel-0.3.9.3-audit.md +108 -0
- taskuary-0.3.9.4/taskuary/templates/history/counsel-0.3.9.3-buttons.md +108 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/terminal.py +24 -8
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/toolcatalog.py +37 -15
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/triage.py +13 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/verdicts.py +23 -46
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/voice.py +3 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/walk.py +10 -10
- taskuary-0.3.9.4/taskuary/web/assets/AssistantGame-CcG9vjWw.js +4 -0
- taskuary-0.3.9.2/taskuary/web/assets/GameScene-CD364KhR.js → taskuary-0.3.9.4/taskuary/web/assets/GameScene-xQkkdnyo.js +1 -1
- taskuary-0.3.9.4/taskuary/web/assets/HubView-B6GquZ4c.js +1 -0
- taskuary-0.3.9.4/taskuary/web/assets/TasksView-D4p3JiDN.js +1 -0
- taskuary-0.3.9.4/taskuary/web/assets/index-5REVSOmO.js +666 -0
- taskuary-0.3.9.2/taskuary/web/assets/index-dSnQFS_I.css → taskuary-0.3.9.4/taskuary/web/assets/index-CK_5N4BE.css +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/index.html +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/welcome.py +11 -7
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/witness.py +19 -4
- taskuary-0.3.9.4/taskuary/words.json +31 -0
- taskuary-0.3.9.4/taskuary/words.py +36 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/workerstate.py +5 -0
- taskuary-0.3.9.4/taskuary/workflows.py +309 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/wrapup.py +102 -18
- {taskuary-0.3.9.2 → taskuary-0.3.9.4/taskuary.egg-info}/PKG-INFO +3 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/SOURCES.txt +29 -6
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_advisor.py +83 -7
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_reply.py +15 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_alchemy.py +2 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_answered_yourself.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_answers.py +12 -12
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_api.py +20 -6
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_appfacts.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_acts.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_reactions.py +23 -19
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_auto_start.py +9 -8
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_batch.py +1 -1
- taskuary-0.3.9.4/tests/test_batch_session_end.py +386 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_brain_resolver.py +4 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_brain_said.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_browser_workflow.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_button_promises.py +2 -2
- taskuary-0.3.9.4/tests/test_buttons.py +224 -0
- taskuary-0.3.9.4/tests/test_capabilities.py +133 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_proposals.py +58 -9
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_setup.py +8 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chatformat.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_connections.py +3 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_close_slots.py +11 -11
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_closeout.py +17 -17
- taskuary-0.3.9.4/tests/test_coding_needs_a_cli.py +68 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_compose.py +3 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_compose_sources.py +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_compose_workflows.py +16 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_concierge.py +96 -13
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_continue_session.py +4 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_core.py +9 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_demo.py +105 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ending_a_run_writes_the_answer.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_explicit_completion.py +2 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_firstrun.py +114 -10
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_funnel.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_general.py +3 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_general_report_note.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_chat.py +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_handbook.py +7 -1
- taskuary-0.3.9.4/tests/test_hipaa_ai.py +76 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ideas_triage.py +8 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ignore_sender.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lane_vocabulary.py +2 -1
- taskuary-0.3.9.4/tests/test_lanes_registry.py +71 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_later_today.py +9 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lifecycle.py +16 -8
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_no_reply_is_the_writers_call.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_onboarding_walk.py +4 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_openai_compatible_brains.py +3 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_outbound_reports.py +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_browse_pass.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_picks.py +5 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_walk_ux.py +10 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_playbook_and_closeout.py +10 -10
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_remind.py +4 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_remote_assistant.py +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reopened_conversation.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_channels.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_watch.py +4 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_order_and_research.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_routing.py +5 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_triage.py +9 -6
- taskuary-0.3.9.4/tests/test_report_triage_line.py +270 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_review_delivery_safety.py +5 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_roles.py +4 -4
- taskuary-0.3.9.4/tests/test_row_presentation.py +84 -0
- taskuary-0.3.9.4/tests/test_send_is_not_close.py +131 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_send_outcomes.py +6 -6
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_endings.py +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_settings_paths.py +14 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_settings_schema.py +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_setup.py +26 -17
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_setup_about.py +11 -1
- taskuary-0.3.9.4/tests/test_setup_state.py +121 -0
- taskuary-0.3.9.4/tests/test_signature_learn.py +57 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_since.py +12 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_skillimport.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_email.py +3 -3
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_taskstate.py +7 -5
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_terminal.py +3 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_thinking_model_room.py +2 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_joins.py +3 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_urgent.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_voice.py +5 -4
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_welcome_and_voice.py +8 -2
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_why_not_started.py +6 -6
- taskuary-0.3.9.4/tests/test_words.py +72 -0
- taskuary-0.3.9.4/tests/test_workflow_brain.py +196 -0
- taskuary-0.3.9.4/tests/test_workflow_one_road.py +200 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_workflows.py +12 -7
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_zz_chipverbs.py +1 -1
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_zz_toolcatalog.py +8 -8
- taskuary-0.3.9.2/taskuary/lanes.json +0 -208
- taskuary-0.3.9.2/taskuary/web/assets/AssistantGame-BfHjsQy0.js +0 -4
- taskuary-0.3.9.2/taskuary/web/assets/HubView-BBhAZ5Hj.js +0 -1
- taskuary-0.3.9.2/taskuary/web/assets/TasksView-CoJa2HrT.js +0 -1
- taskuary-0.3.9.2/taskuary/web/assets/index-D0DogMv8.js +0 -658
- taskuary-0.3.9.2/taskuary/workflows.py +0 -151
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/LICENSE +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/setup.cfg +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/__init__.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/acp.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/aidefaults.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/appfacts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/artifacts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/assistantblocks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/autoreply.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/aws.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/azure.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/background.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/blackboard.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/brief.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/browserview.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/bugreport.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/calendar.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/categories.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/chains.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/chatformat.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/chatservers.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/claude_artifacts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cli_connections.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cli_install_terminal.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cliinstall.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/climodels.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/clipool.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/clis.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/clisetup.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cloudfix.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/config.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/connectorcatalog.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/context.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/continuity.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/databases.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/deps.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/desktop.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/devtools.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/digest.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/docsync.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/doorway_browse.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/evening.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/files.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/floor.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/ghcloseout.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/github.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/goals.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/handraise.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/hooks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/hub.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/imessage.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/instance.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/intacct.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/interview.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/invoice_workflow.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/jev.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/kbembed.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/knowledge.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/launchkey.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/learn.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/learnedgraph.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/linkedin.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/live.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/logs.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/mailauth.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/mcp.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/msauth.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/mssql.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/net.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/origin.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/ownwork.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/people.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/people_pages.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/playbook_facts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/playbooks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/pm.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/policy.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/problems.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_all.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_inventory.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_membership.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_navigation.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_order.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_projection.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_rail.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_reads.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_startup.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/projects.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/promptmap.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/proof.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/quickbooks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/rank.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/redact.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/reshape.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/retention.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/robinhood.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/roles.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/routing.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/routingmemory.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/search.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/semantic.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/senders.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sentjudge.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/session_artifacts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sessionfiles.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sessionrecord.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/settings_schema.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sharepoint.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sheets.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/simplefin.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/skillimport.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/skills/soul-interview/SKILL.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/skills/taskuary-setup/SKILL.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/social.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/spawn.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/taskstate.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/teller.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/agent.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/analyst.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/ap.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/assistant.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/coding.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/coordinator.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/digest.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.3.5.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.6.8.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.6.9-examples.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.6.9-remind.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.6.9.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.7.10.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.7.4.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.7.7.md +0 -0
- /taskuary-0.3.9.2/taskuary/templates/counsel.md → /taskuary-0.3.9.4/taskuary/templates/history/counsel-0.3.9.3.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/how-it-works.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/job.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/learned.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/marketer.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/playbook.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/profile.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/researcher.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/soul.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/style.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/trader.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/triage.md +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/testing.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/toil.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/treg.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/triage_kind_rules.json +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/update.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/vault.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/wabridge.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/waitroom.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/favicon.ico +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/favicon.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/assistant.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/board.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/connections.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/docs.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/hub.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/reports.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/settings.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/tasks.png +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/webguard.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/bridge.mjs +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/package.json +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/policy.mjs +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/poll.mjs +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/roster.mjs +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whoami.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/zoho.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/dependency_links.txt +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/entry_points.txt +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/requires.txt +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/top_level.txt +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_acp.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_advisor_idea_words.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_answer_route.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_answers_and_reminders.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_asking.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_environment.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_identity.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_profiles.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_sentence.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_source.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_wall.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ai_defaults.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ai_not_overruled.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_aisetup.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_an_inbox_is_not_a_destination.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_api_web.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_api_worker_signals.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_app_uptime.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_approval_interrupt.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_approve_what_was_shown.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_archive_is_read.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_asks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_blocks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_can_look_things_up.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_doorways.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_fast.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_ideas.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_notifications.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_presentation.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_verdicts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_async_triage.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_audit_chain.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_audit_fixes.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_autoreply.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_aws_region.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_azure_discovery.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_background_work.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_banner_is_one_rule.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_blackboard.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_brain_layer.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_brain_reaches_the_session.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_browser_session.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_browserview.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_bugreport.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_bugreport_api.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_bugreport_draft.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_bugreport_scrub.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_calendar.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_calendar_today.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_canvas_relay.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_canvas_sections.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_card_story_phone.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_categories.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cc.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cc_triage.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_doors.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_echo_mail.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_freshness.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_is_not_one_task.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_queue.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_relationship.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_retention.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_shows.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_trust.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chatgptauth.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chatservers.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chinese_clis.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_claude_artifacts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_clean_context.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_failure.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_help.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_install.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_install_terminal.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_not_assumed.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_on_fresh_path.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_prompt_road.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_setup.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_update.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_climodels.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_clipool.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_clis.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_close_with_a_note.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cloud.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cloud_sources.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cloudfix.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_coding_session_continuity.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_completion_freshness.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_concierge_counsel.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_config.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_context.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_context_refresh_freshness.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_coordination.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_correction_doors.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_counsel.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_counsel_consumers.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_counsel_migration.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_counsel_sections.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_current_restore.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cwlogs_paging.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_danger_verdict.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_data_is_coding.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_databases.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_deps.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_desktop.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_devin.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_devtools.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_diff_review.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_digest_brief.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_dispatch_retries.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_docs_and_llm.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_docs_flow.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_docs_manifest.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_draft_choices.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_due_days.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_duplicate_connectors.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_edit_recipient.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_email_chains.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_email_identity_routing.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ending_keeps_the_write_up.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_evening_brief.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_every_card_is_reachable.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_every_cli_startable.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_exe_splash.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_factory.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_failed_acts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_feed_lookups.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_feed_working.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_files.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_final_answer_capture.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_finished_chat_stays_finished.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_first_run_triage.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_floating_assistant.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_floor.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_floor_bypasses.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_floor_wave_b.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_follow_up_verdict.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_fresh_evaluation.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_freshness.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_freshness_walk.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_general_agent_permissions.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_general_knows_the_repos.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_github_auto.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_github_images.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_github_poll_scope.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goal_serves.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_api.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_promises.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_rail.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_store.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_guard.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hand_task_checklist.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_handbook_topics.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_handoff_channels.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_handraise.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_harvest.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_held_ask_answers.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_histgen.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_home_is_never_yours.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hook_off_loop.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hook_token_file.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hooks_events.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hooks_version.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_idea_verdicts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ignore_sender_quiets_its_work.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_images.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_imap_catchup.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_imap_history.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_imapmail.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_imessage.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_inline_pictures.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_intacct.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_interrupted_work.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_invite_is_not_work.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_invoice_workflow.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_jev.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_judge_reads_the_conclusion.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_kind_dispatch.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_knowledge.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_knowledge_semantic.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_launch_key.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_launch_key_private.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_layer_profiles.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_learnedgraph.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lifespan_loops_are_guarded.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_linkedin.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_linkedin_signin.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_live.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_local_file.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lookup_limits.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lookups.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mail_catchup.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mail_fetch_cost.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mail_folders.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mailauth.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mark_read.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_markets.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mcp.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_meeting_prep.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_message_thread.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_messengers.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_model_list.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_morning_line.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_msauth.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mssql.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_multi_question.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_muse.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_net.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_new_task_from_words.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_new_walk_off_the_lifespan.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_no_dispatch_while_agent_runs.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_no_pydantic_v1.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_noop_ending.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_not_coding.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_note_retrieval.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_one_app_one_reason.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_one_instance.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_one_pty_one_geometry.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_only_your_own_thread.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_operations.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin_doors.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin_launch.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin_roads.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin_seed.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_outbox.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_outcomes.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_own_rows_no_reply.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_pane_theme.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_people.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_people_pages.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_permit.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_person_name.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_agent_card.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_follows_up.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_plain_failures.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_playbook_facts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_playbook_setup.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_playbooks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_pm.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_poll_lanes.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_poll_overlap.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_poll_parallel.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_poll_sources.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_pr_comments.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_press_never_waits.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_problems.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_problems_dismiss.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_procedure_selection.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_processing_demo_replay.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_processing_ledger.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_profile_is_a_role.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_progress_without_markers.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_projects.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_prompt_images.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_prompt_sources.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_promptmap_and_catalog.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_proof_ci_proposals.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_protocol_marks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_pypi_downloads.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_quickbooks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_qwen.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_rail_decisions.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_rank.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_rate_limit.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_read_text.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_recent_closures.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reclassify.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_redact.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_redact_doors.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_remote_sections.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_always_drafts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_attachments.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_envelope.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_leaves_by_smtp.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_loop_in.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_needs_a_correspondent.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_opens_at_once.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_sees_pictures.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_sources.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_target.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_voice.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_repo_choice_triage.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_alerts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_deliver.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_delivery_gate.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_headline.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_one_road.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_prompt_isolation.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_refusal.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_research.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_research_more.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_restricted_cli.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_review_delivery_api.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_review_task.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reviews.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_robinhood.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_routing_memory.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_s3_poll_paging.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_scopes.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_search.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_security_followups.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_seed_fits_a_tty.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_seeded_reports.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_selector_vocabulary.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_semantic.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_send_targets.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sender_history.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sender_trust.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sender_words.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sentjudge.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_artifacts.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_continuity.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_files.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_record.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_settings_defaults_json.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_setup_skill.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_setup_walk.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sheets_sharepoint.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_simplefin.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_slipped.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_social.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_someone_else_replied.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_soul_interview.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stand_ins_stay_out_of_code.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_startup_contract.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stay_open.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stay_open_doors.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_store_app_cli.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_store_hotpaths.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_store_pokes.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stranger_floor_more.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stranger_hub_wall.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stranger_live_fixes.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stranger_token.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_strip_signoff.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sync_clock.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_table_context.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_taken_care_of.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_ask.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_checklist.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_controls_operations.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_footprint.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_identity.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_refs.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_tools.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_telegram_buttons.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_teller.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_the_exe_ships_what_the_wheel_ships.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_the_split_holds.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_toil.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_tracker_revisions.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_treg.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_cleanup.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_dataset.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_errors.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_guide.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_images.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_pr_rule.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_reads_not_guesses.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_retry_sweep.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_sees_meetings.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_typed_words_press.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_update.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_update_refused.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_urgent_and_handoff.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_vault.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_verdict_paths.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_verdict_shape.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_verdict_sticks.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_vision.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_wabridge.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_wabridge_log_trim.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_waitroom.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_walk_follows_the_rail.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_walk_order.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_watermark.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_web_entrypoint.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_webguard.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_whatsapp_documents.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_whatsapp_images.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_whoami.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_withdrawn.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_witness.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_brief.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_events.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_resumes.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_scenarios.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_surfaces.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_workerstate_said.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_xlsx_report_headers.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_zz_lastword.py +0 -0
- {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_zz_setupchat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: taskuary
|
|
3
|
-
Version: 0.3.9.
|
|
3
|
+
Version: 0.3.9.4
|
|
4
4
|
Summary: Your work manager. Locally. Securely. In control. Mail, chats and tickets in one list; your agents do the work, you approve. Runs on your machine.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/ldbumble/taskuary
|
|
@@ -71,7 +71,7 @@ Dynamic: license-file
|
|
|
71
71
|
|
|
72
72
|
[](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml)
|
|
73
73
|
[](https://scorecard.dev/viewer/?uri=github.com/ldbumble/taskuary)
|
|
74
|
-
[](https://pypi.org/project/taskuary/)
|
|
75
75
|
[](https://github.com/ldbumble/taskuary)
|
|
76
76
|
[](LICENSE)
|
|
77
77
|
[](https://github.com/ldbumble/taskuary/stargazers)
|
|
@@ -82,11 +82,9 @@ Dynamic: license-file
|
|
|
82
82
|
|
|
83
83
|
**A personal AI assistant for your job.** Mail, chats and tickets become tasks, the agents you already use (Claude Code, Codex, Gemini) do the work, and nothing goes out until you approve. Open source, runs on your machine, no subscription.
|
|
84
84
|
|
|
85
|
-
Compared with hosted assistants like Fyxer, Taskuary is free and open source, runs on your machine, and hands the work to agents you already use.
|
|
86
|
-
|
|
87
85
|

|
|
88
86
|
|
|
89
|
-
Taskuary is early—currently **v0.3.9.
|
|
87
|
+
Taskuary is early—currently **v0.3.9.4**—so breaking changes are still possible before 1.0.
|
|
90
88
|
|
|
91
89
|
<p align="center">
|
|
92
90
|
<a href="https://taskuary.com/demo/"><img
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml)
|
|
6
6
|
[](https://scorecard.dev/viewer/?uri=github.com/ldbumble/taskuary)
|
|
7
|
-
[](https://pypi.org/project/taskuary/)
|
|
8
8
|
[](https://github.com/ldbumble/taskuary)
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
[](https://github.com/ldbumble/taskuary/stargazers)
|
|
@@ -15,11 +15,9 @@
|
|
|
15
15
|
|
|
16
16
|
**A personal AI assistant for your job.** Mail, chats and tickets become tasks, the agents you already use (Claude Code, Codex, Gemini) do the work, and nothing goes out until you approve. Open source, runs on your machine, no subscription.
|
|
17
17
|
|
|
18
|
-
Compared with hosted assistants like Fyxer, Taskuary is free and open source, runs on your machine, and hands the work to agents you already use.
|
|
19
|
-
|
|
20
18
|

|
|
21
19
|
|
|
22
|
-
Taskuary is early—currently **v0.3.9.
|
|
20
|
+
Taskuary is early—currently **v0.3.9.4**—so breaking changes are still possible before 1.0.
|
|
23
21
|
|
|
24
22
|
<p align="center">
|
|
25
23
|
<a href="https://taskuary.com/demo/"><img
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "taskuary"
|
|
7
|
-
version = "0.3.9.
|
|
7
|
+
version = "0.3.9.4"
|
|
8
8
|
description = "Your work manager. Locally. Securely. In control. Mail, chats and tickets in one list; your agents do the work, you approve. Runs on your machine."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -11,8 +11,9 @@ a per-hour cap, the light gear, a small prompt, the bigger read only for the ite
|
|
|
11
11
|
import hashlib, json, re, threading
|
|
12
12
|
from datetime import datetime, timedelta
|
|
13
13
|
from loguru import logger
|
|
14
|
-
from . import concierge
|
|
14
|
+
from . import buttons, concierge
|
|
15
15
|
from .llm import build_llm, ask_json
|
|
16
|
+
L = buttons.label # the prompt names a button by its one label (buttons.json)
|
|
16
17
|
|
|
17
18
|
ON_KEY, CAP_KEY, CAP_DEFAULT = 'advisor_events', 'advisor_event_cap', 30
|
|
18
19
|
BACKGROUND = True # the suite turns this off (tests/conftest.py): a judgement runs only when a test asks for it inline
|
|
@@ -24,6 +25,12 @@ def target_of(store, key: str):
|
|
|
24
25
|
"""A rail key -> (target kind, id), or None for a key with nothing to advise on (a connection, a meeting, a batch)."""
|
|
25
26
|
m = re.match(r'^(task|agent|wrap|msg|report):(\d+)$', str(key or ''))
|
|
26
27
|
if m: return ('task' if m.group(1) in ('task', 'agent', 'wrap') else 'message', int(m.group(2)))
|
|
28
|
+
# a draft waiting for your yes is keyed by its review (funnel's review:N, in a bare store and the demo): advised as the
|
|
29
|
+
# task it answers for, else the message - read as "nothing to advise on", every draft on the demo's rail had an empty bar
|
|
30
|
+
m = re.match(r'^review:(\d+)$', str(key or ''))
|
|
31
|
+
if m:
|
|
32
|
+
r = store.get_review(int(m.group(1))) or {}
|
|
33
|
+
return ('task', int(r['TaskId'])) if r.get('TaskId') else ('message', int(r['MessageId'])) if r.get('MessageId') else None
|
|
27
34
|
if str(key or '').startswith('processing:'):
|
|
28
35
|
# the inventory's key names an ITEM; its members say what it is made of (a task outranks its mail rows)
|
|
29
36
|
try:
|
|
@@ -55,9 +62,30 @@ def _write(store, *, target_kind, target_id, key, event, revision, tier=1, line=
|
|
|
55
62
|
'VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
|
|
56
63
|
(target_kind, int(target_id), key, event, revision, int(tier), line or '', verb, label, json.dumps(list(count)),
|
|
57
64
|
json.dumps(list(evidence)), model, dropped, _now()))
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
# A drop for an OUTSIDE reason is not a verdict on the item: with no AI, opening an item wrote "no brain" and the line never
|
|
66
|
+
# came once one was connected; 30 reads in an hour left every later item a "cap" for good (2026-10-17 audit). The next look
|
|
67
|
+
# tries again. "nothing to say", "verb not offered", "no item", "no actions" stand for the revision.
|
|
68
|
+
RETRY = ('no brain', 'cap', 'no answer')
|
|
69
|
+
def retryable(r) -> bool: return bool(r) and not r.get('Verb') and str(r.get('Dropped') or '').startswith(RETRY)
|
|
70
|
+
def _at(store, target_kind, target_id, revision, own=None) -> list:
|
|
71
|
+
"""The rows at this revision - only those written for the item whose keys are `own`, when given."""
|
|
72
|
+
rs = store._rows('SELECT * FROM advice WHERE TargetKind=? AND TargetId=? AND Revision=? ORDER BY Id DESC', (target_kind, int(target_id), revision))
|
|
73
|
+
return rs if own is None else [r for r in rs if r.get('Key') in own]
|
|
74
|
+
def row(store, target_kind: str, target_id, revision: str, own=None):
|
|
75
|
+
"""The row that stands at this revision: the newest with a verb at any tier - a later tier-2 drop sorted first by tier hid
|
|
76
|
+
a good tier-1 line - else the newest verdict. Retryable drops are never it."""
|
|
77
|
+
rs = _at(store, target_kind, target_id, revision, own)
|
|
78
|
+
return next((r for r in rs if r.get('Verb')), None) or next((r for r in rs if not retryable(r)), None)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ADVICE IS KEYED TO ITS ITEM: one task can stand on the rail twice - its draft (review:N) and its agent (agent:N) - and a line
|
|
82
|
+
# written for one, with a verb only that one's row carries, stood over the other (2026-10-18). A row belongs to the item it was
|
|
83
|
+
# judged as: its rail key, or a key that names that same item (its aliases: task:N for the processing inventory's key).
|
|
84
|
+
def keys_of(item: dict | None, key: str = None) -> set:
|
|
85
|
+
return {k for k in (key, *((item or {}).get('key'), *((item or {}).get('aliases') or []))) if k}
|
|
86
|
+
def _own(store, tgt, key: str, rs: list) -> set:
|
|
87
|
+
"""The keys whose rows are `key`'s - read off the item only when a row at this revision was written under another key."""
|
|
88
|
+
return {key} if all(r.get('Key') == key for r in rs) else keys_of(_item(store, *tgt, key=key), key)
|
|
61
89
|
def rows(store, target_kind: str, target_id, limit: int = 10) -> list:
|
|
62
90
|
return store._rows('SELECT * FROM advice WHERE TargetKind=? AND TargetId=? ORDER BY Id DESC LIMIT ?', (target_kind, int(target_id), limit))
|
|
63
91
|
|
|
@@ -69,7 +97,8 @@ SYSTEM = (
|
|
|
69
97
|
"the item's own facts point at one verb. Never invent a number: the numbers in the ledger lines are the only ones you may use, "
|
|
70
98
|
"and you cite their ids. A ledger line says what HAPPENED, never whether it worked: \"continued\" means the session was started "
|
|
71
99
|
"again, nothing more - never call it a success, and never say something was merged, sent or fixed unless a line says exactly that. "
|
|
72
|
-
"The line is plain words for the owner: the ids go in \"evidence\" only,
|
|
100
|
+
"The line is plain words for the owner, who may never have written code: the ids go in \"evidence\" only, the verb is named by "
|
|
101
|
+
"its label, never its id, and never a word from the item's own bookkeeping (lane, kind, triage, session, model, an event name). "
|
|
73
102
|
"The reason must be the fact that makes THIS verb right, and it must hold up on its own: someone or an agent waiting on the "
|
|
74
103
|
"owner is a reason to answer, never a reason to put it off. Ending an agent's session is right when its work is done or no "
|
|
75
104
|
"longer wanted; when it has finished something for the owner to review or send, the move is the one that reviews or sends it. If none of the verbs offered is the right move, say nothing - a "
|
|
@@ -77,8 +106,18 @@ SYSTEM = (
|
|
|
77
106
|
"Answer with JSON only:{\"verb\": \"<one of the verbs>\" or null, \"line\": \"<sentence>\" or \"\", "
|
|
78
107
|
"\"evidence\": [\"<ids from the lines below>\"]}. "
|
|
79
108
|
"EXCEPT when the EVENT is item.shown: the owner is looking at this item right now and is owed a next step, so pick the verb the "
|
|
80
|
-
"item's own facts make right (a person waiting on them:
|
|
81
|
-
"
|
|
109
|
+
f"item's own facts make right (a person waiting on them: {L('reply')}; an agent asking them something: {L('answer_agent')}; nothing "
|
|
110
|
+
f"for them to do: {L('close')} or {L('let_go')}; work an agent left: {L('continue')} or {L('approve')}; a draft waiting: {L('approve')}; "
|
|
111
|
+
f"a reply already sent - sending never closes the task - and nothing left to do: {L('close')}; a reply that failed to "
|
|
112
|
+
"send: the fix offered with it) - whichever of those is "
|
|
113
|
+
"OFFERED - and say why in plain words - say nothing only when no verb offered fits at all.")
|
|
114
|
+
def _system(store) -> str:
|
|
115
|
+
"""SYSTEM plus the owner's own Voice section of COUNSEL: the Advisor's line sits in the same box as the chat's, so it
|
|
116
|
+
speaks by the same rules - it never had them, and said "lane" and "session" to a finance user (2026-10-17 audit)."""
|
|
117
|
+
from . import counsel
|
|
118
|
+
try: voice = counsel.sections(counsel.load(store)).get(counsel.VOICE_HEAD, '').strip()
|
|
119
|
+
except Exception: voice = ''
|
|
120
|
+
return f"{SYSTEM}\n\nHOW THE LINE SPEAKS (the owner's own rules):\n{voice}" if voice else SYSTEM
|
|
82
121
|
# the event every item on the table gets, when no other event judged it at its current revision (Advisor audit, 2026-10-15)
|
|
83
122
|
SHOWN = 'item.shown'
|
|
84
123
|
WANT = {'type': 'object', 'properties': {'verb': {'type': ['string', 'null']}, 'line': {'type': 'string'},
|
|
@@ -86,9 +125,10 @@ WANT = {'type': 'object', 'properties': {'verb': {'type': ['string', 'null']}, '
|
|
|
86
125
|
_EV = re.compile(r'^(out|mem|rv|task)\d+$')
|
|
87
126
|
|
|
88
127
|
|
|
89
|
-
def _item(store, target_kind, target_id):
|
|
90
|
-
"""The card the rail would show for this target -
|
|
91
|
-
processing inventory's (`processing:...`) in a real install and a legacy
|
|
128
|
+
def _item(store, target_kind, target_id, key: str = None):
|
|
129
|
+
"""The card the rail would show for this target - the one keyed `key` when asked for an item (keys_of), else found by its task
|
|
130
|
+
or message id, since the rail's key spelling is the processing inventory's (`processing:...`) in a real install and a legacy
|
|
131
|
+
alias in a bare store."""
|
|
92
132
|
from . import funnel
|
|
93
133
|
if target_kind == 'task':
|
|
94
134
|
t = store.get_task(target_id) or {}
|
|
@@ -98,7 +138,9 @@ def _item(store, target_kind, target_id):
|
|
|
98
138
|
items = (funnel.full_items(store) or []) + pile # read items kept: the one on the table is often read
|
|
99
139
|
except Exception: items = []
|
|
100
140
|
f = 'tid' if target_kind == 'task' else 'mid'
|
|
101
|
-
|
|
141
|
+
mine = [i for i in items if i.get(f) == int(target_id)]
|
|
142
|
+
return (next((i for i in mine if key and key in keys_of(i)), None) or next(iter(mine), None)
|
|
143
|
+
or funnel.item_for_key(store, key_of(target_kind, target_id)))
|
|
102
144
|
|
|
103
145
|
|
|
104
146
|
def habit(store, verb: str, item: dict) -> tuple:
|
|
@@ -112,6 +154,15 @@ def habit(store, verb: str, item: dict) -> tuple:
|
|
|
112
154
|
lambda r: json.loads(r['f'] or '{}').get('answer_days') is not None)}.get(verb)
|
|
113
155
|
if not q: return (0, 0)
|
|
114
156
|
rs = store._rows(q[0]); return (sum(1 for r in rs if q[1](r)), len(rs))
|
|
157
|
+
# ...and what each count MEASURES, said so: "You chose Mark done 2 of 3 times in a moment like this" was read off closes that
|
|
158
|
+
# held and answers to nudges, counted over every item, not this kind of moment (2026-10-17 audit)
|
|
159
|
+
MEASURES = {'continue': 'You picked the work back up {n} of the last {m} times an agent stopped',
|
|
160
|
+
'approve': 'You sent {n} of your last {m} drafts as written',
|
|
161
|
+
'close': '{n} of the last {m} tasks you closed stayed closed',
|
|
162
|
+
'chase': '{n} of your last {m} nudges got an answer'}
|
|
163
|
+
def says(verb: str, count) -> str:
|
|
164
|
+
n, m = (list(count) + [0, 0])[:2]
|
|
165
|
+
return MEASURES[verb].format(n=n, m=m) + '.' if verb in MEASURES and m >= 2 else ''
|
|
115
166
|
def pill(label: str, count) -> str:
|
|
116
167
|
n, m = (list(count) + [0, 0])[:2]
|
|
117
168
|
return f'{label} · {n} of {m} times' if m >= 2 else str(label or '')
|
|
@@ -120,7 +171,12 @@ def pill(label: str, count) -> str:
|
|
|
120
171
|
def _prompt(store, event, item, verbs, tier, target_kind, target_id) -> str:
|
|
121
172
|
from .learn import injectable
|
|
122
173
|
from . import outcomes
|
|
123
|
-
|
|
174
|
+
from . import funnel
|
|
175
|
+
facts = {k: item.get(k) for k in ('ref', 'title', 'who', 'when', 'why', 'channel') if item.get(k)}
|
|
176
|
+
# where it stands, in the rail's own words - a lane id handed over as-is came back in the line ("the lane is blocked")
|
|
177
|
+
kinds = {k['key']: k['word'] for k in funnel._VOCAB['kinds']}
|
|
178
|
+
stands = kinds.get(item.get('kind')) or funnel.LANE_WORDS.get(item.get('lane'), ('',))[0]
|
|
179
|
+
if stands: facts['where it stands'] = stands
|
|
124
180
|
lines = [f'EVENT: {event}', 'THE ITEM: ' + json.dumps(facts), f"PREVIEW: {str(item.get('preview') or '')[:300]}",
|
|
125
181
|
'VERBS OFFERED: ' + ', '.join(f"{v['verb']} ({v['label']})" for v in verbs)]
|
|
126
182
|
if target_kind == 'task':
|
|
@@ -139,7 +195,7 @@ def _prompt(store, event, item, verbs, tier, target_kind, target_id) -> str:
|
|
|
139
195
|
at = continuity.last_agent_turn(store, int(target_id))
|
|
140
196
|
mail = continuity.mail_since(store, int(target_id), at) if at else []
|
|
141
197
|
if mail:
|
|
142
|
-
lines.append(f"NEW SINCE THE AGENT'S LAST TURN ({at}) - its saved conversation is from BEFORE these;
|
|
198
|
+
lines.append(f"NEW SINCE THE AGENT'S LAST TURN ({at}) - its saved conversation is from BEFORE these; Keep going hands "
|
|
143
199
|
"them to it first:\n" + '\n'.join(f"- {m.get('FromName') or m.get('FromEmail')} ({m.get('CreatedAt')}): {m.get('Subject') or ''}"
|
|
144
200
|
f" - {' '.join(str(m.get('BodyText') or '').split())[:500]}" for m in mail[-3:]))
|
|
145
201
|
t = store.get_task(int(target_id)) or {}
|
|
@@ -149,7 +205,7 @@ def _prompt(store, event, item, verbs, tier, target_kind, target_id) -> str:
|
|
|
149
205
|
lrn = injectable(store.doc('learned') or '')
|
|
150
206
|
if lrn.strip(): lines.append('LEARNED (the owner, from their own verdicts):\n' + lrn[:2000])
|
|
151
207
|
led = [f"out{r['Id']}: {outcomes._sentence(store, r)}" for r in outcomes.rows_for(store, target_kind, target_id) if r.get('ResolvedAt')][:5]
|
|
152
|
-
led += [f"{v['
|
|
208
|
+
led += [f"{v['label']}: {says(v['verb'], c)}" for v in verbs for c in [habit(store, v['verb'], item)] if says(v['verb'], c)]
|
|
153
209
|
if led: lines.append('THE OUTCOME LEDGER (what came of actions like this):\n' + '\n'.join(led))
|
|
154
210
|
if tier >= 2: # the bigger read, only for the item on the table
|
|
155
211
|
from .counsel import dossier
|
|
@@ -173,27 +229,39 @@ def plain(line: str, verb: str, label: str) -> str:
|
|
|
173
229
|
|
|
174
230
|
|
|
175
231
|
def _offered(verbs: list, said: str):
|
|
176
|
-
"""The verb the model named, as the prompt listed it: "approve (Send
|
|
232
|
+
"""The verb the model named, as the prompt listed it: "approve (Send)" copied whole, the bare id, or the label alone -
|
|
177
233
|
an exact-id match dropped three right answers as "verb not offered" (2026-10-13)."""
|
|
178
234
|
w = ' '.join(str(said or '').split()).lower(); bare = re.sub(r'\s*\(.*\)\s*$', '', w)
|
|
179
235
|
return next((v for v in verbs if w in (v['verb'].lower(), f"{v['verb']} ({v['label']})".lower(), str(v['label']).lower())
|
|
180
236
|
or bare == v['verb'].lower()), None)
|
|
181
237
|
|
|
182
238
|
|
|
183
|
-
def judge(store, event: str,target_kind: str, target_id, rev: str, tier: int = 1, llm=None) -> int:
|
|
184
|
-
key
|
|
239
|
+
def judge(store, event: str,target_kind: str, target_id, rev: str, tier: int = 1, llm=None, key: str = None) -> int:
|
|
240
|
+
"""Judge one item at one revision - the item keyed `key` when the strip asked for it, else the target's first card - and
|
|
241
|
+
write the row under that item's own key (keys_of), so it is never read back over another item of the same task."""
|
|
242
|
+
item = _item(store, target_kind, target_id, key)
|
|
243
|
+
key = (item or {}).get('key') or key or key_of(target_kind, target_id)
|
|
244
|
+
own = keys_of(item, key)
|
|
185
245
|
def W(**kw): return _write(store, target_kind=target_kind, target_id=target_id, key=key, event=event, revision=rev, tier=tier, **kw)
|
|
186
|
-
item = _item(store, target_kind, target_id)
|
|
187
246
|
if not item: return W(dropped='no item')
|
|
188
|
-
|
|
247
|
+
if quiet(item): return W(dropped='left to the item')
|
|
248
|
+
verbs = offered(store, item)
|
|
189
249
|
if not verbs: return W(dropped='no actions')
|
|
250
|
+
have = row(store, target_kind, target_id, rev, own) # two events in one poll: the second finds the first's row
|
|
251
|
+
if judged(have, tier): return have['Id']
|
|
190
252
|
brain = llm or build_llm(store)
|
|
191
|
-
if not brain:
|
|
192
|
-
|
|
193
|
-
|
|
253
|
+
if not brain:
|
|
254
|
+
# once per revision, and said: the strip asks for an AI (for_key's {"none": "no_ai"}) - a repeat would loop the re-read
|
|
255
|
+
last = next(iter(_at(store, target_kind, target_id, rev, own)), None)
|
|
256
|
+
if last and last.get('Dropped') == 'no brain': return last['Id']
|
|
257
|
+
rid = W(dropped='no brain'); _emit(key, target_kind, target_id); return rid
|
|
194
258
|
model = getattr(brain, 'last_pick', None) or getattr(brain, 'model', None) or 'light'
|
|
195
|
-
ans = ask_json(brain,
|
|
259
|
+
ans = ask_json(brain, _system(store), _prompt(store, event, item, verbs, tier, target_kind, target_id), want=WANT, max_tokens=200)
|
|
196
260
|
d = ans.data if isinstance(ans.data, dict) else {}
|
|
261
|
+
# a line that landed while this one was thinking stands: a tier-2 answer, drop or not, never replaces a line the owner may
|
|
262
|
+
# already be reaching for (B5 - the filled button moved under the cursor seconds after the item opened)
|
|
263
|
+
now = row(store, target_kind, target_id, rev, own)
|
|
264
|
+
if now and now.get('Verb'): return now['Id']
|
|
197
265
|
if not d: return W(dropped=f'no answer: {ans.error or "not an object"}'[:200], model=model)
|
|
198
266
|
verb, line = d.get('verb'), ' '.join(str(d.get('line') or '').split())[:200]
|
|
199
267
|
ev = [e for e in (d.get('evidence') or []) if isinstance(e, str) and _EV.match(e)][:6]
|
|
@@ -203,11 +271,58 @@ def judge(store, event: str,target_kind: str, target_id, rev: str, tier: int = 1
|
|
|
203
271
|
if not hit: return W(dropped=f'verb not offered: {verb}'[:120], model=model, line=line, evidence=ev)
|
|
204
272
|
line = plain(line, verb, hit['label'])
|
|
205
273
|
rid = W(line=line, verb=verb, label=hit['label'],count=habit(store, verb, item), evidence=ev, model=model)
|
|
274
|
+
_emit(key, target_kind, target_id); return rid
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _emit(key, target_kind, target_id):
|
|
206
278
|
try:
|
|
207
279
|
from . import live
|
|
208
280
|
live.emit(live.ADVICE, key=key, target_kind=target_kind, target_id=int(target_id))
|
|
209
281
|
except Exception: pass
|
|
210
|
-
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def judged(have, tier: int) -> bool:
|
|
285
|
+
"""A line stands at any tier (the bigger read runs only where the first one found none); a verdict drop stands for its own
|
|
286
|
+
tier and below, so the item on the table still earns the bigger read after the small one said nothing."""
|
|
287
|
+
return bool(have) and (bool(have.get('Verb')) or int(have.get('Tier') or 1) >= tier)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def quiet(item: dict) -> bool:
|
|
291
|
+
"""Where the Advisor keeps out of it. Mail the AI never sorted: the row's own Sort it again is the move, and the Advisor,
|
|
292
|
+
offered only Make a task / Send to agent / Not ours, put the dark button on "Not ours" for mail nobody read. A report that
|
|
293
|
+
ran fine: it is read, not acted on, and the only verbs it carries create work (2026-10-17 audit)."""
|
|
294
|
+
return item.get('lane') == 'unjudged' or (item.get('kind') == 'report' and not item.get('bad'))
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def delivery_fix(store, item: dict) -> dict | None:
|
|
298
|
+
"""{label, href} of the place that fixes the item's failed send - the draft's envelope (Deliver.fix, kept across a reload),
|
|
299
|
+
else the newest act on the item when it failed with one (OutcomeJson.fix). None when nothing failed, or it named no place."""
|
|
300
|
+
ok = lambda f: f if isinstance(f, dict) and f.get('label') and f.get('href') else None
|
|
301
|
+
r = (store.get_review(int(item['rid'])) if item.get('rid') else None) or {}
|
|
302
|
+
try: env = json.loads(r.get('Deliver') or '{}') or {}
|
|
303
|
+
except (TypeError, ValueError): env = {}
|
|
304
|
+
if isinstance(env, dict) and (r.get('DeliveryState') or env.get('delivery')) == 'failed' and ok(env.get('fix')): return ok(env['fix'])
|
|
305
|
+
try: ops = store.operations_for(item.get('tid'), [item['mid']] if item.get('mid') else [])
|
|
306
|
+
except Exception: ops = []
|
|
307
|
+
last = ops[-1] if ops else {}
|
|
308
|
+
try: out = json.loads(last.get('OutcomeJson') or '{}') if last.get('Status') == 'error' else {}
|
|
309
|
+
except (TypeError, ValueError): out = {}
|
|
310
|
+
return ok((out or {}).get('fix')) if isinstance(out, dict) else None
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def offered(store, item: dict) -> list:
|
|
314
|
+
"""THE ITEM'S REAL BUTTONS, AND NOTHING IT CANNOT DO: the verbs its row carries minus Next - chips_for, which already drops
|
|
315
|
+
what this install cannot do (capabilities.py: no Send on a draft whose channel cannot send, no coding agent with no
|
|
316
|
+
coding tool) - plus the row's own fix when a send failed and named the place that fixes it, under that place's own name.
|
|
317
|
+
An agent waiting on the owner carries Answer it there (chips_for) - its card once offered only End and Remind me, which the
|
|
318
|
+
prompt forbids for someone waiting, so the Advisor stood silent (2026-10-17 audit). Not added here: a paused, stalled or
|
|
319
|
+
stopped agent has nobody listening, and the row knows which is which."""
|
|
320
|
+
verbs = [c for c in concierge.chips_for(store, item) if c.get('verb') != 'next']
|
|
321
|
+
try: fix = delivery_fix(store, item)
|
|
322
|
+
except Exception as e:
|
|
323
|
+
logger.debug(f'advisor: no fix read for {item.get("key")} - {e}'); fix = None
|
|
324
|
+
# the fix leads: a send that failed is fixed before it is sent again (ReviewDecision.jsx draws it as '<rid>:fix')
|
|
325
|
+
return ([buttons.chip('fix') | {'label': fix['label'], 'href': fix['href']}] if fix else []) + verbs
|
|
211
326
|
|
|
212
327
|
|
|
213
328
|
def _capped(store) -> bool:
|
|
@@ -220,27 +335,31 @@ def _capped(store) -> bool:
|
|
|
220
335
|
_INFLIGHT, _LOCK = set(), threading.Lock() # (kind, id, revision, tier) being judged right now
|
|
221
336
|
|
|
222
337
|
|
|
223
|
-
def notice(store, event: str, target_kind: str, target_id, *, tier: int = 1, wait: bool = False, llm=None):
|
|
224
|
-
"""The one door every event calls. Never raises: a hook, a close or a poll must not fail for advice.
|
|
338
|
+
def notice(store, event: str, target_kind: str, target_id, *, tier: int = 1, wait: bool = False, llm=None, key: str = None):
|
|
339
|
+
"""The one door every event calls. Never raises: a hook, a close or a poll must not fail for advice. `key` is the item the
|
|
340
|
+
strip asked for (for_key): only that item's rows count as judged. An event names a target, and any row at its revision does.
|
|
225
341
|
Returns the row id when judged inline (tests, `wait=True`), None when skipped or sent to the background."""
|
|
226
342
|
try:
|
|
227
343
|
if str(store.get_setting(ON_KEY, '1') or '1') != '1' or not target_id: return None
|
|
228
344
|
rev = revision(store, target_kind, target_id)
|
|
229
|
-
|
|
230
|
-
if
|
|
231
|
-
if _capped(store):
|
|
232
|
-
|
|
345
|
+
own = _own(store, (target_kind, target_id), key, _at(store, target_kind, target_id, rev)) if key else None
|
|
346
|
+
if judged(row(store, target_kind, target_id, rev, own), tier): return None # judged at this revision already
|
|
347
|
+
if _capped(store):
|
|
348
|
+
last = next(iter(_at(store, target_kind, target_id, rev, own)), None)
|
|
349
|
+
if last and last.get('Dropped') == 'cap': return last['Id'] # one cap row per revision, retried next look
|
|
350
|
+
return _write(store, target_kind=target_kind, target_id=target_id, key=key or key_of(target_kind, target_id), event=event, revision=rev, tier=tier, dropped='cap')
|
|
351
|
+
mark = (target_kind, int(target_id), rev, int(tier), key)
|
|
233
352
|
with _LOCK:
|
|
234
353
|
if mark in _INFLIGHT: return None # the same moment, judged on another thread
|
|
235
354
|
_INFLIGHT.add(mark)
|
|
236
355
|
def done():
|
|
237
356
|
with _LOCK: _INFLIGHT.discard(mark)
|
|
238
357
|
if wait:
|
|
239
|
-
try: return judge(store, event, target_kind, target_id, rev, tier, llm)
|
|
358
|
+
try: return judge(store, event, target_kind, target_id, rev, tier, llm, key)
|
|
240
359
|
finally: done()
|
|
241
360
|
if not BACKGROUND: done(); return None
|
|
242
361
|
def go():
|
|
243
|
-
try: judge(store, event, target_kind, target_id, rev, tier, llm)
|
|
362
|
+
try: judge(store, event, target_kind, target_id, rev, tier, llm, key)
|
|
244
363
|
except Exception as e: logger.warning(f'advisor: {event} on {target_kind} {target_id} not judged - {e}')
|
|
245
364
|
finally: done()
|
|
246
365
|
threading.Thread(target=go, daemon=True, name=f'advise-{target_kind}-{target_id}').start()
|
|
@@ -250,8 +369,13 @@ def notice(store, event: str, target_kind: str, target_id, *, tier: int = 1, wai
|
|
|
250
369
|
|
|
251
370
|
def _payload(r: dict) -> dict:
|
|
252
371
|
count = json.loads(r.get('CountJson') or '[0,0]')
|
|
253
|
-
|
|
254
|
-
|
|
372
|
+
# a row judged under an older wording ("Take it myself", "Close out") shows today's name; a state's name (Approve) is kept
|
|
373
|
+
verb = concierge.canon_verb(r['Verb']) if r.get('Verb') else r.get('Verb')
|
|
374
|
+
if r.get('Verb') and not verb: r = {**r, 'Line': ''} # its button is gone (Prep me): the line pointed at nothing
|
|
375
|
+
# a fix is named by the place it opens ("Connect a mailbox"), never the generic button word
|
|
376
|
+
lbl = r['Label'] if r.get('Label') in buttons.labels() or (verb == 'fix' and r.get('Label')) else buttons.label(verb or '') or r.get('Label')
|
|
377
|
+
return {'key': r['Key'], 'line': plain(r['Line'] or '', r['Verb'] or '', lbl or '') if r.get('Line') else r.get('Line'), 'verb': verb, 'label': lbl, 'pill': pill(lbl, count), 'count': count,
|
|
378
|
+
'says': says(r['Verb'] or '', count), 'evidence': json.loads(r.get('EvidenceJson') or '[]'), 'revision': r['Revision'], 'tier': r['Tier'], 'at': r['CreatedAt']}
|
|
255
379
|
|
|
256
380
|
|
|
257
381
|
def _at_work(store, target_kind: str, target_id) -> bool:
|
|
@@ -265,16 +389,28 @@ def _at_work(store, target_kind: str, target_id) -> bool:
|
|
|
265
389
|
|
|
266
390
|
def for_key(store, key: str) -> dict:
|
|
267
391
|
"""What the prompt box shows for the item on the table: the row at the item's CURRENT revision, or nothing. A changed
|
|
268
|
-
item drops its old pill by this one comparison - no cleanup pass. The item on the table earns the bigger read, once
|
|
392
|
+
item drops its old pill by this one comparison - no cleanup pass. The item on the table earns the bigger read, once, and
|
|
393
|
+
only where the small read left no line: a tier-2 answer swapped the line and moved the filled button seconds after the item
|
|
394
|
+
opened, under the owner's hand (B5, 2026-10-17). {"none": "no_ai"} is the strip's cue to ask for an AI."""
|
|
269
395
|
tgt = target_of(store, key)
|
|
270
396
|
if not tgt or _at_work(store, *tgt): return {}
|
|
271
|
-
rev = revision(store, *tgt);
|
|
272
|
-
|
|
397
|
+
rev = revision(store, *tgt); rs = _at(store, tgt[0], tgt[1], rev)
|
|
398
|
+
# only the rows written for THIS item (keys_of): a line judged over the same task's other card is not this one's
|
|
399
|
+
own = _own(store, tgt, key, rs); rs = [x for x in rs if x.get('Key') in own]; r = row(store, tgt[0], tgt[1], rev, own)
|
|
400
|
+
if r and r.get('Verb'):
|
|
401
|
+
out = _payload(r) | {'key': key}
|
|
402
|
+
# a fix is a place, not a proposal: the page opens its href where the row has no '<rid>:fix' of its own to press (a failed
|
|
403
|
+
# act with no draft on the table) - read live, so a fix already made carries no stale link
|
|
404
|
+
if out.get('verb') == 'fix':
|
|
405
|
+
try: f = delivery_fix(store, _item(store, *tgt, key=key) or {})
|
|
406
|
+
except Exception: f = None
|
|
407
|
+
if f: out['href'] = f['href']
|
|
408
|
+
return out
|
|
273
409
|
# NEVER LEFT GUESSING (the owner, 2026-10-15: "the advisor ... should be guiding at all times never leaving it guessing"): only
|
|
274
410
|
# eight events ever judged an item, so a fresh email or a task that moved since its last event had an empty bar for good. The
|
|
275
411
|
# item on the table is judged now, at this revision, once - the line arrives by the `advice` live event the page already reads
|
|
276
|
-
if not r: notice(store, SHOWN, tgt[0], tgt[1], tier=2)
|
|
277
|
-
return
|
|
412
|
+
if not judged(r, 2): notice(store, r['Event'] if r else SHOWN, tgt[0], tgt[1], tier=2, key=key)
|
|
413
|
+
return {'none': 'no_ai'} if rs and rs[0].get('Dropped') == 'no brain' else {}
|
|
278
414
|
|
|
279
415
|
|
|
280
416
|
def notes(store, key: str, limit: int = 10) -> list:
|
|
@@ -294,7 +430,22 @@ def notes(store, key: str, limit: int = 10) -> list:
|
|
|
294
430
|
def block(store, item: dict) -> str:
|
|
295
431
|
"""The Advisor's line for the chat's system prompt, so 'why?' is answered from its evidence - a lookup, not a think."""
|
|
296
432
|
d = for_key(store, (item or {}).get('key') or '') if item else {}
|
|
297
|
-
if not d: return ''
|
|
298
|
-
|
|
433
|
+
if not d.get('verb'): return ''
|
|
434
|
+
# the button's name and what the evidence SAYS: "verb stop_agent; evidence: out13" was handed to the chat as-is, and came
|
|
435
|
+
# back to the owner in its answer (2026-10-17 audit)
|
|
436
|
+
ev = '; '.join(filter(None, (evidence_words(store, e) for e in d['evidence']))) or 'the item itself'
|
|
299
437
|
return (f"THE ADVISOR'S LINE on this item (if the owner asks why, this is the answer; the numbers are the ledger's): "
|
|
300
|
-
f"\"{d['line']}\" -
|
|
438
|
+
f"\"{d['line']}\" - its button is {d['label']}" + (f" ({d['says']})" if d.get('says') else '') + f"; it rests on: {ev}.")
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def evidence_words(store, ev_id: str) -> str:
|
|
442
|
+
"""One evidence id as what it says: an outcome as the ledger's own sentence, anything else as the label it resolves to."""
|
|
443
|
+
try:
|
|
444
|
+
if str(ev_id).startswith('out'):
|
|
445
|
+
from . import outcomes
|
|
446
|
+
r = store._one('SELECT * FROM outcome WHERE Id=?', (int(ev_id[3:]),))
|
|
447
|
+
return outcomes._sentence(store, r) if r else ''
|
|
448
|
+
from .learnedgraph import _resolve
|
|
449
|
+
lbl = _resolve(store, ev_id).get('label')
|
|
450
|
+
return '' if lbl == ev_id else str(lbl or '')
|
|
451
|
+
except Exception: return ''
|
|
@@ -274,11 +274,11 @@ def signed_out_msg(name: str, why: str, cmd: str = '') -> str:
|
|
|
274
274
|
The name that arrives here is the PROFILE's - every install ships one called `coding` - so the
|
|
275
275
|
CLI is read off the command it runs, which is the rule cliinstall.recipe_for exists for. Told
|
|
276
276
|
the profile name, _LOGIN_HOW.get('coding') missed every time and always had."""
|
|
277
|
-
from . import cliinstall
|
|
277
|
+
from . import cliinstall, words
|
|
278
278
|
cli = cliinstall.recipe_for(cmd) or name
|
|
279
279
|
how = _LOGIN_HOW.get(cli, f"run `{cli}` and sign in again")
|
|
280
280
|
return (f"{name} is signed out on this machine ({why.strip()[:160]}). Press Set it up on "
|
|
281
|
-
f"
|
|
281
|
+
f"{words.name('ai_apps')} and sign in there in the pane that opens - or {how} in a terminal.")
|
|
282
282
|
|
|
283
283
|
|
|
284
284
|
# Windows refuses to START some installs rather than failing inside them, and says only
|
|
@@ -451,6 +451,12 @@ def _codex_tool(item: dict):
|
|
|
451
451
|
return None
|
|
452
452
|
|
|
453
453
|
|
|
454
|
+
def coding_ready(store) -> bool:
|
|
455
|
+
"""CODING EXISTS ONLY WHERE A CODING TOOL CAN START (the owner, 2026-10-16: "if no cli tool like cloud api tools no coding"):
|
|
456
|
+
a connected CLI whose command runs on this computer. A ChatGPT sign-in or an API card - HIPAA AI included - is no coding tool."""
|
|
457
|
+
return any(runs_here(conn) for _key, conn in connection_brains(store))
|
|
458
|
+
|
|
459
|
+
|
|
454
460
|
def runs_here(profile: dict) -> bool:
|
|
455
461
|
"""Does this profile's command resolve to something we can start?"""
|
|
456
462
|
try: return bool(_resolve_cmd((profile or {}).get('cmd') or 'claude'))
|
|
@@ -699,7 +705,7 @@ def roster_line(store, a: dict) -> tuple:
|
|
|
699
705
|
try: prof = json.loads(a.get('Config') or '{}')
|
|
700
706
|
except ValueError: prof = {}
|
|
701
707
|
if prof.get('triage_enabled') is False:
|
|
702
|
-
return '', 'not offered
|
|
708
|
+
return '', 'not offered new work - "Can be given new work from your mail" is off', 'not_offered'
|
|
703
709
|
purpose = profile_purpose(a['Name'], prof, a.get('Kind') or 'coding')
|
|
704
710
|
if not purpose: return '', 'no purpose set - triage has nothing to choose it by', 'no_purpose'
|
|
705
711
|
if len(purpose) > ROSTER_PURPOSE_MAX: purpose = purpose[:ROSTER_PURPOSE_MAX - 1].rstrip() + '…'
|
|
@@ -1041,7 +1047,7 @@ def run_acp(profile: dict, prompt: str, trace, resume: str = None, cancel=None,
|
|
|
1041
1047
|
if profile.get('model'):
|
|
1042
1048
|
from .climodels import split_pick
|
|
1043
1049
|
model, _ = split_pick(profile['model'])
|
|
1044
|
-
cmd += [profile.get('model_arg') or '--model', model]
|
|
1050
|
+
if model: cmd += [profile.get('model_arg') or '--model', model]
|
|
1045
1051
|
cwd = profile.get('cwd')
|
|
1046
1052
|
trace('prompt', 'prompt_sent_to_agent', prompt)
|
|
1047
1053
|
trace('tool', 'cli', f'{name} over acp cwd={cwd or os.getcwd()}' + (f' resume={resume}' if resume else ''))
|
|
@@ -1136,7 +1142,8 @@ def run_cli(profile: dict, prompt: str, trace, resume: str = None, cancel=None,
|
|
|
1136
1142
|
from .climodels import split_pick
|
|
1137
1143
|
from .climodels import effort_args
|
|
1138
1144
|
m, eff = split_pick(profile['model'])
|
|
1139
|
-
|
|
1145
|
+
# '@high' is the CLI's own model at that effort (a workflow's effort alone, workflows.brain): no empty model flag
|
|
1146
|
+
cmd += ([profile.get('model_arg') or '--model', m] if m else []) + effort_args(_cli_name(name), eff)
|
|
1140
1147
|
# A CONVERSATION KEPT OPEN: the Assistant and the general agent name theirs (`keep_alive`), and claude's
|
|
1141
1148
|
# stream-json input serves every turn from one process instead of starting the CLI per call (clipool).
|
|
1142
1149
|
keep = profile.get('keep_alive')
|
|
@@ -13,7 +13,7 @@ And "Done" is a plain close - no report, no proposals, no reply draft; the conne
|
|
|
13
13
|
result is the report.
|
|
14
14
|
"""
|
|
15
15
|
import json
|
|
16
|
-
from . import config
|
|
16
|
+
from . import config, words
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
KIND = 'setup'
|
|
@@ -81,7 +81,7 @@ def prompt(c: dict, server: dict, guide: list, fields: list, secret_label: str,
|
|
|
81
81
|
# Nothing to hand the setup to (B10, 2026-10-11): a new install without any AI CLI answered the card's
|
|
82
82
|
# biggest button with "command not found: claude" - true, and nothing the owner could do with it.
|
|
83
83
|
NO_AI = ("No AI app is set up on this computer yet, so there is nothing to hand this setup to. Set one up under "
|
|
84
|
-
"
|
|
84
|
+
f"{words.name('ai_apps')} and press this again - or follow the Guide tab and fill the card yourself.")
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
def runner(store, agent: str = None) -> str:
|
|
@@ -91,7 +91,7 @@ def runner(store, agent: str = None) -> str:
|
|
|
91
91
|
from . import agents as hub, terminal as term
|
|
92
92
|
agent = (agent or hub.default_agent(store)).strip()
|
|
93
93
|
row = store.get_agent(agent)
|
|
94
|
-
if not row: raise ValueError(f'no CLI agent named {agent!r} - add one under
|
|
94
|
+
if not row: raise ValueError(f'no CLI agent named {agent!r} - add one under {words.name("ai_apps")} first')
|
|
95
95
|
profile = term.with_brain(json.loads(row.get('Config') or '{}'), hub.brain_command(store, agent))
|
|
96
96
|
try: hub._resolve_cmd(profile.get('cmd') or 'claude')
|
|
97
97
|
except FileNotFoundError: raise ValueError(NO_AI) from None
|
|
@@ -125,7 +125,7 @@ def start(store, server: dict, cid: int, guide: list, fields: list = None, secre
|
|
|
125
125
|
except Exception as e:
|
|
126
126
|
# found is not always runnable (a shim whose target went): the task this press made goes with it
|
|
127
127
|
if not reused: store.delete_task(tid)
|
|
128
|
-
if isinstance(e, OSError): raise ValueError(f"{agent} is set up here but would not start ({e}). Open
|
|
128
|
+
if isinstance(e, OSError): raise ValueError(f"{agent} is set up here but would not start ({e}). Open {words.name('ai_apps')} "
|
|
129
129
|
"and press Test or Update on it, then press this again.") from None
|
|
130
130
|
raise
|
|
131
131
|
t.keep_transcript = False
|
|
@@ -17,7 +17,8 @@ class AlchemyError(RuntimeError):
|
|
|
17
17
|
def _key(cfg):
|
|
18
18
|
key = str(cfg.get('api_key') or '').strip()
|
|
19
19
|
if not key:
|
|
20
|
-
|
|
20
|
+
from . import words
|
|
21
|
+
raise AlchemyError(f"no Alchemy API key saved - {words.card('Alchemy')}")
|
|
21
22
|
return key
|
|
22
23
|
|
|
23
24
|
|
|
@@ -291,7 +291,7 @@ def stop_watching(store, t: dict, quiet: bool = False) -> str | None:
|
|
|
291
291
|
"""A watch at its 30 days ends, and says so with the way back (watch_task again). One with no start of its own -
|
|
292
292
|
from before watches kept one - ends quietly."""
|
|
293
293
|
from .store import task_ref
|
|
294
|
-
line = None if quiet else f"I've stopped watching for {_who(_waiting_on(store, t))}'s answer on {task_ref(t['TaskId'])} {_title(t)}. Keep going?"
|
|
294
|
+
line = None if quiet else f"I've stopped watching for {_who(_waiting_on(store, t))}'s answer on {task_ref(t['TaskId'])} {_title(t)}. Should I watch for it again?" # "Keep going?" read as the Keep going button
|
|
295
295
|
if line and not _say(store, t, line, desktop=True): return None
|
|
296
296
|
store._exec('UPDATE task SET AskedWatch=NULL WHERE TaskId=?', (t['TaskId'],))
|
|
297
297
|
return line
|