tawn 0.1.0__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.
- tawn-0.1.0/LICENSE +21 -0
- tawn-0.1.0/PKG-INFO +201 -0
- tawn-0.1.0/README.md +131 -0
- tawn-0.1.0/pyproject.toml +94 -0
- tawn-0.1.0/setup.cfg +4 -0
- tawn-0.1.0/setup.py +51 -0
- tawn-0.1.0/src/tawn/__init__.py +3 -0
- tawn-0.1.0/src/tawn/_webserver.py +66 -0
- tawn-0.1.0/src/tawn/branding.py +82 -0
- tawn-0.1.0/src/tawn/capability/__init__.py +1 -0
- tawn-0.1.0/src/tawn/capability/audit.py +87 -0
- tawn-0.1.0/src/tawn/capability/fs.py +67 -0
- tawn-0.1.0/src/tawn/capability/grants.py +53 -0
- tawn-0.1.0/src/tawn/capability/integrity.py +38 -0
- tawn-0.1.0/src/tawn/cli.py +2183 -0
- tawn-0.1.0/src/tawn/compiler/__init__.py +0 -0
- tawn-0.1.0/src/tawn/compiler/classifier.py +79 -0
- tawn-0.1.0/src/tawn/compiler/compiler.py +409 -0
- tawn-0.1.0/src/tawn/compiler/conflicts.py +49 -0
- tawn-0.1.0/src/tawn/compiler/delta.py +179 -0
- tawn-0.1.0/src/tawn/compiler/embedder.py +208 -0
- tawn-0.1.0/src/tawn/compiler/entities.py +126 -0
- tawn-0.1.0/src/tawn/compiler/parser.py +237 -0
- tawn-0.1.0/src/tawn/compiler/wiki.py +197 -0
- tawn-0.1.0/src/tawn/config.py +26 -0
- tawn-0.1.0/src/tawn/db.py +107 -0
- tawn-0.1.0/src/tawn/dbsetup.py +60 -0
- tawn-0.1.0/src/tawn/domains/__init__.py +1 -0
- tawn-0.1.0/src/tawn/domains/academic/__init__.py +22 -0
- tawn-0.1.0/src/tawn/domains/base.py +33 -0
- tawn-0.1.0/src/tawn/domains/creation.py +104 -0
- tawn-0.1.0/src/tawn/domains/hobby/__init__.py +16 -0
- tawn-0.1.0/src/tawn/domains/records.py +112 -0
- tawn-0.1.0/src/tawn/domains/registry.py +116 -0
- tawn-0.1.0/src/tawn/domains/research/__init__.py +21 -0
- tawn-0.1.0/src/tawn/domains/stub.py +32 -0
- tawn-0.1.0/src/tawn/domains/wealth/__init__.py +11 -0
- tawn-0.1.0/src/tawn/domains/wealth/api.py +51 -0
- tawn-0.1.0/src/tawn/domains/wealth/cli.py +105 -0
- tawn-0.1.0/src/tawn/domains/wealth/dashboard.py +62 -0
- tawn-0.1.0/src/tawn/domains/wealth/holdings.py +76 -0
- tawn-0.1.0/src/tawn/domains/wealth/prices.py +101 -0
- tawn-0.1.0/src/tawn/domains/wealth/schedule.py +63 -0
- tawn-0.1.0/src/tawn/domains/wealth/snapshot.py +118 -0
- tawn-0.1.0/src/tawn/domains/work/__init__.py +17 -0
- tawn-0.1.0/src/tawn/federation/__init__.py +0 -0
- tawn-0.1.0/src/tawn/federation/adapters/__init__.py +0 -0
- tawn-0.1.0/src/tawn/federation/adapters/base.py +35 -0
- tawn-0.1.0/src/tawn/federation/adapters/chatgpt.py +59 -0
- tawn-0.1.0/src/tawn/federation/adapters/claude_ai.py +43 -0
- tawn-0.1.0/src/tawn/federation/adapters/claude_code.py +84 -0
- tawn-0.1.0/src/tawn/federation/adapters/codex.py +71 -0
- tawn-0.1.0/src/tawn/federation/adapters/gemini.py +46 -0
- tawn-0.1.0/src/tawn/federation/adapters/gemini_cli.py +109 -0
- tawn-0.1.0/src/tawn/federation/adapters/generic.py +49 -0
- tawn-0.1.0/src/tawn/federation/config.py +41 -0
- tawn-0.1.0/src/tawn/federation/discovery.py +122 -0
- tawn-0.1.0/src/tawn/federation/dispatcher.py +43 -0
- tawn-0.1.0/src/tawn/federation/exporter.py +112 -0
- tawn-0.1.0/src/tawn/federation/merge.py +172 -0
- tawn-0.1.0/src/tawn/federation/normalizer.py +151 -0
- tawn-0.1.0/src/tawn/federation/schema.py +38 -0
- tawn-0.1.0/src/tawn/federation/systemd.py +128 -0
- tawn-0.1.0/src/tawn/federation/watcher.py +98 -0
- tawn-0.1.0/src/tawn/history.py +80 -0
- tawn-0.1.0/src/tawn/home.py +93 -0
- tawn-0.1.0/src/tawn/ignore.py +183 -0
- tawn-0.1.0/src/tawn/mcp_server.py +75 -0
- tawn-0.1.0/src/tawn/memory/__init__.py +0 -0
- tawn-0.1.0/src/tawn/memory/brief.py +72 -0
- tawn-0.1.0/src/tawn/memory/note.py +62 -0
- tawn-0.1.0/src/tawn/memory/recall.py +175 -0
- tawn-0.1.0/src/tawn/memory/schema.py +154 -0
- tawn-0.1.0/src/tawn/model/__init__.py +1 -0
- tawn-0.1.0/src/tawn/model/breaker.py +57 -0
- tawn-0.1.0/src/tawn/model/catalog.py +106 -0
- tawn-0.1.0/src/tawn/model/directory.py +95 -0
- tawn-0.1.0/src/tawn/model/identity.py +44 -0
- tawn-0.1.0/src/tawn/model/keys.py +52 -0
- tawn-0.1.0/src/tawn/model/ledger.py +93 -0
- tawn-0.1.0/src/tawn/model/personality.py +59 -0
- tawn-0.1.0/src/tawn/model/providers/__init__.py +1 -0
- tawn-0.1.0/src/tawn/model/providers/anthropic.py +127 -0
- tawn-0.1.0/src/tawn/model/providers/gemini.py +138 -0
- tawn-0.1.0/src/tawn/model/providers/ollama.py +149 -0
- tawn-0.1.0/src/tawn/model/providers/openai_compat.py +156 -0
- tawn-0.1.0/src/tawn/model/router.py +346 -0
- tawn-0.1.0/src/tawn/model/types.py +72 -0
- tawn-0.1.0/src/tawn/updater.py +179 -0
- tawn-0.1.0/src/tawn/user_config.py +124 -0
- tawn-0.1.0/src/tawn/web/__init__.py +3 -0
- tawn-0.1.0/src/tawn/web/app.py +290 -0
- tawn-0.1.0/src/tawn/web/dist/assets/abnfDiagram-VRR7QNED-C5F_AKgo.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/arc-DfuEWumi.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/architectureDiagram-ZJ3FMSHR-CMdbMQ-v.js +36 -0
- tawn-0.1.0/src/tawn/web/dist/assets/blockDiagram-677ZJIJ3-BvWKvlkz.js +132 -0
- tawn-0.1.0/src/tawn/web/dist/assets/c4Diagram-LMCZKHZV-cmtcJnEh.js +10 -0
- tawn-0.1.0/src/tawn/web/dist/assets/channel-1wBTkNV8.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-2Q5K7J3B-CVkZvg6J.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-32BRIVSS-BJnUTK_p.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-5VM5RSS4-BgCFFy0k.js +15 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-EX3LRPZG-D3opRKGp.js +231 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-JWPE2WC7-BQBJybxG.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-MOJQB5TN-DPCuIYGK.js +88 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-RYQCIY6F-BGrEIzMk.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-V7JOEXUC-16qlVcj5.js +206 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-VR4S4FIN-Dri-A7dn.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/chunk-XXDRQBXY-BZJRsKXY.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/classDiagram-OUVF2IWQ-CidNYYIR.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/classDiagram-v2-EOCWNBFH-CidNYYIR.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/cose-bilkent-JH36ORCC-B7ClDWJL.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/cynefin-VYW2F7L2-DdT7ZLm1.js +178 -0
- tawn-0.1.0/src/tawn/web/dist/assets/cynefinDiagram-TSTJHNR4-D3XVPeTI.js +62 -0
- tawn-0.1.0/src/tawn/web/dist/assets/cytoscape.esm-CUqq0XTU.js +331 -0
- tawn-0.1.0/src/tawn/web/dist/assets/dagre-VKFMJZFB-C7hI6zFs.js +4 -0
- tawn-0.1.0/src/tawn/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/diagram-FQU43EPY-BwkzyqxA.js +3 -0
- tawn-0.1.0/src/tawn/web/dist/assets/diagram-G47NLZAW-BNQLclaM.js +24 -0
- tawn-0.1.0/src/tawn/web/dist/assets/diagram-NH7WQ7WH-C89oedn8.js +24 -0
- tawn-0.1.0/src/tawn/web/dist/assets/diagram-OA4YK3LP-CM_ra1CZ.js +30 -0
- tawn-0.1.0/src/tawn/web/dist/assets/diagram-WEI45ONY-CIyDX7LQ.js +41 -0
- tawn-0.1.0/src/tawn/web/dist/assets/ebnfDiagram-CCIWWBDH-CStWDurL.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/erDiagram-Q63AITRT-BwAeP1e2.js +85 -0
- tawn-0.1.0/src/tawn/web/dist/assets/flowDiagram-23GEKE2U-CAA-JOsf.js +156 -0
- tawn-0.1.0/src/tawn/web/dist/assets/ganttDiagram-NO4QXBWP-7bajtVpE.js +292 -0
- tawn-0.1.0/src/tawn/web/dist/assets/gitGraphDiagram-IHSO6WYX-qW76mQDo.js +106 -0
- tawn-0.1.0/src/tawn/web/dist/assets/graph-C2PyVmSI.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/index-BaAvK0kS.js +162 -0
- tawn-0.1.0/src/tawn/web/dist/assets/index-CPMCxrJ6.js +3 -0
- tawn-0.1.0/src/tawn/web/dist/assets/index-DMnyYUiC.css +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/infoDiagram-FWYZ7A6U-BN3TAAMm.js +2 -0
- tawn-0.1.0/src/tawn/web/dist/assets/init-Gi6I4Gst.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/ishikawaDiagram-FXEZZL3T-DIjUQHYT.js +70 -0
- tawn-0.1.0/src/tawn/web/dist/assets/journeyDiagram-5HDEW3XC-Cd_0i_MI.js +139 -0
- tawn-0.1.0/src/tawn/web/dist/assets/kanban-definition-HUTT4EX6-EJykSLKC.js +89 -0
- tawn-0.1.0/src/tawn/web/dist/assets/katex-C5jXJg4s.js +257 -0
- tawn-0.1.0/src/tawn/web/dist/assets/layout-HEHzrzvT.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/linear-DZV_74YI.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/map-BQHxRNoK.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/mermaid.core-Cs_D-MaZ.js +314 -0
- tawn-0.1.0/src/tawn/web/dist/assets/mindmap-definition-LN4V7U3C-Dayioghr.js +96 -0
- tawn-0.1.0/src/tawn/web/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/pegDiagram-2B236MQR-CEg98Wsy.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/pieDiagram-ENE6RG2P-BWzY0gy2.js +39 -0
- tawn-0.1.0/src/tawn/web/dist/assets/quadrantDiagram-ABIIQ3AL-GoCE2r_5.js +7 -0
- tawn-0.1.0/src/tawn/web/dist/assets/railroadDiagram-RFXS5EU6-BxTtKfWT.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/requirementDiagram-TGXJPOKE-CD0t2ic5.js +84 -0
- tawn-0.1.0/src/tawn/web/dist/assets/sankeyDiagram-HTMAVEWB-Om9xv51_.js +40 -0
- tawn-0.1.0/src/tawn/web/dist/assets/sequenceDiagram-DBY2YBRQ-Ct9pa12Y.js +162 -0
- tawn-0.1.0/src/tawn/web/dist/assets/sizeCapture-X5ZJPWSS-D0lniTrU.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/stateDiagram-2N3HPSRC-C3JQoYro.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/stateDiagram-v2-6OUMAXLB-s_yFnFGS.js +1 -0
- tawn-0.1.0/src/tawn/web/dist/assets/swimlanes-5IMT3BWC-B0FKBUkt.js +2 -0
- tawn-0.1.0/src/tawn/web/dist/assets/swimlanesDiagram-G3AALYLV-aVA3YxQh.js +8 -0
- tawn-0.1.0/src/tawn/web/dist/assets/timeline-definition-FHXFAJF6-MhKDYH6H.js +120 -0
- tawn-0.1.0/src/tawn/web/dist/assets/vennDiagram-L72KCM5P-CqvlQmOm.js +34 -0
- tawn-0.1.0/src/tawn/web/dist/assets/wardleyDiagram-EHGQE667-DdS-6LAr.js +78 -0
- tawn-0.1.0/src/tawn/web/dist/assets/xychartDiagram-FW5EYKEG-DpAi9dnU.js +7 -0
- tawn-0.1.0/src/tawn/web/dist/favicon.svg +10 -0
- tawn-0.1.0/src/tawn/web/dist/index.html +31 -0
- tawn-0.1.0/src/tawn/web/routes/__init__.py +0 -0
- tawn-0.1.0/src/tawn/web/routes/chat.py +231 -0
- tawn-0.1.0/src/tawn/web/routes/domains.py +85 -0
- tawn-0.1.0/src/tawn/web/routes/federation.py +411 -0
- tawn-0.1.0/src/tawn/web/routes/grants.py +118 -0
- tawn-0.1.0/src/tawn/web/routes/history.py +23 -0
- tawn-0.1.0/src/tawn/web/routes/memory.py +276 -0
- tawn-0.1.0/src/tawn/web/routes/profile.py +29 -0
- tawn-0.1.0/src/tawn/web/routes/setup.py +100 -0
- tawn-0.1.0/src/tawn/web/routes/update.py +47 -0
- tawn-0.1.0/src/tawn.egg-info/PKG-INFO +201 -0
- tawn-0.1.0/src/tawn.egg-info/SOURCES.txt +248 -0
- tawn-0.1.0/src/tawn.egg-info/dependency_links.txt +1 -0
- tawn-0.1.0/src/tawn.egg-info/entry_points.txt +9 -0
- tawn-0.1.0/src/tawn.egg-info/requires.txt +50 -0
- tawn-0.1.0/src/tawn.egg-info/top_level.txt +1 -0
- tawn-0.1.0/tests/test_anthropic.py +126 -0
- tawn-0.1.0/tests/test_audit.py +19 -0
- tawn-0.1.0/tests/test_branding.py +28 -0
- tawn-0.1.0/tests/test_breaker.py +61 -0
- tawn-0.1.0/tests/test_catalog.py +34 -0
- tawn-0.1.0/tests/test_cli.py +48 -0
- tawn-0.1.0/tests/test_cli_federation.py +60 -0
- tawn-0.1.0/tests/test_cli_memory_commands.py +95 -0
- tawn-0.1.0/tests/test_compiler_compiler.py +88 -0
- tawn-0.1.0/tests/test_compiler_conflicts.py +65 -0
- tawn-0.1.0/tests/test_compiler_delta.py +73 -0
- tawn-0.1.0/tests/test_compiler_embedder.py +81 -0
- tawn-0.1.0/tests/test_compiler_entities.py +85 -0
- tawn-0.1.0/tests/test_compiler_orchestrator.py +116 -0
- tawn-0.1.0/tests/test_compiler_parser.py +90 -0
- tawn-0.1.0/tests/test_compiler_wiki.py +85 -0
- tawn-0.1.0/tests/test_config.py +15 -0
- tawn-0.1.0/tests/test_dashboard.py +41 -0
- tawn-0.1.0/tests/test_db.py +28 -0
- tawn-0.1.0/tests/test_db_setup.py +52 -0
- tawn-0.1.0/tests/test_directory.py +81 -0
- tawn-0.1.0/tests/test_domain_base.py +33 -0
- tawn-0.1.0/tests/test_domain_cli.py +38 -0
- tawn-0.1.0/tests/test_domain_creation.py +53 -0
- tawn-0.1.0/tests/test_domain_records.py +73 -0
- tawn-0.1.0/tests/test_domain_registry.py +80 -0
- tawn-0.1.0/tests/test_domain_stubs.py +38 -0
- tawn-0.1.0/tests/test_domain_wealth_register.py +10 -0
- tawn-0.1.0/tests/test_federation_adapters.py +320 -0
- tawn-0.1.0/tests/test_federation_config.py +32 -0
- tawn-0.1.0/tests/test_federation_discovery.py +50 -0
- tawn-0.1.0/tests/test_federation_dispatcher.py +56 -0
- tawn-0.1.0/tests/test_federation_exporter.py +83 -0
- tawn-0.1.0/tests/test_federation_merge.py +103 -0
- tawn-0.1.0/tests/test_federation_normalizer.py +66 -0
- tawn-0.1.0/tests/test_federation_routes.py +102 -0
- tawn-0.1.0/tests/test_federation_systemd.py +58 -0
- tawn-0.1.0/tests/test_federation_watcher.py +116 -0
- tawn-0.1.0/tests/test_fs.py +86 -0
- tawn-0.1.0/tests/test_gemini.py +135 -0
- tawn-0.1.0/tests/test_grants.py +49 -0
- tawn-0.1.0/tests/test_holdings.py +71 -0
- tawn-0.1.0/tests/test_home.py +24 -0
- tawn-0.1.0/tests/test_home_skeleton.py +24 -0
- tawn-0.1.0/tests/test_identity.py +31 -0
- tawn-0.1.0/tests/test_integrity.py +35 -0
- tawn-0.1.0/tests/test_keys.py +75 -0
- tawn-0.1.0/tests/test_ledger.py +67 -0
- tawn-0.1.0/tests/test_mcp_tools.py +32 -0
- tawn-0.1.0/tests/test_memory_brief.py +103 -0
- tawn-0.1.0/tests/test_memory_note.py +79 -0
- tawn-0.1.0/tests/test_memory_recall.py +121 -0
- tawn-0.1.0/tests/test_memory_schema.py +72 -0
- tawn-0.1.0/tests/test_memory_verbs.py +193 -0
- tawn-0.1.0/tests/test_model_types.py +35 -0
- tawn-0.1.0/tests/test_ollama.py +75 -0
- tawn-0.1.0/tests/test_ollama_setup.py +88 -0
- tawn-0.1.0/tests/test_openai_compat.py +122 -0
- tawn-0.1.0/tests/test_prices.py +99 -0
- tawn-0.1.0/tests/test_router.py +260 -0
- tawn-0.1.0/tests/test_schedule.py +23 -0
- tawn-0.1.0/tests/test_snapshot.py +60 -0
- tawn-0.1.0/tests/test_stage0_e2e.py +31 -0
- tawn-0.1.0/tests/test_stage1_e2e.py +48 -0
- tawn-0.1.0/tests/test_stage2_e2e.py +280 -0
- tawn-0.1.0/tests/test_types_stream_chunk.py +20 -0
- tawn-0.1.0/tests/test_url_providers.py +54 -0
- tawn-0.1.0/tests/test_user_config.py +100 -0
- tawn-0.1.0/tests/test_web.py +72 -0
- tawn-0.1.0/tests/test_web_chat_routes.py +47 -0
- tawn-0.1.0/tests/test_web_domain_routes.py +70 -0
- tawn-0.1.0/tests/test_web_grants_routes.py +54 -0
- tawn-0.1.0/tests/test_web_memory_routes.py +120 -0
- tawn-0.1.0/tests/test_web_setup_routes.py +53 -0
tawn-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Testimony Adekoya
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
tawn-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tawn
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Tawn — the personal digital twin. Local-first memory and context core for your work, wealth, research, and academic life.
|
|
5
|
+
Author-email: Testimony Adekoya <testimonyadekoya.02@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/tawn-hq/tawn
|
|
8
|
+
Project-URL: Repository, https://github.com/tawn-hq/tawn
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/tawn-hq/tawn/issues
|
|
10
|
+
Keywords: ai,personal-ai,digital-twin,memory,mcp,rag,local-first,llm
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Environment :: Web Environment
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Operating System :: MacOS
|
|
19
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Office/Business
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Requires-Python: >=3.12
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: pydantic>=2.7
|
|
29
|
+
Requires-Dist: pydantic-settings>=2.2
|
|
30
|
+
Requires-Dist: PyYAML>=6.0
|
|
31
|
+
Requires-Dist: typer>=0.12
|
|
32
|
+
Requires-Dist: SQLAlchemy>=2.0
|
|
33
|
+
Requires-Dist: psycopg[binary]>=3.1
|
|
34
|
+
Requires-Dist: httpx>=0.27
|
|
35
|
+
Requires-Dist: rich>=13.7
|
|
36
|
+
Requires-Dist: fastapi>=0.111
|
|
37
|
+
Requires-Dist: uvicorn>=0.30
|
|
38
|
+
Requires-Dist: keyring>=25.0
|
|
39
|
+
Requires-Dist: python-frontmatter>=1.1
|
|
40
|
+
Requires-Dist: rapidfuzz>=3.0
|
|
41
|
+
Requires-Dist: watchfiles>=0.21
|
|
42
|
+
Provides-Extra: anthropic
|
|
43
|
+
Requires-Dist: anthropic>=0.100; extra == "anthropic"
|
|
44
|
+
Provides-Extra: openai
|
|
45
|
+
Requires-Dist: openai>=2.0; extra == "openai"
|
|
46
|
+
Provides-Extra: gemini
|
|
47
|
+
Requires-Dist: google-genai>=1.0; extra == "gemini"
|
|
48
|
+
Provides-Extra: ollama
|
|
49
|
+
Requires-Dist: ollama>=0.4; extra == "ollama"
|
|
50
|
+
Provides-Extra: vectors
|
|
51
|
+
Requires-Dist: pgvector>=0.3; extra == "vectors"
|
|
52
|
+
Provides-Extra: mcp
|
|
53
|
+
Requires-Dist: fastmcp>=2.0; extra == "mcp"
|
|
54
|
+
Provides-Extra: providers
|
|
55
|
+
Requires-Dist: anthropic>=0.100; extra == "providers"
|
|
56
|
+
Requires-Dist: openai>=2.0; extra == "providers"
|
|
57
|
+
Requires-Dist: google-genai>=1.0; extra == "providers"
|
|
58
|
+
Requires-Dist: ollama>=0.4; extra == "providers"
|
|
59
|
+
Provides-Extra: full
|
|
60
|
+
Requires-Dist: anthropic>=0.100; extra == "full"
|
|
61
|
+
Requires-Dist: openai>=2.0; extra == "full"
|
|
62
|
+
Requires-Dist: google-genai>=1.0; extra == "full"
|
|
63
|
+
Requires-Dist: ollama>=0.4; extra == "full"
|
|
64
|
+
Requires-Dist: pgvector>=0.3; extra == "full"
|
|
65
|
+
Requires-Dist: fastmcp>=2.0; extra == "full"
|
|
66
|
+
Provides-Extra: dev
|
|
67
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
68
|
+
Requires-Dist: respx>=0.21; extra == "dev"
|
|
69
|
+
Dynamic: license-file
|
|
70
|
+
|
|
71
|
+
# Tawn — the twin you own
|
|
72
|
+
|
|
73
|
+
> **taw (ת) + own** — Local-first personal digital twin. Your data, your machine, your intelligence.
|
|
74
|
+
|
|
75
|
+
Tawn is a self-hosted memory and context core that unifies your work, wealth, research, and academic life into one searchable brain — shared across every AI agent you use (Claude Code, Cursor, Gemini CLI, and others).
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
pip install tawn
|
|
79
|
+
tawn init
|
|
80
|
+
tawn web start # opens the web dashboard at http://tawn:8787
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## What it does
|
|
84
|
+
|
|
85
|
+
- **Memory federation** — indexes conversations from Claude, ChatGPT, Gemini, Obsidian, and local files into one semantic store
|
|
86
|
+
- **Domain modules** — Work, Wealth (read-only), Research, and Academic — each with its own compiled wiki and entity graph
|
|
87
|
+
- **Multi-provider model routing** — Anthropic, OpenAI, Gemini, DeepSeek, OpenRouter, Ollama; local by default, cloud when needed
|
|
88
|
+
- **MCP server** — any MCP-compatible agent gets `recall`, `note`, and `brief` verbs against your twin's memory
|
|
89
|
+
- **Web dashboard** — streaming chat, memory browser, audit log, settings — at `tawn:8787`
|
|
90
|
+
- **Capability grants** — deny-all filesystem access by default; every read and write is audited
|
|
91
|
+
|
|
92
|
+
## Quick start
|
|
93
|
+
|
|
94
|
+
### Requirements
|
|
95
|
+
|
|
96
|
+
- Python 3.12+
|
|
97
|
+
- PostgreSQL (for memory and federation tables)
|
|
98
|
+
- Node.js 18+ (only needed if installing from source)
|
|
99
|
+
|
|
100
|
+
### Install
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# fast core install (add providers when needed)
|
|
104
|
+
pipx install tawn
|
|
105
|
+
|
|
106
|
+
# or install everything at once
|
|
107
|
+
pipx install "tawn[full]"
|
|
108
|
+
|
|
109
|
+
# individual provider extras
|
|
110
|
+
pip install "tawn[anthropic]" # Claude
|
|
111
|
+
pip install "tawn[openai]" # OpenAI / OpenRouter
|
|
112
|
+
pip install "tawn[gemini]" # Google Gemini
|
|
113
|
+
pip install "tawn[ollama]" # local models
|
|
114
|
+
pip install "tawn[vectors]" # pgvector for semantic search
|
|
115
|
+
pip install "tawn[mcp]" # MCP server
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Setup
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
tawn init # creates ~/.tawn/
|
|
122
|
+
tawn db setup # initialises PostgreSQL
|
|
123
|
+
tawn web start # starts the web server at tawn:8787
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Configure model providers:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
tawn setup # interactive wizard — sets API keys, DB, local model
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Or set keys directly:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# keys are stored in the OS keyring, never in files
|
|
136
|
+
tawn setup # interactive
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### MCP integration (Claude Code)
|
|
140
|
+
|
|
141
|
+
Add to your `~/.claude/claude.json`:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"mcpServers": {
|
|
146
|
+
"tawn": {
|
|
147
|
+
"command": "tawn",
|
|
148
|
+
"args": ["mcp"]
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Then from any Claude session: `tawn.recall("…")`, `tawn.note("…")`, `tawn.brief("work")`.
|
|
155
|
+
|
|
156
|
+
## Domain modules
|
|
157
|
+
|
|
158
|
+
| Domain | What it tracks |
|
|
159
|
+
|--------|---------------|
|
|
160
|
+
| **work** | Tasks, projects, decisions — per employer |
|
|
161
|
+
| **wealth** | Portfolio, net worth, holdings — **read-only, never trades** |
|
|
162
|
+
| **research** | Papers, experiments, entity graph, morning brief |
|
|
163
|
+
| **academic** | Applications, deadlines, proposal drafts |
|
|
164
|
+
|
|
165
|
+
Extend with your own domain:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
tawn domain add health # scaffolds a new domain plugin
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## CLI reference
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
tawn # chat with your twin
|
|
175
|
+
tawn note "…" # append a note to today's raw file
|
|
176
|
+
tawn recall "query" # semantic search over compiled memory
|
|
177
|
+
tawn brief work # daily summary for a domain
|
|
178
|
+
tawn compile # compile raw/ into wiki + vectors
|
|
179
|
+
tawn federation sources # list federated AI tool sources
|
|
180
|
+
tawn federation merge # ingest pending federation records
|
|
181
|
+
tawn web start/stop/status # web server control
|
|
182
|
+
tawn update # check and install latest release
|
|
183
|
+
tawn config list # view all settings
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Architecture
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
~/.tawn/
|
|
190
|
+
├── raw/ # immutable ingested sources
|
|
191
|
+
├── wiki/ # compiled markdown knowledge
|
|
192
|
+
├── federation/ # AI tool exports + adapters
|
|
193
|
+
├── grants.yaml # capability grants (deny-all default)
|
|
194
|
+
└── audit.log # every write, every cross-domain action
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
API server binds to `127.0.0.1` only. Wealth core is read-only. No withdrawal credentials ever stored.
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT — see [LICENSE](LICENSE).
|
tawn-0.1.0/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Tawn — the twin you own
|
|
2
|
+
|
|
3
|
+
> **taw (ת) + own** — Local-first personal digital twin. Your data, your machine, your intelligence.
|
|
4
|
+
|
|
5
|
+
Tawn is a self-hosted memory and context core that unifies your work, wealth, research, and academic life into one searchable brain — shared across every AI agent you use (Claude Code, Cursor, Gemini CLI, and others).
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pip install tawn
|
|
9
|
+
tawn init
|
|
10
|
+
tawn web start # opens the web dashboard at http://tawn:8787
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## What it does
|
|
14
|
+
|
|
15
|
+
- **Memory federation** — indexes conversations from Claude, ChatGPT, Gemini, Obsidian, and local files into one semantic store
|
|
16
|
+
- **Domain modules** — Work, Wealth (read-only), Research, and Academic — each with its own compiled wiki and entity graph
|
|
17
|
+
- **Multi-provider model routing** — Anthropic, OpenAI, Gemini, DeepSeek, OpenRouter, Ollama; local by default, cloud when needed
|
|
18
|
+
- **MCP server** — any MCP-compatible agent gets `recall`, `note`, and `brief` verbs against your twin's memory
|
|
19
|
+
- **Web dashboard** — streaming chat, memory browser, audit log, settings — at `tawn:8787`
|
|
20
|
+
- **Capability grants** — deny-all filesystem access by default; every read and write is audited
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
### Requirements
|
|
25
|
+
|
|
26
|
+
- Python 3.12+
|
|
27
|
+
- PostgreSQL (for memory and federation tables)
|
|
28
|
+
- Node.js 18+ (only needed if installing from source)
|
|
29
|
+
|
|
30
|
+
### Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# fast core install (add providers when needed)
|
|
34
|
+
pipx install tawn
|
|
35
|
+
|
|
36
|
+
# or install everything at once
|
|
37
|
+
pipx install "tawn[full]"
|
|
38
|
+
|
|
39
|
+
# individual provider extras
|
|
40
|
+
pip install "tawn[anthropic]" # Claude
|
|
41
|
+
pip install "tawn[openai]" # OpenAI / OpenRouter
|
|
42
|
+
pip install "tawn[gemini]" # Google Gemini
|
|
43
|
+
pip install "tawn[ollama]" # local models
|
|
44
|
+
pip install "tawn[vectors]" # pgvector for semantic search
|
|
45
|
+
pip install "tawn[mcp]" # MCP server
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Setup
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
tawn init # creates ~/.tawn/
|
|
52
|
+
tawn db setup # initialises PostgreSQL
|
|
53
|
+
tawn web start # starts the web server at tawn:8787
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Configure model providers:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
tawn setup # interactive wizard — sets API keys, DB, local model
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Or set keys directly:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# keys are stored in the OS keyring, never in files
|
|
66
|
+
tawn setup # interactive
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### MCP integration (Claude Code)
|
|
70
|
+
|
|
71
|
+
Add to your `~/.claude/claude.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"tawn": {
|
|
77
|
+
"command": "tawn",
|
|
78
|
+
"args": ["mcp"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then from any Claude session: `tawn.recall("…")`, `tawn.note("…")`, `tawn.brief("work")`.
|
|
85
|
+
|
|
86
|
+
## Domain modules
|
|
87
|
+
|
|
88
|
+
| Domain | What it tracks |
|
|
89
|
+
|--------|---------------|
|
|
90
|
+
| **work** | Tasks, projects, decisions — per employer |
|
|
91
|
+
| **wealth** | Portfolio, net worth, holdings — **read-only, never trades** |
|
|
92
|
+
| **research** | Papers, experiments, entity graph, morning brief |
|
|
93
|
+
| **academic** | Applications, deadlines, proposal drafts |
|
|
94
|
+
|
|
95
|
+
Extend with your own domain:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
tawn domain add health # scaffolds a new domain plugin
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## CLI reference
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
tawn # chat with your twin
|
|
105
|
+
tawn note "…" # append a note to today's raw file
|
|
106
|
+
tawn recall "query" # semantic search over compiled memory
|
|
107
|
+
tawn brief work # daily summary for a domain
|
|
108
|
+
tawn compile # compile raw/ into wiki + vectors
|
|
109
|
+
tawn federation sources # list federated AI tool sources
|
|
110
|
+
tawn federation merge # ingest pending federation records
|
|
111
|
+
tawn web start/stop/status # web server control
|
|
112
|
+
tawn update # check and install latest release
|
|
113
|
+
tawn config list # view all settings
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Architecture
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
~/.tawn/
|
|
120
|
+
├── raw/ # immutable ingested sources
|
|
121
|
+
├── wiki/ # compiled markdown knowledge
|
|
122
|
+
├── federation/ # AI tool exports + adapters
|
|
123
|
+
├── grants.yaml # capability grants (deny-all default)
|
|
124
|
+
└── audit.log # every write, every cross-domain action
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
API server binds to `127.0.0.1` only. Wealth core is read-only. No withdrawal credentials ever stored.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tawn"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Tawn — the personal digital twin. Local-first memory and context core for your work, wealth, research, and academic life."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Testimony Adekoya", email = "testimonyadekoya.02@gmail.com" },
|
|
13
|
+
]
|
|
14
|
+
keywords = ["ai", "personal-ai", "digital-twin", "memory", "mcp", "rag", "local-first", "llm"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Environment :: Web Environment",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Intended Audience :: End Users/Desktop",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Operating System :: POSIX :: Linux",
|
|
23
|
+
"Operating System :: MacOS",
|
|
24
|
+
"Operating System :: Microsoft :: Windows",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Topic :: Office/Business",
|
|
29
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
30
|
+
]
|
|
31
|
+
requires-python = ">=3.12"
|
|
32
|
+
dependencies = [
|
|
33
|
+
# core — always installed
|
|
34
|
+
"pydantic>=2.7",
|
|
35
|
+
"pydantic-settings>=2.2",
|
|
36
|
+
"PyYAML>=6.0",
|
|
37
|
+
"typer>=0.12",
|
|
38
|
+
"SQLAlchemy>=2.0",
|
|
39
|
+
"psycopg[binary]>=3.1",
|
|
40
|
+
"httpx>=0.27",
|
|
41
|
+
"rich>=13.7",
|
|
42
|
+
"fastapi>=0.111",
|
|
43
|
+
"uvicorn>=0.30",
|
|
44
|
+
"keyring>=25.0",
|
|
45
|
+
"python-frontmatter>=1.1",
|
|
46
|
+
"rapidfuzz>=3.0",
|
|
47
|
+
"watchfiles>=0.21",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[project.optional-dependencies]
|
|
51
|
+
# individual provider extras
|
|
52
|
+
anthropic = ["anthropic>=0.100"]
|
|
53
|
+
openai = ["openai>=2.0"]
|
|
54
|
+
gemini = ["google-genai>=1.0"]
|
|
55
|
+
ollama = ["ollama>=0.4"]
|
|
56
|
+
vectors = ["pgvector>=0.3"]
|
|
57
|
+
mcp = ["fastmcp>=2.0"]
|
|
58
|
+
# convenience meta-extras
|
|
59
|
+
providers = ["anthropic>=0.100", "openai>=2.0", "google-genai>=1.0", "ollama>=0.4"]
|
|
60
|
+
full = [
|
|
61
|
+
"anthropic>=0.100", "openai>=2.0", "google-genai>=1.0",
|
|
62
|
+
"ollama>=0.4", "pgvector>=0.3", "fastmcp>=2.0",
|
|
63
|
+
]
|
|
64
|
+
dev = ["pytest>=8.0", "respx>=0.21"]
|
|
65
|
+
|
|
66
|
+
[project.urls]
|
|
67
|
+
Homepage = "https://github.com/tawn-hq/tawn"
|
|
68
|
+
Repository = "https://github.com/tawn-hq/tawn"
|
|
69
|
+
"Bug Tracker" = "https://github.com/tawn-hq/tawn/issues"
|
|
70
|
+
|
|
71
|
+
[project.scripts]
|
|
72
|
+
tawn = "tawn.cli:app"
|
|
73
|
+
|
|
74
|
+
[project.entry-points."tawn.domains"]
|
|
75
|
+
wealth = "tawn.domains.wealth:register"
|
|
76
|
+
work = "tawn.domains.work:register"
|
|
77
|
+
research = "tawn.domains.research:register"
|
|
78
|
+
academic = "tawn.domains.academic:register"
|
|
79
|
+
hobby = "tawn.domains.hobby:register"
|
|
80
|
+
|
|
81
|
+
[tool.setuptools.packages.find]
|
|
82
|
+
where = ["src"]
|
|
83
|
+
|
|
84
|
+
[tool.setuptools.package-data]
|
|
85
|
+
tawn = [
|
|
86
|
+
"web/dist/**/*",
|
|
87
|
+
"web/dist/*",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
[tool.pytest.ini_options]
|
|
91
|
+
testpaths = ["tests"]
|
|
92
|
+
|
|
93
|
+
[tool.tawn.scripts]
|
|
94
|
+
build-web = "cd frontend && npm install && npm run build"
|
tawn-0.1.0/setup.cfg
ADDED
tawn-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import subprocess
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from setuptools import setup
|
|
6
|
+
from setuptools.command.build_py import build_py
|
|
7
|
+
|
|
8
|
+
HERE = Path(__file__).parent
|
|
9
|
+
FRONTEND = HERE / "frontend"
|
|
10
|
+
DIST_SRC = FRONTEND / "dist"
|
|
11
|
+
# frontend dist lands inside the package so it's included in the wheel
|
|
12
|
+
DIST_DST = HERE / "src" / "tawn" / "web" / "dist"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BuildFrontend(build_py):
|
|
16
|
+
def run(self):
|
|
17
|
+
# `python -m build`'s default flow builds the wheel from an
|
|
18
|
+
# isolated copy of the *sdist*, not the working tree — and the
|
|
19
|
+
# sdist never contains the top-level frontend/ dir (it's not part
|
|
20
|
+
# of the Python package, so nothing declares it for inclusion).
|
|
21
|
+
# `src/tawn/web/dist` DOES ship in the sdist (it's inside the
|
|
22
|
+
# package, matched by package-data), so if the workflow already
|
|
23
|
+
# populated it — build the frontend, then `cp -r dist/. ../src/
|
|
24
|
+
# tawn/web/dist/`, exactly like publish.yml — there's nothing left
|
|
25
|
+
# to do here and no reason to expect frontend/ to exist at all.
|
|
26
|
+
already_bundled = DIST_DST.is_dir() and any(DIST_DST.iterdir())
|
|
27
|
+
if not already_bundled:
|
|
28
|
+
if FRONTEND.is_dir():
|
|
29
|
+
if not DIST_SRC.is_dir():
|
|
30
|
+
if shutil.which("npm"):
|
|
31
|
+
subprocess.run(["npm", "ci"], cwd=str(FRONTEND), check=True)
|
|
32
|
+
subprocess.run(["npm", "run", "build"], cwd=str(FRONTEND), check=True)
|
|
33
|
+
else:
|
|
34
|
+
import warnings
|
|
35
|
+
warnings.warn("npm not found — web dashboard will not be bundled", stacklevel=2)
|
|
36
|
+
if DIST_SRC.is_dir():
|
|
37
|
+
if DIST_DST.exists():
|
|
38
|
+
shutil.rmtree(DIST_DST)
|
|
39
|
+
shutil.copytree(DIST_SRC, DIST_DST)
|
|
40
|
+
else:
|
|
41
|
+
import warnings
|
|
42
|
+
warnings.warn(
|
|
43
|
+
"frontend/ not present (isolated sdist build?) and no "
|
|
44
|
+
"pre-built web/dist — web dashboard will not be bundled",
|
|
45
|
+
stacklevel=2,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
super().run()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
setup(cmdclass={"build_py": BuildFrontend})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Internal entrypoint for the background web server process.
|
|
2
|
+
|
|
3
|
+
Run as: python -m tawn._webserver <port>
|
|
4
|
+
Not intended for direct user invocation — use `tawn web start/stop`.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _start_auto_compiler(engine) -> None:
|
|
11
|
+
import threading
|
|
12
|
+
import time
|
|
13
|
+
from tawn.db import session as db_session
|
|
14
|
+
from tawn.compiler.compiler import run_compile as run_compiler
|
|
15
|
+
from tawn.federation.merge import scan_all_sources, merge_pending
|
|
16
|
+
from tawn.home import tawn_home
|
|
17
|
+
|
|
18
|
+
def _bootstrap_then_loop():
|
|
19
|
+
# Bootstrap: ingest + merge all existing federation files on startup.
|
|
20
|
+
# Runs in this background thread, not before uvicorn.run() — a
|
|
21
|
+
# source directory can hold thousands of files (a size cap on
|
|
22
|
+
# individual files exists, but the walk itself over many entries
|
|
23
|
+
# still takes real time), and the web server must bind its port
|
|
24
|
+
# immediately regardless of how long that one-time scan takes.
|
|
25
|
+
try:
|
|
26
|
+
with db_session(engine) as s:
|
|
27
|
+
n = scan_all_sources(tawn_home(), s)
|
|
28
|
+
if n > 0:
|
|
29
|
+
merge_pending(tawn_home(), s)
|
|
30
|
+
except Exception:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
while True:
|
|
34
|
+
try:
|
|
35
|
+
with db_session(engine) as session:
|
|
36
|
+
run_compiler(tawn_home(), session)
|
|
37
|
+
except Exception:
|
|
38
|
+
pass
|
|
39
|
+
time.sleep(30 * 60) # 30-minute interval
|
|
40
|
+
|
|
41
|
+
t = threading.Thread(target=_bootstrap_then_loop, name="tawn-auto-compiler", daemon=True)
|
|
42
|
+
t.start()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def main(port: int = 8787) -> None:
|
|
46
|
+
import uvicorn
|
|
47
|
+
from tawn.db import make_engine
|
|
48
|
+
from tawn.web import create_app
|
|
49
|
+
|
|
50
|
+
from tawn.db import init_db
|
|
51
|
+
from tawn.updater import start_daily_updater
|
|
52
|
+
engine = make_engine(pooled=True)
|
|
53
|
+
init_db(engine)
|
|
54
|
+
start_daily_updater()
|
|
55
|
+
_start_auto_compiler(engine)
|
|
56
|
+
uvicorn.run(
|
|
57
|
+
create_app(engine),
|
|
58
|
+
host="127.0.0.1",
|
|
59
|
+
port=port,
|
|
60
|
+
log_level="warning",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8787
|
|
66
|
+
main(port)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Branded terminal identity (brand/README.md: Cairn × Sandstone & Lapis).
|
|
2
|
+
|
|
3
|
+
The cairn: three stones, lapis capstone. The wordmark lettering follows
|
|
4
|
+
the drawn monoline mark — rounded, lowercase, final n in lapis.
|
|
5
|
+
Colors are the brand tokens; Rich truecolor degrades gracefully.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from rich.columns import Columns
|
|
9
|
+
from rich.console import Group
|
|
10
|
+
from rich.padding import Padding
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
from rich.text import Text
|
|
13
|
+
|
|
14
|
+
# brand tokens (brand/tokens.css) — dark-ground values; terminals are
|
|
15
|
+
# usually dark, and both lapis values pass on light too.
|
|
16
|
+
LAPIS = "#4A7BC8"
|
|
17
|
+
BONE = "#EFE9DC"
|
|
18
|
+
MUTED = "#ADA28C"
|
|
19
|
+
|
|
20
|
+
_CAIRN = [
|
|
21
|
+
(" ▄██▄ ", LAPIS),
|
|
22
|
+
(" ▀██▀ ", LAPIS),
|
|
23
|
+
(" ▄████▄ ", BONE),
|
|
24
|
+
(" ▀████▀ ", BONE),
|
|
25
|
+
(" ▄██████▄ ", BONE),
|
|
26
|
+
(" ▀██████▀ ", BONE),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
# monoline block lettering — t a w in bone, n in lapis (the letter that
|
|
30
|
+
# makes it *own*), matching the wordmark rule in brand/README.md
|
|
31
|
+
_LETTERS = [
|
|
32
|
+
("▄█▄ ▄▀▀▄ █ █ ", "█▀▀▄"),
|
|
33
|
+
(" █ █▄▄█ █ ▄ █ ", "█ █"),
|
|
34
|
+
(" ▀▄ █ █ ▀▄▀▄▀ ", "█ █"),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def cairn() -> Text:
|
|
39
|
+
art = Text()
|
|
40
|
+
for i, (line, color) in enumerate(_CAIRN):
|
|
41
|
+
art.append(line, style=color)
|
|
42
|
+
if i < len(_CAIRN) - 1:
|
|
43
|
+
art.append("\n")
|
|
44
|
+
return art
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def wordmark() -> Text:
|
|
48
|
+
art = Text()
|
|
49
|
+
for i, (taw, n) in enumerate(_LETTERS):
|
|
50
|
+
art.append(taw, style=f"bold {BONE}")
|
|
51
|
+
art.append(n, style=f"bold {LAPIS}")
|
|
52
|
+
if i < len(_LETTERS) - 1:
|
|
53
|
+
art.append("\n")
|
|
54
|
+
return art
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def banner(version: str) -> Group:
|
|
58
|
+
lockup = Columns([cairn(), Padding(wordmark(), (1, 0, 0, 2))], padding=(0, 2))
|
|
59
|
+
tag = Text()
|
|
60
|
+
tag.append("the twin you own", style=f"italic {MUTED}")
|
|
61
|
+
tag.append(f" · v{version}", style=MUTED)
|
|
62
|
+
return Group(lockup, Padding(tag, (0, 0, 0, 1)))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def status_table(rows: list[tuple[str, bool, str]]) -> Table:
|
|
66
|
+
t = Table(show_header=False, box=None, padding=(0, 1))
|
|
67
|
+
t.add_column(style=MUTED)
|
|
68
|
+
t.add_column()
|
|
69
|
+
t.add_column(style=MUTED)
|
|
70
|
+
for name, ok, detail in rows:
|
|
71
|
+
mark = Text("●", style="green" if ok else "red")
|
|
72
|
+
t.add_row(name, mark, detail)
|
|
73
|
+
return t
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def commands_table(commands: list[tuple[str, str]]) -> Table:
|
|
77
|
+
t = Table(show_header=False, box=None, padding=(0, 1))
|
|
78
|
+
t.add_column(style=f"bold {LAPIS}")
|
|
79
|
+
t.add_column(style=MUTED)
|
|
80
|
+
for cmd, desc in commands:
|
|
81
|
+
t.add_row(cmd, desc)
|
|
82
|
+
return t
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Capability layer: grants, integrity, audit, and the FS chokepoint."""
|