create-workframe 0.1.12 → 0.1.13
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.
- package/README.md +1 -1
- package/bin/create-workframe.js +2 -2
- package/bin/workframe.js +130 -2
- package/docs/security.md +2 -2
- package/package.json +1 -1
- package/scripts/bundle-workframe-ui.mjs +9 -0
- package/scripts/sync-canonical-to-package.mjs +1 -0
- package/scripts/verify-public-deploy.sh +65 -3
- package/workframe-api/action_proxy.py +23 -17
- package/workframe-api/activity_feed.py +798 -0
- package/workframe-api/api_meta.py +157 -0
- package/workframe-api/auth_gate.py +566 -0
- package/workframe-api/avatar_registry.py +343 -0
- package/workframe-api/broker_audit.py +164 -0
- package/workframe-api/cell_authority.py +231 -0
- package/workframe-api/chat_bind.py +319 -0
- package/workframe-api/chat_sessions.py +509 -0
- package/workframe-api/chat_stream.py +694 -0
- package/workframe-api/cleanup_dogfood_smoke.py +252 -0
- package/workframe-api/credential_broker.py +162 -0
- package/workframe-api/credential_resolve.py +202 -0
- package/workframe-api/credential_store.py +245 -0
- package/workframe-api/crew_registry.py +250 -0
- package/workframe-api/db_schema.py +755 -0
- package/workframe-api/docker_gateway.py +166 -0
- package/workframe-api/doctor_runtime.py +109 -0
- package/workframe-api/domain/__init__.py +47 -0
- package/workframe-api/domain/entities.py +252 -0
- package/workframe-api/domain/schema/workframe-domain.schema.json +278 -0
- package/workframe-api/egress_policy.py +42 -0
- package/workframe-api/handler_modules/__init__.py +17 -0
- package/workframe-api/handler_modules/handler_admin.py +542 -0
- package/workframe-api/handler_modules/handler_auth.py +512 -0
- package/workframe-api/handler_modules/handler_chat.py +641 -0
- package/workframe-api/handler_modules/handler_install.py +178 -0
- package/workframe-api/handler_modules/handler_provider.py +325 -0
- package/workframe-api/handler_modules/handler_workspace.py +1420 -0
- package/workframe-api/health_monitor.py +80 -0
- package/workframe-api/hermes_admin.py +756 -0
- package/workframe-api/hermes_profiles.py +1328 -0
- package/workframe-api/install_api.py +123 -0
- package/workframe-api/kanban_cron.py +473 -0
- package/workframe-api/lane_bindings.py +423 -0
- package/workframe-api/llm_proxy.py +17 -43
- package/workframe-api/mention_helpers.py +180 -0
- package/workframe-api/mention_invoke.py +431 -0
- package/workframe-api/model_surface.py +1139 -0
- package/workframe-api/oauth_pending.py +85 -0
- package/workframe-api/oauth_redirect.py +381 -0
- package/workframe-api/package.json +2 -2
- package/workframe-api/profile_api_lifecycle.py +66 -0
- package/workframe-api/profile_gateway.py +436 -0
- package/workframe-api/provider_bindings.py +673 -0
- package/workframe-api/provider_bootstrap.py +347 -0
- package/workframe-api/provider_catalog.py +180 -0
- package/workframe-api/rooms.py +1613 -0
- package/workframe-api/route_registry.py +331 -191
- package/workframe-api/run-typecheck.mjs +2 -1
- package/workframe-api/run_authority.py +287 -0
- package/workframe-api/run_ledger.py +470 -0
- package/workframe-api/run_surface_wiring.py +344 -0
- package/workframe-api/runtime_cohort.py +752 -0
- package/workframe-api/runtime_tokens.py +127 -0
- package/workframe-api/server.py +1453 -19513
- package/workframe-api/snapshot_feed.py +49 -0
- package/workframe-api/stack_config.py +33 -1
- package/workframe-api/supervisor_client.py +154 -0
- package/workframe-api/test_api_meta_build_stamp.py +34 -0
- package/workframe-api/test_cell_authority.py +79 -0
- package/workframe-api/test_chat_bind.py +48 -0
- package/workframe-api/test_credential_lease_matrix.py +171 -0
- package/workframe-api/test_credential_resolve.py +51 -0
- package/workframe-api/test_credential_store.py +27 -0
- package/workframe-api/test_dogfood_flows.py +346 -0
- package/workframe-api/test_domain_entities.py +152 -0
- package/workframe-api/test_exception_hygiene.py +12 -0
- package/workframe-api/test_hermes_admin.py +72 -0
- package/workframe-api/test_install_wizard_resume.py +78 -0
- package/workframe-api/test_local_bootstrap.py +67 -0
- package/workframe-api/test_mention_helpers.py +35 -0
- package/workframe-api/test_mention_invoke.py +26 -0
- package/workframe-api/test_model_surface_consistency.py +1 -0
- package/workframe-api/test_oauth_pending.py +41 -0
- package/workframe-api/test_provider_bindings.py +52 -0
- package/workframe-api/test_provider_catalog.py +28 -0
- package/workframe-api/test_route_registry.py +171 -35
- package/workframe-api/test_run_authority.py +112 -0
- package/workframe-api/test_run_ledger.py +157 -0
- package/workframe-api/test_run_surface_wiring.py +130 -0
- package/workframe-api/test_runtime_cohort.py +85 -0
- package/workframe-api/test_secure_mode_docker_boundary.py +39 -0
- package/workframe-api/test_server_reexports.py +99 -0
- package/workframe-api/test_stack_config_install_smtp.py +7 -0
- package/workframe-api/turn_credentials.py +28 -13
- package/workframe-api/turn_overlay.py +715 -0
- package/workframe-api/updates.py +16 -1
- package/workframe-api/user_prefs.py +387 -0
- package/workframe-api/wf032_extract_remaining_handlers.py +417 -0
- package/workframe-api/workspace_bootstrap.py +536 -0
- package/workframe-api/workspace_files.py +344 -0
- package/workframe-api/workspace_messaging.py +206 -0
- package/workframe-api/zk_auth.py +3 -2
- package/workframe-supervisor/server.py +10 -1
- package/workframe-supervisor/test_supervisor_negative.py +75 -0
- package/workframe-ui/public/assets/{arc-B0OFRGmJ.js → arc-aUUffclm.js} +1 -1
- package/workframe-ui/public/assets/architecture-7EHR7CIX-BSUP4S8J.js +1 -0
- package/workframe-ui/public/assets/{architectureDiagram-3BPJPVTR-DeBNltHS.js → architectureDiagram-3BPJPVTR-DU6oaqIb.js} +1 -1
- package/workframe-ui/public/assets/{blockDiagram-GPEHLZMM-BDhCHu7I.js → blockDiagram-GPEHLZMM-D2p8BU6-.js} +1 -1
- package/workframe-ui/public/assets/{c4Diagram-AAUBKEIU-olcDYvtI.js → c4Diagram-AAUBKEIU-ouwyPmTJ.js} +1 -1
- package/workframe-ui/public/assets/channel-DOunZZ0X.js +1 -0
- package/workframe-ui/public/assets/{chunk-2J33WTMH-D0obCBn_.js → chunk-2J33WTMH-DsE7U5dj.js} +1 -1
- package/workframe-ui/public/assets/{chunk-3OPIFGDE-DX93f-ZZ.js → chunk-3OPIFGDE-DM0kkZ9h.js} +1 -1
- package/workframe-ui/public/assets/{chunk-4BX2VUAB-BX9B5wUs.js → chunk-4BX2VUAB-CQ8mAyXp.js} +1 -1
- package/workframe-ui/public/assets/{chunk-55IACEB6-C4DGc6RO.js → chunk-55IACEB6-DN1BDtbH.js} +1 -1
- package/workframe-ui/public/assets/{chunk-5ZQYHXKU-Crlja9Lf.js → chunk-5ZQYHXKU-BzK2KqOt.js} +1 -1
- package/workframe-ui/public/assets/{chunk-727SXJPM-JYSm3szI.js → chunk-727SXJPM-C3AxtOi9.js} +1 -1
- package/workframe-ui/public/assets/{chunk-AQP2D5EJ-_KslxVEl.js → chunk-AQP2D5EJ-4mVwEFuD.js} +1 -1
- package/workframe-ui/public/assets/{chunk-BSJP7CBP-CpTO-jU8.js → chunk-BSJP7CBP-23kN2q0A.js} +1 -1
- package/workframe-ui/public/assets/{chunk-CSCIHK7Q-JGUkCmbI.js → chunk-CSCIHK7Q-CPBKVW-L.js} +2 -2
- package/workframe-ui/public/assets/{chunk-FMBD7UC4-BscBwGaC.js → chunk-FMBD7UC4-CKqcYq7K.js} +1 -1
- package/workframe-ui/public/assets/{chunk-KSCS5N6A-5ZTZ0bpX.js → chunk-KSCS5N6A-JRQnhxQE.js} +1 -1
- package/workframe-ui/public/assets/{chunk-L5ZTLDWV-DxvitYbW.js → chunk-L5ZTLDWV-BLZrdIwa.js} +1 -1
- package/workframe-ui/public/assets/chunk-LZXEDZCA-DisG0XJT.js +2 -0
- package/workframe-ui/public/assets/{chunk-ND2GUHAM-Cayl0iV9.js → chunk-ND2GUHAM-ClAOxArS.js} +1 -1
- package/workframe-ui/public/assets/{chunk-NZK2D7GU-_7dyBR5G.js → chunk-NZK2D7GU-XUE1aNkm.js} +1 -1
- package/workframe-ui/public/assets/{chunk-O5CBEL6O--xTpD0yi.js → chunk-O5CBEL6O-DDN-Ifon.js} +1 -1
- package/workframe-ui/public/assets/chunk-QZHKN3VN-EVQ0VMd5.js +1 -0
- package/workframe-ui/public/assets/chunk-WU5MYG2G-k_-ZsLOS.js +1 -0
- package/workframe-ui/public/assets/{chunk-XPW4576I-CwxJQaeK.js → chunk-XPW4576I-B4_iYZ6r.js} +1 -1
- package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-W9WVQsby.js +1 -0
- package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-W9WVQsby.js +1 -0
- package/workframe-ui/public/assets/{cose-bilkent-S5V4N54A-CCspENYv.js → cose-bilkent-S5V4N54A-Cy1HhS7j.js} +1 -1
- package/workframe-ui/public/assets/{dagre-BM42HDAG-Dv8V6R60.js → dagre-BM42HDAG-Bjal81Ie.js} +1 -1
- package/workframe-ui/public/assets/{diagram-2AECGRRQ-Da48hFPT.js → diagram-2AECGRRQ-v5Gdvzp_.js} +1 -1
- package/workframe-ui/public/assets/{diagram-5GNKFQAL-dTihc7-3.js → diagram-5GNKFQAL-DuyRdfmY.js} +1 -1
- package/workframe-ui/public/assets/{diagram-KO2AKTUF-D_Jqu699.js → diagram-KO2AKTUF-WwWCGbIW.js} +1 -1
- package/workframe-ui/public/assets/{diagram-LMA3HP47-Bt8PtEaZ.js → diagram-LMA3HP47-DTYwZALT.js} +1 -1
- package/workframe-ui/public/assets/{diagram-OG6HWLK6-BtmPjlh0.js → diagram-OG6HWLK6-B46kBIqE.js} +1 -1
- package/workframe-ui/public/assets/{dist-Cz2turIT.js → dist-mQWmB3z6.js} +1 -1
- package/workframe-ui/public/assets/{erDiagram-TEJ5UH35-BxMGCflX.js → erDiagram-TEJ5UH35-__40xO-y.js} +1 -1
- package/workframe-ui/public/assets/eventmodeling-FCH6USID-Cm1uRTxU.js +1 -0
- package/workframe-ui/public/assets/{flowDiagram-I6XJVG4X-ivyroIZt.js → flowDiagram-I6XJVG4X-Cwj6dVUz.js} +1 -1
- package/workframe-ui/public/assets/{ganttDiagram-6RSMTGT7-B9llwShx.js → ganttDiagram-6RSMTGT7-D_IOSwAS.js} +1 -1
- package/workframe-ui/public/assets/{gitGraph-WXDBUCRP-BFQHk4bw.js → gitGraph-WXDBUCRP-C1vGecee.js} +1 -1
- package/workframe-ui/public/assets/{gitGraphDiagram-PVQCEYII-ursegLbc.js → gitGraphDiagram-PVQCEYII-DMTxFJxn.js} +1 -1
- package/workframe-ui/public/assets/index-BdiM4-lI.js +130 -0
- package/workframe-ui/public/assets/index-Fnad47vV.css +1 -0
- package/workframe-ui/public/assets/{info-J43DQDTF-DQpifAsB.js → info-J43DQDTF-CwjmyPmD.js} +1 -1
- package/workframe-ui/public/assets/{infoDiagram-5YYISTIA-C16XP2Q7.js → infoDiagram-5YYISTIA-BGzh7ZL2.js} +1 -1
- package/workframe-ui/public/assets/{ishikawaDiagram-YF4QCWOH-CiJoz7rP.js → ishikawaDiagram-YF4QCWOH-BLXdnR_5.js} +1 -1
- package/workframe-ui/public/assets/{journeyDiagram-JHISSGLW-CVwEvvUL.js → journeyDiagram-JHISSGLW-BK3behMe.js} +1 -1
- package/workframe-ui/public/assets/{kanban-definition-UN3LZRKU-CWQ6hX5i.js → kanban-definition-UN3LZRKU-Bx172cCl.js} +1 -1
- package/workframe-ui/public/assets/{line-CgQsmU35.js → line-BTCEHb7l.js} +1 -1
- package/workframe-ui/public/assets/{linear-Bxbc77dL.js → linear-CkbydpnK.js} +1 -1
- package/workframe-ui/public/assets/{mermaid-parser.core-C_jMeF0a.js → mermaid-parser.core-DvrtArpk.js} +2 -2
- package/workframe-ui/public/assets/{mermaid.core-4RKV9MZP.js → mermaid.core-yj_1x_qj.js} +3 -3
- package/workframe-ui/public/assets/{mindmap-definition-RKZ34NQL-DZ7y7Sz0.js → mindmap-definition-RKZ34NQL-BXbMltQ0.js} +1 -1
- package/workframe-ui/public/assets/{packet-YPE3B663-B9h2I7Vq.js → packet-YPE3B663-9pVCBQ7S.js} +1 -1
- package/workframe-ui/public/assets/{pie-LRSECV5Y-B2mP5uHm.js → pie-LRSECV5Y-CdqoWesP.js} +1 -1
- package/workframe-ui/public/assets/{pieDiagram-4H26LBE5-DyYKyKiP.js → pieDiagram-4H26LBE5-kGs-VfXd.js} +1 -1
- package/workframe-ui/public/assets/{quadrantDiagram-W4KKPZXB-CL_6nej-.js → quadrantDiagram-W4KKPZXB-D9D8gQw5.js} +1 -1
- package/workframe-ui/public/assets/{radar-GUYGQ44K-CNKNDQ7S.js → radar-GUYGQ44K-d4zMZpQS.js} +1 -1
- package/workframe-ui/public/assets/{requirementDiagram-4Y6WPE33-eWU_mhFa.js → requirementDiagram-4Y6WPE33-BI7EQ9zc.js} +1 -1
- package/workframe-ui/public/assets/{sankeyDiagram-5OEKKPKP-DrjcXvEQ.js → sankeyDiagram-5OEKKPKP-Bcz19jQB.js} +1 -1
- package/workframe-ui/public/assets/{sequenceDiagram-3UESZ5HK-BHWR1xTJ.js → sequenceDiagram-3UESZ5HK-iQiCEfYp.js} +1 -1
- package/workframe-ui/public/assets/{src-DfJB8kV1.js → src-D6mvlP96.js} +1 -1
- package/workframe-ui/public/assets/{stateDiagram-AJRCARHV-BGJbSd3I.js → stateDiagram-AJRCARHV-CxaTXs02.js} +1 -1
- package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-CXikj9xi.js +1 -0
- package/workframe-ui/public/assets/{timeline-definition-PNZ67QCA-DkwoCjiZ.js → timeline-definition-PNZ67QCA-Bej-EAnf.js} +1 -1
- package/workframe-ui/public/assets/{treeView-BLDUP644-GxfhiqoW.js → treeView-BLDUP644-C7PnnzwX.js} +1 -1
- package/workframe-ui/public/assets/{treemap-LRROVOQU-DxrOsars.js → treemap-LRROVOQU-CqISLmkO.js} +1 -1
- package/workframe-ui/public/assets/{vennDiagram-CIIHVFJN-BsWhpUfr.js → vennDiagram-CIIHVFJN-eJMTTEW-.js} +1 -1
- package/workframe-ui/public/assets/{wardley-L42UT6IY-CrFZWMHS.js → wardley-L42UT6IY-D4sMroBF.js} +1 -1
- package/workframe-ui/public/assets/{wardleyDiagram-YWT4CUSO-DV8Xpf5I.js → wardleyDiagram-YWT4CUSO-DC3DCUs7.js} +1 -1
- package/workframe-ui/public/assets/{xychartDiagram-2RQKCTM6-DqMqnwdZ.js → xychartDiagram-2RQKCTM6-BeMaM6Aq.js} +1 -1
- package/workframe-ui/public/index.html +7 -5
- package/workframe-ui/public/workframe-build.json +5 -0
- package/workframe-ui/public/assets/architecture-7EHR7CIX-Dwwi9yA0.js +0 -1
- package/workframe-ui/public/assets/channel-fNHbDpV4.js +0 -1
- package/workframe-ui/public/assets/chunk-LZXEDZCA-DMfdMUwz.js +0 -2
- package/workframe-ui/public/assets/chunk-QZHKN3VN-ewTgEQK8.js +0 -1
- package/workframe-ui/public/assets/chunk-WU5MYG2G-D4Tg-A0l.js +0 -1
- package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-CFAgBpEl.js +0 -1
- package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-CFAgBpEl.js +0 -1
- package/workframe-ui/public/assets/eventmodeling-FCH6USID-BIJTP5k-.js +0 -1
- package/workframe-ui/public/assets/index-8CuZDEIG.css +0 -1
- package/workframe-ui/public/assets/index-xS9lFekI.js +0 -129
- package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-CMLuNyeC.js +0 -1
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""WF-032: extract remaining Handler route groups into handler_modules mixins."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ast
|
|
6
|
+
import re
|
|
7
|
+
import textwrap
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
ROOT = Path(__file__).resolve().parent
|
|
11
|
+
SERVER = ROOT / "server.py"
|
|
12
|
+
|
|
13
|
+
AUTH_METHODS = [
|
|
14
|
+
"_route_post_auth_google_start",
|
|
15
|
+
"_route_post_auth_local_bootstrap",
|
|
16
|
+
"_route_post_auth_bootstrap",
|
|
17
|
+
"_route_post_setup",
|
|
18
|
+
"_route_post_auth_start",
|
|
19
|
+
"_route_post_auth_verify",
|
|
20
|
+
"_route_post_auth_logout",
|
|
21
|
+
"_route_post_auth_refresh",
|
|
22
|
+
"_route_get_auth_hermes_dashboard_gate",
|
|
23
|
+
"_route_get_auth_google_callback",
|
|
24
|
+
"_route_get_oauth_github_callback",
|
|
25
|
+
"_route_get_oauth_discord_callback",
|
|
26
|
+
"_route_get_oauth_stripe_callback",
|
|
27
|
+
"_route_get_me",
|
|
28
|
+
"_route_get_me_onboarding",
|
|
29
|
+
"_route_patch_me",
|
|
30
|
+
"_route_patch_me_native_agent",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
PROVIDER_METHODS = [
|
|
34
|
+
"_handle_internal_llm_proxy",
|
|
35
|
+
"_handle_internal_action_proxy",
|
|
36
|
+
"_handle_internal_run_record",
|
|
37
|
+
"_route_get_user_credentials",
|
|
38
|
+
"_route_get_me_credentials",
|
|
39
|
+
"_route_get_me_providers",
|
|
40
|
+
"_route_post_me_credentials",
|
|
41
|
+
"_route_post_me_telegram_link",
|
|
42
|
+
"_route_pattern_get_me_oauth_status",
|
|
43
|
+
"_route_pattern_get_agent_credentials",
|
|
44
|
+
"_route_pattern_post_me_oauth_start",
|
|
45
|
+
"_route_pattern_post_me_providers_disconnect",
|
|
46
|
+
"_route_pattern_delete_me_credentials",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
ADMIN_METHODS = [
|
|
50
|
+
"_route_get_meta",
|
|
51
|
+
"_route_get_health",
|
|
52
|
+
"_route_get_setup_status",
|
|
53
|
+
"_route_get_public_site_meta",
|
|
54
|
+
"_route_get_public_link_preview",
|
|
55
|
+
"_route_get_public_manifest",
|
|
56
|
+
"_route_get_me_cohort",
|
|
57
|
+
"_route_get_agents",
|
|
58
|
+
"_route_get_snapshot",
|
|
59
|
+
"_route_get_activity_detail",
|
|
60
|
+
"_route_get_files_tree",
|
|
61
|
+
"_route_get_files_list",
|
|
62
|
+
"_route_get_files_state",
|
|
63
|
+
"_route_get_files_read",
|
|
64
|
+
"_route_get_files_raw",
|
|
65
|
+
"_route_get_routes",
|
|
66
|
+
"_route_post_files_write",
|
|
67
|
+
"_route_post_files_upload",
|
|
68
|
+
"_route_get_admin_vault_status",
|
|
69
|
+
"_route_get_doctor_agent_dm_runtimes",
|
|
70
|
+
"_route_get_admin_updates",
|
|
71
|
+
"_route_post_admin_updates_apply",
|
|
72
|
+
"_route_post_admin_stack_restart_gateway",
|
|
73
|
+
"_route_post_admin_vault_init",
|
|
74
|
+
"_route_post_admin_vault_unlock",
|
|
75
|
+
"_route_post_admin_vault_seal",
|
|
76
|
+
"_route_post_admin_vault_wipe",
|
|
77
|
+
"_route_get_supervisor_profile_status",
|
|
78
|
+
"_route_get_supervisor_stack_status",
|
|
79
|
+
"_route_get_admin_audit",
|
|
80
|
+
"_route_get_events",
|
|
81
|
+
"_route_pattern_get_public_branding",
|
|
82
|
+
"_supervisor_proxy_post",
|
|
83
|
+
"_route_post_supervisor_profile_start",
|
|
84
|
+
"_route_post_supervisor_profile_stop",
|
|
85
|
+
"_route_post_supervisor_profile_disable",
|
|
86
|
+
"_route_pattern_post_memory",
|
|
87
|
+
"_route_pattern_delete_memory",
|
|
88
|
+
"_route_patch_doctor_repair",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
MODULE_SPECS: dict[str, tuple[str, str, list[str]]] = {
|
|
92
|
+
"handler_auth.py": (
|
|
93
|
+
"AuthRoutesMixin",
|
|
94
|
+
"Auth / session / OAuth callback route handlers (WF-032 slice).",
|
|
95
|
+
AUTH_METHODS,
|
|
96
|
+
),
|
|
97
|
+
"handler_provider.py": (
|
|
98
|
+
"ProviderRoutesMixin",
|
|
99
|
+
"Provider credentials / OAuth connect / internal LLM proxy (WF-032 slice).",
|
|
100
|
+
PROVIDER_METHODS,
|
|
101
|
+
),
|
|
102
|
+
"handler_admin.py": (
|
|
103
|
+
"AdminRoutesMixin",
|
|
104
|
+
"Admin / meta / doctor / supervisor / data-read routes (WF-032 slice).",
|
|
105
|
+
ADMIN_METHODS,
|
|
106
|
+
),
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
IMPORTS_BY_MODULE = {
|
|
110
|
+
"handler_auth.py": """\
|
|
111
|
+
from __future__ import annotations
|
|
112
|
+
|
|
113
|
+
import json
|
|
114
|
+
import os
|
|
115
|
+
import re
|
|
116
|
+
import secrets
|
|
117
|
+
import sqlite3
|
|
118
|
+
import time
|
|
119
|
+
import urllib.parse
|
|
120
|
+
import uuid
|
|
121
|
+
from datetime import datetime, timezone
|
|
122
|
+
from typing import Any
|
|
123
|
+
|
|
124
|
+
import auth_rate_limit
|
|
125
|
+
import google_auth
|
|
126
|
+
import stack_config
|
|
127
|
+
from email_sender import APP_BASE_URL
|
|
128
|
+
""",
|
|
129
|
+
"handler_provider.py": """\
|
|
130
|
+
from __future__ import annotations
|
|
131
|
+
|
|
132
|
+
import sqlite3
|
|
133
|
+
from typing import Any
|
|
134
|
+
|
|
135
|
+
import action_proxy
|
|
136
|
+
import internal_proxy_auth
|
|
137
|
+
import llm_proxy
|
|
138
|
+
import openrouter_catalog
|
|
139
|
+
import platform_auth
|
|
140
|
+
import run_surface_wiring
|
|
141
|
+
""",
|
|
142
|
+
"handler_admin.py": """\
|
|
143
|
+
from __future__ import annotations
|
|
144
|
+
|
|
145
|
+
import json
|
|
146
|
+
import os
|
|
147
|
+
import re
|
|
148
|
+
import sqlite3
|
|
149
|
+
import time
|
|
150
|
+
import urllib.parse
|
|
151
|
+
from pathlib import Path
|
|
152
|
+
from typing import Any
|
|
153
|
+
|
|
154
|
+
import activity_feed
|
|
155
|
+
import credential_vault
|
|
156
|
+
import doctor_audit
|
|
157
|
+
import site_meta
|
|
158
|
+
import stack_updates
|
|
159
|
+
from supervisor_client import _supervisor_request
|
|
160
|
+
""",
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _read_server() -> str:
|
|
165
|
+
return SERVER.read_text(encoding="utf-8-sig")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _server_names() -> set[str]:
|
|
169
|
+
tree = ast.parse(_read_server())
|
|
170
|
+
names: set[str] = set()
|
|
171
|
+
for node in tree.body:
|
|
172
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
173
|
+
names.add(node.name)
|
|
174
|
+
elif isinstance(node, ast.Assign):
|
|
175
|
+
for t in node.targets:
|
|
176
|
+
if isinstance(t, ast.Name):
|
|
177
|
+
names.add(t.id)
|
|
178
|
+
elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
|
|
179
|
+
names.add(node.target.id)
|
|
180
|
+
return names
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _extract_handler_methods(source: str, wanted: set[str]) -> dict[str, str]:
|
|
184
|
+
lines = source.splitlines()
|
|
185
|
+
in_handler = False
|
|
186
|
+
class_indent = 0
|
|
187
|
+
body_indent = 4
|
|
188
|
+
current: str | None = None
|
|
189
|
+
buf: list[str] = []
|
|
190
|
+
out: dict[str, list[str]] = {}
|
|
191
|
+
|
|
192
|
+
for line in lines:
|
|
193
|
+
if not in_handler:
|
|
194
|
+
if line.startswith("class Handler("):
|
|
195
|
+
in_handler = True
|
|
196
|
+
class_indent = len(line) - len(line.lstrip())
|
|
197
|
+
body_indent = class_indent + 4
|
|
198
|
+
continue
|
|
199
|
+
stripped = line.lstrip()
|
|
200
|
+
if not stripped:
|
|
201
|
+
if current:
|
|
202
|
+
buf.append(line)
|
|
203
|
+
continue
|
|
204
|
+
indent = len(line) - len(stripped)
|
|
205
|
+
if indent <= class_indent and stripped and not stripped.startswith("#"):
|
|
206
|
+
break
|
|
207
|
+
if stripped.startswith("def ") and indent == body_indent:
|
|
208
|
+
if current and current in wanted:
|
|
209
|
+
out[current] = buf
|
|
210
|
+
name = stripped.split("(")[0].replace("def ", "").strip()
|
|
211
|
+
current = name if name in wanted else None
|
|
212
|
+
buf = [line] if current else []
|
|
213
|
+
continue
|
|
214
|
+
if current:
|
|
215
|
+
buf.append(line)
|
|
216
|
+
|
|
217
|
+
if current and current in wanted:
|
|
218
|
+
out[current] = buf
|
|
219
|
+
return {k: "\n".join(v).rstrip() + "\n" for k, v in out.items()}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _rewrite_method_body(method_src: str, server_names: set[str]) -> str:
|
|
223
|
+
lines = method_src.splitlines()
|
|
224
|
+
if not lines:
|
|
225
|
+
return method_src
|
|
226
|
+
def_line = lines[0]
|
|
227
|
+
body_lines = lines[1:]
|
|
228
|
+
while body_lines and not body_lines[0].strip():
|
|
229
|
+
body_lines.pop(0)
|
|
230
|
+
if not body_lines:
|
|
231
|
+
return method_src
|
|
232
|
+
|
|
233
|
+
body_indent = len(body_lines[0]) - len(body_lines[0].lstrip())
|
|
234
|
+
dedented = textwrap.dedent("\n".join(body_lines))
|
|
235
|
+
|
|
236
|
+
# Lazy rewrite: prefix server-level bare names with srv.
|
|
237
|
+
tokens = set(re.findall(r"\b([A-Za-z_][A-Za-z0-9_]*)\b", dedented))
|
|
238
|
+
skip = {
|
|
239
|
+
"self",
|
|
240
|
+
"True",
|
|
241
|
+
"False",
|
|
242
|
+
"None",
|
|
243
|
+
"dict",
|
|
244
|
+
"list",
|
|
245
|
+
"str",
|
|
246
|
+
"int",
|
|
247
|
+
"bool",
|
|
248
|
+
"Any",
|
|
249
|
+
"Exception",
|
|
250
|
+
"ValueError",
|
|
251
|
+
"RuntimeError",
|
|
252
|
+
"OSError",
|
|
253
|
+
"sqlite3",
|
|
254
|
+
"json",
|
|
255
|
+
"os",
|
|
256
|
+
"re",
|
|
257
|
+
"time",
|
|
258
|
+
"uuid",
|
|
259
|
+
"secrets",
|
|
260
|
+
"urllib",
|
|
261
|
+
"Path",
|
|
262
|
+
"datetime",
|
|
263
|
+
"timezone",
|
|
264
|
+
"auth_rate_limit",
|
|
265
|
+
"google_auth",
|
|
266
|
+
"stack_config",
|
|
267
|
+
"APP_BASE_URL",
|
|
268
|
+
"action_proxy",
|
|
269
|
+
"internal_proxy_auth",
|
|
270
|
+
"llm_proxy",
|
|
271
|
+
"openrouter_catalog",
|
|
272
|
+
"platform_auth",
|
|
273
|
+
"run_surface_wiring",
|
|
274
|
+
"activity_feed",
|
|
275
|
+
"credential_vault",
|
|
276
|
+
"doctor_audit",
|
|
277
|
+
"site_meta",
|
|
278
|
+
"stack_updates",
|
|
279
|
+
"_supervisor_request",
|
|
280
|
+
}
|
|
281
|
+
replace_names = sorted((tokens & server_names) - skip, key=len, reverse=True)
|
|
282
|
+
for name in replace_names:
|
|
283
|
+
dedented = re.sub(rf"\b{name}\b", f"srv.{name}", dedented)
|
|
284
|
+
|
|
285
|
+
new_body = textwrap.indent(
|
|
286
|
+
"srv = _srv()\n" + dedented.rstrip() + "\n",
|
|
287
|
+
" " * body_indent,
|
|
288
|
+
)
|
|
289
|
+
return def_line + "\n" + new_body
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _build_module(filename: str, class_name: str, doc: str, methods: list[str], extracted: dict[str, str], server_names: set[str]) -> str:
|
|
293
|
+
parts = [f'"""{doc}"""', "", IMPORTS_BY_MODULE[filename].rstrip(), "", "", "def _srv():", " import server", "", " return server", "", "", f"class {class_name}:"]
|
|
294
|
+
missing = []
|
|
295
|
+
for name in methods:
|
|
296
|
+
if name not in extracted:
|
|
297
|
+
missing.append(name)
|
|
298
|
+
continue
|
|
299
|
+
rewritten = _rewrite_method_body(extracted[name], server_names)
|
|
300
|
+
parts.append("")
|
|
301
|
+
parts.append(textwrap.indent(rewritten.rstrip(), " "))
|
|
302
|
+
if missing:
|
|
303
|
+
raise SystemExit(f"{filename}: missing methods {missing}")
|
|
304
|
+
return "\n".join(parts) + "\n"
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def main() -> None:
|
|
308
|
+
source = _read_server()
|
|
309
|
+
all_methods = set(AUTH_METHODS + PROVIDER_METHODS + ADMIN_METHODS)
|
|
310
|
+
extracted = _extract_handler_methods(source, all_methods)
|
|
311
|
+
server_names = _server_names()
|
|
312
|
+
|
|
313
|
+
for filename, (class_name, doc, methods) in MODULE_SPECS.items():
|
|
314
|
+
mod_path = ROOT / "handler_modules" / filename
|
|
315
|
+
mod_path.write_text(_build_module(filename, class_name, doc, methods, extracted, server_names), encoding="utf-8")
|
|
316
|
+
print(f"wrote {mod_path.name} ({len(methods)} methods)")
|
|
317
|
+
|
|
318
|
+
# Strip extracted methods from server.py Handler class
|
|
319
|
+
lines = source.splitlines(keepends=True)
|
|
320
|
+
in_handler = False
|
|
321
|
+
class_indent = 0
|
|
322
|
+
body_indent = 4
|
|
323
|
+
skip = False
|
|
324
|
+
out: list[str] = []
|
|
325
|
+
i = 0
|
|
326
|
+
while i < len(lines):
|
|
327
|
+
line = lines[i]
|
|
328
|
+
if not in_handler:
|
|
329
|
+
out.append(line)
|
|
330
|
+
if line.startswith("class Handler("):
|
|
331
|
+
in_handler = True
|
|
332
|
+
class_indent = len(line) - len(line.lstrip())
|
|
333
|
+
body_indent = class_indent + 4
|
|
334
|
+
i += 1
|
|
335
|
+
continue
|
|
336
|
+
stripped = line.lstrip()
|
|
337
|
+
indent = len(line) - len(stripped)
|
|
338
|
+
if indent <= class_indent and stripped and not stripped.startswith("#"):
|
|
339
|
+
skip = False
|
|
340
|
+
out.append(line)
|
|
341
|
+
i += 1
|
|
342
|
+
continue
|
|
343
|
+
if stripped.startswith("def ") and indent == body_indent:
|
|
344
|
+
name = stripped.split("(")[0].replace("def ", "").strip()
|
|
345
|
+
if name in all_methods:
|
|
346
|
+
skip = True
|
|
347
|
+
i += 1
|
|
348
|
+
continue
|
|
349
|
+
skip = False
|
|
350
|
+
out.append(line)
|
|
351
|
+
i += 1
|
|
352
|
+
continue
|
|
353
|
+
if skip:
|
|
354
|
+
i += 1
|
|
355
|
+
continue
|
|
356
|
+
out.append(line)
|
|
357
|
+
i += 1
|
|
358
|
+
|
|
359
|
+
new_source = "".join(out)
|
|
360
|
+
# Update Handler class bases
|
|
361
|
+
new_source = new_source.replace(
|
|
362
|
+
"class Handler(WorkspaceRoutesMixin, ChatRoutesMixin, InstallRoutesMixin, BaseHTTPRequestHandler):",
|
|
363
|
+
"class Handler(\n"
|
|
364
|
+
" AdminRoutesMixin,\n"
|
|
365
|
+
" ProviderRoutesMixin,\n"
|
|
366
|
+
" AuthRoutesMixin,\n"
|
|
367
|
+
" WorkspaceRoutesMixin,\n"
|
|
368
|
+
" ChatRoutesMixin,\n"
|
|
369
|
+
" InstallRoutesMixin,\n"
|
|
370
|
+
" BaseHTTPRequestHandler,\n"
|
|
371
|
+
"):",
|
|
372
|
+
)
|
|
373
|
+
new_source = new_source.replace(
|
|
374
|
+
"from handler_modules import ChatRoutesMixin, InstallRoutesMixin, WorkspaceRoutesMixin",
|
|
375
|
+
"from handler_modules import (\n"
|
|
376
|
+
" AdminRoutesMixin,\n"
|
|
377
|
+
" AuthRoutesMixin,\n"
|
|
378
|
+
" ChatRoutesMixin,\n"
|
|
379
|
+
" InstallRoutesMixin,\n"
|
|
380
|
+
" ProviderRoutesMixin,\n"
|
|
381
|
+
" WorkspaceRoutesMixin,\n"
|
|
382
|
+
")",
|
|
383
|
+
)
|
|
384
|
+
# Remove WF-037 comment block before first remaining route if empty gap
|
|
385
|
+
new_source = re.sub(
|
|
386
|
+
r"\n # WF-037 data-read GET handlers \(registered in route_registry\.ROUTES\)\n\n",
|
|
387
|
+
"\n",
|
|
388
|
+
new_source,
|
|
389
|
+
count=1,
|
|
390
|
+
)
|
|
391
|
+
SERVER.write_text(new_source, encoding="utf-8")
|
|
392
|
+
print(f"patched server.py -> {(len(new_source.splitlines()))} lines")
|
|
393
|
+
|
|
394
|
+
init = ROOT / "handler_modules" / "__init__.py"
|
|
395
|
+
init.write_text(
|
|
396
|
+
'"""Handler route mixins extracted from server.Handler (WF-032)."""\n\n'
|
|
397
|
+
"from handler_modules.handler_admin import AdminRoutesMixin\n"
|
|
398
|
+
"from handler_modules.handler_auth import AuthRoutesMixin\n"
|
|
399
|
+
"from handler_modules.handler_chat import ChatRoutesMixin\n"
|
|
400
|
+
"from handler_modules.handler_install import InstallRoutesMixin\n"
|
|
401
|
+
"from handler_modules.handler_provider import ProviderRoutesMixin\n"
|
|
402
|
+
"from handler_modules.handler_workspace import WorkspaceRoutesMixin\n\n"
|
|
403
|
+
'__all__ = [\n'
|
|
404
|
+
' "AdminRoutesMixin",\n'
|
|
405
|
+
' "AuthRoutesMixin",\n'
|
|
406
|
+
' "ChatRoutesMixin",\n'
|
|
407
|
+
' "InstallRoutesMixin",\n'
|
|
408
|
+
' "ProviderRoutesMixin",\n'
|
|
409
|
+
' "WorkspaceRoutesMixin",\n'
|
|
410
|
+
"]\n",
|
|
411
|
+
encoding="utf-8",
|
|
412
|
+
)
|
|
413
|
+
print("updated handler_modules/__init__.py")
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
if __name__ == "__main__":
|
|
417
|
+
main()
|