From 681c881c817222a27adbf47717ca86560f7bc45b Mon Sep 17 00:00:00 2001
From: Nasser <42423897+Abdulnaser97@users.noreply.github.com>
Date: Fri, 14 Nov 2025 22:19:25 -0500
Subject: [PATCH 1/5] CodeCanvas: Save
---
activitywatch.CodeCanvas | 10199 +++++++++++++++++++++++++++++++++++++
1 file changed, 10199 insertions(+)
create mode 100644 activitywatch.CodeCanvas
diff --git a/activitywatch.CodeCanvas b/activitywatch.CodeCanvas
new file mode 100644
index 00000000..b8f3e8ca
--- /dev/null
+++ b/activitywatch.CodeCanvas
@@ -0,0 +1,10199 @@
+{
+ "drawioXML": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n",
+ "fileName": "activitywatch.CodeCanvas",
+ "fileURL": "github",
+ "diagramTemplateVersion": 0.2,
+ "filePath": "activitywatch.CodeCanvas",
+ "repoData": {
+ "README.md": {
+ "path": "README.md",
+ "fileName": "README.md",
+ "cellName": "README.md",
+ "cellId": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5",
+ "visible": true,
+ "children": [
+ "README.md-simstep-9396ef3a-ed06-4635-bb1d-3b136660bcc4"
+ ]
+ },
+ "aw-client": {
+ "path": "aw-client",
+ "fileName": "aw-client",
+ "cellName": "aw-client",
+ "cellId": "900d6121-1844-48ba-9a18-db1ec6ea9793",
+ "visible": true,
+ "children": [
+ "aw-client/aw_client",
+ "aw-client/examples"
+ ]
+ },
+ "aw-client/aw_client": {
+ "path": "aw-client/aw_client",
+ "fileName": "aw_client",
+ "cellName": "aw_client",
+ "cellId": "48103d9a-f009-4555-bb82-435f417b0644",
+ "visible": true,
+ "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793",
+ "children": [
+ "aw-client/aw_client/client.py",
+ "aw-client/aw_client/queries.py"
+ ]
+ },
+ "aw-client/aw_client/client.py": {
+ "path": "aw-client/aw_client/client.py",
+ "fileName": "client.py",
+ "cellName": "client.py",
+ "cellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "visible": true,
+ "parentCellId": "48103d9a-f009-4555-bb82-435f417b0644",
+ "children": [
+ "aw-client/aw_client/client.py-simstep-432d1978-befd-4dfd-979b-fe28821d4e00",
+ "generated-edge-simstep-11bc8b75-0103-4652-9fec-e55af41400a0-78766ca9-9103-486a-8755-f57a09e7f5a7",
+ "generated-edge-simstep-c1a26d9b-d661-4a99-8275-39a414824ed6-6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
+ "generated-edge-simstep-9eeb592f-5c44-4ce1-a7a0-261bc6d6b679-e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
+ "aw-client/aw_client/client.py-simstep-06f7c9e7-1c78-4114-867b-3dbb20dcc427",
+ "generated-edge-simstep-5dc6bd77-15d2-44c3-b665-8de88288c314-71408ae2-19e6-4327-bab9-8918af09c855",
+ "aw-client/aw_client/client.py-simstep-8739f5eb-aec2-47f1-b1e6-a05a2bb65acd",
+ "aw-client/aw_client/client.py-simstep-ea6d2274-023a-4d5f-abf4-0414c6c7f68d",
+ "generated-edge-simstep-8efaf2e1-7c6d-4820-90a5-2abb80bf65ed-5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
+ "generated-edge-simstep-f5c06885-1138-4c13-ae70-10b9d409be5b-ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
+ "aw-client/aw_client/client.py-simstep-0d34430a-af81-407b-8817-672288674005",
+ "aw-client/aw_client/client.py-simstep-642425c3-abd7-45fe-b5a9-a76bf90a9477",
+ "generated-edge-simstep-834b7dbc-5efe-41ac-b75b-e43ad32141df-62388ee6-67f4-4adc-b08e-90deeb10efd4",
+ "generated-edge-simstep-33e5b4e9-bd66-45f5-ab0f-543737810b99-ec5d6b90-2f5f-4a07-b0e8-da3610035a92"
+ ]
+ },
+ "aw-client/aw_client/queries.py": {
+ "path": "aw-client/aw_client/queries.py",
+ "fileName": "queries.py",
+ "cellName": "queries.py",
+ "cellId": "941d7da8-a28d-4d5e-806f-3b546909f74e",
+ "visible": true,
+ "parentCellId": "48103d9a-f009-4555-bb82-435f417b0644",
+ "children": [
+ "aw-client/aw_client/queries.py-simstep-81f31a9b-3434-4458-a7d3-bdcf610af75e",
+ "aw-client/aw_client/queries.py-simstep-1b40cfa3-9cf5-4dc3-830f-74cb1d476d50"
+ ]
+ },
+ "aw-client/examples": {
+ "path": "aw-client/examples",
+ "fileName": "examples",
+ "cellName": "examples",
+ "cellId": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c",
+ "visible": true,
+ "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793",
+ "children": [
+ "aw-client/examples/working_hours.py"
+ ]
+ },
+ "aw-client/examples/working_hours.py": {
+ "path": "aw-client/examples/working_hours.py",
+ "fileName": "working_hours.py",
+ "cellName": "working_hours.py",
+ "cellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
+ "visible": true,
+ "parentCellId": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c",
+ "children": [
+ "aw-client/examples/working_hours.py-simstep-e90cee0c-3a20-498b-97b9-2086a61dc02b",
+ "aw-client/examples/working_hours.py-simstep-e38db73e-b347-4786-8efd-1e7cab44f73f",
+ "generated-edge-simstep-5aa97ae5-7e30-4d15-8f12-05942f2e75c9-aecc1e90-5e71-43f4-a5b8-757de329fe3a",
+ "generated-edge-simstep-65443293-5e86-4e71-9e8d-19d61bd162d9-c8cbde86-13c0-4232-898e-104d815a805c"
+ ]
+ },
+ "aw-core": {
+ "path": "aw-core",
+ "fileName": "aw-core",
+ "cellName": "aw-core",
+ "cellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
+ "visible": true,
+ "children": [
+ "aw-core/aw_datastore",
+ "aw-core/aw_query",
+ "aw-core/aw_transform"
+ ]
+ },
+ "aw-core/aw_datastore": {
+ "path": "aw-core/aw_datastore",
+ "fileName": "aw_datastore",
+ "cellName": "aw_datastore",
+ "cellId": "5093a30d-28ac-4c2b-811d-65c61efc0882",
+ "visible": true,
+ "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
+ "children": [
+ "aw-core/aw_datastore/datastore.py",
+ "aw-core/aw_datastore/storages"
+ ]
+ },
+ "aw-core/aw_datastore/datastore.py": {
+ "path": "aw-core/aw_datastore/datastore.py",
+ "fileName": "datastore.py",
+ "cellName": "datastore.py",
+ "cellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
+ "visible": true,
+ "parentCellId": "5093a30d-28ac-4c2b-811d-65c61efc0882",
+ "children": [
+ "aw-core/aw_datastore/datastore.py-simstep-5573707d-aa48-4a66-a3dc-25c841986d39",
+ "generated-edge-simstep-ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c-e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4"
+ ]
+ },
+ "aw-core/aw_datastore/storages": {
+ "path": "aw-core/aw_datastore/storages",
+ "fileName": "storages",
+ "cellName": "storages",
+ "cellId": "b2eb5c59-4162-4dea-ac74-511f22996f00",
+ "visible": true,
+ "parentCellId": "5093a30d-28ac-4c2b-811d-65c61efc0882",
+ "children": [
+ "aw-core/aw_datastore/storages/peewee.py"
+ ]
+ },
+ "aw-core/aw_datastore/storages/peewee.py": {
+ "path": "aw-core/aw_datastore/storages/peewee.py",
+ "fileName": "peewee.py",
+ "cellName": "peewee.py",
+ "cellId": "a63cc090-4355-47fb-8b22-62cd1b842ddb",
+ "visible": true,
+ "parentCellId": "b2eb5c59-4162-4dea-ac74-511f22996f00"
+ },
+ "aw-core/aw_query": {
+ "path": "aw-core/aw_query",
+ "fileName": "aw_query",
+ "cellName": "aw_query",
+ "cellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
+ "visible": true,
+ "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
+ "children": [
+ "aw-core/aw_query/query2.py",
+ "aw-core/aw_query/functions.py"
+ ]
+ },
+ "aw-core/aw_query/functions.py": {
+ "path": "aw-core/aw_query/functions.py",
+ "fileName": "functions.py",
+ "cellName": "functions.py",
+ "cellId": "e1b937af-2584-42ee-8281-e1bffda373ae",
+ "visible": true,
+ "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
+ "children": [
+ "aw-core/aw_query/functions.py-simstep-6ea3ab36-027f-40b9-a0ba-9ede77ae1117"
+ ]
+ },
+ "aw-core/aw_query/query2.py": {
+ "path": "aw-core/aw_query/query2.py",
+ "fileName": "query2.py",
+ "cellName": "query2.py",
+ "cellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
+ "visible": true,
+ "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
+ "children": [
+ "aw-core/aw_query/query2.py-simstep-5f7b6985-edf0-42eb-8822-847d0d7b8e9b",
+ "aw-core/aw_query/query2.py-simstep-ab3fe2d5-9396-4241-b64e-2a187e97de75",
+ "generated-edge-simstep-7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6-4059fcbe-a1ee-41d0-b576-55a1d278bca0"
+ ]
+ },
+ "aw-core/aw_transform": {
+ "path": "aw-core/aw_transform",
+ "fileName": "aw_transform",
+ "cellName": "aw_transform",
+ "cellId": "34f5debb-c898-419f-9c17-186d2a5f6e85",
+ "visible": true,
+ "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
+ "children": [
+ "aw-core/aw_transform/heartbeats.py"
+ ]
+ },
+ "aw-core/aw_transform/heartbeats.py": {
+ "path": "aw-core/aw_transform/heartbeats.py",
+ "fileName": "heartbeats.py",
+ "cellName": "heartbeats.py",
+ "cellId": "6860aa38-bc11-4d81-9260-87eba1c02581",
+ "visible": true,
+ "parentCellId": "34f5debb-c898-419f-9c17-186d2a5f6e85",
+ "children": [
+ "aw-core/aw_transform/heartbeats.py-simstep-d2eac5dc-58f7-408c-beba-c1711beec25a",
+ "generated-edge-simstep-9f918447-9e45-4c3b-b34f-658f58d35495-31cd2b01-8df9-4d95-9a91-d4c3aa153eb0"
+ ]
+ },
+ "aw-notify": {
+ "path": "aw-notify",
+ "fileName": "aw-notify",
+ "cellName": "aw-notify",
+ "cellId": "0b23a1ca-091a-4f70-b49e-95910c8179bf",
+ "visible": true,
+ "children": [
+ "aw-notify/aw_notify"
+ ]
+ },
+ "aw-notify/aw_notify": {
+ "path": "aw-notify/aw_notify",
+ "fileName": "aw_notify",
+ "cellName": "aw_notify",
+ "cellId": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7",
+ "visible": true,
+ "parentCellId": "0b23a1ca-091a-4f70-b49e-95910c8179bf",
+ "children": [
+ "aw-notify/aw_notify/main.py"
+ ]
+ },
+ "aw-notify/aw_notify/main.py": {
+ "path": "aw-notify/aw_notify/main.py",
+ "fileName": "main.py",
+ "cellName": "main.py",
+ "cellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "visible": true,
+ "parentCellId": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7",
+ "children": [
+ "aw-notify/aw_notify/main.py-simstep-2108914e-2569-47bf-aa87-af337de03f8c",
+ "aw-notify/aw_notify/main.py-simstep-9b9a0f90-d7a7-40fb-8573-53b470ecf85d",
+ "aw-notify/aw_notify/main.py-simstep-f636bdd6-a8e3-47ec-9f9d-986b21a81868",
+ "aw-notify/aw_notify/main.py-simstep-945e3312-c7c9-4722-953b-94dc0feee249",
+ "aw-notify/aw_notify/main.py-simstep-9c0b3f20-5c18-418a-82f7-78b04ebda9b5",
+ "aw-notify/aw_notify/main.py-simstep-a66f8ebc-93f8-4f9c-8f19-03bd951d1e98",
+ "aw-notify/aw_notify/main.py-simstep-21533839-7ba4-4cfa-864a-2f67198cad68",
+ "generated-edge-simstep-3c977159-c34d-4907-9004-e5aaff3f3bdc-f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
+ "generated-edge-simstep-7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b-22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
+ "generated-edge-simstep-f20bb756-15f3-4a7c-914b-aa61470cc435-5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
+ "generated-edge-simstep-027140c6-aa16-4070-89d3-3b553168e65e-5595958a-cf9d-4894-9824-ecc89e5cf956",
+ "generated-edge-simstep-92487214-03b7-430e-aab5-b5a5fb85b2cb-1b9dc1d5-e6a7-4069-8473-2156853d662e",
+ "generated-edge-simstep-c8b0fe19-76a8-458d-9923-c2f270e306b3-08e05622-d948-47eb-a56d-3d6782d638c0",
+ "generated-edge-simstep-e46653da-3493-419e-8f9c-397be83fe894-17c4cd6c-69f5-4df8-ac77-6955a0518939"
+ ]
+ },
+ "aw-qt": {
+ "path": "aw-qt",
+ "fileName": "aw-qt",
+ "cellName": "aw-qt",
+ "cellId": "315afad3-54aa-4009-bbe4-8e17ade01ec1",
+ "visible": true,
+ "children": [
+ "aw-qt/aw_qt"
+ ]
+ },
+ "aw-qt/aw_qt": {
+ "path": "aw-qt/aw_qt",
+ "fileName": "aw_qt",
+ "cellName": "aw_qt",
+ "cellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
+ "visible": true,
+ "parentCellId": "315afad3-54aa-4009-bbe4-8e17ade01ec1",
+ "children": [
+ "aw-qt/aw_qt/main.py",
+ "aw-qt/aw_qt/config.py",
+ "aw-qt/aw_qt/manager.py",
+ "aw-qt/aw_qt/trayicon.py"
+ ]
+ },
+ "aw-qt/aw_qt/config.py": {
+ "path": "aw-qt/aw_qt/config.py",
+ "fileName": "config.py",
+ "cellName": "config.py",
+ "cellId": "f47c0efe-5fd2-488b-b325-b2965448260a",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
+ "children": [
+ "aw-qt/aw_qt/config.py-simstep-c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a"
+ ]
+ },
+ "aw-qt/aw_qt/main.py": {
+ "path": "aw-qt/aw_qt/main.py",
+ "fileName": "main.py",
+ "cellName": "main.py",
+ "cellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
+ "children": [
+ "aw-qt/aw_qt/main.py-simstep-61d1a03e-ed06-496d-8495-36419b9c8607",
+ "generated-edge-simstep-6084ca69-514e-4bde-b2c0-1d33b26203e8-1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
+ "generated-edge-simstep-540119c2-b541-4342-aa59-233b4f0f8db5-030668a5-a377-4710-b39f-95efb5fa4768"
+ ]
+ },
+ "aw-qt/aw_qt/manager.py": {
+ "path": "aw-qt/aw_qt/manager.py",
+ "fileName": "manager.py",
+ "cellName": "manager.py",
+ "cellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
+ "children": [
+ "aw-qt/aw_qt/manager.py-simstep-e716abbb-c96e-4613-bca2-0c094e8df129",
+ "aw-qt/aw_qt/manager.py-simstep-8be10173-751a-4da9-99a9-321c23e71aaa",
+ "aw-qt/aw_qt/manager.py-simstep-520ab3f2-ef6c-4334-89fc-280f6d86d14b",
+ "aw-qt/aw_qt/manager.py-simstep-899b57ba-4a68-4620-977a-80981d089e85",
+ "aw-qt/aw_qt/manager.py-simstep-6173a9e1-ecfa-4dd9-9f82-f80579406011",
+ "generated-edge-simstep-9aeaf443-6741-4557-9671-67d596f456b3-1fb5a75e-9c49-490d-b412-04ac1c7205fa",
+ "generated-edge-simstep-f968357d-53c4-41e8-b71f-c581c08b52e6-a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
+ "generated-edge-simstep-fdff8ecd-12b9-4bc0-ba7b-9402d26b1737-9d4dee50-64ef-459a-98fa-839761e16813"
+ ]
+ },
+ "aw-qt/aw_qt/trayicon.py": {
+ "path": "aw-qt/aw_qt/trayicon.py",
+ "fileName": "trayicon.py",
+ "cellName": "trayicon.py",
+ "cellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
+ "children": [
+ "aw-qt/aw_qt/trayicon.py-simstep-6ae15f2e-5331-4153-b9d2-2a297b65c55f",
+ "aw-qt/aw_qt/trayicon.py-simstep-08d88f03-4133-41d6-9cbb-0df16703b864",
+ "aw-qt/aw_qt/trayicon.py-simstep-01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9",
+ "aw-qt/aw_qt/trayicon.py-simstep-a71f6cd0-490a-40b5-8a05-1c873f208882",
+ "generated-edge-simstep-03fd319d-4ffe-47cf-bf39-ac388da80fa7-dfaa3fc8-eca8-4c67-b926-87798f511adb",
+ "generated-edge-simstep-8e583414-7b87-42c9-bdb2-e56259be4cdf-d9e460b6-432d-49c8-8e76-0d8750aa2c10",
+ "generated-edge-simstep-c0115129-b34b-4d27-9f73-cf2dc142ea81-f704019b-d227-47ad-8761-9a2ea01516cb",
+ "generated-edge-simstep-7775ac80-c954-464e-b230-b233216ee5e3-ba9e605d-98a7-4b50-979a-05bf7213c681",
+ "generated-edge-simstep-1ed5cd16-b593-41cf-84f2-233a8d64a227-2298c4b5-17de-487f-b592-2ac0f95eca84"
+ ]
+ },
+ "aw-server": {
+ "path": "aw-server",
+ "fileName": "aw-server",
+ "cellName": "aw-server",
+ "cellId": "efb8048c-455c-4e7a-aa18-9e8b04779b71",
+ "visible": true,
+ "children": [
+ "aw-server/aw_server"
+ ]
+ },
+ "aw-server/aw_server": {
+ "path": "aw-server/aw_server",
+ "fileName": "aw_server",
+ "cellName": "aw_server",
+ "cellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
+ "visible": true,
+ "parentCellId": "efb8048c-455c-4e7a-aa18-9e8b04779b71",
+ "children": [
+ "aw-server/aw_server/rest.py",
+ "aw-server/aw_server/api.py"
+ ]
+ },
+ "aw-server/aw_server/api.py": {
+ "path": "aw-server/aw_server/api.py",
+ "fileName": "api.py",
+ "cellName": "api.py",
+ "cellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
+ "children": [
+ "aw-server/aw_server/api.py-simstep-addb33f5-b815-49f0-9b54-a8ee3fb3b87b",
+ "generated-edge-simstep-cd6c54a5-c0bd-4b99-9446-ea921ee876a6-6a5be6b6-e11d-460d-8193-427f3a9e42ac",
+ "aw-server/aw_server/api.py-simstep-a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31",
+ "generated-edge-simstep-833f0f0f-ec00-4960-b1f9-46d8a8530a01-b79b67f9-1be1-48f1-920a-9ebdd4417272",
+ "aw-server/aw_server/api.py-simstep-7357e239-3712-4b55-a94c-2165ea1f3255",
+ "aw-server/aw_server/api.py-simstep-bb678fe2-e6e3-472b-8ae4-95e362d4bdaf",
+ "aw-server/aw_server/api.py-simstep-976cfbd0-8946-4157-81b0-0ae6dffa43e1",
+ "generated-edge-simstep-40b16e25-734b-44d2-86cd-7c301723ff5f-9aec4875-5718-4c38-a57c-1d3053c38ba5",
+ "aw-server/aw_server/api.py-simstep-d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6",
+ "aw-server/aw_server/api.py-simstep-5fb7b7d5-1759-43dc-a711-b2b0b5df3893",
+ "aw-server/aw_server/api.py-simstep-4050248c-1638-452c-8826-677a7a2fece8",
+ "aw-server/aw_server/api.py-simstep-164ed08b-0873-499b-b945-e062cf362429",
+ "generated-edge-simstep-60764034-1b94-4c15-9015-09e8b775f736-ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
+ "generated-edge-simstep-7a5f8838-8ed9-47b3-907f-077efeedaa10-272a1088-1b0c-43f9-8335-d7055539c813",
+ "generated-edge-simstep-7e01821d-906c-4518-a1e0-6b71be84291a-941b8c57-be7c-49cd-ba2a-d2237f8f129b",
+ "generated-edge-simstep-666a933a-7a74-4d90-be19-7610f7bd3d74-1f7db50a-bc15-48d1-9f06-27ed743afa75"
+ ]
+ },
+ "aw-server/aw_server/rest.py": {
+ "path": "aw-server/aw_server/rest.py",
+ "fileName": "rest.py",
+ "cellName": "rest.py",
+ "cellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
+ "children": [
+ "generated-edge-simstep-97f58e0a-cbeb-4895-b613-d8e9fd129a42-5a7fba44-6d4d-4836-bc13-ed69518c9d45",
+ "aw-server/aw_server/rest.py-simstep-671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7",
+ "generated-edge-simstep-5a0d9b17-b09a-4aa5-9234-c01cb2aadef4-891bfe3a-f22a-4998-acea-aa6d0c362821",
+ "generated-edge-simstep-fe43857f-ef7d-455d-a9c4-37d54d12207a-c4b6d403-d2a9-4cff-8a72-31189a53c0db",
+ "aw-server/aw_server/rest.py-simstep-e98f7509-f28f-4534-8f2a-f525edc73f69",
+ "generated-edge-simstep-02717bea-6ee3-48ef-8c41-0c9f3e9d9a58-a676f81f-8c68-4fc8-94b7-583bada02d70",
+ "generated-edge-simstep-d57d2bf7-916c-44cd-844d-b1900c276925-a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
+ "aw-server/aw_server/rest.py-simstep-7bdce779-492f-4dee-a68d-4e6d28dc079a",
+ "aw-server/aw_server/rest.py-simstep-cfd637bd-f6b2-44cf-8330-7b2c59c0658b",
+ "aw-server/aw_server/rest.py-simstep-3e1decf0-1329-4da8-a7c7-870ffe960a54",
+ "aw-server/aw_server/rest.py-simstep-3fd4d48c-e70c-4217-92c1-7554445cf03b",
+ "generated-edge-simstep-6449735d-8c85-4d49-bb8c-c2b1f9918ffc-8515a29c-385b-4ec5-886c-ba3a3a48518e",
+ "generated-edge-simstep-988adf58-e1be-4352-be66-4f02188fc28a-0614b31f-64d9-4e85-a5f5-6304f0702bd7"
+ ]
+ },
+ "aw-server-rust": {
+ "path": "aw-server-rust",
+ "fileName": "aw-server-rust",
+ "cellName": "aw-server-rust",
+ "cellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
+ "visible": true,
+ "children": [
+ "aw-server-rust/aw-server",
+ "aw-server-rust/aw-query",
+ "aw-server-rust/aw-datastore",
+ "aw-server-rust/aw-transform",
+ "aw-server-rust/aw-client-rust"
+ ]
+ },
+ "aw-server-rust/aw-client-rust": {
+ "path": "aw-server-rust/aw-client-rust",
+ "fileName": "aw-client-rust",
+ "cellName": "aw-client-rust",
+ "cellId": "22692aea-cd7a-4c08-8c76-c16bb5499546",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
+ "children": [
+ "aw-server-rust/aw-client-rust/src"
+ ]
+ },
+ "aw-server-rust/aw-client-rust/src": {
+ "path": "aw-server-rust/aw-client-rust/src",
+ "fileName": "src",
+ "cellName": "src",
+ "cellId": "08296022-1e80-4653-821d-b48d9cf30c68",
+ "visible": true,
+ "parentCellId": "22692aea-cd7a-4c08-8c76-c16bb5499546",
+ "children": [
+ "aw-server-rust/aw-client-rust/src/blocking.rs",
+ "aw-server-rust/aw-client-rust/src/lib.rs"
+ ]
+ },
+ "aw-server-rust/aw-client-rust/src/blocking.rs": {
+ "path": "aw-server-rust/aw-client-rust/src/blocking.rs",
+ "fileName": "blocking.rs",
+ "cellName": "blocking.rs",
+ "cellId": "8dafeb60-1305-46f7-baac-4153d6d18539",
+ "visible": true,
+ "parentCellId": "08296022-1e80-4653-821d-b48d9cf30c68",
+ "children": [
+ "aw-server-rust/aw-client-rust/src/blocking.rs-simstep-3118dc4c-d7ad-4996-aa81-a205ccdf6e72"
+ ]
+ },
+ "aw-server-rust/aw-client-rust/src/lib.rs": {
+ "path": "aw-server-rust/aw-client-rust/src/lib.rs",
+ "fileName": "lib.rs",
+ "cellName": "lib.rs",
+ "cellId": "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf",
+ "visible": true,
+ "parentCellId": "08296022-1e80-4653-821d-b48d9cf30c68",
+ "children": [
+ "generated-edge-simstep-97542310-17cf-4c99-9ce9-a328dffa5f4c-ed18dcc0-5e4a-44fb-b661-f746f1e893f1"
+ ]
+ },
+ "aw-server-rust/aw-datastore": {
+ "path": "aw-server-rust/aw-datastore",
+ "fileName": "aw-datastore",
+ "cellName": "aw-datastore",
+ "cellId": "a542ca3c-9d99-490f-89de-186bb284b0fe",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
+ "children": [
+ "aw-server-rust/aw-datastore/src"
+ ]
+ },
+ "aw-server-rust/aw-datastore/src": {
+ "path": "aw-server-rust/aw-datastore/src",
+ "fileName": "src",
+ "cellName": "src",
+ "cellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
+ "visible": true,
+ "parentCellId": "a542ca3c-9d99-490f-89de-186bb284b0fe",
+ "children": [
+ "aw-server-rust/aw-datastore/src/worker.rs",
+ "aw-server-rust/aw-datastore/src/datastore.rs"
+ ]
+ },
+ "aw-server-rust/aw-datastore/src/datastore.rs": {
+ "path": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "fileName": "datastore.rs",
+ "cellName": "datastore.rs",
+ "cellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "visible": true,
+ "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
+ "children": [
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-ff017206-8323-4caa-9eca-4fc760c2470f",
+ "generated-edge-simstep-f69e7df0-6666-4b48-a0a6-1000c8ccede0-9792d1f0-08be-4f90-8e68-3caee0eb2498",
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-c59f4b10-f6c9-4fd8-ba70-ea60667a01e8",
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-da146aa5-e96f-4db6-a36f-b405b1a11255",
+ "generated-edge-simstep-7b396541-e74f-4baf-9b1b-c1f7a914ba7a-0fe644bb-a583-40d8-9377-3641c90c4f62",
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-04bbbe33-e9de-4c5f-b925-27196d20ef1d",
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-1b3cdf02-5dad-411c-a35e-9250c8aafc9d",
+ "generated-edge-simstep-5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619-561eebea-ee66-4251-a29c-64c2e3aae490"
+ ]
+ },
+ "aw-server-rust/aw-datastore/src/worker.rs": {
+ "path": "aw-server-rust/aw-datastore/src/worker.rs",
+ "fileName": "worker.rs",
+ "cellName": "worker.rs",
+ "cellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
+ "visible": true,
+ "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
+ "children": [
+ "generated-edge-simstep-e1bf9f3c-e763-4e75-8c62-1a8d739d53cc-5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
+ "aw-server-rust/aw-datastore/src/worker.rs-simstep-b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3",
+ "aw-server-rust/aw-datastore/src/worker.rs-simstep-a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb",
+ "generated-edge-simstep-eefd671a-3b08-4336-bd26-cb6eb04070ec-21d1c973-0f67-4aca-9d1b-eade3b5d347b",
+ "generated-edge-simstep-9750ac2c-c0fb-4fe5-815f-398886fc827b-959b342e-eb44-4255-8176-1600a5fa17ac"
+ ]
+ },
+ "aw-server-rust/aw-query": {
+ "path": "aw-server-rust/aw-query",
+ "fileName": "aw-query",
+ "cellName": "aw-query",
+ "cellId": "d70684b2-06ba-4f18-9c40-80de0778c035",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
+ "children": [
+ "aw-server-rust/aw-query/src"
+ ]
+ },
+ "aw-server-rust/aw-query/src": {
+ "path": "aw-server-rust/aw-query/src",
+ "fileName": "src",
+ "cellName": "src",
+ "cellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
+ "visible": true,
+ "parentCellId": "d70684b2-06ba-4f18-9c40-80de0778c035",
+ "children": [
+ "aw-server-rust/aw-query/src/lib.rs",
+ "aw-server-rust/aw-query/src/interpret.rs",
+ "aw-server-rust/aw-query/src/functions.rs",
+ "aw-server-rust/aw-query/src/datatype.rs"
+ ]
+ },
+ "aw-server-rust/aw-query/src/datatype.rs": {
+ "path": "aw-server-rust/aw-query/src/datatype.rs",
+ "fileName": "datatype.rs",
+ "cellName": "datatype.rs",
+ "cellId": "60cb37da-078e-4380-88f0-e6746007277d",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
+ "children": [
+ "generated-edge-simstep-e598a658-8e0e-4a76-9310-af0d60ec5828-79c14e32-8192-488e-ab72-b9c4c6edb346"
+ ]
+ },
+ "aw-server-rust/aw-query/src/functions.rs": {
+ "path": "aw-server-rust/aw-query/src/functions.rs",
+ "fileName": "functions.rs",
+ "cellName": "functions.rs",
+ "cellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
+ "children": [
+ "aw-server-rust/aw-query/src/functions.rs-simstep-475886bc-26d3-4528-84ae-2f9c8e1dfcf9",
+ "generated-edge-simstep-f7dfb334-099f-4750-a893-cd96b1c46278-7a14a4d3-a453-4e33-9b10-fb192e40e34e",
+ "aw-server-rust/aw-query/src/functions.rs-simstep-af6c51b2-ee18-406c-acc6-6e5d9588d012",
+ "aw-server-rust/aw-query/src/functions.rs-simstep-06d75f72-3fc8-47d8-85ab-f7fa317f4de5",
+ "aw-server-rust/aw-query/src/functions.rs-simstep-cc5cfecf-cee9-4582-aa6c-b74787a11da8",
+ "generated-edge-simstep-914107de-b38a-4307-ab2c-e257ed3d2fb5-9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
+ "generated-edge-simstep-d78663e6-a6d4-4ba7-a922-436bd075e457-2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe"
+ ]
+ },
+ "aw-server-rust/aw-query/src/interpret.rs": {
+ "path": "aw-server-rust/aw-query/src/interpret.rs",
+ "fileName": "interpret.rs",
+ "cellName": "interpret.rs",
+ "cellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
+ "children": [
+ "aw-server-rust/aw-query/src/interpret.rs-simstep-18492fe4-5b57-4749-a2e8-d18f3c546e89",
+ "generated-edge-simstep-00784ae1-bb99-494c-bf46-fe5947de5066-8f8d2c55-63c0-48ec-b931-f848e245688f",
+ "generated-edge-simstep-78aaa465-8377-43f1-9ba6-36ddcf9300cf-8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
+ "aw-server-rust/aw-query/src/interpret.rs-simstep-e3204124-26ff-4799-8462-100305c27ae1",
+ "aw-server-rust/aw-query/src/interpret.rs-simstep-9382ac29-7930-4f83-afdd-deb2bfc221e3",
+ "generated-edge-simstep-f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5-15dfaeb9-fb37-4296-972f-0188abd0b353",
+ "aw-server-rust/aw-query/src/interpret.rs-simstep-f7c58723-a402-45d1-8070-59c196e20fb2"
+ ]
+ },
+ "aw-server-rust/aw-query/src/lib.rs": {
+ "path": "aw-server-rust/aw-query/src/lib.rs",
+ "fileName": "lib.rs",
+ "cellName": "lib.rs",
+ "cellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
+ "children": [
+ "aw-server-rust/aw-query/src/lib.rs-simstep-3291e01a-482d-401b-98b5-759573be65ca",
+ "aw-server-rust/aw-query/src/lib.rs-simstep-024a46d7-abc2-4c35-92d1-900d198f748c",
+ "generated-edge-simstep-acc1ad56-50cb-41ab-9217-f8d15af6686c-e72e1881-49ce-41ad-966a-90a26ca47453",
+ "aw-server-rust/aw-query/src/lib.rs-simstep-b482a39f-e520-4d4d-8b2f-d1298922763f"
+ ]
+ },
+ "aw-server-rust/aw-server": {
+ "path": "aw-server-rust/aw-server",
+ "fileName": "aw-server",
+ "cellName": "aw-server",
+ "cellId": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
+ "children": [
+ "aw-server-rust/aw-server/src"
+ ]
+ },
+ "aw-server-rust/aw-server/src": {
+ "path": "aw-server-rust/aw-server/src",
+ "fileName": "src",
+ "cellName": "src",
+ "cellId": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e",
+ "visible": true,
+ "parentCellId": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c",
+ "children": [
+ "aw-server-rust/aw-server/src/endpoints"
+ ]
+ },
+ "aw-server-rust/aw-server/src/endpoints": {
+ "path": "aw-server-rust/aw-server/src/endpoints",
+ "fileName": "endpoints",
+ "cellName": "endpoints",
+ "cellId": "11799249-188d-43b3-b410-54dcff47aeba",
+ "visible": true,
+ "parentCellId": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e",
+ "children": [
+ "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs"
+ ]
+ },
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs": {
+ "path": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "fileName": "bucket.rs",
+ "cellName": "bucket.rs",
+ "cellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
+ "visible": true,
+ "parentCellId": "11799249-188d-43b3-b410-54dcff47aeba",
+ "children": [
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs-simstep-41b8b1d6-f9fe-47ad-851e-574e804f7171",
+ "generated-edge-simstep-7e361c3d-a5a9-45f3-a83d-98e39ff45675-2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
+ "generated-edge-simstep-bfcc2f87-9167-4784-a3b3-f71d6e7a6e71-4a4afbdf-0303-4d84-bbf8-5121c74965a0"
+ ]
+ },
+ "aw-server-rust/aw-server/src/endpoints/query.rs": {
+ "path": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "fileName": "query.rs",
+ "cellName": "query.rs",
+ "cellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "visible": true,
+ "parentCellId": "11799249-188d-43b3-b410-54dcff47aeba",
+ "children": [
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-e91513ab-13ec-4eea-9942-9620dbe3b92b",
+ "generated-edge-simstep-a7b6aefb-1401-4756-bfa1-1eb9a76cde07-c8403507-4895-4695-84b5-9305afdc3c9f",
+ "generated-edge-simstep-785d1355-bf16-42a7-846e-a2bf3ecbb35b-889f0869-2c33-499b-a558-ede80ee18a54",
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-1c25a330-b713-4866-9440-8737c787ce33",
+ "generated-edge-simstep-6eb126a9-5234-4495-9727-ec2741ce9660-d3cb01a0-d8cd-4382-b122-d1234b0562bc",
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-868edfd6-1f03-416e-88dc-7b09d05e4ba5",
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-f52d6bfa-55fe-49ee-9f20-60bf296c76f4",
+ "generated-edge-simstep-b835d5e0-434d-4469-94fe-d309114a9ef1-8f02d20c-25fe-4a28-99de-3e8908d0a66f",
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-c988a25d-05ad-4c19-87ac-362c79af1d00",
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-72197f38-6e3b-432c-be11-ce5fbb94efb9",
+ "generated-edge-simstep-98777081-df05-4b5c-89f6-5076fab00e92-31b60323-3a65-4184-a42f-f577f3a958ff",
+ "generated-edge-simstep-633d97c2-762a-45cb-8900-308ab124d526-3f00132f-3930-4b99-82cf-1ca7f818661b"
+ ]
+ },
+ "aw-server-rust/aw-transform": {
+ "path": "aw-server-rust/aw-transform",
+ "fileName": "aw-transform",
+ "cellName": "aw-transform",
+ "cellId": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
+ "children": [
+ "aw-server-rust/aw-transform/src"
+ ]
+ },
+ "aw-server-rust/aw-transform/src": {
+ "path": "aw-server-rust/aw-transform/src",
+ "fileName": "src",
+ "cellName": "src",
+ "cellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
+ "visible": true,
+ "parentCellId": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8",
+ "children": [
+ "aw-server-rust/aw-transform/src/filter_period.rs",
+ "aw-server-rust/aw-transform/src/classify.rs"
+ ]
+ },
+ "aw-server-rust/aw-transform/src/classify.rs": {
+ "path": "aw-server-rust/aw-transform/src/classify.rs",
+ "fileName": "classify.rs",
+ "cellName": "classify.rs",
+ "cellId": "22d8d360-9b15-49db-bc15-de087f960e23",
+ "visible": true,
+ "parentCellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
+ "children": [
+ "aw-server-rust/aw-transform/src/classify.rs-simstep-55815d72-39f6-4201-ad99-6ebd57d0eece",
+ "aw-server-rust/aw-transform/src/classify.rs-simstep-e863b0b1-c3ce-4b13-ad7d-a7438f650035",
+ "generated-edge-simstep-9f7f50e4-03c6-4d7c-95c8-3317d37115eb-341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
+ "generated-edge-simstep-ebd328dc-4cdf-452d-b4aa-10b65e9c354d-b4391f38-d9ee-4377-8568-efca87206124"
+ ]
+ },
+ "aw-server-rust/aw-transform/src/filter_period.rs": {
+ "path": "aw-server-rust/aw-transform/src/filter_period.rs",
+ "fileName": "filter_period.rs",
+ "cellName": "filter_period.rs",
+ "cellId": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca",
+ "visible": true,
+ "parentCellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
+ "children": [
+ "aw-server-rust/aw-transform/src/filter_period.rs-simstep-50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10"
+ ]
+ },
+ "aw-watcher-afk": {
+ "path": "aw-watcher-afk",
+ "fileName": "aw-watcher-afk",
+ "cellName": "aw-watcher-afk",
+ "cellId": "7ee7b20f-9df9-4269-8f41-bc7e191503bd",
+ "visible": true,
+ "children": [
+ "aw-watcher-afk/aw_watcher_afk"
+ ]
+ },
+ "aw-watcher-afk/aw_watcher_afk": {
+ "path": "aw-watcher-afk/aw_watcher_afk",
+ "fileName": "aw_watcher_afk",
+ "cellName": "aw_watcher_afk",
+ "cellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
+ "visible": true,
+ "parentCellId": "7ee7b20f-9df9-4269-8f41-bc7e191503bd",
+ "children": [
+ "aw-watcher-afk/aw_watcher_afk/__main__.py",
+ "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "aw-watcher-afk/aw_watcher_afk/unix.py"
+ ]
+ },
+ "aw-watcher-afk/aw_watcher_afk/__main__.py": {
+ "path": "aw-watcher-afk/aw_watcher_afk/__main__.py",
+ "fileName": "__main__.py",
+ "cellName": "__main__.py",
+ "cellId": "d242d1ad-7cdf-414b-812a-f3e5af153562",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
+ "children": [
+ "aw-watcher-afk/aw_watcher_afk/__main__.py-simstep-8ffbcadf-f26a-483a-9902-95e5a761de64",
+ "generated-edge-simstep-60e1002f-9782-4c8d-b104-f4bb172e2c91-7c2f1d5b-706c-4dd2-9d8c-62b3e6886250"
+ ]
+ },
+ "aw-watcher-afk/aw_watcher_afk/afk.py": {
+ "path": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "fileName": "afk.py",
+ "cellName": "afk.py",
+ "cellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
+ "children": [
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-daeeac12-287a-4144-9028-6ea841b196c4",
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-6579f587-817d-4d23-a9df-86abc54273ae",
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-3e0e033c-c32f-4d0d-aa65-a278d77e80c7",
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-dc58bc3e-b09e-4df2-870b-76419e78dd3d",
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-1e5ad77f-aeff-49b6-9634-65e52f011a83",
+ "generated-edge-simstep-1422a5f8-ad2e-4b32-8955-ee6bb3053286-1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
+ "generated-edge-simstep-2588211c-b086-4768-8a87-a86764c7e5cd-e514d9e2-e803-4041-b693-65878401b214",
+ "generated-edge-simstep-9195e582-b3fa-4848-b151-0236a8a5d176-eeb9224a-fff6-4652-b733-ea430b820a2c",
+ "generated-edge-simstep-78d78341-ced8-4fc6-bc93-ce4a62c8adf6-196358b9-6ae9-4f52-ad78-ff88b4a49403",
+ "generated-edge-simstep-c9a127c1-afd0-4def-a0fe-c490c9b64039-b520b088-6f6f-4b32-afba-5ef244691c44",
+ "generated-edge-simstep-9fde1b44-5dbf-4530-88e2-ca54c220b462-f0e34997-66ab-4bc2-9a5e-1f00b40d47b0"
+ ]
+ },
+ "aw-watcher-afk/aw_watcher_afk/unix.py": {
+ "path": "aw-watcher-afk/aw_watcher_afk/unix.py",
+ "fileName": "unix.py",
+ "cellName": "unix.py",
+ "cellId": "72e53989-6741-4b0d-b49c-f58d0333cdd1",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
+ "children": [
+ "aw-watcher-afk/aw_watcher_afk/unix.py-simstep-4d2c85c7-0754-429a-8a55-c64d4da0d37c"
+ ]
+ },
+ "aw-watcher-window": {
+ "path": "aw-watcher-window",
+ "fileName": "aw-watcher-window",
+ "cellName": "aw-watcher-window",
+ "cellId": "02d954ad-e1f5-4853-9860-a553ea21245b",
+ "visible": true,
+ "children": [
+ "aw-watcher-window/aw_watcher_window"
+ ]
+ },
+ "aw-watcher-window/aw_watcher_window": {
+ "path": "aw-watcher-window/aw_watcher_window",
+ "fileName": "aw_watcher_window",
+ "cellName": "aw_watcher_window",
+ "cellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
+ "visible": true,
+ "parentCellId": "02d954ad-e1f5-4853-9860-a553ea21245b",
+ "children": [
+ "aw-watcher-window/aw_watcher_window/main.py",
+ "aw-watcher-window/aw_watcher_window/lib.py",
+ "aw-watcher-window/aw_watcher_window/macos.swift"
+ ]
+ },
+ "aw-watcher-window/aw_watcher_window/lib.py": {
+ "path": "aw-watcher-window/aw_watcher_window/lib.py",
+ "fileName": "lib.py",
+ "cellName": "lib.py",
+ "cellId": "f55ac327-589c-4d8a-ac08-6db49ae00e75",
+ "visible": true,
+ "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
+ "children": [
+ "aw-watcher-window/aw_watcher_window/lib.py-simstep-3e57e810-18fe-461f-a33c-f3eb0773ecf5"
+ ]
+ },
+ "aw-watcher-window/aw_watcher_window/macos.swift": {
+ "path": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "fileName": "macos.swift",
+ "cellName": "macos.swift",
+ "cellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
+ "visible": true,
+ "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
+ "children": [
+ "aw-watcher-window/aw_watcher_window/macos.swift-simstep-46ccc29e-b251-435a-8768-4304d477261a",
+ "aw-watcher-window/aw_watcher_window/macos.swift-simstep-e873b3e2-2ebd-43ee-8f97-e02f869578f7",
+ "aw-watcher-window/aw_watcher_window/macos.swift-simstep-8420fd6c-dba4-41c0-b11d-7280a428ab36",
+ "generated-edge-simstep-b6456941-3a8f-452d-a4eb-67915b00d5b3-4d96dbc5-cd5e-4ef9-8733-721776e8fb8f"
+ ]
+ },
+ "aw-watcher-window/aw_watcher_window/main.py": {
+ "path": "aw-watcher-window/aw_watcher_window/main.py",
+ "fileName": "main.py",
+ "cellName": "main.py",
+ "cellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
+ "visible": true,
+ "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
+ "children": [
+ "aw-watcher-window/aw_watcher_window/main.py-simstep-caf92190-4958-42b9-b962-d21c9ff6c62d",
+ "aw-watcher-window/aw_watcher_window/main.py-simstep-706e836d-c3e2-4048-9eae-95e761ca9ffa",
+ "generated-edge-simstep-39835fd9-a301-482d-8b6d-9d16abbbaa29-6d9c0750-fa20-47af-9135-6cc6444cb6b0",
+ "generated-edge-simstep-81f5cf5a-47ed-4fce-9c97-27559b1c7976-3fe51be8-fc72-4a07-8a11-bef3ffb6dd26"
+ ]
+ },
+ "02d954ad-e1f5-4853-9860-a553ea21245b": {
+ "path": "02d954ad-e1f5-4853-9860-a553ea21245b",
+ "cellName": "aw-watcher-window",
+ "cellId": "02d954ad-e1f5-4853-9860-a553ea21245b",
+ "visible": true
+ },
+ "900d6121-1844-48ba-9a18-db1ec6ea9793": {
+ "path": "900d6121-1844-48ba-9a18-db1ec6ea9793",
+ "cellName": "aw-client",
+ "cellId": "900d6121-1844-48ba-9a18-db1ec6ea9793",
+ "visible": true
+ },
+ "efb8048c-455c-4e7a-aa18-9e8b04779b71": {
+ "path": "efb8048c-455c-4e7a-aa18-9e8b04779b71",
+ "cellName": "aw-server",
+ "cellId": "efb8048c-455c-4e7a-aa18-9e8b04779b71",
+ "visible": true
+ },
+ "1eed769a-5d0a-443c-9cc3-4e8f59c84abb": {
+ "path": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
+ "cellName": "aw-core",
+ "cellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
+ "visible": true
+ },
+ "306c9af9-c4b4-4bea-85d2-fc4830dedc4c": {
+ "path": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
+ "cellName": "aw_watcher_window",
+ "cellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
+ "visible": true,
+ "parentCellId": "02d954ad-e1f5-4853-9860-a553ea21245b"
+ },
+ "48103d9a-f009-4555-bb82-435f417b0644": {
+ "path": "48103d9a-f009-4555-bb82-435f417b0644",
+ "cellName": "aw_client",
+ "cellId": "48103d9a-f009-4555-bb82-435f417b0644",
+ "visible": true,
+ "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793"
+ },
+ "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49": {
+ "path": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
+ "cellName": "aw_server",
+ "cellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
+ "visible": true,
+ "parentCellId": "efb8048c-455c-4e7a-aa18-9e8b04779b71"
+ },
+ "5093a30d-28ac-4c2b-811d-65c61efc0882": {
+ "path": "5093a30d-28ac-4c2b-811d-65c61efc0882",
+ "cellName": "aw_datastore",
+ "cellId": "5093a30d-28ac-4c2b-811d-65c61efc0882",
+ "visible": true,
+ "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb"
+ },
+ "1bbc4c76-4066-4521-a1d8-0248c1418060": {
+ "path": "1bbc4c76-4066-4521-a1d8-0248c1418060",
+ "cellName": "main.py",
+ "cellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
+ "visible": true,
+ "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
+ },
+ "f55ac327-589c-4d8a-ac08-6db49ae00e75": {
+ "path": "f55ac327-589c-4d8a-ac08-6db49ae00e75",
+ "cellName": "lib.py",
+ "cellId": "f55ac327-589c-4d8a-ac08-6db49ae00e75",
+ "visible": true,
+ "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
+ },
+ "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2": {
+ "path": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "cellName": "client.py",
+ "cellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "visible": true,
+ "parentCellId": "48103d9a-f009-4555-bb82-435f417b0644"
+ },
+ "7f67f305-e40b-496e-87a4-97725d0636a0": {
+ "path": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "cellName": "rest.py",
+ "cellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
+ },
+ "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc": {
+ "path": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "cellName": "api.py",
+ "cellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
+ },
+ "aba7852e-7836-4343-ae26-5ecb9a02d42d": {
+ "path": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
+ "cellName": "datastore.py",
+ "cellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
+ "visible": true,
+ "parentCellId": "5093a30d-28ac-4c2b-811d-65c61efc0882"
+ },
+ "b2eb5c59-4162-4dea-ac74-511f22996f00": {
+ "path": "b2eb5c59-4162-4dea-ac74-511f22996f00",
+ "cellName": "storages",
+ "cellId": "b2eb5c59-4162-4dea-ac74-511f22996f00",
+ "visible": true,
+ "parentCellId": "5093a30d-28ac-4c2b-811d-65c61efc0882"
+ },
+ "a63cc090-4355-47fb-8b22-62cd1b842ddb": {
+ "path": "a63cc090-4355-47fb-8b22-62cd1b842ddb",
+ "cellName": "peewee.py",
+ "cellId": "a63cc090-4355-47fb-8b22-62cd1b842ddb",
+ "visible": true,
+ "parentCellId": "b2eb5c59-4162-4dea-ac74-511f22996f00"
+ },
+ "638a5f20-935f-4345-8eaf-dfcd2aa6efb4": {
+ "path": "638a5f20-935f-4345-8eaf-dfcd2aa6efb4",
+ "cellName": "Watcher Initialization - main.py:L62-69",
+ "cellId": "638a5f20-935f-4345-8eaf-dfcd2aa6efb4",
+ "visible": true,
+ "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060"
+ },
+ "aw-watcher-window/aw_watcher_window/main.py-simstep-caf92190-4958-42b9-b962-d21c9ff6c62d": {
+ "path": "aw-watcher-window/aw_watcher_window/main.py-simstep-caf92190-4958-42b9-b962-d21c9ff6c62d",
+ "fileName": "main.py",
+ "wiki": "The `aw-watcher-window` process starts. It parses arguments, sets up logging, and initializes the `ActivityWatchClient`. It also ensures a bucket for storing window activity exists on the server.",
+ "cellName": "Watcher Initialization - main.py:L62-69",
+ "cellId": "638a5f20-935f-4345-8eaf-dfcd2aa6efb4",
+ "visible": true,
+ "startLine": 62,
+ "endLine": 69,
+ "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
+ "parentPath": "aw-watcher-window/aw_watcher_window/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "caf92190-4958-42b9-b962-d21c9ff6c62d"
+ }
+ ]
+ },
+ "89c12f0e-0649-4963-8e57-d7fd7da30bc4": {
+ "path": "89c12f0e-0649-4963-8e57-d7fd7da30bc4",
+ "cellName": "Get Current Window Information - lib.py:L58-73",
+ "cellId": "89c12f0e-0649-4963-8e57-d7fd7da30bc4",
+ "visible": true,
+ "parentCellId": "f55ac327-589c-4d8a-ac08-6db49ae00e75"
+ },
+ "aw-watcher-window/aw_watcher_window/lib.py-simstep-3e57e810-18fe-461f-a33c-f3eb0773ecf5": {
+ "path": "aw-watcher-window/aw_watcher_window/lib.py-simstep-3e57e810-18fe-461f-a33c-f3eb0773ecf5",
+ "fileName": "lib.py",
+ "wiki": "Inside the loop, the `get_current_window` function is called. This function acts as a dispatcher, calling the appropriate OS-specific implementation to get the currently focused application and window title.",
+ "cellName": "Get Current Window Information - lib.py:L58-73",
+ "cellId": "89c12f0e-0649-4963-8e57-d7fd7da30bc4",
+ "visible": true,
+ "startLine": 58,
+ "endLine": 73,
+ "parentCellId": "f55ac327-589c-4d8a-ac08-6db49ae00e75",
+ "parentPath": "aw-watcher-window/aw_watcher_window/lib.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "3e57e810-18fe-461f-a33c-f3eb0773ecf5"
+ }
+ ]
+ },
+ "30328419-4cc4-4ea2-a7fb-1728782b23aa": {
+ "path": "30328419-4cc4-4ea2-a7fb-1728782b23aa",
+ "cellName": "Send Heartbeat via Client - main.py:L160-162",
+ "cellId": "30328419-4cc4-4ea2-a7fb-1728782b23aa",
+ "visible": true,
+ "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060"
+ },
+ "aw-watcher-window/aw_watcher_window/main.py-simstep-706e836d-c3e2-4048-9eae-95e761ca9ffa": {
+ "path": "aw-watcher-window/aw_watcher_window/main.py-simstep-706e836d-c3e2-4048-9eae-95e761ca9ffa",
+ "fileName": "main.py",
+ "wiki": "The created event is sent as a heartbeat to the `aw-server` using the `ActivityWatchClient`. The `queued=True` parameter enables local event merging and a persistent queue for offline robustness.",
+ "cellName": "Send Heartbeat via Client - main.py:L160-162",
+ "cellId": "30328419-4cc4-4ea2-a7fb-1728782b23aa",
+ "visible": true,
+ "startLine": 160,
+ "endLine": 162,
+ "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
+ "parentPath": "aw-watcher-window/aw_watcher_window/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "706e836d-c3e2-4048-9eae-95e761ca9ffa"
+ }
+ ]
+ },
+ "82482fcc-b698-4f91-a27c-a4110d012d99": {
+ "path": "82482fcc-b698-4f91-a27c-a4110d012d99",
+ "cellName": "Queue and Dispatch Request - client.py:L531-533",
+ "cellId": "82482fcc-b698-4f91-a27c-a4110d012d99",
+ "visible": true,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
+ },
+ "aw-client/aw_client/client.py-simstep-432d1978-befd-4dfd-979b-fe28821d4e00": {
+ "path": "aw-client/aw_client/client.py-simstep-432d1978-befd-4dfd-979b-fe28821d4e00",
+ "fileName": "client.py",
+ "wiki": "The `RequestQueue` thread picks up the heartbeat request. It formats an HTTP POST request to the server's heartbeat API endpoint: `/api/0/buckets/{bucket_id}/heartbeat`.",
+ "cellName": "Queue and Dispatch Request - client.py:L531-533",
+ "cellId": "82482fcc-b698-4f91-a27c-a4110d012d99",
+ "visible": true,
+ "startLine": 531,
+ "endLine": 533,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "432d1978-befd-4dfd-979b-fe28821d4e00"
+ }
+ ]
+ },
+ "2217c8ca-4cbb-4721-acb9-1057b3b16d69": {
+ "path": "2217c8ca-4cbb-4721-acb9-1057b3b16d69",
+ "cellName": "Server-Side Heartbeat Logic - api.py:L254-337",
+ "cellId": "2217c8ca-4cbb-4721-acb9-1057b3b16d69",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-addb33f5-b815-49f0-9b54-a8ee3fb3b87b": {
+ "path": "aw-server/aw_server/api.py-simstep-addb33f5-b815-49f0-9b54-a8ee3fb3b87b",
+ "fileName": "api.py",
+ "wiki": "The `HeartbeatResource`'s `post` method calls the `api.heartbeat` function, which contains the main server-side logic. It fetches the last event from the bucket and determines if the new heartbeat should be merged with it (by extending its duration) or if a new event should be created.",
+ "cellName": "Server-Side Heartbeat Logic - api.py:L254-337",
+ "cellId": "2217c8ca-4cbb-4721-acb9-1057b3b16d69",
+ "visible": true,
+ "startLine": 254,
+ "endLine": 337,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "addb33f5-b815-49f0-9b54-a8ee3fb3b87b"
+ }
+ ]
+ },
+ "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a": {
+ "path": "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a",
+ "cellName": "Persist Event to Database - datastore.py:L127-188",
+ "cellId": "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a",
+ "visible": true,
+ "parentCellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d"
+ },
+ "aw-core/aw_datastore/datastore.py-simstep-5573707d-aa48-4a66-a3dc-25c841986d39": {
+ "path": "aw-core/aw_datastore/datastore.py-simstep-5573707d-aa48-4a66-a3dc-25c841986d39",
+ "fileName": "datastore.py",
+ "wiki": "The `datastore`'s `Bucket` object calls the appropriate method on the configured storage strategy (e.g., `PeeweeStorage`). If merging, `replace_last` is used to update the last event. If it's a new event, `insert` is used.",
+ "cellName": "Persist Event to Database - datastore.py:L127-188",
+ "cellId": "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a",
+ "visible": true,
+ "startLine": 127,
+ "endLine": 188,
+ "parentCellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
+ "parentPath": "aw-core/aw_datastore/datastore.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "5573707d-aa48-4a66-a3dc-25c841986d39"
+ }
+ ]
+ },
+ "6d9c0750-fa20-47af-9135-6cc6444cb6b0": {
+ "path": "6d9c0750-fa20-47af-9135-6cc6444cb6b0",
+ "cellName": "Start Heartbeat\nLoop",
+ "cellId": "6d9c0750-fa20-47af-9135-6cc6444cb6b0",
+ "visible": true,
+ "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
+ },
+ "generated-edge-simstep-39835fd9-a301-482d-8b6d-9d16abbbaa29-6d9c0750-fa20-47af-9135-6cc6444cb6b0": {
+ "path": "generated-edge-simstep-39835fd9-a301-482d-8b6d-9d16abbbaa29-6d9c0750-fa20-47af-9135-6cc6444cb6b0",
+ "fileName": "main.py",
+ "cellName": "Start Heartbeat Loop",
+ "cellId": "6d9c0750-fa20-47af-9135-6cc6444cb6b0",
+ "visible": true,
+ "startLine": 98,
+ "endLine": 109,
+ "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
+ "parentPath": "aw-watcher-window/aw_watcher_window/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "39835fd9-a301-482d-8b6d-9d16abbbaa29"
+ }
+ ]
+ },
+ "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26": {
+ "path": "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
+ "cellName": "Create Window\nEvent",
+ "cellId": "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
+ "visible": true,
+ "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
+ },
+ "generated-edge-simstep-81f5cf5a-47ed-4fce-9c97-27559b1c7976-3fe51be8-fc72-4a07-8a11-bef3ffb6dd26": {
+ "path": "generated-edge-simstep-81f5cf5a-47ed-4fce-9c97-27559b1c7976-3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
+ "fileName": "main.py",
+ "cellName": "Create Window Event",
+ "cellId": "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
+ "visible": true,
+ "startLine": 154,
+ "endLine": 155,
+ "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
+ "parentPath": "aw-watcher-window/aw_watcher_window/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "81f5cf5a-47ed-4fce-9c97-27559b1c7976"
+ }
+ ]
+ },
+ "78766ca9-9103-486a-8755-f57a09e7f5a7": {
+ "path": "78766ca9-9103-486a-8755-f57a09e7f5a7",
+ "cellName": "Local Heartbeat\nPre-Merging",
+ "cellId": "78766ca9-9103-486a-8755-f57a09e7f5a7",
+ "visible": true
+ },
+ "generated-edge-simstep-11bc8b75-0103-4652-9fec-e55af41400a0-78766ca9-9103-486a-8755-f57a09e7f5a7": {
+ "path": "generated-edge-simstep-11bc8b75-0103-4652-9fec-e55af41400a0-78766ca9-9103-486a-8755-f57a09e7f5a7",
+ "fileName": "client.py",
+ "cellName": "Local Heartbeat Pre-Merging",
+ "cellId": "78766ca9-9103-486a-8755-f57a09e7f5a7",
+ "visible": true,
+ "startLine": 244,
+ "endLine": 259,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "11bc8b75-0103-4652-9fec-e55af41400a0"
+ }
+ ]
+ },
+ "5a7fba44-6d4d-4836-bc13-ed69518c9d45": {
+ "path": "5a7fba44-6d4d-4836-bc13-ed69518c9d45",
+ "cellName": "API Call:\nHeartbeat Received",
+ "cellId": "5a7fba44-6d4d-4836-bc13-ed69518c9d45",
+ "visible": true
+ },
+ "generated-edge-simstep-97f58e0a-cbeb-4895-b613-d8e9fd129a42-5a7fba44-6d4d-4836-bc13-ed69518c9d45": {
+ "path": "generated-edge-simstep-97f58e0a-cbeb-4895-b613-d8e9fd129a42-5a7fba44-6d4d-4836-bc13-ed69518c9d45",
+ "fileName": "rest.py",
+ "cellName": "API Call: Heartbeat Received",
+ "cellId": "5a7fba44-6d4d-4836-bc13-ed69518c9d45",
+ "visible": true,
+ "startLine": 272,
+ "endLine": 276,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "97f58e0a-cbeb-4895-b613-d8e9fd129a42"
+ }
+ ]
+ },
+ "6a5be6b6-e11d-460d-8193-427f3a9e42ac": {
+ "path": "6a5be6b6-e11d-460d-8193-427f3a9e42ac",
+ "cellName": "Data to\nDatastore",
+ "cellId": "6a5be6b6-e11d-460d-8193-427f3a9e42ac",
+ "visible": true
+ },
+ "generated-edge-simstep-cd6c54a5-c0bd-4b99-9446-ea921ee876a6-6a5be6b6-e11d-460d-8193-427f3a9e42ac": {
+ "path": "generated-edge-simstep-cd6c54a5-c0bd-4b99-9446-ea921ee876a6-6a5be6b6-e11d-460d-8193-427f3a9e42ac",
+ "fileName": "api.py",
+ "cellName": "Data to Datastore",
+ "cellId": "6a5be6b6-e11d-460d-8193-427f3a9e42ac",
+ "visible": true,
+ "startLine": 314,
+ "endLine": 335,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How automated application and window time tracking works",
+ "simStepId": "cd6c54a5-c0bd-4b99-9446-ea921ee876a6"
+ }
+ ]
+ },
+ "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0": {
+ "path": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
+ "cellName": "aw-server-rust",
+ "cellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
+ "visible": true
+ },
+ "d4939ae3-d0c2-44b2-90c5-9a7791e083b5": {
+ "path": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5",
+ "cellName": "README.md",
+ "cellId": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5",
+ "visible": true
+ },
+ "e4fd3d3d-801a-4bc3-8891-9fdd6222369c": {
+ "path": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c",
+ "cellName": "aw-server",
+ "cellId": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "d70684b2-06ba-4f18-9c40-80de0778c035": {
+ "path": "d70684b2-06ba-4f18-9c40-80de0778c035",
+ "cellName": "aw-query",
+ "cellId": "d70684b2-06ba-4f18-9c40-80de0778c035",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "a542ca3c-9d99-490f-89de-186bb284b0fe": {
+ "path": "a542ca3c-9d99-490f-89de-186bb284b0fe",
+ "cellName": "aw-datastore",
+ "cellId": "a542ca3c-9d99-490f-89de-186bb284b0fe",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "6d2ab9ea-9e77-402f-a726-95d44e0f23c8": {
+ "path": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8",
+ "cellName": "aw-transform",
+ "cellId": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "941d7da8-a28d-4d5e-806f-3b546909f74e": {
+ "path": "941d7da8-a28d-4d5e-806f-3b546909f74e",
+ "cellName": "queries.py",
+ "cellId": "941d7da8-a28d-4d5e-806f-3b546909f74e",
+ "visible": true,
+ "parentCellId": "48103d9a-f009-4555-bb82-435f417b0644"
+ },
+ "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e": {
+ "path": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e",
+ "cellName": "src",
+ "cellId": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e",
+ "visible": true,
+ "parentCellId": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c"
+ },
+ "e6b26caf-0857-4e8d-8f29-124af90c1966": {
+ "path": "e6b26caf-0857-4e8d-8f29-124af90c1966",
+ "cellName": "src",
+ "cellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
+ "visible": true,
+ "parentCellId": "d70684b2-06ba-4f18-9c40-80de0778c035"
+ },
+ "234cf403-9edd-4f7e-96eb-81e90587bbdc": {
+ "path": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
+ "cellName": "src",
+ "cellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
+ "visible": true,
+ "parentCellId": "a542ca3c-9d99-490f-89de-186bb284b0fe"
+ },
+ "7e71e7fe-f8aa-4693-a92e-4c3b664c1528": {
+ "path": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
+ "cellName": "src",
+ "cellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
+ "visible": true,
+ "parentCellId": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8"
+ },
+ "11799249-188d-43b3-b410-54dcff47aeba": {
+ "path": "11799249-188d-43b3-b410-54dcff47aeba",
+ "cellName": "endpoints",
+ "cellId": "11799249-188d-43b3-b410-54dcff47aeba",
+ "visible": true,
+ "parentCellId": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e"
+ },
+ "d020e6ae-765b-4374-947a-57f7ad4a9237": {
+ "path": "d020e6ae-765b-4374-947a-57f7ad4a9237",
+ "cellName": "lib.rs",
+ "cellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
+ },
+ "9b5e1d70-af70-4de3-9b35-73b774a50c3c": {
+ "path": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "cellName": "interpret.rs",
+ "cellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
+ },
+ "bf649fa4-66cc-4975-8549-aa2f1db4a11e": {
+ "path": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "cellName": "functions.rs",
+ "cellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
+ },
+ "c3bb8632-e3d6-4b2f-86ea-2472e155f19e": {
+ "path": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
+ "cellName": "worker.rs",
+ "cellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
+ "visible": true,
+ "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc"
+ },
+ "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f": {
+ "path": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "cellName": "datastore.rs",
+ "cellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "visible": true,
+ "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc"
+ },
+ "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca": {
+ "path": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca",
+ "cellName": "filter_period.rs",
+ "cellId": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca",
+ "visible": true,
+ "parentCellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528"
+ },
+ "873444c7-80ea-4a0b-8620-92fc96cce006": {
+ "path": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "cellName": "query.rs",
+ "cellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "visible": true,
+ "parentCellId": "11799249-188d-43b3-b410-54dcff47aeba"
+ },
+ "12f9554d-dd4e-4f66-bd20-8845b718ef19": {
+ "path": "12f9554d-dd4e-4f66-bd20-8845b718ef19",
+ "cellName": "Client-side: Construct Activity Query - queries.py:L243-301",
+ "cellId": "12f9554d-dd4e-4f66-bd20-8845b718ef19",
+ "visible": true,
+ "parentCellId": "941d7da8-a28d-4d5e-806f-3b546909f74e"
+ },
+ "aw-client/aw_client/queries.py-simstep-81f31a9b-3434-4458-a7d3-bdcf610af75e": {
+ "path": "aw-client/aw_client/queries.py-simstep-81f31a9b-3434-4458-a7d3-bdcf610af75e",
+ "fileName": "queries.py",
+ "wiki": "The user accesses the ActivityWatch web UI. The frontend constructs a query using the ActivityWatch Query Language to fetch and process data for the main dashboard visualization. This query is designed to get window and AFK (Away From Keyboard) events, filter out AFK periods, categorize activities based on rules, and aggregate the results.",
+ "cellName": "Client-side: Construct Activity Query - queries.py:L243-301",
+ "cellId": "12f9554d-dd4e-4f66-bd20-8845b718ef19",
+ "visible": true,
+ "startLine": 243,
+ "endLine": 301,
+ "parentCellId": "941d7da8-a28d-4d5e-806f-3b546909f74e",
+ "parentPath": "aw-client/aw_client/queries.py",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "81f31a9b-3434-4458-a7d3-bdcf610af75e"
+ }
+ ]
+ },
+ "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1": {
+ "path": "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1",
+ "cellName": "Backend: Receive Query Request - query.rs:L9-23",
+ "cellId": "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1",
+ "visible": true,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
+ },
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-e91513ab-13ec-4eea-9942-9620dbe3b92b": {
+ "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-e91513ab-13ec-4eea-9942-9620dbe3b92b",
+ "fileName": "query.rs",
+ "wiki": "The `aw-server-rust` (or the Python equivalent `aw-server`) receives the POST request. The `/api/0/query` endpoint deserializes the JSON body into a `Query` struct containing the query statements and time intervals.",
+ "cellName": "Backend: Receive Query Request - query.rs:L9-23",
+ "cellId": "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1",
+ "visible": true,
+ "startLine": 9,
+ "endLine": 23,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "e91513ab-13ec-4eea-9942-9620dbe3b92b"
+ }
+ ]
+ },
+ "a9279dbc-8fda-434c-bc5a-4eefaca0df56": {
+ "path": "a9279dbc-8fda-434c-bc5a-4eefaca0df56",
+ "cellName": "Query Engine: Parse and Interpret - lib.rs:L53-64",
+ "cellId": "a9279dbc-8fda-434c-bc5a-4eefaca0df56",
+ "visible": true,
+ "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237"
+ },
+ "aw-server-rust/aw-query/src/lib.rs-simstep-3291e01a-482d-401b-98b5-759573be65ca": {
+ "path": "aw-server-rust/aw-query/src/lib.rs-simstep-3291e01a-482d-401b-98b5-759573be65ca",
+ "fileName": "lib.rs",
+ "wiki": "The `aw_query::query` function orchestrates the execution. It first uses a lexer to tokenize the query string, then a parser to build an Abstract Syntax Tree (AST). Finally, it invokes the interpreter to execute the AST.",
+ "cellName": "Query Engine: Parse and Interpret - lib.rs:L53-64",
+ "cellId": "a9279dbc-8fda-434c-bc5a-4eefaca0df56",
+ "visible": true,
+ "startLine": 53,
+ "endLine": 64,
+ "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
+ "parentPath": "aw-server-rust/aw-query/src/lib.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "3291e01a-482d-401b-98b5-759573be65ca"
+ }
+ ]
+ },
+ "be2c99a2-8b27-487f-9c8f-e1d1836613cc": {
+ "path": "be2c99a2-8b27-487f-9c8f-e1d1836613cc",
+ "cellName": "Execute `query_bucket` - functions.rs:L139-168",
+ "cellId": "be2c99a2-8b27-487f-9c8f-e1d1836613cc",
+ "visible": true,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e"
+ },
+ "aw-server-rust/aw-query/src/functions.rs-simstep-475886bc-26d3-4528-84ae-2f9c8e1dfcf9": {
+ "path": "aw-server-rust/aw-query/src/functions.rs-simstep-475886bc-26d3-4528-84ae-2f9c8e1dfcf9",
+ "fileName": "functions.rs",
+ "wiki": "The `query_bucket` function is executed. It reads the time interval from its environment and makes a call to the datastore's `get_events` method to fetch raw event data from the specified bucket.",
+ "cellName": "Execute `query_bucket` - functions.rs:L139-168",
+ "cellId": "be2c99a2-8b27-487f-9c8f-e1d1836613cc",
+ "visible": true,
+ "startLine": 139,
+ "endLine": 168,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "parentPath": "aw-server-rust/aw-query/src/functions.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "475886bc-26d3-4528-84ae-2f9c8e1dfcf9"
+ }
+ ]
+ },
+ "48d1c5e2-32b3-4eaf-9005-dd0a65a77448": {
+ "path": "48d1c5e2-32b3-4eaf-9005-dd0a65a77448",
+ "cellName": "Datastore: Retrieve Events from SQLite - datastore.rs:L700-797",
+ "cellId": "48d1c5e2-32b3-4eaf-9005-dd0a65a77448",
+ "visible": true,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
+ },
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-ff017206-8323-4caa-9eca-4fc760c2470f": {
+ "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-ff017206-8323-4caa-9eca-4fc760c2470f",
+ "fileName": "datastore.rs",
+ "wiki": "The `aw-datastore` component executes a `SELECT` query against its SQLite database. It retrieves all events from the `aw-watcher-window_my-desktop` bucket that fall within the specified time range.",
+ "cellName": "Datastore: Retrieve Events from SQLite - datastore.rs:L700-797",
+ "cellId": "48d1c5e2-32b3-4eaf-9005-dd0a65a77448",
+ "visible": true,
+ "startLine": 700,
+ "endLine": 797,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "ff017206-8323-4caa-9eca-4fc760c2470f"
+ }
+ ]
+ },
+ "48a7e119-b25c-4b9f-9a95-bd649493ff48": {
+ "path": "48a7e119-b25c-4b9f-9a95-bd649493ff48",
+ "cellName": "Transform: Filter AFK Periods - filter_period.rs:L20-69",
+ "cellId": "48a7e119-b25c-4b9f-9a95-bd649493ff48",
+ "visible": true,
+ "parentCellId": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca"
+ },
+ "aw-server-rust/aw-transform/src/filter_period.rs-simstep-50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10": {
+ "path": "aw-server-rust/aw-transform/src/filter_period.rs-simstep-50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10",
+ "fileName": "filter_period.rs",
+ "wiki": "The interpreter continues executing the query, calling transformation functions like `filter_period_intersect`. This function takes the window activity events and intersects them with the 'not-afk' events, effectively removing any time the user was away from the keyboard.",
+ "cellName": "Transform: Filter AFK Periods - filter_period.rs:L20-69",
+ "cellId": "48a7e119-b25c-4b9f-9a95-bd649493ff48",
+ "visible": true,
+ "startLine": 20,
+ "endLine": 69,
+ "parentCellId": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca",
+ "parentPath": "aw-server-rust/aw-transform/src/filter_period.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10"
+ }
+ ]
+ },
+ "63ebaed0-610a-46cd-8a5b-392c2874aecb": {
+ "path": "63ebaed0-610a-46cd-8a5b-392c2874aecb",
+ "cellName": "Final Aggregation and Return - interpret.rs:L30-33",
+ "cellId": "63ebaed0-610a-46cd-8a5b-392c2874aecb",
+ "visible": true,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c"
+ },
+ "aw-server-rust/aw-query/src/interpret.rs-simstep-18492fe4-5b57-4749-a2e8-d18f3c546e89": {
+ "path": "aw-server-rust/aw-query/src/interpret.rs-simstep-18492fe4-5b57-4749-a2e8-d18f3c546e89",
+ "fileName": "interpret.rs",
+ "wiki": "The interpreter completes the query by performing final aggregations like `merge_events_by_keys` and `sort_by_duration`. It assembles the results into a final dictionary structure as defined by the `RETURN` statement in the query script.",
+ "cellName": "Final Aggregation and Return - interpret.rs:L30-33",
+ "cellId": "63ebaed0-610a-46cd-8a5b-392c2874aecb",
+ "visible": true,
+ "startLine": 30,
+ "endLine": 33,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "18492fe4-5b57-4749-a2e8-d18f3c546e89"
+ }
+ ]
+ },
+ "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd": {
+ "path": "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd",
+ "cellName": "Frontend: Render Dashboard - README.md:L243-250",
+ "cellId": "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd",
+ "visible": true,
+ "parentCellId": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5"
+ },
+ "README.md-simstep-9396ef3a-ed06-4635-bb1d-3b136660bcc4": {
+ "path": "README.md-simstep-9396ef3a-ed06-4635-bb1d-3b136660bcc4",
+ "fileName": "README.md",
+ "wiki": "The `aw-webui` frontend receives the JSON data. Its JavaScript code then processes this data to render the various visualizations on the activity dashboard, such as the top applications and categories pie charts, and the activity timeline.",
+ "cellName": "Frontend: Render Dashboard - README.md:L243-250",
+ "cellId": "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd",
+ "visible": true,
+ "startLine": 243,
+ "endLine": 250,
+ "parentCellId": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5",
+ "parentPath": "README.md",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "9396ef3a-ed06-4635-bb1d-3b136660bcc4"
+ }
+ ]
+ },
+ "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f": {
+ "path": "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
+ "cellName": "API Call:\nPOST /api/0/query/",
+ "cellId": "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
+ "visible": true
+ },
+ "generated-edge-simstep-c1a26d9b-d661-4a99-8275-39a414824ed6-6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f": {
+ "path": "generated-edge-simstep-c1a26d9b-d661-4a99-8275-39a414824ed6-6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
+ "fileName": "client.py",
+ "cellName": "API Call: POST /api/0/query/",
+ "cellId": "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
+ "visible": true,
+ "startLine": 305,
+ "endLine": 339,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "c1a26d9b-d661-4a99-8275-39a414824ed6"
+ }
+ ]
+ },
+ "c8403507-4895-4695-84b5-9305afdc3c9f": {
+ "path": "c8403507-4895-4695-84b5-9305afdc3c9f",
+ "cellName": "API Endpoint\n-> Query\nEngine",
+ "cellId": "c8403507-4895-4695-84b5-9305afdc3c9f",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-a7b6aefb-1401-4756-bfa1-1eb9a76cde07-c8403507-4895-4695-84b5-9305afdc3c9f": {
+ "path": "generated-edge-simstep-a7b6aefb-1401-4756-bfa1-1eb9a76cde07-c8403507-4895-4695-84b5-9305afdc3c9f",
+ "fileName": "query.rs",
+ "cellName": "API Endpoint -> Query Engine",
+ "cellId": "c8403507-4895-4695-84b5-9305afdc3c9f",
+ "visible": true,
+ "startLine": 16,
+ "endLine": 16,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "a7b6aefb-1401-4756-bfa1-1eb9a76cde07"
+ }
+ ]
+ },
+ "8f8d2c55-63c0-48ec-b931-f848e245688f": {
+ "path": "8f8d2c55-63c0-48ec-b931-f848e245688f",
+ "cellName": "Interpreter ->\n`query_bucket`",
+ "cellId": "8f8d2c55-63c0-48ec-b931-f848e245688f",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
+ },
+ "generated-edge-simstep-00784ae1-bb99-494c-bf46-fe5947de5066-8f8d2c55-63c0-48ec-b931-f848e245688f": {
+ "path": "generated-edge-simstep-00784ae1-bb99-494c-bf46-fe5947de5066-8f8d2c55-63c0-48ec-b931-f848e245688f",
+ "fileName": "interpret.rs",
+ "cellName": "Interpreter -> `query_bucket`",
+ "cellId": "8f8d2c55-63c0-48ec-b931-f848e245688f",
+ "visible": true,
+ "startLine": 213,
+ "endLine": 226,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "00784ae1-bb99-494c-bf46-fe5947de5066"
+ }
+ ]
+ },
+ "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013": {
+ "path": "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
+ "cellName": "`query_bucket` ->\nDatastore",
+ "cellId": "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-e1bf9f3c-e763-4e75-8c62-1a8d739d53cc-5f0c5a39-ef1b-43eb-8332-3fc7e3b98013": {
+ "path": "generated-edge-simstep-e1bf9f3c-e763-4e75-8c62-1a8d739d53cc-5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
+ "fileName": "worker.rs",
+ "cellName": "`query_bucket` -> Datastore",
+ "cellId": "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
+ "visible": true,
+ "startLine": 414,
+ "endLine": 430,
+ "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
+ "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "e1bf9f3c-e763-4e75-8c62-1a8d739d53cc"
+ }
+ ]
+ },
+ "7a14a4d3-a453-4e33-9b10-fb192e40e34e": {
+ "path": "7a14a4d3-a453-4e33-9b10-fb192e40e34e",
+ "cellName": "Datastore ->\nQuery Engine",
+ "cellId": "7a14a4d3-a453-4e33-9b10-fb192e40e34e",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-f7dfb334-099f-4750-a893-cd96b1c46278-7a14a4d3-a453-4e33-9b10-fb192e40e34e": {
+ "path": "generated-edge-simstep-f7dfb334-099f-4750-a893-cd96b1c46278-7a14a4d3-a453-4e33-9b10-fb192e40e34e",
+ "fileName": "functions.rs",
+ "cellName": "Datastore -> Query Engine",
+ "cellId": "7a14a4d3-a453-4e33-9b10-fb192e40e34e",
+ "visible": true,
+ "startLine": 163,
+ "endLine": 167,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "parentPath": "aw-server-rust/aw-query/src/functions.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "f7dfb334-099f-4750-a893-cd96b1c46278"
+ }
+ ]
+ },
+ "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa": {
+ "path": "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
+ "cellName": "Return Transformed\nData",
+ "cellId": "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-78aaa465-8377-43f1-9ba6-36ddcf9300cf-8dd706f0-fb9b-496a-8ba8-26f289f0e2fa": {
+ "path": "generated-edge-simstep-78aaa465-8377-43f1-9ba6-36ddcf9300cf-8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
+ "fileName": "interpret.rs",
+ "cellName": "Return Transformed Data",
+ "cellId": "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
+ "visible": true,
+ "startLine": 36,
+ "endLine": 228,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "78aaa465-8377-43f1-9ba6-36ddcf9300cf"
+ }
+ ]
+ },
+ "889f0869-2c33-499b-a558-ede80ee18a54": {
+ "path": "889f0869-2c33-499b-a558-ede80ee18a54",
+ "cellName": "API Response:\nSend Processed\nData",
+ "cellId": "889f0869-2c33-499b-a558-ede80ee18a54",
+ "visible": true
+ },
+ "generated-edge-simstep-785d1355-bf16-42a7-846e-a2bf3ecbb35b-889f0869-2c33-499b-a558-ede80ee18a54": {
+ "path": "generated-edge-simstep-785d1355-bf16-42a7-846e-a2bf3ecbb35b-889f0869-2c33-499b-a558-ede80ee18a54",
+ "fileName": "query.rs",
+ "cellName": "API Response: Send Processed Data",
+ "cellId": "889f0869-2c33-499b-a558-ede80ee18a54",
+ "visible": true,
+ "startLine": 28,
+ "endLine": 28,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity data visualization works",
+ "simStepId": "785d1355-bf16-42a7-846e-a2bf3ecbb35b"
+ }
+ ]
+ },
+ "0b23a1ca-091a-4f70-b49e-95910c8179bf": {
+ "path": "0b23a1ca-091a-4f70-b49e-95910c8179bf",
+ "cellName": "aw-notify",
+ "cellId": "0b23a1ca-091a-4f70-b49e-95910c8179bf",
+ "visible": true
+ },
+ "4d835cac-01b7-4b3d-a7f5-189f89fda1c7": {
+ "path": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7",
+ "cellName": "aw_notify",
+ "cellId": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7",
+ "visible": true,
+ "parentCellId": "0b23a1ca-091a-4f70-b49e-95910c8179bf"
+ },
+ "954ebccb-39ec-4c50-aca4-0ac8c09e6358": {
+ "path": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "cellName": "main.py",
+ "cellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "visible": true,
+ "parentCellId": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7"
+ },
+ "60cb37da-078e-4380-88f0-e6746007277d": {
+ "path": "60cb37da-078e-4380-88f0-e6746007277d",
+ "cellName": "datatype.rs",
+ "cellId": "60cb37da-078e-4380-88f0-e6746007277d",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
+ },
+ "22d8d360-9b15-49db-bc15-de087f960e23": {
+ "path": "22d8d360-9b15-49db-bc15-de087f960e23",
+ "cellName": "classify.rs",
+ "cellId": "22d8d360-9b15-49db-bc15-de087f960e23",
+ "visible": true,
+ "parentCellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528"
+ },
+ "49029598-25ad-4498-b744-e2180f404fe5": {
+ "path": "49029598-25ad-4498-b744-e2180f404fe5",
+ "cellName": "Query Construction - queries.py:L84-151",
+ "cellId": "49029598-25ad-4498-b744-e2180f404fe5",
+ "visible": true,
+ "parentCellId": "941d7da8-a28d-4d5e-806f-3b546909f74e"
+ },
+ "aw-client/aw_client/queries.py-simstep-1b40cfa3-9cf5-4dc3-830f-74cb1d476d50": {
+ "path": "aw-client/aw_client/queries.py-simstep-1b40cfa3-9cf5-4dc3-830f-74cb1d476d50",
+ "fileName": "queries.py",
+ "wiki": "A client application or script constructs a query to fetch and categorize events. The `canonicalEvents` function is often used, which includes a `categorize` step. The categorization rules (classes) can be provided directly or fetched from the server's settings.",
+ "cellName": "Query Construction - queries.py:L84-151",
+ "cellId": "49029598-25ad-4498-b744-e2180f404fe5",
+ "visible": true,
+ "startLine": 84,
+ "endLine": 151,
+ "parentCellId": "941d7da8-a28d-4d5e-806f-3b546909f74e",
+ "parentPath": "aw-client/aw_client/queries.py",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "1b40cfa3-9cf5-4dc3-830f-74cb1d476d50"
+ }
+ ]
+ },
+ "ff986e21-7050-4c3d-ae40-3a678f46221d": {
+ "path": "ff986e21-7050-4c3d-ae40-3a678f46221d",
+ "cellName": "Query Engine: Function Invocation - functions.rs:L278-295",
+ "cellId": "ff986e21-7050-4c3d-ae40-3a678f46221d",
+ "visible": true,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e"
+ },
+ "aw-server-rust/aw-query/src/functions.rs-simstep-af6c51b2-ee18-406c-acc6-6e5d9588d012": {
+ "path": "aw-server-rust/aw-query/src/functions.rs-simstep-af6c51b2-ee18-406c-acc6-6e5d9588d012",
+ "fileName": "functions.rs",
+ "wiki": "The `aw-server-rust` query engine parses the query, recognizes the `categorize` function call, and invokes its registered implementation, passing the fetched events and rules as arguments.",
+ "cellName": "Query Engine: Function Invocation - functions.rs:L278-295",
+ "cellId": "ff986e21-7050-4c3d-ae40-3a678f46221d",
+ "visible": true,
+ "startLine": 278,
+ "endLine": 295,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "parentPath": "aw-server-rust/aw-query/src/functions.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "af6c51b2-ee18-406c-acc6-6e5d9588d012"
+ }
+ ]
+ },
+ "e99fcabc-934a-46cd-8823-d3e04ceea63c": {
+ "path": "e99fcabc-934a-46cd-8823-d3e04ceea63c",
+ "cellName": "Categorization Core Logic - classify.rs:L70-76",
+ "cellId": "e99fcabc-934a-46cd-8823-d3e04ceea63c",
+ "visible": true,
+ "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23"
+ },
+ "aw-server-rust/aw-transform/src/classify.rs-simstep-55815d72-39f6-4201-ad99-6ebd57d0eece": {
+ "path": "aw-server-rust/aw-transform/src/classify.rs-simstep-55815d72-39f6-4201-ad99-6ebd57d0eece",
+ "fileName": "classify.rs",
+ "wiki": "The main `categorize` function iterates through each event and applies the list of rules to it by calling `categorize_one`.",
+ "cellName": "Categorization Core Logic - classify.rs:L70-76",
+ "cellId": "e99fcabc-934a-46cd-8823-d3e04ceea63c",
+ "visible": true,
+ "startLine": 70,
+ "endLine": 76,
+ "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23",
+ "parentPath": "aw-server-rust/aw-transform/src/classify.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "55815d72-39f6-4201-ad99-6ebd57d0eece"
+ }
+ ]
+ },
+ "294c7beb-b479-47e2-bd3c-6d616497ecd2": {
+ "path": "294c7beb-b479-47e2-bd3c-6d616497ecd2",
+ "cellName": "Select Highest-Ranking Category - classify.rs:L116-122",
+ "cellId": "294c7beb-b479-47e2-bd3c-6d616497ecd2",
+ "visible": true,
+ "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23"
+ },
+ "aw-server-rust/aw-transform/src/classify.rs-simstep-e863b0b1-c3ce-4b13-ad7d-a7438f650035": {
+ "path": "aw-server-rust/aw-transform/src/classify.rs-simstep-e863b0b1-c3ce-4b13-ad7d-a7438f650035",
+ "fileName": "classify.rs",
+ "wiki": "If an event matches multiple categories, this function selects the most specific one. Specificity is determined by the depth of the category hierarchy (e.g., `['Work', 'Programming', 'Rust']` is deeper than `['Work', 'Programming']`). If no rules match, a default category of `['Uncategorized']` is assigned.",
+ "cellName": "Select Highest-Ranking Category - classify.rs:L116-122",
+ "cellId": "294c7beb-b479-47e2-bd3c-6d616497ecd2",
+ "visible": true,
+ "startLine": 116,
+ "endLine": 122,
+ "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23",
+ "parentPath": "aw-server-rust/aw-transform/src/classify.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "e863b0b1-c3ce-4b13-ad7d-a7438f650035"
+ }
+ ]
+ },
+ "9847b0a7-39f2-44f8-ae14-73eab42d8894": {
+ "path": "9847b0a7-39f2-44f8-ae14-73eab42d8894",
+ "cellName": "Client Consumes Categorized Data - main.py:L123-130",
+ "cellId": "9847b0a7-39f2-44f8-ae14-73eab42d8894",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "aw-notify/aw_notify/main.py-simstep-2108914e-2569-47bf-aa87-af337de03f8c": {
+ "path": "aw-notify/aw_notify/main.py-simstep-2108914e-2569-47bf-aa87-af337de03f8c",
+ "fileName": "main.py",
+ "wiki": "The client application receives the categorized events. It can then use the `$category` field to perform aggregations and generate reports, such as calculating the total time spent in each top-level category for the day.",
+ "cellName": "Client Consumes Categorized Data - main.py:L123-130",
+ "cellId": "9847b0a7-39f2-44f8-ae14-73eab42d8894",
+ "visible": true,
+ "startLine": 123,
+ "endLine": 130,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "2108914e-2569-47bf-aa87-af337de03f8c"
+ }
+ ]
+ },
+ "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661": {
+ "path": "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
+ "cellName": "API Call:\nExecute Query",
+ "cellId": "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
+ "visible": true
+ },
+ "generated-edge-simstep-9eeb592f-5c44-4ce1-a7a0-261bc6d6b679-e0c2455d-d2a0-4b88-bd3a-6f7b2472a661": {
+ "path": "generated-edge-simstep-9eeb592f-5c44-4ce1-a7a0-261bc6d6b679-e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
+ "fileName": "client.py",
+ "cellName": "API Call: Execute Query",
+ "cellId": "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
+ "visible": true,
+ "startLine": 119,
+ "endLine": 131,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "9eeb592f-5c44-4ce1-a7a0-261bc6d6b679"
+ }
+ ]
+ },
+ "79c14e32-8192-488e-ab72-b9c4c6edb346": {
+ "path": "79c14e32-8192-488e-ab72-b9c4c6edb346",
+ "cellName": "Data Transformation:\nConvert Rules",
+ "cellId": "79c14e32-8192-488e-ab72-b9c4c6edb346",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-e598a658-8e0e-4a76-9310-af0d60ec5828-79c14e32-8192-488e-ab72-b9c4c6edb346": {
+ "path": "generated-edge-simstep-e598a658-8e0e-4a76-9310-af0d60ec5828-79c14e32-8192-488e-ab72-b9c4c6edb346",
+ "fileName": "datatype.rs",
+ "cellName": "Data Transformation: Convert Rules",
+ "cellId": "79c14e32-8192-488e-ab72-b9c4c6edb346",
+ "visible": true,
+ "startLine": 272,
+ "endLine": 346,
+ "parentCellId": "60cb37da-078e-4380-88f0-e6746007277d",
+ "parentPath": "aw-server-rust/aw-query/src/datatype.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "e598a658-8e0e-4a76-9310-af0d60ec5828"
+ }
+ ]
+ },
+ "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8": {
+ "path": "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
+ "cellName": "Event-Rule Matching",
+ "cellId": "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
+ "visible": true,
+ "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23"
+ },
+ "generated-edge-simstep-9f7f50e4-03c6-4d7c-95c8-3317d37115eb-341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8": {
+ "path": "generated-edge-simstep-9f7f50e4-03c6-4d7c-95c8-3317d37115eb-341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
+ "fileName": "classify.rs",
+ "cellName": "Event-Rule Matching",
+ "cellId": "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
+ "visible": true,
+ "startLine": 49,
+ "endLine": 57,
+ "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23",
+ "parentPath": "aw-server-rust/aw-transform/src/classify.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "9f7f50e4-03c6-4d7c-95c8-3317d37115eb"
+ }
+ ]
+ },
+ "b4391f38-d9ee-4377-8568-efca87206124": {
+ "path": "b4391f38-d9ee-4377-8568-efca87206124",
+ "cellName": "Return Categorized\nEvents",
+ "cellId": "b4391f38-d9ee-4377-8568-efca87206124",
+ "visible": true
+ },
+ "generated-edge-simstep-ebd328dc-4cdf-452d-b4aa-10b65e9c354d-b4391f38-d9ee-4377-8568-efca87206124": {
+ "path": "generated-edge-simstep-ebd328dc-4cdf-452d-b4aa-10b65e9c354d-b4391f38-d9ee-4377-8568-efca87206124",
+ "fileName": "classify.rs",
+ "cellName": "Return Categorized Events",
+ "cellId": "b4391f38-d9ee-4377-8568-efca87206124",
+ "visible": true,
+ "startLine": 85,
+ "endLine": 88,
+ "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23",
+ "parentPath": "aw-server-rust/aw-transform/src/classify.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How activity categorization works",
+ "simStepId": "ebd328dc-4cdf-452d-b4aa-10b65e9c354d"
+ }
+ ]
+ },
+ "701d49bd-2670-4a9f-8ffd-52f62726ddc0": {
+ "path": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
+ "cellName": "aw_query",
+ "cellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
+ "visible": true,
+ "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb"
+ },
+ "22692aea-cd7a-4c08-8c76-c16bb5499546": {
+ "path": "22692aea-cd7a-4c08-8c76-c16bb5499546",
+ "cellName": "aw-client-rust",
+ "cellId": "22692aea-cd7a-4c08-8c76-c16bb5499546",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "0fb8ce44-e9ea-4e8a-a049-33211b003d20": {
+ "path": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
+ "cellName": "query2.py",
+ "cellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
+ "visible": true,
+ "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0"
+ },
+ "e1b937af-2584-42ee-8281-e1bffda373ae": {
+ "path": "e1b937af-2584-42ee-8281-e1bffda373ae",
+ "cellName": "functions.py",
+ "cellId": "e1b937af-2584-42ee-8281-e1bffda373ae",
+ "visible": true,
+ "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0"
+ },
+ "08296022-1e80-4653-821d-b48d9cf30c68": {
+ "path": "08296022-1e80-4653-821d-b48d9cf30c68",
+ "cellName": "src",
+ "cellId": "08296022-1e80-4653-821d-b48d9cf30c68",
+ "visible": true,
+ "parentCellId": "22692aea-cd7a-4c08-8c76-c16bb5499546"
+ },
+ "8dafeb60-1305-46f7-baac-4153d6d18539": {
+ "path": "8dafeb60-1305-46f7-baac-4153d6d18539",
+ "cellName": "blocking.rs",
+ "cellId": "8dafeb60-1305-46f7-baac-4153d6d18539",
+ "visible": true,
+ "parentCellId": "08296022-1e80-4653-821d-b48d9cf30c68"
+ },
+ "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf": {
+ "path": "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf",
+ "cellName": "lib.rs",
+ "cellId": "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf",
+ "visible": true,
+ "parentCellId": "08296022-1e80-4653-821d-b48d9cf30c68"
+ },
+ "5540d168-0892-4d44-a835-530768fbad09": {
+ "path": "5540d168-0892-4d44-a835-530768fbad09",
+ "cellName": "Python Flow: Client Initiates API Query - client.py:L305-338",
+ "cellId": "5540d168-0892-4d44-a835-530768fbad09",
+ "visible": true,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
+ },
+ "aw-client/aw_client/client.py-simstep-06f7c9e7-1c78-4114-867b-3dbb20dcc427": {
+ "path": "aw-client/aw_client/client.py-simstep-06f7c9e7-1c78-4114-867b-3dbb20dcc427",
+ "fileName": "client.py",
+ "wiki": "A client application, using the `aw-client` library, constructs a query to fetch data from the ActivityWatch server. It specifies the query string and the time periods to analyze.",
+ "cellName": "Python Flow: Client Initiates API Query - client.py:L305-338",
+ "cellId": "5540d168-0892-4d44-a835-530768fbad09",
+ "visible": true,
+ "startLine": 305,
+ "endLine": 338,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "06f7c9e7-1c78-4114-867b-3dbb20dcc427"
+ }
+ ]
+ },
+ "abf45adb-988a-4613-ab4a-acb8cef0c90a": {
+ "path": "abf45adb-988a-4613-ab4a-acb8cef0c90a",
+ "cellName": "Python Flow: API Endpoint Receives Request - rest.py:L310-326",
+ "cellId": "abf45adb-988a-4613-ab4a-acb8cef0c90a",
+ "visible": true,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
+ },
+ "aw-server/aw_server/rest.py-simstep-671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7": {
+ "path": "aw-server/aw_server/rest.py-simstep-671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7",
+ "fileName": "rest.py",
+ "wiki": "The Flask-based `aw-server` receives the incoming POST request. The `/api/0/query/` route is handled by the `QueryResource`, which extracts the query payload from the request.",
+ "cellName": "Python Flow: API Endpoint Receives Request - rest.py:L310-326",
+ "cellId": "abf45adb-988a-4613-ab4a-acb8cef0c90a",
+ "visible": true,
+ "startLine": 310,
+ "endLine": 326,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7"
+ }
+ ]
+ },
+ "96c3be58-d96a-4b11-b4f3-e778387f76b8": {
+ "path": "96c3be58-d96a-4b11-b4f3-e778387f76b8",
+ "cellName": "Python Flow: ServerAPI Orchestrates Query - api.py:L339-349",
+ "cellId": "96c3be58-d96a-4b11-b4f3-e778387f76b8",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31": {
+ "path": "aw-server/aw_server/api.py-simstep-a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31",
+ "fileName": "api.py",
+ "wiki": "The `ServerAPI.query2` method iterates through each specified time period and invokes the core query engine (`query2.query`) from `aw-core` for each one.",
+ "cellName": "Python Flow: ServerAPI Orchestrates Query - api.py:L339-349",
+ "cellId": "96c3be58-d96a-4b11-b4f3-e778387f76b8",
+ "visible": true,
+ "startLine": 339,
+ "endLine": 349,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31"
+ }
+ ]
+ },
+ "c0a28353-be8d-4bc8-a1be-2879961fc4df": {
+ "path": "c0a28353-be8d-4bc8-a1be-2879961fc4df",
+ "cellName": "Python Flow: Parse and Interpret Query - query2.py:L404-418",
+ "cellId": "c0a28353-be8d-4bc8-a1be-2879961fc4df",
+ "visible": true,
+ "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20"
+ },
+ "aw-core/aw_query/query2.py-simstep-5f7b6985-edf0-42eb-8822-847d0d7b8e9b": {
+ "path": "aw-core/aw_query/query2.py-simstep-5f7b6985-edf0-42eb-8822-847d0d7b8e9b",
+ "fileName": "query2.py",
+ "wiki": "The `query` function in `aw-core/aw_query/query2.py` acts as the interpreter. It splits the query into individual statements, parses each one into tokens (like variables and function calls), and then interprets them chronologically. Function calls are resolved by looking them up in the `functions` dictionary, which is populated by functions in `aw-core/aw_query/functions.py`.",
+ "cellName": "Python Flow: Parse and Interpret Query - query2.py:L404-418",
+ "cellId": "c0a28353-be8d-4bc8-a1be-2879961fc4df",
+ "visible": true,
+ "startLine": 404,
+ "endLine": 418,
+ "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
+ "parentPath": "aw-core/aw_query/query2.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "5f7b6985-edf0-42eb-8822-847d0d7b8e9b"
+ }
+ ]
+ },
+ "fb0bcd2a-5999-47fc-bb41-11233e3544fa": {
+ "path": "fb0bcd2a-5999-47fc-bb41-11233e3544fa",
+ "cellName": "Python Flow: Fetch Events from Datastore - functions.py:L151-164",
+ "cellId": "fb0bcd2a-5999-47fc-bb41-11233e3544fa",
+ "visible": true,
+ "parentCellId": "e1b937af-2584-42ee-8281-e1bffda373ae"
+ },
+ "aw-core/aw_query/functions.py-simstep-6ea3ab36-027f-40b9-a0ba-9ede77ae1117": {
+ "path": "aw-core/aw_query/functions.py-simstep-6ea3ab36-027f-40b9-a0ba-9ede77ae1117",
+ "fileName": "functions.py",
+ "wiki": "The `q2_query_bucket` function interacts with the datastore to fetch events for the specified bucket and time range.",
+ "cellName": "Python Flow: Fetch Events from Datastore - functions.py:L151-164",
+ "cellId": "fb0bcd2a-5999-47fc-bb41-11233e3544fa",
+ "visible": true,
+ "startLine": 151,
+ "endLine": 164,
+ "parentCellId": "e1b937af-2584-42ee-8281-e1bffda373ae",
+ "parentPath": "aw-core/aw_query/functions.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "6ea3ab36-027f-40b9-a0ba-9ede77ae1117"
+ }
+ ]
+ },
+ "5eb14d26-499c-4ea4-8282-3f923646dbdb": {
+ "path": "5eb14d26-499c-4ea4-8282-3f923646dbdb",
+ "cellName": "Python Flow: Finalize and Return Result - query2.py:L396-401",
+ "cellId": "5eb14d26-499c-4ea4-8282-3f923646dbdb",
+ "visible": true,
+ "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20"
+ },
+ "aw-core/aw_query/query2.py-simstep-ab3fe2d5-9396-4241-b64e-2a187e97de75": {
+ "path": "aw-core/aw_query/query2.py-simstep-ab3fe2d5-9396-4241-b64e-2a187e97de75",
+ "fileName": "query2.py",
+ "wiki": "The interpreter completes all statements. The `get_return` function is called to extract the final value assigned to the `RETURN` variable from the execution namespace.",
+ "cellName": "Python Flow: Finalize and Return Result - query2.py:L396-401",
+ "cellId": "5eb14d26-499c-4ea4-8282-3f923646dbdb",
+ "visible": true,
+ "startLine": 396,
+ "endLine": 401,
+ "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
+ "parentPath": "aw-core/aw_query/query2.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "ab3fe2d5-9396-4241-b64e-2a187e97de75"
+ }
+ ]
+ },
+ "7ace16a3-9438-4e78-bcf9-79131079c89d": {
+ "path": "7ace16a3-9438-4e78-bcf9-79131079c89d",
+ "cellName": "Rust Flow: Client Initiates API Query - blocking.rs:L64-69",
+ "cellId": "7ace16a3-9438-4e78-bcf9-79131079c89d",
+ "visible": true,
+ "parentCellId": "8dafeb60-1305-46f7-baac-4153d6d18539"
+ },
+ "aw-server-rust/aw-client-rust/src/blocking.rs-simstep-3118dc4c-d7ad-4996-aa81-a205ccdf6e72": {
+ "path": "aw-server-rust/aw-client-rust/src/blocking.rs-simstep-3118dc4c-d7ad-4996-aa81-a205ccdf6e72",
+ "fileName": "blocking.rs",
+ "wiki": "A client application sends a query to the ActivityWatch server. This example uses the Rust client for consistency, but any HTTP client can be used.",
+ "cellName": "Rust Flow: Client Initiates API Query - blocking.rs:L64-69",
+ "cellId": "7ace16a3-9438-4e78-bcf9-79131079c89d",
+ "visible": true,
+ "startLine": 64,
+ "endLine": 69,
+ "parentCellId": "8dafeb60-1305-46f7-baac-4153d6d18539",
+ "parentPath": "aw-server-rust/aw-client-rust/src/blocking.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "3118dc4c-d7ad-4996-aa81-a205ccdf6e72"
+ }
+ ]
+ },
+ "b93b83dd-fff3-44dc-ac22-3ea63117c222": {
+ "path": "b93b83dd-fff3-44dc-ac22-3ea63117c222",
+ "cellName": "Rust Flow: API Endpoint Receives Request - query.rs:L9-29",
+ "cellId": "b93b83dd-fff3-44dc-ac22-3ea63117c222",
+ "visible": true,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
+ },
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-1c25a330-b713-4866-9440-8737c787ce33": {
+ "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-1c25a330-b713-4866-9440-8737c787ce33",
+ "fileName": "query.rs",
+ "wiki": "The Rocket-based `aw-server-rust` receives the request. The `query` endpoint in `endpoints/query.rs` deserializes the JSON payload into a `Query` struct and joins the query lines.",
+ "cellName": "Rust Flow: API Endpoint Receives Request - query.rs:L9-29",
+ "cellId": "b93b83dd-fff3-44dc-ac22-3ea63117c222",
+ "visible": true,
+ "startLine": 9,
+ "endLine": 29,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "1c25a330-b713-4866-9440-8737c787ce33"
+ }
+ ]
+ },
+ "d8afb2b7-af24-431a-b206-828a8b7cef2a": {
+ "path": "d8afb2b7-af24-431a-b206-828a8b7cef2a",
+ "cellName": "Rust Flow: Lexing and Parsing - lib.rs:L53-62",
+ "cellId": "d8afb2b7-af24-431a-b206-828a8b7cef2a",
+ "visible": true,
+ "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237"
+ },
+ "aw-server-rust/aw-query/src/lib.rs-simstep-024a46d7-abc2-4c35-92d1-900d198f748c": {
+ "path": "aw-server-rust/aw-query/src/lib.rs-simstep-024a46d7-abc2-4c35-92d1-900d198f748c",
+ "fileName": "lib.rs",
+ "wiki": "The `aw_query::query` function first uses a lexer (`lexer.rs`) to convert the query string into a stream of tokens. Then, a parser (`parser.rs`) consumes the tokens to build an Abstract Syntax Tree (AST) representing the query's structure.",
+ "cellName": "Rust Flow: Lexing and Parsing - lib.rs:L53-62",
+ "cellId": "d8afb2b7-af24-431a-b206-828a8b7cef2a",
+ "visible": true,
+ "startLine": 53,
+ "endLine": 62,
+ "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
+ "parentPath": "aw-server-rust/aw-query/src/lib.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "024a46d7-abc2-4c35-92d1-900d198f748c"
+ }
+ ]
+ },
+ "630bda35-fbd5-40ec-b47d-37ad66379d94": {
+ "path": "630bda35-fbd5-40ec-b47d-37ad66379d94",
+ "cellName": "Rust Flow: Interpret AST - interpret.rs:L21-34",
+ "cellId": "630bda35-fbd5-40ec-b47d-37ad66379d94",
+ "visible": true,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c"
+ },
+ "aw-server-rust/aw-query/src/interpret.rs-simstep-e3204124-26ff-4799-8462-100305c27ae1": {
+ "path": "aw-server-rust/aw-query/src/interpret.rs-simstep-e3204124-26ff-4799-8462-100305c27ae1",
+ "fileName": "interpret.rs",
+ "wiki": "The `interpret_prog` function in `interpret.rs` initializes an environment and recursively evaluates each expression (`Expr`) in the AST using `interpret_expr`. Function calls are resolved by looking up their names in the environment, which is pre-populated with built-in functions from `functions.rs`.",
+ "cellName": "Rust Flow: Interpret AST - interpret.rs:L21-34",
+ "cellId": "630bda35-fbd5-40ec-b47d-37ad66379d94",
+ "visible": true,
+ "startLine": 21,
+ "endLine": 34,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "e3204124-26ff-4799-8462-100305c27ae1"
+ }
+ ]
+ },
+ "eecd0f91-7c53-4352-8d85-05c3dd46bee1": {
+ "path": "eecd0f91-7c53-4352-8d85-05c3dd46bee1",
+ "cellName": "Rust Flow: Fetch Events from Datastore - functions.rs:L139-167",
+ "cellId": "eecd0f91-7c53-4352-8d85-05c3dd46bee1",
+ "visible": true,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e"
+ },
+ "aw-server-rust/aw-query/src/functions.rs-simstep-06d75f72-3fc8-47d8-85ab-f7fa317f4de5": {
+ "path": "aw-server-rust/aw-query/src/functions.rs-simstep-06d75f72-3fc8-47d8-85ab-f7fa317f4de5",
+ "fileName": "functions.rs",
+ "wiki": "The `query_bucket` function calls the datastore's `get_events` method to retrieve events from the specified bucket within the given time interval.",
+ "cellName": "Rust Flow: Fetch Events from Datastore - functions.rs:L139-167",
+ "cellId": "eecd0f91-7c53-4352-8d85-05c3dd46bee1",
+ "visible": true,
+ "startLine": 139,
+ "endLine": 167,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "parentPath": "aw-server-rust/aw-query/src/functions.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "06d75f72-3fc8-47d8-85ab-f7fa317f4de5"
+ }
+ ]
+ },
+ "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4": {
+ "path": "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4",
+ "cellName": "Rust Flow: Finalize and Return Result - interpret.rs:L30-33",
+ "cellId": "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4",
+ "visible": true,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c"
+ },
+ "aw-server-rust/aw-query/src/interpret.rs-simstep-9382ac29-7930-4f83-afdd-deb2bfc221e3": {
+ "path": "aw-server-rust/aw-query/src/interpret.rs-simstep-9382ac29-7930-4f83-afdd-deb2bfc221e3",
+ "fileName": "interpret.rs",
+ "wiki": "After executing all statements (including handling the `Return` expression which sets the special `RETURN` variable in the environment), the `interpret_prog` function retrieves the final value from the environment.",
+ "cellName": "Rust Flow: Finalize and Return Result - interpret.rs:L30-33",
+ "cellId": "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4",
+ "visible": true,
+ "startLine": 30,
+ "endLine": 33,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "9382ac29-7930-4f83-afdd-deb2bfc221e3"
+ }
+ ]
+ },
+ "71408ae2-19e6-4327-bab9-8918af09c855": {
+ "path": "71408ae2-19e6-4327-bab9-8918af09c855",
+ "cellName": "API Call:\nTransmit Query\nto Python\nServer",
+ "cellId": "71408ae2-19e6-4327-bab9-8918af09c855",
+ "visible": true
+ },
+ "generated-edge-simstep-5dc6bd77-15d2-44c3-b665-8de88288c314-71408ae2-19e6-4327-bab9-8918af09c855": {
+ "path": "generated-edge-simstep-5dc6bd77-15d2-44c3-b665-8de88288c314-71408ae2-19e6-4327-bab9-8918af09c855",
+ "fileName": "client.py",
+ "cellName": "API Call: Transmit Query to Python Server",
+ "cellId": "71408ae2-19e6-4327-bab9-8918af09c855",
+ "visible": true,
+ "startLine": 115,
+ "endLine": 127,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "5dc6bd77-15d2-44c3-b665-8de88288c314"
+ }
+ ]
+ },
+ "891bfe3a-f22a-4998-acea-aa6d0c362821": {
+ "path": "891bfe3a-f22a-4998-acea-aa6d0c362821",
+ "cellName": "Data Flow:\nPass Query\nto API\nLogic",
+ "cellId": "891bfe3a-f22a-4998-acea-aa6d0c362821",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
+ },
+ "generated-edge-simstep-5a0d9b17-b09a-4aa5-9234-c01cb2aadef4-891bfe3a-f22a-4998-acea-aa6d0c362821": {
+ "path": "generated-edge-simstep-5a0d9b17-b09a-4aa5-9234-c01cb2aadef4-891bfe3a-f22a-4998-acea-aa6d0c362821",
+ "fileName": "rest.py",
+ "cellName": "Data Flow: Pass Query to API Logic",
+ "cellId": "891bfe3a-f22a-4998-acea-aa6d0c362821",
+ "visible": true,
+ "startLine": 320,
+ "endLine": 323,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "5a0d9b17-b09a-4aa5-9234-c01cb2aadef4"
+ }
+ ]
+ },
+ "b79b67f9-1be1-48f1-920a-9ebdd4417272": {
+ "path": "b79b67f9-1be1-48f1-920a-9ebdd4417272",
+ "cellName": "Data Flow:\nPass Query\nto Interpreter",
+ "cellId": "b79b67f9-1be1-48f1-920a-9ebdd4417272",
+ "visible": true
+ },
+ "generated-edge-simstep-833f0f0f-ec00-4960-b1f9-46d8a8530a01-b79b67f9-1be1-48f1-920a-9ebdd4417272": {
+ "path": "generated-edge-simstep-833f0f0f-ec00-4960-b1f9-46d8a8530a01-b79b67f9-1be1-48f1-920a-9ebdd4417272",
+ "fileName": "api.py",
+ "cellName": "Data Flow: Pass Query to Interpreter",
+ "cellId": "b79b67f9-1be1-48f1-920a-9ebdd4417272",
+ "visible": true,
+ "startLine": 348,
+ "endLine": 348,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "833f0f0f-ec00-4960-b1f9-46d8a8530a01"
+ }
+ ]
+ },
+ "4059fcbe-a1ee-41d0-b576-55a1d278bca0": {
+ "path": "4059fcbe-a1ee-41d0-b576-55a1d278bca0",
+ "cellName": "Data Flow:\nExecute Query\nFunction",
+ "cellId": "4059fcbe-a1ee-41d0-b576-55a1d278bca0",
+ "visible": true,
+ "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0"
+ },
+ "generated-edge-simstep-7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6-4059fcbe-a1ee-41d0-b576-55a1d278bca0": {
+ "path": "generated-edge-simstep-7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6-4059fcbe-a1ee-41d0-b576-55a1d278bca0",
+ "fileName": "query2.py",
+ "cellName": "Data Flow: Execute Query Function",
+ "cellId": "4059fcbe-a1ee-41d0-b576-55a1d278bca0",
+ "visible": true,
+ "startLine": 133,
+ "endLine": 148,
+ "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
+ "parentPath": "aw-core/aw_query/query2.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6"
+ }
+ ]
+ },
+ "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4": {
+ "path": "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
+ "cellName": "Data Flow:\nReturn Events\nto Interpreter",
+ "cellId": "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
+ "visible": true,
+ "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0"
+ },
+ "generated-edge-simstep-ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c-e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4": {
+ "path": "generated-edge-simstep-ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c-e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
+ "fileName": "datastore.py",
+ "cellName": "Data Flow: Return Events to Interpreter",
+ "cellId": "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
+ "visible": true,
+ "startLine": 88,
+ "endLine": 114,
+ "parentCellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
+ "parentPath": "aw-core/aw_datastore/datastore.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c"
+ }
+ ]
+ },
+ "c4b6d403-d2a9-4cff-8a72-31189a53c0db": {
+ "path": "c4b6d403-d2a9-4cff-8a72-31189a53c0db",
+ "cellName": "API Call:\nSend JSON\nResponse",
+ "cellId": "c4b6d403-d2a9-4cff-8a72-31189a53c0db",
+ "visible": true
+ },
+ "generated-edge-simstep-fe43857f-ef7d-455d-a9c4-37d54d12207a-c4b6d403-d2a9-4cff-8a72-31189a53c0db": {
+ "path": "generated-edge-simstep-fe43857f-ef7d-455d-a9c4-37d54d12207a-c4b6d403-d2a9-4cff-8a72-31189a53c0db",
+ "fileName": "rest.py",
+ "cellName": "API Call: Send JSON Response",
+ "cellId": "c4b6d403-d2a9-4cff-8a72-31189a53c0db",
+ "visible": true,
+ "startLine": 323,
+ "endLine": 323,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "fe43857f-ef7d-455d-a9c4-37d54d12207a"
+ }
+ ]
+ },
+ "ed18dcc0-5e4a-44fb-b661-f746f1e893f1": {
+ "path": "ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
+ "cellName": "API Call:\nTransmit Query\nto Rust\nServer",
+ "cellId": "ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-97542310-17cf-4c99-9ce9-a328dffa5f4c-ed18dcc0-5e4a-44fb-b661-f746f1e893f1": {
+ "path": "generated-edge-simstep-97542310-17cf-4c99-9ce9-a328dffa5f4c-ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
+ "fileName": "lib.rs",
+ "cellName": "API Call: Transmit Query to Rust Server",
+ "cellId": "ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
+ "visible": true,
+ "startLine": 112,
+ "endLine": 137,
+ "parentCellId": "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf",
+ "parentPath": "aw-server-rust/aw-client-rust/src/lib.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "97542310-17cf-4c99-9ce9-a328dffa5f4c"
+ }
+ ]
+ },
+ "d3cb01a0-d8cd-4382-b122-d1234b0562bc": {
+ "path": "d3cb01a0-d8cd-4382-b122-d1234b0562bc",
+ "cellName": "Data Flow:\nPass Query\nto Core\nEngine",
+ "cellId": "d3cb01a0-d8cd-4382-b122-d1234b0562bc",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-6eb126a9-5234-4495-9727-ec2741ce9660-d3cb01a0-d8cd-4382-b122-d1234b0562bc": {
+ "path": "generated-edge-simstep-6eb126a9-5234-4495-9727-ec2741ce9660-d3cb01a0-d8cd-4382-b122-d1234b0562bc",
+ "fileName": "query.rs",
+ "cellName": "Data Flow: Pass Query to Core Engine",
+ "cellId": "d3cb01a0-d8cd-4382-b122-d1234b0562bc",
+ "visible": true,
+ "startLine": 16,
+ "endLine": 24,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "6eb126a9-5234-4495-9727-ec2741ce9660"
+ }
+ ]
+ },
+ "e72e1881-49ce-41ad-966a-90a26ca47453": {
+ "path": "e72e1881-49ce-41ad-966a-90a26ca47453",
+ "cellName": "Data Flow:\nPass AST\nto Interpreter",
+ "cellId": "e72e1881-49ce-41ad-966a-90a26ca47453",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
+ },
+ "generated-edge-simstep-acc1ad56-50cb-41ab-9217-f8d15af6686c-e72e1881-49ce-41ad-966a-90a26ca47453": {
+ "path": "generated-edge-simstep-acc1ad56-50cb-41ab-9217-f8d15af6686c-e72e1881-49ce-41ad-966a-90a26ca47453",
+ "fileName": "lib.rs",
+ "cellName": "Data Flow: Pass AST to Interpreter",
+ "cellId": "e72e1881-49ce-41ad-966a-90a26ca47453",
+ "visible": true,
+ "startLine": 63,
+ "endLine": 63,
+ "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
+ "parentPath": "aw-server-rust/aw-query/src/lib.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "acc1ad56-50cb-41ab-9217-f8d15af6686c"
+ }
+ ]
+ },
+ "15dfaeb9-fb37-4296-972f-0188abd0b353": {
+ "path": "15dfaeb9-fb37-4296-972f-0188abd0b353",
+ "cellName": "Data Flow:\nExecute Query\nFunction",
+ "cellId": "15dfaeb9-fb37-4296-972f-0188abd0b353",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
+ },
+ "generated-edge-simstep-f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5-15dfaeb9-fb37-4296-972f-0188abd0b353": {
+ "path": "generated-edge-simstep-f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5-15dfaeb9-fb37-4296-972f-0188abd0b353",
+ "fileName": "interpret.rs",
+ "cellName": "Data Flow: Execute Query Function",
+ "cellId": "15dfaeb9-fb37-4296-972f-0188abd0b353",
+ "visible": true,
+ "startLine": 213,
+ "endLine": 226,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5"
+ }
+ ]
+ },
+ "9792d1f0-08be-4f90-8e68-3caee0eb2498": {
+ "path": "9792d1f0-08be-4f90-8e68-3caee0eb2498",
+ "cellName": "Data Flow:\nReturn Events\nto Interpreter",
+ "cellId": "9792d1f0-08be-4f90-8e68-3caee0eb2498",
+ "visible": true,
+ "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
+ },
+ "generated-edge-simstep-f69e7df0-6666-4b48-a0a6-1000c8ccede0-9792d1f0-08be-4f90-8e68-3caee0eb2498": {
+ "path": "generated-edge-simstep-f69e7df0-6666-4b48-a0a6-1000c8ccede0-9792d1f0-08be-4f90-8e68-3caee0eb2498",
+ "fileName": "datastore.rs",
+ "cellName": "Data Flow: Return Events to Interpreter",
+ "cellId": "9792d1f0-08be-4f90-8e68-3caee0eb2498",
+ "visible": true,
+ "startLine": 700,
+ "endLine": 797,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the data query language works",
+ "simStepId": "f69e7df0-6666-4b48-a0a6-1000c8ccede0"
+ }
+ ]
+ },
+ "7ee7b20f-9df9-4269-8f41-bc7e191503bd": {
+ "path": "7ee7b20f-9df9-4269-8f41-bc7e191503bd",
+ "cellName": "aw-watcher-afk",
+ "cellId": "7ee7b20f-9df9-4269-8f41-bc7e191503bd",
+ "visible": true
+ },
+ "8f0b906e-fb77-4a52-aee5-1f494bec596c": {
+ "path": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
+ "cellName": "aw_watcher_afk",
+ "cellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
+ "visible": true,
+ "parentCellId": "7ee7b20f-9df9-4269-8f41-bc7e191503bd"
+ },
+ "d242d1ad-7cdf-414b-812a-f3e5af153562": {
+ "path": "d242d1ad-7cdf-414b-812a-f3e5af153562",
+ "cellName": "__main__.py",
+ "cellId": "d242d1ad-7cdf-414b-812a-f3e5af153562",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
+ },
+ "c443335f-7f08-4436-8862-5aab2adcf7e0": {
+ "path": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "cellName": "afk.py",
+ "cellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
+ },
+ "72e53989-6741-4b0d-b49c-f58d0333cdd1": {
+ "path": "72e53989-6741-4b0d-b49c-f58d0333cdd1",
+ "cellName": "unix.py",
+ "cellId": "72e53989-6741-4b0d-b49c-f58d0333cdd1",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
+ },
+ "ba27c535-e0e5-44ae-b9f0-2827227ebfe2": {
+ "path": "ba27c535-e0e5-44ae-b9f0-2827227ebfe2",
+ "cellName": "AFK Watcher Entrypoint - __main__.py:L7-21",
+ "cellId": "ba27c535-e0e5-44ae-b9f0-2827227ebfe2",
+ "visible": true,
+ "parentCellId": "d242d1ad-7cdf-414b-812a-f3e5af153562"
+ },
+ "aw-watcher-afk/aw_watcher_afk/__main__.py-simstep-8ffbcadf-f26a-483a-9902-95e5a761de64": {
+ "path": "aw-watcher-afk/aw_watcher_afk/__main__.py-simstep-8ffbcadf-f26a-483a-9902-95e5a761de64",
+ "fileName": "__main__.py",
+ "wiki": "The `aw-watcher-afk` process is started. The `main` function is called, which parses command-line arguments, sets up logging, and initializes the `AFKWatcher`.",
+ "cellName": "AFK Watcher Entrypoint - __main__.py:L7-21",
+ "cellId": "ba27c535-e0e5-44ae-b9f0-2827227ebfe2",
+ "visible": true,
+ "startLine": 7,
+ "endLine": 21,
+ "parentCellId": "d242d1ad-7cdf-414b-812a-f3e5af153562",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/__main__.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "8ffbcadf-f26a-483a-9902-95e5a761de64"
+ }
+ ]
+ },
+ "79468b99-a4de-48b7-bb67-506dc0dcb41c": {
+ "path": "79468b99-a4de-48b7-bb67-506dc0dcb41c",
+ "cellName": "Load Configuration - afk.py:L42-53",
+ "cellId": "79468b99-a4de-48b7-bb67-506dc0dcb41c",
+ "visible": true,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
+ },
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-daeeac12-287a-4144-9028-6ea841b196c4": {
+ "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-daeeac12-287a-4144-9028-6ea841b196c4",
+ "fileName": "afk.py",
+ "wiki": "The `AFKWatcher` constructor loads its configuration, setting the `timeout` (time of inactivity to be considered AFK) and `poll_time` (how often to check for activity). It also initializes the `ActivityWatchClient` to communicate with the server.",
+ "cellName": "Load Configuration - afk.py:L42-53",
+ "cellId": "79468b99-a4de-48b7-bb67-506dc0dcb41c",
+ "visible": true,
+ "startLine": 42,
+ "endLine": 53,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "daeeac12-287a-4144-9028-6ea841b196c4"
+ }
+ ]
+ },
+ "6b45de30-296e-4896-915c-371f09843599": {
+ "path": "6b45de30-296e-4896-915c-371f09843599",
+ "cellName": "Check User Activity - afk.py:L86",
+ "cellId": "6b45de30-296e-4896-915c-371f09843599",
+ "visible": true,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
+ },
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-6579f587-817d-4d23-a9df-86abc54273ae": {
+ "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-6579f587-817d-4d23-a9df-86abc54273ae",
+ "fileName": "afk.py",
+ "wiki": "Inside the `heartbeat_loop`, the watcher calls `seconds_since_last_input()` to get the time elapsed since the last keyboard or mouse activity from the operating system.",
+ "cellName": "Check User Activity - afk.py:L86",
+ "cellId": "6b45de30-296e-4896-915c-371f09843599",
+ "visible": true,
+ "startLine": 86,
+ "endLine": 86,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "6579f587-817d-4d23-a9df-86abc54273ae"
+ }
+ ]
+ },
+ "b7321a6c-302b-4701-9ea5-5c05c6d3e71b": {
+ "path": "b7321a6c-302b-4701-9ea5-5c05c6d3e71b",
+ "cellName": "Get Idle Time (Unix Example) - unix.py:L21-31",
+ "cellId": "b7321a6c-302b-4701-9ea5-5c05c6d3e71b",
+ "visible": true,
+ "parentCellId": "72e53989-6741-4b0d-b49c-f58d0333cdd1"
+ },
+ "aw-watcher-afk/aw_watcher_afk/unix.py-simstep-4d2c85c7-0754-429a-8a55-c64d4da0d37c": {
+ "path": "aw-watcher-afk/aw_watcher_afk/unix.py-simstep-4d2c85c7-0754-429a-8a55-c64d4da0d37c",
+ "fileName": "unix.py",
+ "wiki": "On Unix-like systems, listeners for mouse and keyboard events are checked. If a new event has occurred since the last check, the `last_activity` timestamp is updated. The function then returns the total seconds between now and the last recorded activity.",
+ "cellName": "Get Idle Time (Unix Example) - unix.py:L21-31",
+ "cellId": "b7321a6c-302b-4701-9ea5-5c05c6d3e71b",
+ "visible": true,
+ "startLine": 21,
+ "endLine": 31,
+ "parentCellId": "72e53989-6741-4b0d-b49c-f58d0333cdd1",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/unix.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "4d2c85c7-0754-429a-8a55-c64d4da0d37c"
+ }
+ ]
+ },
+ "faab8465-be29-479d-890a-7936dc5cfbdd": {
+ "path": "faab8465-be29-479d-890a-7936dc5cfbdd",
+ "cellName": "Detect State Change: User Becomes AFK - afk.py:L98-105",
+ "cellId": "faab8465-be29-479d-890a-7936dc5cfbdd",
+ "visible": true,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
+ },
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-3e0e033c-c32f-4d0d-aa65-a278d77e80c7": {
+ "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-3e0e033c-c32f-4d0d-aa65-a278d77e80c7",
+ "fileName": "afk.py",
+ "wiki": "The watcher compares the idle time with the configured timeout. Since the user was previously not AFK (`afk=False`) and the idle time (`185.3s`) is greater than the timeout (`180s`), the user's state changes to AFK.",
+ "cellName": "Detect State Change: User Becomes AFK - afk.py:L98-105",
+ "cellId": "faab8465-be29-479d-890a-7936dc5cfbdd",
+ "visible": true,
+ "startLine": 98,
+ "endLine": 105,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "3e0e033c-c32f-4d0d-aa65-a278d77e80c7"
+ }
+ ]
+ },
+ "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5": {
+ "path": "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5",
+ "cellName": "Prepare Event for Server - afk.py:L55-59",
+ "cellId": "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5",
+ "visible": true,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
+ },
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-dc58bc3e-b09e-4df2-870b-76419e78dd3d": {
+ "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-dc58bc3e-b09e-4df2-870b-76419e78dd3d",
+ "fileName": "afk.py",
+ "wiki": "The `ping` method constructs an `Event` object containing the user's status. It then calls the client's `heartbeat` method to send this event to the `aw-server`.",
+ "cellName": "Prepare Event for Server - afk.py:L55-59",
+ "cellId": "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5",
+ "visible": true,
+ "startLine": 55,
+ "endLine": 59,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "dc58bc3e-b09e-4df2-870b-76419e78dd3d"
+ }
+ ]
+ },
+ "c27977fb-af8a-4779-8f78-a99b40221157": {
+ "path": "c27977fb-af8a-4779-8f78-a99b40221157",
+ "cellName": "Server Receives and Processes Heartbeat - api.py:L268-276",
+ "cellId": "c27977fb-af8a-4779-8f78-a99b40221157",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-7357e239-3712-4b55-a94c-2165ea1f3255": {
+ "path": "aw-server/aw_server/api.py-simstep-7357e239-3712-4b55-a94c-2165ea1f3255",
+ "fileName": "api.py",
+ "wiki": "The `aw-server` receives the heartbeat event. The `heartbeat` method in the API layer checks if the new event's data is the same as the last event. Since the status changed from 'not-afk' to 'afk', it will not merge them and will instead insert a new event.",
+ "cellName": "Server Receives and Processes Heartbeat - api.py:L268-276",
+ "cellId": "c27977fb-af8a-4779-8f78-a99b40221157",
+ "visible": true,
+ "startLine": 268,
+ "endLine": 276,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "7357e239-3712-4b55-a94c-2165ea1f3255"
+ }
+ ]
+ },
+ "802c1941-09e1-4038-a0bf-bd4e553ff6f6": {
+ "path": "802c1941-09e1-4038-a0bf-bd4e553ff6f6",
+ "cellName": "Loop Repeats - afk.py:L76",
+ "cellId": "802c1941-09e1-4038-a0bf-bd4e553ff6f6",
+ "visible": true,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
+ },
+ "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-1e5ad77f-aeff-49b6-9634-65e52f011a83": {
+ "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-1e5ad77f-aeff-49b6-9634-65e52f011a83",
+ "fileName": "afk.py",
+ "wiki": "The process repeats. The watcher continues to send `afk` heartbeats on each poll interval as long as the user remains idle. When activity resumes, the condition `afk and seconds_since_input < self.settings.timeout` will trigger, sending a `not-afk` event and resetting the state.",
+ "cellName": "Loop Repeats - afk.py:L76",
+ "cellId": "802c1941-09e1-4038-a0bf-bd4e553ff6f6",
+ "visible": true,
+ "startLine": 76,
+ "endLine": 76,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "1e5ad77f-aeff-49b6-9634-65e52f011a83"
+ }
+ ]
+ },
+ "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250": {
+ "path": "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
+ "cellName": "Initialize Watcher",
+ "cellId": "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
+ },
+ "generated-edge-simstep-60e1002f-9782-4c8d-b104-f4bb172e2c91-7c2f1d5b-706c-4dd2-9d8c-62b3e6886250": {
+ "path": "generated-edge-simstep-60e1002f-9782-4c8d-b104-f4bb172e2c91-7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
+ "fileName": "__main__.py",
+ "cellName": "Initialize Watcher",
+ "cellId": "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
+ "visible": true,
+ "startLine": 20,
+ "endLine": 20,
+ "parentCellId": "d242d1ad-7cdf-414b-812a-f3e5af153562",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/__main__.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "60e1002f-9782-4c8d-b104-f4bb172e2c91"
+ }
+ ]
+ },
+ "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838": {
+ "path": "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
+ "cellName": "Start Main\nLoop",
+ "cellId": "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
+ "visible": true,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
+ },
+ "generated-edge-simstep-1422a5f8-ad2e-4b32-8955-ee6bb3053286-1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838": {
+ "path": "generated-edge-simstep-1422a5f8-ad2e-4b32-8955-ee6bb3053286-1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
+ "fileName": "afk.py",
+ "cellName": "Start Main Loop",
+ "cellId": "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
+ "visible": true,
+ "startLine": 71,
+ "endLine": 72,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "1422a5f8-ad2e-4b32-8955-ee6bb3053286"
+ }
+ ]
+ },
+ "e514d9e2-e803-4041-b693-65878401b214": {
+ "path": "e514d9e2-e803-4041-b693-65878401b214",
+ "cellName": "Platform-Specific Call",
+ "cellId": "e514d9e2-e803-4041-b693-65878401b214",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
+ },
+ "generated-edge-simstep-2588211c-b086-4768-8a87-a86764c7e5cd-e514d9e2-e803-4041-b693-65878401b214": {
+ "path": "generated-edge-simstep-2588211c-b086-4768-8a87-a86764c7e5cd-e514d9e2-e803-4041-b693-65878401b214",
+ "fileName": "afk.py",
+ "cellName": "Platform-Specific Call",
+ "cellId": "e514d9e2-e803-4041-b693-65878401b214",
+ "visible": true,
+ "startLine": 14,
+ "endLine": 24,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "2588211c-b086-4768-8a87-a86764c7e5cd"
+ }
+ ]
+ },
+ "eeb9224a-fff6-4652-b733-ea430b820a2c": {
+ "path": "eeb9224a-fff6-4652-b733-ea430b820a2c",
+ "cellName": "Return Idle\nTime",
+ "cellId": "eeb9224a-fff6-4652-b733-ea430b820a2c",
+ "visible": true,
+ "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
+ },
+ "generated-edge-simstep-9195e582-b3fa-4848-b151-0236a8a5d176-eeb9224a-fff6-4652-b733-ea430b820a2c": {
+ "path": "generated-edge-simstep-9195e582-b3fa-4848-b151-0236a8a5d176-eeb9224a-fff6-4652-b733-ea430b820a2c",
+ "fileName": "afk.py",
+ "cellName": "Return Idle Time",
+ "cellId": "eeb9224a-fff6-4652-b733-ea430b820a2c",
+ "visible": true,
+ "startLine": 86,
+ "endLine": 86,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "9195e582-b3fa-4848-b151-0236a8a5d176"
+ }
+ ]
+ },
+ "196358b9-6ae9-4f52-ad78-ff88b4a49403": {
+ "path": "196358b9-6ae9-4f52-ad78-ff88b4a49403",
+ "cellName": "Send Final\n'not-afk' Heartbeat",
+ "cellId": "196358b9-6ae9-4f52-ad78-ff88b4a49403",
+ "visible": true,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
+ },
+ "generated-edge-simstep-78d78341-ced8-4fc6-bc93-ce4a62c8adf6-196358b9-6ae9-4f52-ad78-ff88b4a49403": {
+ "path": "generated-edge-simstep-78d78341-ced8-4fc6-bc93-ce4a62c8adf6-196358b9-6ae9-4f52-ad78-ff88b4a49403",
+ "fileName": "afk.py",
+ "cellName": "Send Final 'not-afk' Heartbeat",
+ "cellId": "196358b9-6ae9-4f52-ad78-ff88b4a49403",
+ "visible": true,
+ "startLine": 100,
+ "endLine": 100,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "78d78341-ced8-4fc6-bc93-ce4a62c8adf6"
+ }
+ ]
+ },
+ "b520b088-6f6f-4b32-afba-5ef244691c44": {
+ "path": "b520b088-6f6f-4b32-afba-5ef244691c44",
+ "cellName": "Send First\n'afk' Heartbeat",
+ "cellId": "b520b088-6f6f-4b32-afba-5ef244691c44",
+ "visible": true
+ },
+ "generated-edge-simstep-c9a127c1-afd0-4def-a0fe-c490c9b64039-b520b088-6f6f-4b32-afba-5ef244691c44": {
+ "path": "generated-edge-simstep-c9a127c1-afd0-4def-a0fe-c490c9b64039-b520b088-6f6f-4b32-afba-5ef244691c44",
+ "fileName": "afk.py",
+ "cellName": "Send First 'afk' Heartbeat",
+ "cellId": "b520b088-6f6f-4b32-afba-5ef244691c44",
+ "visible": true,
+ "startLine": 103,
+ "endLine": 105,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "c9a127c1-afd0-4def-a0fe-c490c9b64039"
+ }
+ ]
+ },
+ "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0": {
+ "path": "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
+ "cellName": "Pause for\nPoll Time",
+ "cellId": "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
+ "visible": true
+ },
+ "generated-edge-simstep-9fde1b44-5dbf-4530-88e2-ca54c220b462-f0e34997-66ab-4bc2-9a5e-1f00b40d47b0": {
+ "path": "generated-edge-simstep-9fde1b44-5dbf-4530-88e2-ca54c220b462-f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
+ "fileName": "afk.py",
+ "cellName": "Pause for Poll Time",
+ "cellId": "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
+ "visible": true,
+ "startLine": 119,
+ "endLine": 119,
+ "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
+ "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "simSteps": [
+ {
+ "simulationKey": "How AFK (Away From Keyboard) detection works",
+ "simStepId": "9fde1b44-5dbf-4530-88e2-ca54c220b462"
+ }
+ ]
+ },
+ "34f5debb-c898-419f-9c17-186d2a5f6e85": {
+ "path": "34f5debb-c898-419f-9c17-186d2a5f6e85",
+ "cellName": "aw_transform",
+ "cellId": "34f5debb-c898-419f-9c17-186d2a5f6e85",
+ "visible": true,
+ "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb"
+ },
+ "40ad45bd-b0eb-4f2c-a091-f933962a90b8": {
+ "path": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
+ "cellName": "macos.swift",
+ "cellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
+ "visible": true,
+ "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
+ },
+ "6860aa38-bc11-4d81-9260-87eba1c02581": {
+ "path": "6860aa38-bc11-4d81-9260-87eba1c02581",
+ "cellName": "heartbeats.py",
+ "cellId": "6860aa38-bc11-4d81-9260-87eba1c02581",
+ "visible": true,
+ "parentCellId": "34f5debb-c898-419f-9c17-186d2a5f6e85"
+ },
+ "0f86982d-c1d5-4ceb-8574-3e19c2db7159": {
+ "path": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
+ "cellName": "bucket.rs",
+ "cellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
+ "visible": true,
+ "parentCellId": "11799249-188d-43b3-b410-54dcff47aeba"
+ },
+ "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c": {
+ "path": "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c",
+ "cellName": "[Python Flow - Watcher] Detect Active Window Change - macos.swift:L306-375",
+ "cellId": "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c",
+ "visible": true,
+ "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8"
+ },
+ "aw-watcher-window/aw_watcher_window/macos.swift-simstep-46ccc29e-b251-435a-8768-4304d477261a": {
+ "path": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-46ccc29e-b251-435a-8768-4304d477261a",
+ "fileName": "macos.swift",
+ "wiki": "The `aw-watcher-window` process on macOS, implemented in Swift, detects a change in the active window or its title. An observer callback function like `windowTitleChanged` is triggered, which captures the application name (`app`) and the window title (`title`).",
+ "cellName": "[Python Flow - Watcher] Detect Active Window Change - macos.swift:L306-375",
+ "cellId": "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c",
+ "visible": true,
+ "startLine": 306,
+ "endLine": 375,
+ "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
+ "parentPath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "46ccc29e-b251-435a-8768-4304d477261a"
+ }
+ ]
+ },
+ "67a89dcc-93fc-413d-aa21-eca0b7227bc2": {
+ "path": "67a89dcc-93fc-413d-aa21-eca0b7227bc2",
+ "cellName": "[Python Flow - Watcher] Send Heartbeat API Request - macos.swift:L253-268",
+ "cellId": "67a89dcc-93fc-413d-aa21-eca0b7227bc2",
+ "visible": true,
+ "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8"
+ },
+ "aw-watcher-window/aw_watcher_window/macos.swift-simstep-e873b3e2-2ebd-43ee-8f97-e02f869578f7": {
+ "path": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-e873b3e2-2ebd-43ee-8f97-e02f869578f7",
+ "fileName": "macos.swift",
+ "wiki": "The `sendHeartbeatSingle` function constructs an HTTP POST request. It sets the URL to the heartbeat endpoint, including the bucket name and a calculated `pulsetime` as a query parameter. The heartbeat data is JSON-encoded and sent as the request body.",
+ "cellName": "[Python Flow - Watcher] Send Heartbeat API Request - macos.swift:L253-268",
+ "cellId": "67a89dcc-93fc-413d-aa21-eca0b7227bc2",
+ "visible": true,
+ "startLine": 253,
+ "endLine": 268,
+ "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
+ "parentPath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "e873b3e2-2ebd-43ee-8f97-e02f869578f7"
+ }
+ ]
+ },
+ "9de5f1e4-764e-4be7-90a1-65fa23ca0dea": {
+ "path": "9de5f1e4-764e-4be7-90a1-65fa23ca0dea",
+ "cellName": "[Python Server] Handle Heartbeat Endpoint - rest.py:L283-304",
+ "cellId": "9de5f1e4-764e-4be7-90a1-65fa23ca0dea",
+ "visible": true,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
+ },
+ "aw-server/aw_server/rest.py-simstep-e98f7509-f28f-4534-8f2a-f525edc73f69": {
+ "path": "aw-server/aw_server/rest.py-simstep-e98f7509-f28f-4534-8f2a-f525edc73f69",
+ "fileName": "rest.py",
+ "wiki": "The `aw-server` (Flask) routes the incoming request to the `post` method of the `HeartbeatResource`. This method parses the JSON body into an `Event` object and extracts the `pulsetime` from the URL parameters.",
+ "cellName": "[Python Server] Handle Heartbeat Endpoint - rest.py:L283-304",
+ "cellId": "9de5f1e4-764e-4be7-90a1-65fa23ca0dea",
+ "visible": true,
+ "startLine": 283,
+ "endLine": 304,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "e98f7509-f28f-4534-8f2a-f525edc73f69"
+ }
+ ]
+ },
+ "7c02469d-20a7-415d-940e-fbd82d0fc997": {
+ "path": "7c02469d-20a7-415d-940e-fbd82d0fc997",
+ "cellName": "[Python Server] Process Heartbeat Event - api.py:L254-337",
+ "cellId": "7c02469d-20a7-415d-940e-fbd82d0fc997",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-bb678fe2-e6e3-472b-8ae4-95e362d4bdaf": {
+ "path": "aw-server/aw_server/api.py-simstep-bb678fe2-e6e3-472b-8ae4-95e362d4bdaf",
+ "fileName": "api.py",
+ "wiki": "The `ServerAPI.heartbeat` method retrieves the last event from the specified bucket, either from an in-memory cache (`self.last_event`) or the database. It then compares the data of the new heartbeat with the last event. If the data is the same, it calls `heartbeat_merge` to attempt a merge.",
+ "cellName": "[Python Server] Process Heartbeat Event - api.py:L254-337",
+ "cellId": "7c02469d-20a7-415d-940e-fbd82d0fc997",
+ "visible": true,
+ "startLine": 254,
+ "endLine": 337,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "bb678fe2-e6e3-472b-8ae4-95e362d4bdaf"
+ }
+ ]
+ },
+ "dc7a3836-03e1-4a54-9817-b62f36466ec0": {
+ "path": "dc7a3836-03e1-4a54-9817-b62f36466ec0",
+ "cellName": "[Python Server] Core Merge Logic - heartbeats.py:L26-56",
+ "cellId": "dc7a3836-03e1-4a54-9817-b62f36466ec0",
+ "visible": true,
+ "parentCellId": "6860aa38-bc11-4d81-9260-87eba1c02581"
+ },
+ "aw-core/aw_transform/heartbeats.py-simstep-d2eac5dc-58f7-408c-beba-c1711beec25a": {
+ "path": "aw-core/aw_transform/heartbeats.py-simstep-d2eac5dc-58f7-408c-beba-c1711beec25a",
+ "fileName": "heartbeats.py",
+ "wiki": "The `heartbeat_merge` function checks if the event data is identical and if the new heartbeat's timestamp is within the `pulsetime` window of the last event's end time. If both conditions are met, it creates a new merged event by extending the duration of the last event to cover the time up to the new heartbeat. Otherwise, it returns `None`.",
+ "cellName": "[Python Server] Core Merge Logic - heartbeats.py:L26-56",
+ "cellId": "dc7a3836-03e1-4a54-9817-b62f36466ec0",
+ "visible": true,
+ "startLine": 26,
+ "endLine": 56,
+ "parentCellId": "6860aa38-bc11-4d81-9260-87eba1c02581",
+ "parentPath": "aw-core/aw_transform/heartbeats.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "d2eac5dc-58f7-408c-beba-c1711beec25a"
+ }
+ ]
+ },
+ "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f": {
+ "path": "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f",
+ "cellName": "[Python Server] Update Database - api.py:L313-315",
+ "cellId": "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-976cfbd0-8946-4157-81b0-0ae6dffa43e1": {
+ "path": "aw-server/aw_server/api.py-simstep-976cfbd0-8946-4157-81b0-0ae6dffa43e1",
+ "fileName": "api.py",
+ "wiki": "If a merged event was returned, the `ServerAPI.heartbeat` method updates its local cache (`self.last_event`) and calls `self.db[bucket_id].replace_last(merged)` to persist the change in the database. This replaces the previous event with the new, longer-duration event. If no merged event was returned, it inserts a new event instead.",
+ "cellName": "[Python Server] Update Database - api.py:L313-315",
+ "cellId": "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f",
+ "visible": true,
+ "startLine": 313,
+ "endLine": 315,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "976cfbd0-8946-4157-81b0-0ae6dffa43e1"
+ }
+ ]
+ },
+ "b3da175e-36b5-4025-ba15-6c54e1d850dd": {
+ "path": "b3da175e-36b5-4025-ba15-6c54e1d850dd",
+ "cellName": "[Rust Flow - Watcher] Detect and Send Heartbeat - macos.swift:L203-268",
+ "cellId": "b3da175e-36b5-4025-ba15-6c54e1d850dd",
+ "visible": true,
+ "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8"
+ },
+ "aw-watcher-window/aw_watcher_window/macos.swift-simstep-8420fd6c-dba4-41c0-b11d-7280a428ab36": {
+ "path": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-8420fd6c-dba4-41c0-b11d-7280a428ab36",
+ "fileName": "macos.swift",
+ "wiki": "This step marks the beginning of the alternative `aw-server-rust` implementation flow. The process is initiated in the same way as the Python flow: a watcher detects an activity change and prepares a heartbeat event. The Swift-based watcher is implementation-agnostic and sends the same HTTP request regardless of the server.",
+ "cellName": "[Rust Flow - Watcher] Detect and Send Heartbeat - macos.swift:L203-268",
+ "cellId": "b3da175e-36b5-4025-ba15-6c54e1d850dd",
+ "visible": true,
+ "startLine": 203,
+ "endLine": 268,
+ "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
+ "parentPath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "8420fd6c-dba4-41c0-b11d-7280a428ab36"
+ }
+ ]
+ },
+ "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926": {
+ "path": "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926",
+ "cellName": "[Rust Server] Handle Heartbeat Endpoint - bucket.rs:L150-162",
+ "cellId": "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926",
+ "visible": true,
+ "parentCellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159"
+ },
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs-simstep-41b8b1d6-f9fe-47ad-851e-574e804f7171": {
+ "path": "aw-server-rust/aw-server/src/endpoints/bucket.rs-simstep-41b8b1d6-f9fe-47ad-851e-574e804f7171",
+ "fileName": "bucket.rs",
+ "wiki": "The `aw-server-rust` (Rocket) routes the incoming request to the `bucket_events_heartbeat` function. This function parses the JSON body and pulsetime, then calls the `datastore.heartbeat` method to process the event.",
+ "cellName": "[Rust Server] Handle Heartbeat Endpoint - bucket.rs:L150-162",
+ "cellId": "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926",
+ "visible": true,
+ "startLine": 150,
+ "endLine": 162,
+ "parentCellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "41b8b1d6-f9fe-47ad-851e-574e804f7171"
+ }
+ ]
+ },
+ "b6b4c8cb-741a-4e38-b800-61273375cd64": {
+ "path": "b6b4c8cb-741a-4e38-b800-61273375cd64",
+ "cellName": "[Rust Server] Queue Heartbeat Command - worker.rs:L385-399",
+ "cellId": "b6b4c8cb-741a-4e38-b800-61273375cd64",
+ "visible": true,
+ "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e"
+ },
+ "aw-server-rust/aw-datastore/src/worker.rs-simstep-b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3": {
+ "path": "aw-server-rust/aw-datastore/src/worker.rs-simstep-b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3",
+ "fileName": "worker.rs",
+ "wiki": "The `Datastore::heartbeat` method in `worker.rs` creates a `Command::Heartbeat` enum variant and sends it to the datastore worker thread through a multi-producer, single-consumer (mpsc) channel. This decouples API handling from database operations.",
+ "cellName": "[Rust Server] Queue Heartbeat Command - worker.rs:L385-399",
+ "cellId": "b6b4c8cb-741a-4e38-b800-61273375cd64",
+ "visible": true,
+ "startLine": 385,
+ "endLine": 399,
+ "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
+ "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3"
+ }
+ ]
+ },
+ "f0e92638-21d1-4b7e-9f2e-17b67a33ef78": {
+ "path": "f0e92638-21d1-4b7e-9f2e-17b67a33ef78",
+ "cellName": "[Rust Server] Process Heartbeat in Worker - worker.rs:L240-248",
+ "cellId": "f0e92638-21d1-4b7e-9f2e-17b67a33ef78",
+ "visible": true,
+ "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e"
+ },
+ "aw-server-rust/aw-datastore/src/worker.rs-simstep-a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb": {
+ "path": "aw-server-rust/aw-datastore/src/worker.rs-simstep-a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb",
+ "fileName": "worker.rs",
+ "wiki": "The `DatastoreWorker::handle_request` method receives the command, matches it to `Command::Heartbeat`, and calls the `heartbeat` method on the `DatastoreInstance`, which directly interacts with the SQLite database connection.",
+ "cellName": "[Rust Server] Process Heartbeat in Worker - worker.rs:L240-248",
+ "cellId": "f0e92638-21d1-4b7e-9f2e-17b67a33ef78",
+ "visible": true,
+ "startLine": 240,
+ "endLine": 248,
+ "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
+ "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb"
+ }
+ ]
+ },
+ "b0093d22-e8cc-4e9e-8711-7e698b537efc": {
+ "path": "b0093d22-e8cc-4e9e-8711-7e698b537efc",
+ "cellName": "[Rust Server] Core Merge Logic - datastore.rs:L600-642",
+ "cellId": "b0093d22-e8cc-4e9e-8711-7e698b537efc",
+ "visible": true,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
+ },
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-c59f4b10-f6c9-4fd8-ba70-ea60667a01e8": {
+ "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-c59f4b10-f6c9-4fd8-ba70-ea60667a01e8",
+ "fileName": "datastore.rs",
+ "wiki": "The `DatastoreInstance::heartbeat` method retrieves the last event and calls `aw_transform::heartbeat`. This function checks for data equality and pulsetime. If successful, it returns a `Some(merged_event)`. If not, `None`.",
+ "cellName": "[Rust Server] Core Merge Logic - datastore.rs:L600-642",
+ "cellId": "b0093d22-e8cc-4e9e-8711-7e698b537efc",
+ "visible": true,
+ "startLine": 600,
+ "endLine": 642,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "c59f4b10-f6c9-4fd8-ba70-ea60667a01e8"
+ }
+ ]
+ },
+ "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8": {
+ "path": "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8",
+ "cellName": "[Rust Server] Update Database - datastore.rs:L628-639",
+ "cellId": "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8",
+ "visible": true,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
+ },
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-da146aa5-e96f-4db6-a36f-b405b1a11255": {
+ "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-da146aa5-e96f-4db6-a36f-b405b1a11255",
+ "fileName": "datastore.rs",
+ "wiki": "Based on the result from `aw_transform::heartbeat`, the `DatastoreInstance::heartbeat` method either calls `self.replace_last_event` to update the last event in the database with the merged one, or `self.insert_events` to create a new event. The merged or new event is then cached and returned.",
+ "cellName": "[Rust Server] Update Database - datastore.rs:L628-639",
+ "cellId": "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8",
+ "visible": true,
+ "startLine": 628,
+ "endLine": 639,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "da146aa5-e96f-4db6-a36f-b405b1a11255"
+ }
+ ]
+ },
+ "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f": {
+ "path": "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
+ "cellName": "Data Transmission:\nPass Event\nData for\nHeartbeat",
+ "cellId": "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
+ "visible": true,
+ "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8"
+ },
+ "generated-edge-simstep-b6456941-3a8f-452d-a4eb-67915b00d5b3-4d96dbc5-cd5e-4ef9-8733-721776e8fb8f": {
+ "path": "generated-edge-simstep-b6456941-3a8f-452d-a4eb-67915b00d5b3-4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
+ "fileName": "macos.swift",
+ "cellName": "Data Transmission: Pass Event Data for Heartbeat",
+ "cellId": "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
+ "visible": true,
+ "startLine": 373,
+ "endLine": 374,
+ "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
+ "parentPath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "b6456941-3a8f-452d-a4eb-67915b00d5b3"
+ }
+ ]
+ },
+ "a676f81f-8c68-4fc8-94b7-583bada02d70": {
+ "path": "a676f81f-8c68-4fc8-94b7-583bada02d70",
+ "cellName": "API Call:\nWatcher ->\nPython Server",
+ "cellId": "a676f81f-8c68-4fc8-94b7-583bada02d70",
+ "visible": true
+ },
+ "generated-edge-simstep-02717bea-6ee3-48ef-8c41-0c9f3e9d9a58-a676f81f-8c68-4fc8-94b7-583bada02d70": {
+ "path": "generated-edge-simstep-02717bea-6ee3-48ef-8c41-0c9f3e9d9a58-a676f81f-8c68-4fc8-94b7-583bada02d70",
+ "fileName": "rest.py",
+ "cellName": "API Call: Watcher -> Python Server",
+ "cellId": "a676f81f-8c68-4fc8-94b7-583bada02d70",
+ "visible": true,
+ "startLine": 272,
+ "endLine": 272,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "02717bea-6ee3-48ef-8c41-0c9f3e9d9a58"
+ }
+ ]
+ },
+ "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75": {
+ "path": "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
+ "cellName": "Data Transmission:\nREST ->\nAPI Logic",
+ "cellId": "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
+ },
+ "generated-edge-simstep-d57d2bf7-916c-44cd-844d-b1900c276925-a1b18b07-52a9-4bfe-ad37-bdae87d5bd75": {
+ "path": "generated-edge-simstep-d57d2bf7-916c-44cd-844d-b1900c276925-a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
+ "fileName": "rest.py",
+ "cellName": "Data Transmission: REST -> API Logic",
+ "cellId": "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
+ "visible": true,
+ "startLine": 300,
+ "endLine": 300,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "d57d2bf7-916c-44cd-844d-b1900c276925"
+ }
+ ]
+ },
+ "9aec4875-5718-4c38-a57c-1d3053c38ba5": {
+ "path": "9aec4875-5718-4c38-a57c-1d3053c38ba5",
+ "cellName": "Data Transmission:\nPass Events\nto Merge\nFunction",
+ "cellId": "9aec4875-5718-4c38-a57c-1d3053c38ba5",
+ "visible": true
+ },
+ "generated-edge-simstep-40b16e25-734b-44d2-86cd-7c301723ff5f-9aec4875-5718-4c38-a57c-1d3053c38ba5": {
+ "path": "generated-edge-simstep-40b16e25-734b-44d2-86cd-7c301723ff5f-9aec4875-5718-4c38-a57c-1d3053c38ba5",
+ "fileName": "api.py",
+ "cellName": "Data Transmission: Pass Events to Merge Function",
+ "cellId": "9aec4875-5718-4c38-a57c-1d3053c38ba5",
+ "visible": true,
+ "startLine": 305,
+ "endLine": 305,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "40b16e25-734b-44d2-86cd-7c301723ff5f"
+ }
+ ]
+ },
+ "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0": {
+ "path": "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
+ "cellName": "Data Transmission:\nReturn Merged\nEvent",
+ "cellId": "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
+ "visible": true
+ },
+ "generated-edge-simstep-9f918447-9e45-4c3b-b34f-658f58d35495-31cd2b01-8df9-4d95-9a91-d4c3aa153eb0": {
+ "path": "generated-edge-simstep-9f918447-9e45-4c3b-b34f-658f58d35495-31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
+ "fileName": "heartbeats.py",
+ "cellName": "Data Transmission: Return Merged Event",
+ "cellId": "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
+ "visible": true,
+ "startLine": 54,
+ "endLine": 56,
+ "parentCellId": "6860aa38-bc11-4d81-9260-87eba1c02581",
+ "parentPath": "aw-core/aw_transform/heartbeats.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "9f918447-9e45-4c3b-b34f-658f58d35495"
+ }
+ ]
+ },
+ "2df6b81e-6b59-4aec-92c7-e9d9f2332be6": {
+ "path": "2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
+ "cellName": "API Call:\nWatcher ->\nRust Server",
+ "cellId": "2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
+ "visible": true
+ },
+ "generated-edge-simstep-7e361c3d-a5a9-45f3-a83d-98e39ff45675-2df6b81e-6b59-4aec-92c7-e9d9f2332be6": {
+ "path": "generated-edge-simstep-7e361c3d-a5a9-45f3-a83d-98e39ff45675-2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
+ "fileName": "bucket.rs",
+ "cellName": "API Call: Watcher -> Rust Server",
+ "cellId": "2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
+ "visible": true,
+ "startLine": 145,
+ "endLine": 149,
+ "parentCellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "7e361c3d-a5a9-45f3-a83d-98e39ff45675"
+ }
+ ]
+ },
+ "4a4afbdf-0303-4d84-bbf8-5121c74965a0": {
+ "path": "4a4afbdf-0303-4d84-bbf8-5121c74965a0",
+ "cellName": "Data Transmission:\nEndpoint ->\nDatastore",
+ "cellId": "4a4afbdf-0303-4d84-bbf8-5121c74965a0",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-bfcc2f87-9167-4784-a3b3-f71d6e7a6e71-4a4afbdf-0303-4d84-bbf8-5121c74965a0": {
+ "path": "generated-edge-simstep-bfcc2f87-9167-4784-a3b3-f71d6e7a6e71-4a4afbdf-0303-4d84-bbf8-5121c74965a0",
+ "fileName": "bucket.rs",
+ "cellName": "Data Transmission: Endpoint -> Datastore",
+ "cellId": "4a4afbdf-0303-4d84-bbf8-5121c74965a0",
+ "visible": true,
+ "startLine": 158,
+ "endLine": 158,
+ "parentCellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "bfcc2f87-9167-4784-a3b3-f71d6e7a6e71"
+ }
+ ]
+ },
+ "21d1c973-0f67-4aca-9d1b-eade3b5d347b": {
+ "path": "21d1c973-0f67-4aca-9d1b-eade3b5d347b",
+ "cellName": "Data Transmission:\nCommand Channel",
+ "cellId": "21d1c973-0f67-4aca-9d1b-eade3b5d347b",
+ "visible": true,
+ "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e"
+ },
+ "generated-edge-simstep-eefd671a-3b08-4336-bd26-cb6eb04070ec-21d1c973-0f67-4aca-9d1b-eade3b5d347b": {
+ "path": "generated-edge-simstep-eefd671a-3b08-4336-bd26-cb6eb04070ec-21d1c973-0f67-4aca-9d1b-eade3b5d347b",
+ "fileName": "worker.rs",
+ "cellName": "Data Transmission: Command Channel",
+ "cellId": "21d1c973-0f67-4aca-9d1b-eade3b5d347b",
+ "visible": true,
+ "startLine": 167,
+ "endLine": 175,
+ "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
+ "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "eefd671a-3b08-4336-bd26-cb6eb04070ec"
+ }
+ ]
+ },
+ "959b342e-eb44-4255-8176-1600a5fa17ac": {
+ "path": "959b342e-eb44-4255-8176-1600a5fa17ac",
+ "cellName": "Data Transmission:\nWorker ->\nDatastore Instance",
+ "cellId": "959b342e-eb44-4255-8176-1600a5fa17ac",
+ "visible": true,
+ "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc"
+ },
+ "generated-edge-simstep-9750ac2c-c0fb-4fe5-815f-398886fc827b-959b342e-eb44-4255-8176-1600a5fa17ac": {
+ "path": "generated-edge-simstep-9750ac2c-c0fb-4fe5-815f-398886fc827b-959b342e-eb44-4255-8176-1600a5fa17ac",
+ "fileName": "worker.rs",
+ "cellName": "Data Transmission: Worker -> Datastore Instance",
+ "cellId": "959b342e-eb44-4255-8176-1600a5fa17ac",
+ "visible": true,
+ "startLine": 241,
+ "endLine": 241,
+ "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
+ "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "9750ac2c-c0fb-4fe5-815f-398886fc827b"
+ }
+ ]
+ },
+ "0fe644bb-a583-40d8-9377-3641c90c4f62": {
+ "path": "0fe644bb-a583-40d8-9377-3641c90c4f62",
+ "cellName": "Data Transmission:\nPass Events\nto Merge\nFunction",
+ "cellId": "0fe644bb-a583-40d8-9377-3641c90c4f62",
+ "visible": true,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
+ },
+ "generated-edge-simstep-7b396541-e74f-4baf-9b1b-c1f7a914ba7a-0fe644bb-a583-40d8-9377-3641c90c4f62": {
+ "path": "generated-edge-simstep-7b396541-e74f-4baf-9b1b-c1f7a914ba7a-0fe644bb-a583-40d8-9377-3641c90c4f62",
+ "fileName": "datastore.rs",
+ "cellName": "Data Transmission: Pass Events to Merge Function",
+ "cellId": "0fe644bb-a583-40d8-9377-3641c90c4f62",
+ "visible": true,
+ "startLine": 628,
+ "endLine": 628,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How the heartbeat API enables efficient tracking works",
+ "simStepId": "7b396541-e74f-4baf-9b1b-c1f7a914ba7a"
+ }
+ ]
+ },
+ "315afad3-54aa-4009-bbe4-8e17ade01ec1": {
+ "path": "315afad3-54aa-4009-bbe4-8e17ade01ec1",
+ "cellName": "aw-qt",
+ "cellId": "315afad3-54aa-4009-bbe4-8e17ade01ec1",
+ "visible": true
+ },
+ "52098e1d-ea54-42f8-9e69-f6bd54686e33": {
+ "path": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
+ "cellName": "aw_qt",
+ "cellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
+ "visible": true,
+ "parentCellId": "315afad3-54aa-4009-bbe4-8e17ade01ec1"
+ },
+ "9d82da70-d3bc-4199-9292-8dd7e71ab15d": {
+ "path": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
+ "cellName": "main.py",
+ "cellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "f47c0efe-5fd2-488b-b325-b2965448260a": {
+ "path": "f47c0efe-5fd2-488b-b325-b2965448260a",
+ "cellName": "config.py",
+ "cellId": "f47c0efe-5fd2-488b-b325-b2965448260a",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "f2489cff-231c-4352-baac-95f17e0f6395": {
+ "path": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "cellName": "manager.py",
+ "cellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "38fbe4ec-4658-4084-864e-b163e0540497": {
+ "path": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "cellName": "trayicon.py",
+ "cellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "d1bb4e12-29b6-4f70-9931-321214e3ea2a": {
+ "path": "d1bb4e12-29b6-4f70-9931-321214e3ea2a",
+ "cellName": "Application Entrypoint - main.py:L41-53",
+ "cellId": "d1bb4e12-29b6-4f70-9931-321214e3ea2a",
+ "visible": true,
+ "parentCellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d"
+ },
+ "aw-qt/aw_qt/main.py-simstep-61d1a03e-ed06-496d-8495-36419b9c8607": {
+ "path": "aw-qt/aw_qt/main.py-simstep-61d1a03e-ed06-496d-8495-36419b9c8607",
+ "fileName": "main.py",
+ "wiki": "The `aw-qt` application is launched. It parses command-line arguments, sets up logging, loads configuration, and initializes the `Manager`.",
+ "cellName": "Application Entrypoint - main.py:L41-53",
+ "cellId": "d1bb4e12-29b6-4f70-9931-321214e3ea2a",
+ "visible": true,
+ "startLine": 41,
+ "endLine": 53,
+ "parentCellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
+ "parentPath": "aw-qt/aw_qt/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "61d1a03e-ed06-496d-8495-36419b9c8607"
+ }
+ ]
+ },
+ "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc": {
+ "path": "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc",
+ "cellName": "Read Configuration File - config.py:L16-24",
+ "cellId": "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc",
+ "visible": true,
+ "parentCellId": "f47c0efe-5fd2-488b-b325-b2965448260a"
+ },
+ "aw-qt/aw_qt/config.py-simstep-c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a": {
+ "path": "aw-qt/aw_qt/config.py-simstep-c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a",
+ "fileName": "config.py",
+ "wiki": "The `AwQtSettings` class reads the `aw-qt.toml` configuration file to determine which modules to autostart.",
+ "cellName": "Read Configuration File - config.py:L16-24",
+ "cellId": "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc",
+ "visible": true,
+ "startLine": 16,
+ "endLine": 24,
+ "parentCellId": "f47c0efe-5fd2-488b-b325-b2965448260a",
+ "parentPath": "aw-qt/aw_qt/config.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a"
+ }
+ ]
+ },
+ "cae37571-f0ba-4abe-aefd-53e49f26137f": {
+ "path": "cae37571-f0ba-4abe-aefd-53e49f26137f",
+ "cellName": "Discover Modules - manager.py:L241-250",
+ "cellId": "cae37571-f0ba-4abe-aefd-53e49f26137f",
+ "visible": true,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
+ },
+ "aw-qt/aw_qt/manager.py-simstep-e716abbb-c96e-4613-bca2-0c094e8df129": {
+ "path": "aw-qt/aw_qt/manager.py-simstep-e716abbb-c96e-4613-bca2-0c094e8df129",
+ "fileName": "manager.py",
+ "wiki": "The `Manager` class is instantiated and discovers all available `aw-*` executables. It searches for bundled modules within its own directory structure and for system-wide modules in the user's PATH.",
+ "cellName": "Discover Modules - manager.py:L241-250",
+ "cellId": "cae37571-f0ba-4abe-aefd-53e49f26137f",
+ "visible": true,
+ "startLine": 241,
+ "endLine": 250,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "parentPath": "aw-qt/aw_qt/manager.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "e716abbb-c96e-4613-bca2-0c094e8df129"
+ }
+ ]
+ },
+ "8f981b6f-7bed-4d9a-8486-79f85b06d904": {
+ "path": "8f981b6f-7bed-4d9a-8486-79f85b06d904",
+ "cellName": "Spawn Module Process - manager.py:L147-172",
+ "cellId": "8f981b6f-7bed-4d9a-8486-79f85b06d904",
+ "visible": true,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
+ },
+ "aw-qt/aw_qt/manager.py-simstep-8be10173-751a-4da9-99a9-321c23e71aaa": {
+ "path": "aw-qt/aw_qt/manager.py-simstep-8be10173-751a-4da9-99a9-321c23e71aaa",
+ "fileName": "manager.py",
+ "wiki": "For each module designated for autostart, the `Module.start` method is called. This method constructs the execution command and uses `subprocess.Popen` to launch the module as a new, independent process. `aw-server` is started first.",
+ "cellName": "Spawn Module Process - manager.py:L147-172",
+ "cellId": "8f981b6f-7bed-4d9a-8486-79f85b06d904",
+ "visible": true,
+ "startLine": 147,
+ "endLine": 172,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "parentPath": "aw-qt/aw_qt/manager.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "8be10173-751a-4da9-99a9-321c23e71aaa"
+ }
+ ]
+ },
+ "4d657da7-6757-4d72-9324-765a991f73d7": {
+ "path": "4d657da7-6757-4d72-9324-765a991f73d7",
+ "cellName": "Initialize Tray Icon - trayicon.py:L207-211",
+ "cellId": "4d657da7-6757-4d72-9324-765a991f73d7",
+ "visible": true,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
+ },
+ "aw-qt/aw_qt/trayicon.py-simstep-6ae15f2e-5331-4153-b9d2-2a297b65c55f": {
+ "path": "aw-qt/aw_qt/trayicon.py-simstep-6ae15f2e-5331-4153-b9d2-2a297b65c55f",
+ "fileName": "trayicon.py",
+ "wiki": "After attempting to start all autostart modules, the `trayicon.run` function is called. This initializes the PyQt application and creates the system tray icon, making ActivityWatch accessible to the user.",
+ "cellName": "Initialize Tray Icon - trayicon.py:L207-211",
+ "cellId": "4d657da7-6757-4d72-9324-765a991f73d7",
+ "visible": true,
+ "startLine": 207,
+ "endLine": 211,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "6ae15f2e-5331-4153-b9d2-2a297b65c55f"
+ }
+ ]
+ },
+ "05bd0955-8e55-4657-80ee-f6389995db6d": {
+ "path": "05bd0955-8e55-4657-80ee-f6389995db6d",
+ "cellName": "Build Tray Menu - trayicon.py:L174-193",
+ "cellId": "05bd0955-8e55-4657-80ee-f6389995db6d",
+ "visible": true,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
+ },
+ "aw-qt/aw_qt/trayicon.py-simstep-08d88f03-4133-41d6-9cbb-0df16703b864": {
+ "path": "aw-qt/aw_qt/trayicon.py-simstep-08d88f03-4133-41d6-9cbb-0df16703b864",
+ "fileName": "trayicon.py",
+ "wiki": "The `TrayIcon` constructor builds the context menu. It creates a 'Modules' submenu by iterating through the modules discovered by the manager. Each module is represented as a checkable menu item, with its initial state reflecting whether it's currently running.",
+ "cellName": "Build Tray Menu - trayicon.py:L174-193",
+ "cellId": "05bd0955-8e55-4657-80ee-f6389995db6d",
+ "visible": true,
+ "startLine": 174,
+ "endLine": 193,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "08d88f03-4133-41d6-9cbb-0df16703b864"
+ }
+ ]
+ },
+ "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b": {
+ "path": "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b",
+ "cellName": "Toggle Module State - manager.py:L202-206",
+ "cellId": "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b",
+ "visible": true,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
+ },
+ "aw-qt/aw_qt/manager.py-simstep-520ab3f2-ef6c-4334-89fc-280f6d86d14b": {
+ "path": "aw-qt/aw_qt/manager.py-simstep-520ab3f2-ef6c-4334-89fc-280f6d86d14b",
+ "fileName": "manager.py",
+ "wiki": "The `toggle` method in the `Module` class checks if the module is currently started. If it is, it calls `stop()`; otherwise, it calls `start()`.",
+ "cellName": "Toggle Module State - manager.py:L202-206",
+ "cellId": "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b",
+ "visible": true,
+ "startLine": 202,
+ "endLine": 206,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "parentPath": "aw-qt/aw_qt/manager.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "520ab3f2-ef6c-4334-89fc-280f6d86d14b"
+ }
+ ]
+ },
+ "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5": {
+ "path": "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5",
+ "cellName": "Periodic Status Check - trayicon.py:L149-158",
+ "cellId": "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5",
+ "visible": true,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
+ },
+ "aw-qt/aw_qt/trayicon.py-simstep-01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9": {
+ "path": "aw-qt/aw_qt/trayicon.py-simstep-01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9",
+ "fileName": "trayicon.py",
+ "wiki": "A recurring timer in `TrayIcon` triggers `rebuild_modules_menu` every 2 seconds. This function updates the checkmarks in the 'Modules' menu to reflect the current running status of each module.",
+ "cellName": "Periodic Status Check - trayicon.py:L149-158",
+ "cellId": "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5",
+ "visible": true,
+ "startLine": 149,
+ "endLine": 158,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9"
+ }
+ ]
+ },
+ "421b1687-98a6-4773-a7dc-cdc564be5f8e": {
+ "path": "421b1687-98a6-4773-a7dc-cdc564be5f8e",
+ "cellName": "Check if Module Process is Alive - manager.py:L208-214",
+ "cellId": "421b1687-98a6-4773-a7dc-cdc564be5f8e",
+ "visible": true,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
+ },
+ "aw-qt/aw_qt/manager.py-simstep-899b57ba-4a68-4620-977a-80981d089e85": {
+ "path": "aw-qt/aw_qt/manager.py-simstep-899b57ba-4a68-4620-977a-80981d089e85",
+ "fileName": "manager.py",
+ "wiki": "The `is_alive` method polls the subprocess to check its status. It returns `True` if the process is running and `False` otherwise.",
+ "cellName": "Check if Module Process is Alive - manager.py:L208-214",
+ "cellId": "421b1687-98a6-4773-a7dc-cdc564be5f8e",
+ "visible": true,
+ "startLine": 208,
+ "endLine": 214,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "parentPath": "aw-qt/aw_qt/manager.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "899b57ba-4a68-4620-977a-80981d089e85"
+ }
+ ]
+ },
+ "5dd0e28d-e0e9-4433-8db9-e8de93de1abe": {
+ "path": "5dd0e28d-e0e9-4433-8db9-e8de93de1abe",
+ "cellName": "Identify Unexpectedly Stopped Modules - manager.py:L252-253",
+ "cellId": "5dd0e28d-e0e9-4433-8db9-e8de93de1abe",
+ "visible": true,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
+ },
+ "aw-qt/aw_qt/manager.py-simstep-6173a9e1-ecfa-4dd9-9f82-f80579406011": {
+ "path": "aw-qt/aw_qt/manager.py-simstep-6173a9e1-ecfa-4dd9-9f82-f80579406011",
+ "fileName": "manager.py",
+ "wiki": "The `get_unexpected_stops` method filters the list of all modules, returning those that are marked as `started` but are no longer `alive`.",
+ "cellName": "Identify Unexpectedly Stopped Modules - manager.py:L252-253",
+ "cellId": "5dd0e28d-e0e9-4433-8db9-e8de93de1abe",
+ "visible": true,
+ "startLine": 252,
+ "endLine": 253,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "parentPath": "aw-qt/aw_qt/manager.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "6173a9e1-ecfa-4dd9-9f82-f80579406011"
+ }
+ ]
+ },
+ "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc": {
+ "path": "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc",
+ "cellName": "Display Failure Dialog - trayicon.py:L136-147",
+ "cellId": "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc",
+ "visible": true,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
+ },
+ "aw-qt/aw_qt/trayicon.py-simstep-a71f6cd0-490a-40b5-8a05-1c873f208882": {
+ "path": "aw-qt/aw_qt/trayicon.py-simstep-a71f6cd0-490a-40b5-8a05-1c873f208882",
+ "fileName": "trayicon.py",
+ "wiki": "A `QMessageBox` is displayed to the user, informing them that a module has quit unexpectedly. The dialog includes the module's logs and provides a button to restart the module.",
+ "cellName": "Display Failure Dialog - trayicon.py:L136-147",
+ "cellId": "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc",
+ "visible": true,
+ "startLine": 136,
+ "endLine": 147,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "a71f6cd0-490a-40b5-8a05-1c873f208882"
+ }
+ ]
+ },
+ "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7": {
+ "path": "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
+ "cellName": "Load Autostart\nConfig",
+ "cellId": "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "generated-edge-simstep-6084ca69-514e-4bde-b2c0-1d33b26203e8-1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7": {
+ "path": "generated-edge-simstep-6084ca69-514e-4bde-b2c0-1d33b26203e8-1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
+ "fileName": "main.py",
+ "cellName": "Load Autostart Config",
+ "cellId": "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
+ "visible": true,
+ "startLine": 70,
+ "endLine": 70,
+ "parentCellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
+ "parentPath": "aw-qt/aw_qt/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "6084ca69-514e-4bde-b2c0-1d33b26203e8"
+ }
+ ]
+ },
+ "030668a5-a377-4710-b39f-95efb5fa4768": {
+ "path": "030668a5-a377-4710-b39f-95efb5fa4768",
+ "cellName": "Pass Config\nto Manager",
+ "cellId": "030668a5-a377-4710-b39f-95efb5fa4768",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "generated-edge-simstep-540119c2-b541-4342-aa59-233b4f0f8db5-030668a5-a377-4710-b39f-95efb5fa4768": {
+ "path": "generated-edge-simstep-540119c2-b541-4342-aa59-233b4f0f8db5-030668a5-a377-4710-b39f-95efb5fa4768",
+ "fileName": "main.py",
+ "cellName": "Pass Config to Manager",
+ "cellId": "030668a5-a377-4710-b39f-95efb5fa4768",
+ "visible": true,
+ "startLine": 77,
+ "endLine": 78,
+ "parentCellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
+ "parentPath": "aw-qt/aw_qt/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "540119c2-b541-4342-aa59-233b4f0f8db5"
+ }
+ ]
+ },
+ "1fb5a75e-9c49-490d-b412-04ac1c7205fa": {
+ "path": "1fb5a75e-9c49-490d-b412-04ac1c7205fa",
+ "cellName": "Initiate Autostart\nSequence",
+ "cellId": "1fb5a75e-9c49-490d-b412-04ac1c7205fa",
+ "visible": true,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
+ },
+ "generated-edge-simstep-9aeaf443-6741-4557-9671-67d596f456b3-1fb5a75e-9c49-490d-b412-04ac1c7205fa": {
+ "path": "generated-edge-simstep-9aeaf443-6741-4557-9671-67d596f456b3-1fb5a75e-9c49-490d-b412-04ac1c7205fa",
+ "fileName": "manager.py",
+ "cellName": "Initiate Autostart Sequence",
+ "cellId": "1fb5a75e-9c49-490d-b412-04ac1c7205fa",
+ "visible": true,
+ "startLine": 276,
+ "endLine": 286,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "parentPath": "aw-qt/aw_qt/manager.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "9aeaf443-6741-4557-9671-67d596f456b3"
+ }
+ ]
+ },
+ "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9": {
+ "path": "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
+ "cellName": "Module Process\nRunning",
+ "cellId": "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "generated-edge-simstep-f968357d-53c4-41e8-b71f-c581c08b52e6-a5cd2cce-2771-436e-9fc7-aa013ee8bbc9": {
+ "path": "generated-edge-simstep-f968357d-53c4-41e8-b71f-c581c08b52e6-a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
+ "fileName": "manager.py",
+ "cellName": "Module Process Running",
+ "cellId": "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
+ "visible": true,
+ "startLine": 169,
+ "endLine": 171,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "parentPath": "aw-qt/aw_qt/manager.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "f968357d-53c4-41e8-b71f-c581c08b52e6"
+ }
+ ]
+ },
+ "dfaa3fc8-eca8-4c67-b926-87798f511adb": {
+ "path": "dfaa3fc8-eca8-4c67-b926-87798f511adb",
+ "cellName": "Create Tray\nIcon Instance",
+ "cellId": "dfaa3fc8-eca8-4c67-b926-87798f511adb",
+ "visible": true,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
+ },
+ "generated-edge-simstep-03fd319d-4ffe-47cf-bf39-ac388da80fa7-dfaa3fc8-eca8-4c67-b926-87798f511adb": {
+ "path": "generated-edge-simstep-03fd319d-4ffe-47cf-bf39-ac388da80fa7-dfaa3fc8-eca8-4c67-b926-87798f511adb",
+ "fileName": "trayicon.py",
+ "cellName": "Create Tray Icon Instance",
+ "cellId": "dfaa3fc8-eca8-4c67-b926-87798f511adb",
+ "visible": true,
+ "startLine": 259,
+ "endLine": 260,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "03fd319d-4ffe-47cf-bf39-ac388da80fa7"
+ }
+ ]
+ },
+ "d9e460b6-432d-49c8-8e76-0d8750aa2c10": {
+ "path": "d9e460b6-432d-49c8-8e76-0d8750aa2c10",
+ "cellName": "User Toggles\nModule",
+ "cellId": "d9e460b6-432d-49c8-8e76-0d8750aa2c10",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "generated-edge-simstep-8e583414-7b87-42c9-bdb2-e56259be4cdf-d9e460b6-432d-49c8-8e76-0d8750aa2c10": {
+ "path": "generated-edge-simstep-8e583414-7b87-42c9-bdb2-e56259be4cdf-d9e460b6-432d-49c8-8e76-0d8750aa2c10",
+ "fileName": "trayicon.py",
+ "cellName": "User Toggles Module",
+ "cellId": "d9e460b6-432d-49c8-8e76-0d8750aa2c10",
+ "visible": true,
+ "startLine": 179,
+ "endLine": 179,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "8e583414-7b87-42c9-bdb2-e56259be4cdf"
+ }
+ ]
+ },
+ "9d4dee50-64ef-459a-98fa-839761e16813": {
+ "path": "9d4dee50-64ef-459a-98fa-839761e16813",
+ "cellName": "Send Termination\nSignal",
+ "cellId": "9d4dee50-64ef-459a-98fa-839761e16813",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "generated-edge-simstep-fdff8ecd-12b9-4bc0-ba7b-9402d26b1737-9d4dee50-64ef-459a-98fa-839761e16813": {
+ "path": "generated-edge-simstep-fdff8ecd-12b9-4bc0-ba7b-9402d26b1737-9d4dee50-64ef-459a-98fa-839761e16813",
+ "fileName": "manager.py",
+ "cellName": "Send Termination Signal",
+ "cellId": "9d4dee50-64ef-459a-98fa-839761e16813",
+ "visible": true,
+ "startLine": 191,
+ "endLine": 191,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
+ "parentPath": "aw-qt/aw_qt/manager.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "fdff8ecd-12b9-4bc0-ba7b-9402d26b1737"
+ }
+ ]
+ },
+ "f704019b-d227-47ad-8761-9a2ea01516cb": {
+ "path": "f704019b-d227-47ad-8761-9a2ea01516cb",
+ "cellName": "Query Module\nProcess State",
+ "cellId": "f704019b-d227-47ad-8761-9a2ea01516cb",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "generated-edge-simstep-c0115129-b34b-4d27-9f73-cf2dc142ea81-f704019b-d227-47ad-8761-9a2ea01516cb": {
+ "path": "generated-edge-simstep-c0115129-b34b-4d27-9f73-cf2dc142ea81-f704019b-d227-47ad-8761-9a2ea01516cb",
+ "fileName": "trayicon.py",
+ "cellName": "Query Module Process State",
+ "cellId": "f704019b-d227-47ad-8761-9a2ea01516cb",
+ "visible": true,
+ "startLine": 153,
+ "endLine": 153,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "c0115129-b34b-4d27-9f73-cf2dc142ea81"
+ }
+ ]
+ },
+ "ba9e605d-98a7-4b50-979a-05bf7213c681": {
+ "path": "ba9e605d-98a7-4b50-979a-05bf7213c681",
+ "cellName": "Check for\nUnexpected Stops",
+ "cellId": "ba9e605d-98a7-4b50-979a-05bf7213c681",
+ "visible": true,
+ "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
+ },
+ "generated-edge-simstep-7775ac80-c954-464e-b230-b233216ee5e3-ba9e605d-98a7-4b50-979a-05bf7213c681": {
+ "path": "generated-edge-simstep-7775ac80-c954-464e-b230-b233216ee5e3-ba9e605d-98a7-4b50-979a-05bf7213c681",
+ "fileName": "trayicon.py",
+ "cellName": "Check for Unexpected Stops",
+ "cellId": "ba9e605d-98a7-4b50-979a-05bf7213c681",
+ "visible": true,
+ "startLine": 163,
+ "endLine": 163,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "7775ac80-c954-464e-b230-b233216ee5e3"
+ }
+ ]
+ },
+ "2298c4b5-17de-487f-b592-2ac0f95eca84": {
+ "path": "2298c4b5-17de-487f-b592-2ac0f95eca84",
+ "cellName": "Trigger Failure\nNotification",
+ "cellId": "2298c4b5-17de-487f-b592-2ac0f95eca84",
+ "visible": true,
+ "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
+ },
+ "generated-edge-simstep-1ed5cd16-b593-41cf-84f2-233a8d64a227-2298c4b5-17de-487f-b592-2ac0f95eca84": {
+ "path": "generated-edge-simstep-1ed5cd16-b593-41cf-84f2-233a8d64a227-2298c4b5-17de-487f-b592-2ac0f95eca84",
+ "fileName": "trayicon.py",
+ "cellName": "Trigger Failure Notification",
+ "cellId": "2298c4b5-17de-487f-b592-2ac0f95eca84",
+ "visible": true,
+ "startLine": 166,
+ "endLine": 166,
+ "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
+ "parentPath": "aw-qt/aw_qt/trayicon.py",
+ "simSteps": [
+ {
+ "simulationKey": "How the module manager and tray icon works",
+ "simStepId": "1ed5cd16-b593-41cf-84f2-233a8d64a227"
+ }
+ ]
+ },
+ "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1": {
+ "path": "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1",
+ "cellName": "Start Notification Service - main.py:L340-360",
+ "cellId": "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "aw-notify/aw_notify/main.py-simstep-9b9a0f90-d7a7-40fb-8573-53b470ecf85d": {
+ "path": "aw-notify/aw_notify/main.py-simstep-9b9a0f90-d7a7-40fb-8573-53b470ecf85d",
+ "fileName": "main.py",
+ "wiki": "The `aw-notify` service is started from the command line, which calls the `main` function. `main` in turn invokes the `start` function to begin the notification service.",
+ "cellName": "Start Notification Service - main.py:L340-360",
+ "cellId": "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1",
+ "visible": true,
+ "startLine": 340,
+ "endLine": 360,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "9b9a0f90-d7a7-40fb-8573-53b470ecf85d"
+ }
+ ]
+ },
+ "553f1437-5c34-4d6d-8226-417014259fc5": {
+ "path": "553f1437-5c34-4d6d-8226-417014259fc5",
+ "cellName": "Initialize Threshold Alerts - main.py:L380-392",
+ "cellId": "553f1437-5c34-4d6d-8226-417014259fc5",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "aw-notify/aw_notify/main.py-simstep-f636bdd6-a8e3-47ec-9f9d-986b21a81868": {
+ "path": "aw-notify/aw_notify/main.py-simstep-f636bdd6-a8e3-47ec-9f9d-986b21a81868",
+ "fileName": "main.py",
+ "wiki": "The `threshold_alerts` function is called, which creates a list of `CategoryAlert` objects. Each object is configured with a specific category to monitor (e.g., 'Work', 'Twitter'), a list of time thresholds, and a display label.",
+ "cellName": "Initialize Threshold Alerts - main.py:L380-392",
+ "cellId": "553f1437-5c34-4d6d-8226-417014259fc5",
+ "visible": true,
+ "startLine": 380,
+ "endLine": 392,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "f636bdd6-a8e3-47ec-9f9d-986b21a81868"
+ }
+ ]
+ },
+ "1de089eb-60a7-4d7f-bfb5-3f7f23315873": {
+ "path": "1de089eb-60a7-4d7f-bfb5-3f7f23315873",
+ "cellName": "Update Category Time - main.py:L262-276",
+ "cellId": "1de089eb-60a7-4d7f-bfb5-3f7f23315873",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "aw-notify/aw_notify/main.py-simstep-945e3312-c7c9-4722-953b-94dc0feee249": {
+ "path": "aw-notify/aw_notify/main.py-simstep-945e3312-c7c9-4722-953b-94dc0feee249",
+ "fileName": "main.py",
+ "wiki": "The `update` method of a `CategoryAlert` instance is called. It checks if enough time has passed to warrant a new query to the server. If so, it calls `get_time()` to fetch the latest activity duration for its category.",
+ "cellName": "Update Category Time - main.py:L262-276",
+ "cellId": "1de089eb-60a7-4d7f-bfb5-3f7f23315873",
+ "visible": true,
+ "startLine": 262,
+ "endLine": 276,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "945e3312-c7c9-4722-953b-94dc0feee249"
+ }
+ ]
+ },
+ "e567d898-2785-43f6-98ef-f4b6d1232620": {
+ "path": "e567d898-2785-43f6-98ef-f4b6d1232620",
+ "cellName": "Server: Receive and Process Query - query.rs:L9-12",
+ "cellId": "e567d898-2785-43f6-98ef-f4b6d1232620",
+ "visible": true,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
+ },
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-868edfd6-1f03-416e-88dc-7b09d05e4ba5": {
+ "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-868edfd6-1f03-416e-88dc-7b09d05e4ba5",
+ "fileName": "query.rs",
+ "wiki": "The `aw-server-rust` instance receives the POST request at the `/api/0/query` endpoint. The request body, containing the query and time periods, is deserialized.",
+ "cellName": "Server: Receive and Process Query - query.rs:L9-12",
+ "cellId": "e567d898-2785-43f6-98ef-f4b6d1232620",
+ "visible": true,
+ "startLine": 9,
+ "endLine": 12,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "868edfd6-1f03-416e-88dc-7b09d05e4ba5"
+ }
+ ]
+ },
+ "44016962-bb6d-4a70-b13c-4538926a02a4": {
+ "path": "44016962-bb6d-4a70-b13c-4538926a02a4",
+ "cellName": "Server: Fetch Events from Datastore - functions.rs:L150-162",
+ "cellId": "44016962-bb6d-4a70-b13c-4538926a02a4",
+ "visible": true,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e"
+ },
+ "aw-server-rust/aw-query/src/functions.rs-simstep-cc5cfecf-cee9-4582-aa6c-b74787a11da8": {
+ "path": "aw-server-rust/aw-query/src/functions.rs-simstep-cc5cfecf-cee9-4582-aa6c-b74787a11da8",
+ "fileName": "functions.rs",
+ "wiki": "The query interpreter executes the `query_bucket` function from the query string. This function calls `ds.get_events` on the datastore to retrieve all relevant raw events within the specified time interval from the SQLite database.",
+ "cellName": "Server: Fetch Events from Datastore - functions.rs:L150-162",
+ "cellId": "44016962-bb6d-4a70-b13c-4538926a02a4",
+ "visible": true,
+ "startLine": 150,
+ "endLine": 162,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "parentPath": "aw-server-rust/aw-query/src/functions.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "cc5cfecf-cee9-4582-aa6c-b74787a11da8"
+ }
+ ]
+ },
+ "fd5d1362-e41b-43af-bfd8-7f7c344c9849": {
+ "path": "fd5d1362-e41b-43af-bfd8-7f7c344c9849",
+ "cellName": "Server: Send Query Result - query.rs:L28",
+ "cellId": "fd5d1362-e41b-43af-bfd8-7f7c344c9849",
+ "visible": true,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
+ },
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-f52d6bfa-55fe-49ee-9f20-60bf296c76f4": {
+ "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-f52d6bfa-55fe-49ee-9f20-60bf296c76f4",
+ "fileName": "query.rs",
+ "wiki": "After all transformations are complete, the query engine returns the final processed data. The server serializes this data into a JSON array and sends it back as the HTTP response.",
+ "cellName": "Server: Send Query Result - query.rs:L28",
+ "cellId": "fd5d1362-e41b-43af-bfd8-7f7c344c9849",
+ "visible": true,
+ "startLine": 28,
+ "endLine": 28,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "f52d6bfa-55fe-49ee-9f20-60bf296c76f4"
+ }
+ ]
+ },
+ "a01b5cc8-f12f-447b-9879-6b55bda0ef87": {
+ "path": "a01b5cc8-f12f-447b-9879-6b55bda0ef87",
+ "cellName": "Process Query Result and Update State - main.py:L123-130",
+ "cellId": "a01b5cc8-f12f-447b-9879-6b55bda0ef87",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "aw-notify/aw_notify/main.py-simstep-9c0b3f20-5c18-418a-82f7-78b04ebda9b5": {
+ "path": "aw-notify/aw_notify/main.py-simstep-9c0b3f20-5c18-418a-82f7-78b04ebda9b5",
+ "fileName": "main.py",
+ "wiki": "The `get_time` function processes the server response, creating a dictionary mapping each category to its total duration. This dictionary is returned to the `update` method, which then updates the `time_spent` attribute of the `CategoryAlert` instance.",
+ "cellName": "Process Query Result and Update State - main.py:L123-130",
+ "cellId": "a01b5cc8-f12f-447b-9879-6b55bda0ef87",
+ "visible": true,
+ "startLine": 123,
+ "endLine": 130,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "9c0b3f20-5c18-418a-82f7-78b04ebda9b5"
+ }
+ ]
+ },
+ "30303464-f5f8-4155-87e9-b81dda8175d9": {
+ "path": "30303464-f5f8-4155-87e9-b81dda8175d9",
+ "cellName": "Trigger Desktop Notification - main.py:L281-297",
+ "cellId": "30303464-f5f8-4155-87e9-b81dda8175d9",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "aw-notify/aw_notify/main.py-simstep-a66f8ebc-93f8-4f9c-8f19-03bd951d1e98": {
+ "path": "aw-notify/aw_notify/main.py-simstep-a66f8ebc-93f8-4f9c-8f19-03bd951d1e98",
+ "fileName": "main.py",
+ "wiki": "A threshold has been reached (e.g., time spent on 'Work' exceeds 1 hour). The `check` method calls the `notify` function, passing it a title and a formatted message to be displayed to the user.",
+ "cellName": "Trigger Desktop Notification - main.py:L281-297",
+ "cellId": "30303464-f5f8-4155-87e9-b81dda8175d9",
+ "visible": true,
+ "startLine": 281,
+ "endLine": 297,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "a66f8ebc-93f8-4f9c-8f19-03bd951d1e98"
+ }
+ ]
+ },
+ "445477ac-c52d-4053-a45e-8c81da805c88": {
+ "path": "445477ac-c52d-4053-a45e-8c81da805c88",
+ "cellName": "User sees notification - main.py:L149-184",
+ "cellId": "445477ac-c52d-4053-a45e-8c81da805c88",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "aw-notify/aw_notify/main.py-simstep-21533839-7ba4-4cfa-864a-2f67198cad68": {
+ "path": "aw-notify/aw_notify/main.py-simstep-21533839-7ba4-4cfa-864a-2f67198cad68",
+ "fileName": "main.py",
+ "wiki": "The operating system displays a native notification on the user's desktop with the message '💼 Work: 1h'.",
+ "cellName": "User sees notification - main.py:L149-184",
+ "cellId": "445477ac-c52d-4053-a45e-8c81da805c88",
+ "visible": true,
+ "startLine": 149,
+ "endLine": 184,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "21533839-7ba4-4cfa-864a-2f67198cad68"
+ }
+ ]
+ },
+ "f9ddc0fb-c342-4a4a-baec-53c6a2581b80": {
+ "path": "f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
+ "cellName": "Initialize Client\nand Get\nHostname",
+ "cellId": "f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "generated-edge-simstep-3c977159-c34d-4907-9004-e5aaff3f3bdc-f9ddc0fb-c342-4a4a-baec-53c6a2581b80": {
+ "path": "generated-edge-simstep-3c977159-c34d-4907-9004-e5aaff3f3bdc-f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
+ "fileName": "main.py",
+ "cellName": "Initialize Client and Get Hostname",
+ "cellId": "f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
+ "visible": true,
+ "startLine": 368,
+ "endLine": 370,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "3c977159-c34d-4907-9004-e5aaff3f3bdc"
+ }
+ ]
+ },
+ "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e": {
+ "path": "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
+ "cellName": "Enter Main\nLoop",
+ "cellId": "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "generated-edge-simstep-7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b-22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e": {
+ "path": "generated-edge-simstep-7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b-22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
+ "fileName": "main.py",
+ "cellName": "Enter Main Loop",
+ "cellId": "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
+ "visible": true,
+ "startLine": 400,
+ "endLine": 401,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b"
+ }
+ ]
+ },
+ "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd": {
+ "path": "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
+ "cellName": "API Call:\nQuery Server\nfor Activity\nData",
+ "cellId": "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
+ "visible": true
+ },
+ "generated-edge-simstep-f20bb756-15f3-4a7c-914b-aa61470cc435-5f61c8f5-897a-4dc2-81df-1eda2d84d5bd": {
+ "path": "generated-edge-simstep-f20bb756-15f3-4a7c-914b-aa61470cc435-5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
+ "fileName": "main.py",
+ "cellName": "API Call: Query Server for Activity Data",
+ "cellId": "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
+ "visible": true,
+ "startLine": 120,
+ "endLine": 120,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "f20bb756-15f3-4a7c-914b-aa61470cc435"
+ }
+ ]
+ },
+ "8f02d20c-25fe-4a28-99de-3e8908d0a66f": {
+ "path": "8f02d20c-25fe-4a28-99de-3e8908d0a66f",
+ "cellName": "Server: Execute\nQuery",
+ "cellId": "8f02d20c-25fe-4a28-99de-3e8908d0a66f",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-b835d5e0-434d-4469-94fe-d309114a9ef1-8f02d20c-25fe-4a28-99de-3e8908d0a66f": {
+ "path": "generated-edge-simstep-b835d5e0-434d-4469-94fe-d309114a9ef1-8f02d20c-25fe-4a28-99de-3e8908d0a66f",
+ "fileName": "query.rs",
+ "cellName": "Server: Execute Query",
+ "cellId": "8f02d20c-25fe-4a28-99de-3e8908d0a66f",
+ "visible": true,
+ "startLine": 16,
+ "endLine": 16,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "b835d5e0-434d-4469-94fe-d309114a9ef1"
+ }
+ ]
+ },
+ "5595958a-cf9d-4894-9824-ecc89e5cf956": {
+ "path": "5595958a-cf9d-4894-9824-ecc89e5cf956",
+ "cellName": "Server: Transform\nRaw Events",
+ "cellId": "5595958a-cf9d-4894-9824-ecc89e5cf956",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-027140c6-aa16-4070-89d3-3b553168e65e-5595958a-cf9d-4894-9824-ecc89e5cf956": {
+ "path": "generated-edge-simstep-027140c6-aa16-4070-89d3-3b553168e65e-5595958a-cf9d-4894-9824-ecc89e5cf956",
+ "fileName": "main.py",
+ "cellName": "Server: Transform Raw Events",
+ "cellId": "5595958a-cf9d-4894-9824-ecc89e5cf956",
+ "visible": true,
+ "startLine": 115,
+ "endLine": 115,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "027140c6-aa16-4070-89d3-3b553168e65e"
+ }
+ ]
+ },
+ "1b9dc1d5-e6a7-4069-8473-2156853d662e": {
+ "path": "1b9dc1d5-e6a7-4069-8473-2156853d662e",
+ "cellName": "Data Flow:\nReceive and\nParse Server\nResponse",
+ "cellId": "1b9dc1d5-e6a7-4069-8473-2156853d662e",
+ "visible": true
+ },
+ "generated-edge-simstep-92487214-03b7-430e-aab5-b5a5fb85b2cb-1b9dc1d5-e6a7-4069-8473-2156853d662e": {
+ "path": "generated-edge-simstep-92487214-03b7-430e-aab5-b5a5fb85b2cb-1b9dc1d5-e6a7-4069-8473-2156853d662e",
+ "fileName": "main.py",
+ "cellName": "Data Flow: Receive and Parse Server Response",
+ "cellId": "1b9dc1d5-e6a7-4069-8473-2156853d662e",
+ "visible": true,
+ "startLine": 120,
+ "endLine": 120,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "92487214-03b7-430e-aab5-b5a5fb85b2cb"
+ }
+ ]
+ },
+ "08e05622-d948-47eb-a56d-3d6782d638c0": {
+ "path": "08e05622-d948-47eb-a56d-3d6782d638c0",
+ "cellName": "Check for\nThreshold Breach",
+ "cellId": "08e05622-d948-47eb-a56d-3d6782d638c0",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "generated-edge-simstep-c8b0fe19-76a8-458d-9923-c2f270e306b3-08e05622-d948-47eb-a56d-3d6782d638c0": {
+ "path": "generated-edge-simstep-c8b0fe19-76a8-458d-9923-c2f270e306b3-08e05622-d948-47eb-a56d-3d6782d638c0",
+ "fileName": "main.py",
+ "cellName": "Check for Threshold Breach",
+ "cellId": "08e05622-d948-47eb-a56d-3d6782d638c0",
+ "visible": true,
+ "startLine": 402,
+ "endLine": 402,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "c8b0fe19-76a8-458d-9923-c2f270e306b3"
+ }
+ ]
+ },
+ "17c4cd6c-69f5-4df8-ac77-6955a0518939": {
+ "path": "17c4cd6c-69f5-4df8-ac77-6955a0518939",
+ "cellName": "Render Notification",
+ "cellId": "17c4cd6c-69f5-4df8-ac77-6955a0518939",
+ "visible": true,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
+ },
+ "generated-edge-simstep-e46653da-3493-419e-8f9c-397be83fe894-17c4cd6c-69f5-4df8-ac77-6955a0518939": {
+ "path": "generated-edge-simstep-e46653da-3493-419e-8f9c-397be83fe894-17c4cd6c-69f5-4df8-ac77-6955a0518939",
+ "fileName": "main.py",
+ "cellName": "Render Notification",
+ "cellId": "17c4cd6c-69f5-4df8-ac77-6955a0518939",
+ "visible": true,
+ "startLine": 161,
+ "endLine": 177,
+ "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
+ "parentPath": "aw-notify/aw_notify/main.py",
+ "simSteps": [
+ {
+ "simulationKey": "How time-based notifications work",
+ "simStepId": "e46653da-3493-419e-8f9c-397be83fe894"
+ }
+ ]
+ },
+ "a1e562ae-ea06-4c6a-ab92-fa78417115f6": {
+ "path": "a1e562ae-ea06-4c6a-ab92-fa78417115f6",
+ "cellName": "Export Flow: Client Initiates Data Export - client.py:L291-292",
+ "cellId": "a1e562ae-ea06-4c6a-ab92-fa78417115f6",
+ "visible": true,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
+ },
+ "aw-client/aw_client/client.py-simstep-8739f5eb-aec2-47f1-b1e6-a05a2bb65acd": {
+ "path": "aw-client/aw_client/client.py-simstep-8739f5eb-aec2-47f1-b1e6-a05a2bb65acd",
+ "fileName": "client.py",
+ "wiki": "A client application, using `aw-client`, calls the `export_all` method to begin the process of exporting all user data from the ActivityWatch server.",
+ "cellName": "Export Flow: Client Initiates Data Export - client.py:L291-292",
+ "cellId": "a1e562ae-ea06-4c6a-ab92-fa78417115f6",
+ "visible": true,
+ "startLine": 291,
+ "endLine": 292,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "8739f5eb-aec2-47f1-b1e6-a05a2bb65acd"
+ }
+ ]
+ },
+ "07e4d089-e23f-4030-8c10-7dbdbd00e1c7": {
+ "path": "07e4d089-e23f-4030-8c10-7dbdbd00e1c7",
+ "cellName": "Export Flow: Server Handles Export Request - rest.py:L332-344",
+ "cellId": "07e4d089-e23f-4030-8c10-7dbdbd00e1c7",
+ "visible": true,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
+ },
+ "aw-server/aw_server/rest.py-simstep-7bdce779-492f-4dee-a68d-4e6d28dc079a": {
+ "path": "aw-server/aw_server/rest.py-simstep-7bdce779-492f-4dee-a68d-4e6d28dc079a",
+ "fileName": "rest.py",
+ "wiki": "The `aw-server` (Flask application) receives the GET request and routes it to the `get` method of the `ExportAllResource` class, which is responsible for handling data exports.",
+ "cellName": "Export Flow: Server Handles Export Request - rest.py:L332-344",
+ "cellId": "07e4d089-e23f-4030-8c10-7dbdbd00e1c7",
+ "visible": true,
+ "startLine": 332,
+ "endLine": 344,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "7bdce779-492f-4dee-a68d-4e6d28dc079a"
+ }
+ ]
+ },
+ "19faa606-15ad-4c47-a983-692a1f30a667": {
+ "path": "19faa606-15ad-4c47-a983-692a1f30a667",
+ "cellName": "Export Flow: Aggregate All Buckets and Events - api.py:L97-103",
+ "cellId": "19faa606-15ad-4c47-a983-692a1f30a667",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6": {
+ "path": "aw-server/aw_server/api.py-simstep-d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6",
+ "fileName": "api.py",
+ "wiki": "The `export_all` method in the `ServerAPI` class begins by fetching all existing buckets. It then iterates through each bucket to export its metadata and all associated events.",
+ "cellName": "Export Flow: Aggregate All Buckets and Events - api.py:L97-103",
+ "cellId": "19faa606-15ad-4c47-a983-692a1f30a667",
+ "visible": true,
+ "startLine": 97,
+ "endLine": 103,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6"
+ }
+ ]
+ },
+ "e590d109-3712-4d3d-9241-ba9cd9a7eeaa": {
+ "path": "e590d109-3712-4d3d-9241-ba9cd9a7eeaa",
+ "cellName": "Export Flow: Datastore Retrieves Events - api.py:L214-228",
+ "cellId": "e590d109-3712-4d3d-9241-ba9cd9a7eeaa",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-5fb7b7d5-1759-43dc-a711-b2b0b5df3893": {
+ "path": "aw-server/aw_server/api.py-simstep-5fb7b7d5-1759-43dc-a711-b2b0b5df3893",
+ "fileName": "api.py",
+ "wiki": "The `get_events` function in the API layer queries the datastore, which fetches the corresponding events from the underlying database (e.g., SQLite).",
+ "cellName": "Export Flow: Datastore Retrieves Events - api.py:L214-228",
+ "cellId": "e590d109-3712-4d3d-9241-ba9cd9a7eeaa",
+ "visible": true,
+ "startLine": 214,
+ "endLine": 228,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "5fb7b7d5-1759-43dc-a711-b2b0b5df3893"
+ }
+ ]
+ },
+ "6e7e85b1-9708-4f64-ac9e-efc54338c444": {
+ "path": "6e7e85b1-9708-4f64-ac9e-efc54338c444",
+ "cellName": "Export Flow: Server Sends JSON File Response - rest.py:L336-344",
+ "cellId": "6e7e85b1-9708-4f64-ac9e-efc54338c444",
+ "visible": true,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
+ },
+ "aw-server/aw_server/rest.py-simstep-cfd637bd-f6b2-44cf-8330-7b2c59c0658b": {
+ "path": "aw-server/aw_server/rest.py-simstep-cfd637bd-f6b2-44cf-8330-7b2c59c0658b",
+ "fileName": "rest.py",
+ "wiki": "The `ExportAllResource` constructs a final JSON payload and creates an HTTP response with a `Content-Disposition` header, prompting the client to download the data as `aw-buckets-export.json`.",
+ "cellName": "Export Flow: Server Sends JSON File Response - rest.py:L336-344",
+ "cellId": "6e7e85b1-9708-4f64-ac9e-efc54338c444",
+ "visible": true,
+ "startLine": 336,
+ "endLine": 344,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "cfd637bd-f6b2-44cf-8330-7b2c59c0658b"
+ }
+ ]
+ },
+ "e60e25ae-e9aa-4497-8555-7e3d99a4049f": {
+ "path": "e60e25ae-e9aa-4497-8555-7e3d99a4049f",
+ "cellName": "Import Flow: Client Initiates Data Import - client.py:L297-299",
+ "cellId": "e60e25ae-e9aa-4497-8555-7e3d99a4049f",
+ "visible": true,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
+ },
+ "aw-client/aw_client/client.py-simstep-ea6d2274-023a-4d5f-abf4-0414c6c7f68d": {
+ "path": "aw-client/aw_client/client.py-simstep-ea6d2274-023a-4d5f-abf4-0414c6c7f68d",
+ "fileName": "client.py",
+ "wiki": "A client application, such as a script using `aw-client`, calls a method like `import_bucket` to start the data import process. This example shows a single bucket import, but the server supports importing multiple buckets at once.",
+ "cellName": "Import Flow: Client Initiates Data Import - client.py:L297-299",
+ "cellId": "e60e25ae-e9aa-4497-8555-7e3d99a4049f",
+ "visible": true,
+ "startLine": 297,
+ "endLine": 299,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "ea6d2274-023a-4d5f-abf4-0414c6c7f68d"
+ }
+ ]
+ },
+ "12725c25-974e-4363-bb91-c61c8745ed75": {
+ "path": "12725c25-974e-4363-bb91-c61c8745ed75",
+ "cellName": "Import Flow: Server Handles Import Request - rest.py:L129-341",
+ "cellId": "12725c25-974e-4363-bb91-c61c8745ed75",
+ "visible": true,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
+ },
+ "aw-server/aw_server/rest.py-simstep-3e1decf0-1329-4da8-a7c7-870ffe960a54": {
+ "path": "aw-server/aw_server/rest.py-simstep-3e1decf0-1329-4da8-a7c7-870ffe960a54",
+ "fileName": "rest.py",
+ "wiki": "The `aw-server` receives the POST request and routes it to the `post` method of the `ImportAllResource` class. This method extracts the `buckets` data from the request.",
+ "cellName": "Import Flow: Server Handles Import Request - rest.py:L129-341",
+ "cellId": "12725c25-974e-4363-bb91-c61c8745ed75",
+ "visible": true,
+ "startLine": 129,
+ "endLine": 341,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "3e1decf0-1329-4da8-a7c7-870ffe960a54"
+ }
+ ]
+ },
+ "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570": {
+ "path": "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570",
+ "cellName": "Import Flow: Iterate and Import Each Bucket - api.py:L133-135",
+ "cellId": "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-4050248c-1638-452c-8826-677a7a2fece8": {
+ "path": "aw-server/aw_server/api.py-simstep-4050248c-1638-452c-8826-677a7a2fece8",
+ "fileName": "api.py",
+ "wiki": "The `import_all` method loops through each bucket from the input data and calls `import_bucket` to process them individually.",
+ "cellName": "Import Flow: Iterate and Import Each Bucket - api.py:L133-135",
+ "cellId": "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570",
+ "visible": true,
+ "startLine": 133,
+ "endLine": 135,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "4050248c-1638-452c-8826-677a7a2fece8"
+ }
+ ]
+ },
+ "07630c61-6df6-484b-81c3-0984379bfd68": {
+ "path": "07630c61-6df6-484b-81c3-0984379bfd68",
+ "cellName": "Import Flow: Create and Insert Events - api.py:L128-131",
+ "cellId": "07630c61-6df6-484b-81c3-0984379bfd68",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "aw-server/aw_server/api.py-simstep-164ed08b-0873-499b-b945-e062cf362429": {
+ "path": "aw-server/aw_server/api.py-simstep-164ed08b-0873-499b-b945-e062cf362429",
+ "fileName": "api.py",
+ "wiki": "After creating the bucket, `import_bucket` calls `create_events`, which in turn calls the datastore's `insert` method to add all events from the imported data into the newly created bucket.",
+ "cellName": "Import Flow: Create and Insert Events - api.py:L128-131",
+ "cellId": "07630c61-6df6-484b-81c3-0984379bfd68",
+ "visible": true,
+ "startLine": 128,
+ "endLine": 131,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "164ed08b-0873-499b-b945-e062cf362429"
+ }
+ ]
+ },
+ "ae563be0-ff29-4c20-8f6d-6771f04c8da3": {
+ "path": "ae563be0-ff29-4c20-8f6d-6771f04c8da3",
+ "cellName": "Import Flow: Server Sends Success Response - rest.py:L129-341",
+ "cellId": "ae563be0-ff29-4c20-8f6d-6771f04c8da3",
+ "visible": true,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
+ },
+ "aw-server/aw_server/rest.py-simstep-3fd4d48c-e70c-4217-92c1-7554445cf03b": {
+ "path": "aw-server/aw_server/rest.py-simstep-3fd4d48c-e70c-4217-92c1-7554445cf03b",
+ "fileName": "rest.py",
+ "wiki": "After all buckets and events have been successfully imported, the `ImportAllResource` returns a 200 OK status to the client.",
+ "cellName": "Import Flow: Server Sends Success Response - rest.py:L129-341",
+ "cellId": "ae563be0-ff29-4c20-8f6d-6771f04c8da3",
+ "visible": true,
+ "startLine": 129,
+ "endLine": 341,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "3fd4d48c-e70c-4217-92c1-7554445cf03b"
+ }
+ ]
+ },
+ "5fe912cd-a72c-4cc1-969b-b5eb6759ace9": {
+ "path": "5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
+ "cellName": "Export Flow:\nAPI Call\nto Export\nEndpoint",
+ "cellId": "5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
+ "visible": true
+ },
+ "generated-edge-simstep-8efaf2e1-7c6d-4820-90a5-2abb80bf65ed-5fe912cd-a72c-4cc1-969b-b5eb6759ace9": {
+ "path": "generated-edge-simstep-8efaf2e1-7c6d-4820-90a5-2abb80bf65ed-5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
+ "fileName": "client.py",
+ "cellName": "Export Flow: API Call to Export Endpoint",
+ "cellId": "5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
+ "visible": true,
+ "startLine": 292,
+ "endLine": 292,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "8efaf2e1-7c6d-4820-90a5-2abb80bf65ed"
+ }
+ ]
+ },
+ "8515a29c-385b-4ec5-886c-ba3a3a48518e": {
+ "path": "8515a29c-385b-4ec5-886c-ba3a3a48518e",
+ "cellName": "Export Flow:\nCall to\nAPI Layer\nfor Export\nLogic",
+ "cellId": "8515a29c-385b-4ec5-886c-ba3a3a48518e",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
+ },
+ "generated-edge-simstep-6449735d-8c85-4d49-bb8c-c2b1f9918ffc-8515a29c-385b-4ec5-886c-ba3a3a48518e": {
+ "path": "generated-edge-simstep-6449735d-8c85-4d49-bb8c-c2b1f9918ffc-8515a29c-385b-4ec5-886c-ba3a3a48518e",
+ "fileName": "rest.py",
+ "cellName": "Export Flow: Call to API Layer for Export Logic",
+ "cellId": "8515a29c-385b-4ec5-886c-ba3a3a48518e",
+ "visible": true,
+ "startLine": 337,
+ "endLine": 337,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "6449735d-8c85-4d49-bb8c-c2b1f9918ffc"
+ }
+ ]
+ },
+ "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff": {
+ "path": "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
+ "cellName": "Export Flow:\nFetching Events\nfor a\nBucket",
+ "cellId": "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "generated-edge-simstep-60764034-1b94-4c15-9015-09e8b775f736-ec71fb4b-213d-4fa0-bdfa-9882eb11dcff": {
+ "path": "generated-edge-simstep-60764034-1b94-4c15-9015-09e8b775f736-ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
+ "fileName": "api.py",
+ "cellName": "Export Flow: Fetching Events for a Bucket",
+ "cellId": "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
+ "visible": true,
+ "startLine": 91,
+ "endLine": 91,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "60764034-1b94-4c15-9015-09e8b775f736"
+ }
+ ]
+ },
+ "272a1088-1b0c-43f9-8335-d7055539c813": {
+ "path": "272a1088-1b0c-43f9-8335-d7055539c813",
+ "cellName": "Export Flow:\nReturning Exported\nData to\nREST Layer",
+ "cellId": "272a1088-1b0c-43f9-8335-d7055539c813",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
+ },
+ "generated-edge-simstep-7a5f8838-8ed9-47b3-907f-077efeedaa10-272a1088-1b0c-43f9-8335-d7055539c813": {
+ "path": "generated-edge-simstep-7a5f8838-8ed9-47b3-907f-077efeedaa10-272a1088-1b0c-43f9-8335-d7055539c813",
+ "fileName": "api.py",
+ "cellName": "Export Flow: Returning Exported Data to REST Layer",
+ "cellId": "272a1088-1b0c-43f9-8335-d7055539c813",
+ "visible": true,
+ "startLine": 103,
+ "endLine": 103,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "7a5f8838-8ed9-47b3-907f-077efeedaa10"
+ }
+ ]
+ },
+ "ebfbcf3c-bc57-4fe1-866e-fde1b860e633": {
+ "path": "ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
+ "cellName": "Import Flow:\nAPI Call\nto Import\nEndpoint",
+ "cellId": "ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
+ "visible": true
+ },
+ "generated-edge-simstep-f5c06885-1138-4c13-ae70-10b9d409be5b-ebfbcf3c-bc57-4fe1-866e-fde1b860e633": {
+ "path": "generated-edge-simstep-f5c06885-1138-4c13-ae70-10b9d409be5b-ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
+ "fileName": "client.py",
+ "cellName": "Import Flow: API Call to Import Endpoint",
+ "cellId": "ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
+ "visible": true,
+ "startLine": 299,
+ "endLine": 299,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "f5c06885-1138-4c13-ae70-10b9d409be5b"
+ }
+ ]
+ },
+ "0614b31f-64d9-4e85-a5f5-6304f0702bd7": {
+ "path": "0614b31f-64d9-4e85-a5f5-6304f0702bd7",
+ "cellName": "Import Flow:\nCall to\nAPI Layer\nfor Import\nLogic",
+ "cellId": "0614b31f-64d9-4e85-a5f5-6304f0702bd7",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
+ },
+ "generated-edge-simstep-988adf58-e1be-4352-be66-4f02188fc28a-0614b31f-64d9-4e85-a5f5-6304f0702bd7": {
+ "path": "generated-edge-simstep-988adf58-e1be-4352-be66-4f02188fc28a-0614b31f-64d9-4e85-a5f5-6304f0702bd7",
+ "fileName": "rest.py",
+ "cellName": "Import Flow: Call to API Layer for Import Logic",
+ "cellId": "0614b31f-64d9-4e85-a5f5-6304f0702bd7",
+ "visible": true,
+ "startLine": 129,
+ "endLine": 341,
+ "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
+ "parentPath": "aw-server/aw_server/rest.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "988adf58-e1be-4352-be66-4f02188fc28a"
+ }
+ ]
+ },
+ "941b8c57-be7c-49cd-ba2a-d2237f8f129b": {
+ "path": "941b8c57-be7c-49cd-ba2a-d2237f8f129b",
+ "cellName": "Import Flow:\nCreate Bucket\nin Datastore",
+ "cellId": "941b8c57-be7c-49cd-ba2a-d2237f8f129b",
+ "visible": true,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
+ },
+ "generated-edge-simstep-7e01821d-906c-4518-a1e0-6b71be84291a-941b8c57-be7c-49cd-ba2a-d2237f8f129b": {
+ "path": "generated-edge-simstep-7e01821d-906c-4518-a1e0-6b71be84291a-941b8c57-be7c-49cd-ba2a-d2237f8f129b",
+ "fileName": "api.py",
+ "cellName": "Import Flow: Create Bucket in Datastore",
+ "cellId": "941b8c57-be7c-49cd-ba2a-d2237f8f129b",
+ "visible": true,
+ "startLine": 110,
+ "endLine": 120,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "7e01821d-906c-4518-a1e0-6b71be84291a"
+ }
+ ]
+ },
+ "1f7db50a-bc15-48d1-9f06-27ed743afa75": {
+ "path": "1f7db50a-bc15-48d1-9f06-27ed743afa75",
+ "cellName": "Import Flow:\nPersist Events\nto Database",
+ "cellId": "1f7db50a-bc15-48d1-9f06-27ed743afa75",
+ "visible": true,
+ "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
+ },
+ "generated-edge-simstep-666a933a-7a74-4d90-be19-7610f7bd3d74-1f7db50a-bc15-48d1-9f06-27ed743afa75": {
+ "path": "generated-edge-simstep-666a933a-7a74-4d90-be19-7610f7bd3d74-1f7db50a-bc15-48d1-9f06-27ed743afa75",
+ "fileName": "api.py",
+ "cellName": "Import Flow: Persist Events to Database",
+ "cellId": "1f7db50a-bc15-48d1-9f06-27ed743afa75",
+ "visible": true,
+ "startLine": 235,
+ "endLine": 235,
+ "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
+ "parentPath": "aw-server/aw_server/api.py",
+ "simSteps": [
+ {
+ "simulationKey": "How data export and import works",
+ "simStepId": "666a933a-7a74-4d90-be19-7610f7bd3d74"
+ }
+ ]
+ },
+ "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c": {
+ "path": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c",
+ "cellName": "examples",
+ "cellId": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c",
+ "visible": true,
+ "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793"
+ },
+ "9b8f28aa-5406-437c-8363-bcfe0f788580": {
+ "path": "9b8f28aa-5406-437c-8363-bcfe0f788580",
+ "cellName": "working_hours.py",
+ "cellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
+ "visible": true,
+ "parentCellId": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c"
+ },
+ "237e712f-0c66-4488-b6e9-1ef8c3b71b51": {
+ "path": "237e712f-0c66-4488-b6e9-1ef8c3b71b51",
+ "cellName": "Start Script Execution - working_hours.py:L91-115",
+ "cellId": "237e712f-0c66-4488-b6e9-1ef8c3b71b51",
+ "visible": true,
+ "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580"
+ },
+ "aw-client/examples/working_hours.py-simstep-e90cee0c-3a20-498b-97b9-2086a61dc02b": {
+ "path": "aw-client/examples/working_hours.py-simstep-e90cee0c-3a20-498b-97b9-2086a61dc02b",
+ "fileName": "working_hours.py",
+ "wiki": "The user executes the `working_hours.py` script to calculate work time. The script defines a regex for 'Work' activities and sets up time periods to query.",
+ "cellName": "Start Script Execution - working_hours.py:L91-115",
+ "cellId": "237e712f-0c66-4488-b6e9-1ef8c3b71b51",
+ "visible": true,
+ "startLine": 91,
+ "endLine": 115,
+ "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
+ "parentPath": "aw-client/examples/working_hours.py",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "e90cee0c-3a20-498b-97b9-2086a61dc02b"
+ }
+ ]
+ },
+ "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c": {
+ "path": "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c",
+ "cellName": "Prepare API Request - client.py:L305-339",
+ "cellId": "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c",
+ "visible": true,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
+ },
+ "aw-client/aw_client/client.py-simstep-0d34430a-af81-407b-8817-672288674005": {
+ "path": "aw-client/aw_client/client.py-simstep-0d34430a-af81-407b-8817-672288674005",
+ "fileName": "client.py",
+ "wiki": "The `ActivityWatchClient.query` method formats the time periods into ISO 8601 interval strings and packages the query and time periods into a JSON payload for the HTTP POST request.",
+ "cellName": "Prepare API Request - client.py:L305-339",
+ "cellId": "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c",
+ "visible": true,
+ "startLine": 305,
+ "endLine": 339,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "0d34430a-af81-407b-8817-672288674005"
+ }
+ ]
+ },
+ "73994797-596f-4b60-a36e-5f45cba1fcd3": {
+ "path": "73994797-596f-4b60-a36e-5f45cba1fcd3",
+ "cellName": "Receive Query Request (aw-server-rust) - query.rs:L10-23",
+ "cellId": "73994797-596f-4b60-a36e-5f45cba1fcd3",
+ "visible": true,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
+ },
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-c988a25d-05ad-4c19-87ac-362c79af1d00": {
+ "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-c988a25d-05ad-4c19-87ac-362c79af1d00",
+ "fileName": "query.rs",
+ "wiki": "The Rust-based `aw-server` receives the POST request at the `/api/0/query` endpoint. It parses the JSON body into a `Query` struct and prepares to execute the query against the datastore.",
+ "cellName": "Receive Query Request (aw-server-rust) - query.rs:L10-23",
+ "cellId": "73994797-596f-4b60-a36e-5f45cba1fcd3",
+ "visible": true,
+ "startLine": 10,
+ "endLine": 23,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "c988a25d-05ad-4c19-87ac-362c79af1d00"
+ }
+ ]
+ },
+ "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b": {
+ "path": "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b",
+ "cellName": "Parse and Interpret Query - lib.rs:L53-64",
+ "cellId": "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b",
+ "visible": true,
+ "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237"
+ },
+ "aw-server-rust/aw-query/src/lib.rs-simstep-b482a39f-e520-4d4d-8b2f-d1298922763f": {
+ "path": "aw-server-rust/aw-query/src/lib.rs-simstep-b482a39f-e520-4d4d-8b2f-d1298922763f",
+ "fileName": "lib.rs",
+ "wiki": "The `aw_query` library's main function takes the query string, tokenizes it with a lexer, parses it into an Abstract Syntax Tree (AST), and then interprets the AST to execute the query logic.",
+ "cellName": "Parse and Interpret Query - lib.rs:L53-64",
+ "cellId": "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b",
+ "visible": true,
+ "startLine": 53,
+ "endLine": 64,
+ "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
+ "parentPath": "aw-server-rust/aw-query/src/lib.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "b482a39f-e520-4d4d-8b2f-d1298922763f"
+ }
+ ]
+ },
+ "0b3e80ff-b4c9-42db-b067-1a9ba48e9218": {
+ "path": "0b3e80ff-b4c9-42db-b067-1a9ba48e9218",
+ "cellName": "Database Query - datastore.rs:L700-797",
+ "cellId": "0b3e80ff-b4c9-42db-b067-1a9ba48e9218",
+ "visible": true,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
+ },
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-04bbbe33-e9de-4c5f-b925-27196d20ef1d": {
+ "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-04bbbe33-e9de-4c5f-b925-27196d20ef1d",
+ "fileName": "datastore.rs",
+ "wiki": "The datastore worker receives the request and executes a SQL `SELECT` statement against the SQLite database to retrieve the raw event data for the specified bucket and time range.",
+ "cellName": "Database Query - datastore.rs:L700-797",
+ "cellId": "0b3e80ff-b4c9-42db-b067-1a9ba48e9218",
+ "visible": true,
+ "startLine": 700,
+ "endLine": 797,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "04bbbe33-e9de-4c5f-b925-27196d20ef1d"
+ }
+ ]
+ },
+ "60a529b9-b262-4c7f-9baf-5beb50025a86": {
+ "path": "60a529b9-b262-4c7f-9baf-5beb50025a86",
+ "cellName": "Deserialize Events - datastore.rs:L755-780",
+ "cellId": "60a529b9-b262-4c7f-9baf-5beb50025a86",
+ "visible": true,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
+ },
+ "aw-server-rust/aw-datastore/src/datastore.rs-simstep-1b3cdf02-5dad-411c-a35e-9250c8aafc9d": {
+ "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-1b3cdf02-5dad-411c-a35e-9250c8aafc9d",
+ "fileName": "datastore.rs",
+ "wiki": "The datastore layer deserializes the raw database rows into structured `Event` objects.",
+ "cellName": "Deserialize Events - datastore.rs:L755-780",
+ "cellId": "60a529b9-b262-4c7f-9baf-5beb50025a86",
+ "visible": true,
+ "startLine": 755,
+ "endLine": 780,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "1b3cdf02-5dad-411c-a35e-9250c8aafc9d"
+ }
+ ]
+ },
+ "06ecdf3e-50eb-4bf3-9c56-183f98a3186b": {
+ "path": "06ecdf3e-50eb-4bf3-9c56-183f98a3186b",
+ "cellName": "Perform Query Transformations - interpret.rs:L213-226",
+ "cellId": "06ecdf3e-50eb-4bf3-9c56-183f98a3186b",
+ "visible": true,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c"
+ },
+ "aw-server-rust/aw-query/src/interpret.rs-simstep-f7c58723-a402-45d1-8070-59c196e20fb2": {
+ "path": "aw-server-rust/aw-query/src/interpret.rs-simstep-f7c58723-a402-45d1-8070-59c196e20fb2",
+ "fileName": "interpret.rs",
+ "wiki": "The query interpreter continues executing the AST. It applies a series of transformations to the fetched events, such as `flood`, `filter_period_intersect`, `categorize`, `merge_events_by_keys`, and `sum_durations`, as defined in the query string.",
+ "cellName": "Perform Query Transformations - interpret.rs:L213-226",
+ "cellId": "06ecdf3e-50eb-4bf3-9c56-183f98a3186b",
+ "visible": true,
+ "startLine": 213,
+ "endLine": 226,
+ "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
+ "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "f7c58723-a402-45d1-8070-59c196e20fb2"
+ }
+ ]
+ },
+ "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500": {
+ "path": "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500",
+ "cellName": "Serialize and Send Response - query.rs:L28",
+ "cellId": "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500",
+ "visible": true,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
+ },
+ "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-72197f38-6e3b-432c-be11-ce5fbb94efb9": {
+ "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-72197f38-6e3b-432c-be11-ce5fbb94efb9",
+ "fileName": "query.rs",
+ "wiki": "The Rocket endpoint handler serializes the query result into a JSON string and sends it as the HTTP response.",
+ "cellName": "Serialize and Send Response - query.rs:L28",
+ "cellId": "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500",
+ "visible": true,
+ "startLine": 28,
+ "endLine": 28,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "72197f38-6e3b-432c-be11-ce5fbb94efb9"
+ }
+ ]
+ },
+ "7057dbee-ccfe-43f8-9014-90812018a849": {
+ "path": "7057dbee-ccfe-43f8-9014-90812018a849",
+ "cellName": "Process Response in Client - client.py:L338",
+ "cellId": "7057dbee-ccfe-43f8-9014-90812018a849",
+ "visible": true,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
+ },
+ "aw-client/aw_client/client.py-simstep-642425c3-abd7-45fe-b5a9-a76bf90a9477": {
+ "path": "aw-client/aw_client/client.py-simstep-642425c3-abd7-45fe-b5a9-a76bf90a9477",
+ "fileName": "client.py",
+ "wiki": "The `ActivityWatchClient` receives the HTTP response, checks for errors, and parses the JSON body into a Python list of dictionaries.",
+ "cellName": "Process Response in Client - client.py:L338",
+ "cellId": "7057dbee-ccfe-43f8-9014-90812018a849",
+ "visible": true,
+ "startLine": 338,
+ "endLine": 338,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "642425c3-abd7-45fe-b5a9-a76bf90a9477"
+ }
+ ]
+ },
+ "e985450d-2666-412f-acf5-988a5c0c7de5": {
+ "path": "e985450d-2666-412f-acf5-988a5c0c7de5",
+ "cellName": "Process and Display Results - working_hours.py:L113-120",
+ "cellId": "e985450d-2666-412f-acf5-988a5c0c7de5",
+ "visible": true,
+ "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580"
+ },
+ "aw-client/examples/working_hours.py-simstep-e38db73e-b347-4786-8efd-1e7cab44f73f": {
+ "path": "aw-client/examples/working_hours.py-simstep-e38db73e-b347-4786-8efd-1e7cab44f73f",
+ "fileName": "working_hours.py",
+ "wiki": "The `working_hours.py` script receives the processed data, calculates total durations using `generous_approx` (which applies flooding), formats the output, and prints a tabulated summary to the console. It also saves the raw event data to a JSON file.",
+ "cellName": "Process and Display Results - working_hours.py:L113-120",
+ "cellId": "e985450d-2666-412f-acf5-988a5c0c7de5",
+ "visible": true,
+ "startLine": 113,
+ "endLine": 120,
+ "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
+ "parentPath": "aw-client/examples/working_hours.py",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "e38db73e-b347-4786-8efd-1e7cab44f73f"
+ }
+ ]
+ },
+ "aecc1e90-5e71-43f4-a5b8-757de329fe3a": {
+ "path": "aecc1e90-5e71-43f4-a5b8-757de329fe3a",
+ "cellName": "Invoke AW\nClient Query",
+ "cellId": "aecc1e90-5e71-43f4-a5b8-757de329fe3a",
+ "visible": true,
+ "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793"
+ },
+ "generated-edge-simstep-5aa97ae5-7e30-4d15-8f12-05942f2e75c9-aecc1e90-5e71-43f4-a5b8-757de329fe3a": {
+ "path": "generated-edge-simstep-5aa97ae5-7e30-4d15-8f12-05942f2e75c9-aecc1e90-5e71-43f4-a5b8-757de329fe3a",
+ "fileName": "working_hours.py",
+ "cellName": "Invoke AW Client Query",
+ "cellId": "aecc1e90-5e71-43f4-a5b8-757de329fe3a",
+ "visible": true,
+ "startLine": 86,
+ "endLine": 86,
+ "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
+ "parentPath": "aw-client/examples/working_hours.py",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "5aa97ae5-7e30-4d15-8f12-05942f2e75c9"
+ }
+ ]
+ },
+ "62388ee6-67f4-4adc-b08e-90deeb10efd4": {
+ "path": "62388ee6-67f4-4adc-b08e-90deeb10efd4",
+ "cellName": "API Call:\nPOST /api/0/query/",
+ "cellId": "62388ee6-67f4-4adc-b08e-90deeb10efd4",
+ "visible": true
+ },
+ "generated-edge-simstep-834b7dbc-5efe-41ac-b75b-e43ad32141df-62388ee6-67f4-4adc-b08e-90deeb10efd4": {
+ "path": "generated-edge-simstep-834b7dbc-5efe-41ac-b75b-e43ad32141df-62388ee6-67f4-4adc-b08e-90deeb10efd4",
+ "fileName": "client.py",
+ "cellName": "API Call: POST /api/0/query/",
+ "cellId": "62388ee6-67f4-4adc-b08e-90deeb10efd4",
+ "visible": true,
+ "startLine": 122,
+ "endLine": 127,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "834b7dbc-5efe-41ac-b75b-e43ad32141df"
+ }
+ ]
+ },
+ "31b60323-3a65-4184-a42f-f577f3a958ff": {
+ "path": "31b60323-3a65-4184-a42f-f577f3a958ff",
+ "cellName": "Execute Query",
+ "cellId": "31b60323-3a65-4184-a42f-f577f3a958ff",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-98777081-df05-4b5c-89f6-5076fab00e92-31b60323-3a65-4184-a42f-f577f3a958ff": {
+ "path": "generated-edge-simstep-98777081-df05-4b5c-89f6-5076fab00e92-31b60323-3a65-4184-a42f-f577f3a958ff",
+ "fileName": "query.rs",
+ "cellName": "Execute Query",
+ "cellId": "31b60323-3a65-4184-a42f-f577f3a958ff",
+ "visible": true,
+ "startLine": 16,
+ "endLine": 16,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "98777081-df05-4b5c-89f6-5076fab00e92"
+ }
+ ]
+ },
+ "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f": {
+ "path": "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
+ "cellName": "Data Fetch:\n`query_bucket`",
+ "cellId": "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-914107de-b38a-4307-ab2c-e257ed3d2fb5-9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f": {
+ "path": "generated-edge-simstep-914107de-b38a-4307-ab2c-e257ed3d2fb5-9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
+ "fileName": "functions.rs",
+ "cellName": "Data Fetch: `query_bucket`",
+ "cellId": "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
+ "visible": true,
+ "startLine": 139,
+ "endLine": 168,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "parentPath": "aw-server-rust/aw-query/src/functions.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "914107de-b38a-4307-ab2c-e257ed3d2fb5"
+ }
+ ]
+ },
+ "561eebea-ee66-4251-a29c-64c2e3aae490": {
+ "path": "561eebea-ee66-4251-a29c-64c2e3aae490",
+ "cellName": "Return Raw\nEvent Data",
+ "cellId": "561eebea-ee66-4251-a29c-64c2e3aae490",
+ "visible": true,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
+ },
+ "generated-edge-simstep-5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619-561eebea-ee66-4251-a29c-64c2e3aae490": {
+ "path": "generated-edge-simstep-5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619-561eebea-ee66-4251-a29c-64c2e3aae490",
+ "fileName": "datastore.rs",
+ "cellName": "Return Raw Event Data",
+ "cellId": "561eebea-ee66-4251-a29c-64c2e3aae490",
+ "visible": true,
+ "startLine": 748,
+ "endLine": 788,
+ "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
+ "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619"
+ }
+ ]
+ },
+ "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe": {
+ "path": "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
+ "cellName": "Return Deserialized\nEvents",
+ "cellId": "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-d78663e6-a6d4-4ba7-a922-436bd075e457-2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe": {
+ "path": "generated-edge-simstep-d78663e6-a6d4-4ba7-a922-436bd075e457-2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
+ "fileName": "functions.rs",
+ "cellName": "Return Deserialized Events",
+ "cellId": "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
+ "visible": true,
+ "startLine": 167,
+ "endLine": 167,
+ "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
+ "parentPath": "aw-server-rust/aw-query/src/functions.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "d78663e6-a6d4-4ba7-a922-436bd075e457"
+ }
+ ]
+ },
+ "3f00132f-3930-4b99-82cf-1ca7f818661b": {
+ "path": "3f00132f-3930-4b99-82cf-1ca7f818661b",
+ "cellName": "Return Final\nQuery Result",
+ "cellId": "3f00132f-3930-4b99-82cf-1ca7f818661b",
+ "visible": true,
+ "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
+ },
+ "generated-edge-simstep-633d97c2-762a-45cb-8900-308ab124d526-3f00132f-3930-4b99-82cf-1ca7f818661b": {
+ "path": "generated-edge-simstep-633d97c2-762a-45cb-8900-308ab124d526-3f00132f-3930-4b99-82cf-1ca7f818661b",
+ "fileName": "query.rs",
+ "cellName": "Return Final Query Result",
+ "cellId": "3f00132f-3930-4b99-82cf-1ca7f818661b",
+ "visible": true,
+ "startLine": 16,
+ "endLine": 25,
+ "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
+ "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "633d97c2-762a-45cb-8900-308ab124d526"
+ }
+ ]
+ },
+ "ec5d6b90-2f5f-4a07-b0e8-da3610035a92": {
+ "path": "ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
+ "cellName": "HTTP Response",
+ "cellId": "ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
+ "visible": true
+ },
+ "generated-edge-simstep-33e5b4e9-bd66-45f5-ab0f-543737810b99-ec5d6b90-2f5f-4a07-b0e8-da3610035a92": {
+ "path": "generated-edge-simstep-33e5b4e9-bd66-45f5-ab0f-543737810b99-ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
+ "fileName": "client.py",
+ "cellName": "HTTP Response",
+ "cellId": "ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
+ "visible": true,
+ "startLine": 337,
+ "endLine": 338,
+ "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
+ "parentPath": "aw-client/aw_client/client.py",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "33e5b4e9-bd66-45f5-ab0f-543737810b99"
+ }
+ ]
+ },
+ "c8cbde86-13c0-4232-898e-104d815a805c": {
+ "path": "c8cbde86-13c0-4232-898e-104d815a805c",
+ "cellName": "Return Result\nto Script",
+ "cellId": "c8cbde86-13c0-4232-898e-104d815a805c",
+ "visible": true,
+ "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793"
+ },
+ "generated-edge-simstep-65443293-5e86-4e71-9e8d-19d61bd162d9-c8cbde86-13c0-4232-898e-104d815a805c": {
+ "path": "generated-edge-simstep-65443293-5e86-4e71-9e8d-19d61bd162d9-c8cbde86-13c0-4232-898e-104d815a805c",
+ "fileName": "working_hours.py",
+ "cellName": "Return Result to Script",
+ "cellId": "c8cbde86-13c0-4232-898e-104d815a805c",
+ "visible": true,
+ "startLine": 86,
+ "endLine": 86,
+ "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
+ "parentPath": "aw-client/examples/working_hours.py",
+ "simSteps": [
+ {
+ "simulationKey": "How custom scripting with the client library works",
+ "simStepId": "65443293-5e86-4e71-9e8d-19d61bd162d9"
+ }
+ ]
+ }
+ },
+ "simulations": {
+ "How automated application and window time tracking works": {
+ "name": "How automated application and window time tracking works",
+ "simSteps": [
+ {
+ "simStepId": "caf92190-4958-42b9-b962-d21c9ff6c62d",
+ "diagramNodeId": "638a5f20-935f-4345-8eaf-dfcd2aa6efb4",
+ "simStepLabel": "Watcher Initialization",
+ "simStepDescription": "The `aw-watcher-window` process starts. It parses arguments, sets up logging, and initializes the `ActivityWatchClient`. It also ensures a bucket for storing window activity exists on the server.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/main.py",
+ "startLine": "62",
+ "endLine": "69",
+ "relevantVariables": [
+ "ActivityWatchClient",
+ "client",
+ "bucket_id",
+ "event_type"
+ ]
+ },
+ "inputDataExample": "null",
+ "outputDataExample": "{\n \"client_name\": \"aw-watcher-window\",\n \"hostname\": \"my-desktop\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event_type\": \"currentwindow\",\n \"queued\": true,\n \"poll_time\": 1.0\n}"
+ },
+ {
+ "simStepId": "39835fd9-a301-482d-8b6d-9d16abbbaa29",
+ "diagramNodeId": "6d9c0750-fa20-47af-9135-6cc6444cb6b0",
+ "simStepLabel": "Start Heartbeat Loop",
+ "simStepDescription": "The main function enters the `heartbeat_loop`, which will periodically poll for the active window information.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/main.py",
+ "startLine": "98",
+ "endLine": "109",
+ "relevantVariables": [
+ "heartbeat_loop"
+ ]
+ },
+ "inputDataExample": "{\n \"client\": \"\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"poll_time\": 1.0\n}",
+ "outputDataExample": "{\n \"client\": \"\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"poll_time\": 1.0\n}"
+ },
+ {
+ "simStepId": "3e57e810-18fe-461f-a33c-f3eb0773ecf5",
+ "diagramNodeId": "89c12f0e-0649-4963-8e57-d7fd7da30bc4",
+ "simStepLabel": "Get Current Window Information",
+ "simStepDescription": "Inside the loop, the `get_current_window` function is called. This function acts as a dispatcher, calling the appropriate OS-specific implementation to get the currently focused application and window title.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/lib.py",
+ "startLine": "58",
+ "endLine": "73",
+ "relevantVariables": [
+ "get_current_window",
+ "get_current_window_linux",
+ "get_current_window_macos",
+ "get_current_window_windows"
+ ]
+ },
+ "inputDataExample": "{\n \"strategy\": \"xlib\"\n}",
+ "outputDataExample": "{\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n}"
+ },
+ {
+ "simStepId": "81f5cf5a-47ed-4fce-9c97-27559b1c7976",
+ "diagramNodeId": "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
+ "simStepLabel": "Create Window Event",
+ "simStepDescription": "The application name and title are used to create an `Event` object, which represents the user's current activity at this point in time.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/main.py",
+ "startLine": "154",
+ "endLine": "155",
+ "relevantVariables": [
+ "Event",
+ "current_window_event"
+ ]
+ },
+ "inputDataExample": "{\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n}",
+ "outputDataExample": "{\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": 0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}"
+ },
+ {
+ "simStepId": "706e836d-c3e2-4048-9eae-95e761ca9ffa",
+ "diagramNodeId": "30328419-4cc4-4ea2-a7fb-1728782b23aa",
+ "simStepLabel": "Send Heartbeat via Client",
+ "simStepDescription": "The created event is sent as a heartbeat to the `aw-server` using the `ActivityWatchClient`. The `queued=True` parameter enables local event merging and a persistent queue for offline robustness.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/main.py",
+ "startLine": "160",
+ "endLine": "162",
+ "relevantVariables": [
+ "client.heartbeat"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": 0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"pulsetime\": 2.0,\n \"queued\": true\n}",
+ "outputDataExample": "null"
+ },
+ {
+ "simStepId": "11bc8b75-0103-4652-9fec-e55af41400a0",
+ "diagramNodeId": "78766ca9-9103-486a-8755-f57a09e7f5a7",
+ "simStepLabel": "Local Heartbeat Pre-Merging",
+ "simStepDescription": "The `aw-client` library attempts to merge the new heartbeat with the previous one if the data is identical and it's within the `pulsetime` window. If merging occurs and the total duration is less than the `commit_interval`, the event is held locally. Otherwise, it's added to a request queue for sending to the server.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "244",
+ "endLine": "259",
+ "relevantVariables": [
+ "heartbeat_merge",
+ "last_heartbeat",
+ "self.request_queue"
+ ]
+ },
+ "inputDataExample": "{\n \"last_heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"0s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"new_heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": \"0s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"pulsetime\": 2.0\n}",
+ "outputDataExample": "{\n \"last_heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"0s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"new_heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": \"0s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"pulsetime\": 2.0\n}"
+ },
+ {
+ "simStepId": "432d1978-befd-4dfd-979b-fe28821d4e00",
+ "diagramNodeId": "82482fcc-b698-4f91-a27c-a4110d012d99",
+ "simStepLabel": "Queue and Dispatch Request",
+ "simStepDescription": "The `RequestQueue` thread picks up the heartbeat request. It formats an HTTP POST request to the server's heartbeat API endpoint: `/api/0/buckets/{bucket_id}/heartbeat`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "531",
+ "endLine": "533",
+ "relevantVariables": [
+ "RequestQueue._dispatch_request",
+ "self.client._post"
+ ]
+ },
+ "inputDataExample": "{\n \"endpoint\": \"/api/0/buckets/aw-watcher-window_my-desktop/heartbeat?pulsetime=2.0\",\n \"data\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
+ "outputDataExample": "{\n \"method\": \"POST\",\n \"url\": \"http://localhost:5600/api/0/buckets/aw-watcher-window_my-desktop/heartbeat?pulsetime=2.0\",\n \"headers\": {\n \"Content-Type\": \"application/json\"\n },\n \"body\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
+ },
+ {
+ "simStepId": "97f58e0a-cbeb-4895-b613-d8e9fd129a42",
+ "diagramNodeId": "5a7fba44-6d4d-4836-bc13-ed69518c9d45",
+ "simStepLabel": "API Call: Heartbeat Received",
+ "simStepDescription": "The `aw-server` receives the HTTP POST request at the heartbeat endpoint. The Flask-RESTX framework routes this to the `HeartbeatResource`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "272",
+ "endLine": "276",
+ "relevantVariables": [
+ "HeartbeatResource"
+ ]
+ },
+ "inputDataExample": "{\n \"url\": \"/api/0/buckets/aw-watcher-window_my-desktop/heartbeat?pulsetime=2.0\",\n \"body\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
+ "outputDataExample": "{\n \"url\": \"/api/0/buckets/aw-watcher-window_my-desktop/heartbeat?pulsetime=2.0\",\n \"body\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
+ },
+ {
+ "simStepId": "addb33f5-b815-49f0-9b54-a8ee3fb3b87b",
+ "diagramNodeId": "2217c8ca-4cbb-4721-acb9-1057b3b16d69",
+ "simStepLabel": "Server-Side Heartbeat Logic",
+ "simStepDescription": "The `HeartbeatResource`'s `post` method calls the `api.heartbeat` function, which contains the main server-side logic. It fetches the last event from the bucket and determines if the new heartbeat should be merged with it (by extending its duration) or if a new event should be created.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "254",
+ "endLine": "337",
+ "relevantVariables": [
+ "ServerAPI.heartbeat",
+ "heartbeat_merge",
+ "self.db"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": 0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"pulsetime\": 2.0\n}",
+ "outputDataExample": "{\n \"merged_event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"1s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
+ },
+ {
+ "simStepId": "cd6c54a5-c0bd-4b99-9446-ea921ee876a6",
+ "diagramNodeId": "6a5be6b6-e11d-460d-8193-427f3a9e42ac",
+ "simStepLabel": "Data to Datastore",
+ "simStepDescription": "The API layer sends the merged or new event to the datastore abstraction layer to be persisted.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "314",
+ "endLine": "335",
+ "relevantVariables": [
+ "self.db[bucket_id].replace_last",
+ "self.db[bucket_id].insert"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"1s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
+ "outputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"1s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
+ },
+ {
+ "simStepId": "5573707d-aa48-4a66-a3dc-25c841986d39",
+ "diagramNodeId": "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a",
+ "simStepLabel": "Persist Event to Database",
+ "simStepDescription": "The `datastore`'s `Bucket` object calls the appropriate method on the configured storage strategy (e.g., `PeeweeStorage`). If merging, `replace_last` is used to update the last event. If it's a new event, `insert` is used.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_datastore/datastore.py",
+ "startLine": "127",
+ "endLine": "188",
+ "relevantVariables": [
+ "Bucket.insert",
+ "Bucket.replace_last"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event_to_replace_with\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"1s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
+ "outputDataExample": "{\n \"success\": true\n}"
+ },
+ {
+ "simStepId": "960cb01a-addf-4a23-a3d6-c1f868b3524d",
+ "diagramNodeId": "",
+ "simStepLabel": "SQL Execution",
+ "simStepDescription": "The Peewee storage backend translates the high-level `insert` or `replace_last` call into specific SQL statements (INSERT OR REPLACE, or UPDATE) that are executed against the SQLite database file.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_datastore/storages/peewee.py",
+ "startLine": "293",
+ "endLine": "300",
+ "relevantVariables": [
+ "PeeweeStorage.replace_last",
+ "self._get_last",
+ "e.save"
+ ]
+ },
+ "inputDataExample": "{\n \"operation\": \"replace_last\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
+ "outputDataExample": "{\n \"operation\": \"replace_last\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
+ }
+ ],
+ "description": "- A dedicated watcher module (
aw-watcher-window) runs in the background to monitor user activity - It periodically polls the operating system to get the currently focused application name (e
- g
- , 'chrome
- exe') and the title of the active window
- This information is packaged into an
Event object and sent as a heartbeat to the aw-server via the client library - The server stores these events in a specific
bucket for the watcher, creating a continuous timeline of application usage - This process is designed to be cross-platform, with specific implementations for Windows, macOS, and Linux
",
+ "simulationNodesAndEdges": {
+ "638a5f20-935f-4345-8eaf-dfcd2aa6efb4": {
+ "simStepIds": [
+ "caf92190-4958-42b9-b962-d21c9ff6c62d"
+ ]
+ },
+ "89c12f0e-0649-4963-8e57-d7fd7da30bc4": {
+ "simStepIds": [
+ "3e57e810-18fe-461f-a33c-f3eb0773ecf5"
+ ]
+ },
+ "30328419-4cc4-4ea2-a7fb-1728782b23aa": {
+ "simStepIds": [
+ "706e836d-c3e2-4048-9eae-95e761ca9ffa"
+ ]
+ },
+ "82482fcc-b698-4f91-a27c-a4110d012d99": {
+ "simStepIds": [
+ "432d1978-befd-4dfd-979b-fe28821d4e00"
+ ]
+ },
+ "2217c8ca-4cbb-4721-acb9-1057b3b16d69": {
+ "simStepIds": [
+ "addb33f5-b815-49f0-9b54-a8ee3fb3b87b"
+ ]
+ },
+ "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a": {
+ "simStepIds": [
+ "5573707d-aa48-4a66-a3dc-25c841986d39"
+ ]
+ },
+ "6d9c0750-fa20-47af-9135-6cc6444cb6b0": {
+ "simStepIds": [
+ "39835fd9-a301-482d-8b6d-9d16abbbaa29"
+ ]
+ },
+ "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26": {
+ "simStepIds": [
+ "81f5cf5a-47ed-4fce-9c97-27559b1c7976"
+ ]
+ },
+ "78766ca9-9103-486a-8755-f57a09e7f5a7": {
+ "simStepIds": [
+ "11bc8b75-0103-4652-9fec-e55af41400a0"
+ ]
+ },
+ "5a7fba44-6d4d-4836-bc13-ed69518c9d45": {
+ "simStepIds": [
+ "97f58e0a-cbeb-4895-b613-d8e9fd129a42"
+ ]
+ },
+ "6a5be6b6-e11d-460d-8193-427f3a9e42ac": {
+ "simStepIds": [
+ "cd6c54a5-c0bd-4b99-9446-ea921ee876a6"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "aw-watcher-window, get_current_window, heartbeat, ActivityWatchClient, Event",
+ "generationPrompt": "How automated application and window time tracking works",
+ "generationKeywords": "aw-watcher-window, get_current_window, heartbeat, ActivityWatchClient, Event",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 19,
+ "promptTokenCount": 14219,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 124,
+ "promptTokenCount": 90775,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 67,
+ "promptTokenCount": 47327,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": [
+ {
+ "path": "aw-server-rust/aw-server/src/endpoints/import.rs",
+ "container": "server",
+ "triggerType": "http",
+ "identifier": "application/json"
+ }
+ ]
+ },
+ "crossLayerTriggers": [
+ {
+ "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "identifier": "application/json",
+ "type": "http",
+ "matchedTargets": [
+ ".github/workflows/test.yml",
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "aw-server-rust/aw-server/src/endpoints/import.rs"
+ ]
+ }
+ ]
+ }
+ },
+ "How activity data visualization works": {
+ "name": "How activity data visualization works",
+ "simSteps": [
+ {
+ "simStepId": "81f31a9b-3434-4458-a7d3-bdcf610af75e",
+ "diagramNodeId": "12f9554d-dd4e-4f66-bd20-8845b718ef19",
+ "simStepLabel": "Client-side: Construct Activity Query",
+ "simStepDescription": "The user accesses the ActivityWatch web UI. The frontend constructs a query using the ActivityWatch Query Language to fetch and process data for the main dashboard visualization. This query is designed to get window and AFK (Away From Keyboard) events, filter out AFK periods, categorize activities based on rules, and aggregate the results.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/queries.py",
+ "startLine": "243",
+ "endLine": "301",
+ "relevantVariables": [
+ "fullDesktopQuery",
+ "canonicalEvents"
+ ]
+ },
+ "inputDataExample": "{\n \"hostname\": \"my-desktop\",\n \"timeRange\": {\n \"start\": \"2023-10-26T00:00:00Z\",\n \"end\": \"2023-10-27T00:00:00Z\"\n }\n}",
+ "outputDataExample": "{\n \"query\": \"\\n events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\\n not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\\n not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\\n events = filter_period_intersect(events, not_afk);\\n events = categorize(events, [[\\\"Work\\\", {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"GitHub|Stack Overflow\\\"}]]);\\n title_events = sort_by_duration(merge_events_by_keys(events, [\\\"app\\\", \\\"title\\\"]));\\n app_events = sort_by_duration(merge_events_by_keys(title_events, [\\\"app\\\"]));\\n cat_events = sort_by_duration(merge_events_by_keys(events, [\\\"$category\\\"]));\\n duration = sum_durations(events);\\n RETURN = {\\\"events\\\": events, \\\"window\\\": {\\\"app_events\\\": app_events, \\\"title_events\\\": title_events, \\\"cat_events\\\": cat_events, \\\"duration\\\": duration}};\\n \"\n}"
+ },
+ {
+ "simStepId": "c1a26d9b-d661-4a99-8275-39a414824ed6",
+ "diagramNodeId": "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
+ "simStepLabel": "API Call: POST /api/0/query/",
+ "simStepDescription": "The client sends the generated query string and the desired time periods to the `aw-server` via an HTTP POST request to the `/api/0/query/` endpoint.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "305",
+ "endLine": "339",
+ "relevantVariables": [
+ "query"
+ ]
+ },
+ "inputDataExample": "{\n \"timeperiods\": [\n \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n ],\n \"query\": [\n \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\",\n \"not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\",\n \"not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\",\n \"events = filter_period_intersect(events, not_afk);\",\n \"events = categorize(events, [[\\\"Work\\\", {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"GitHub|Stack Overflow\\\"}]]);\",\n \"RETURN = events;\"\n ]\n}",
+ "outputDataExample": "{\n \"timeperiods\": [\n \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n ],\n \"query\": [\n \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\",\n \"not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\",\n \"not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\",\n \"events = filter_period_intersect(events, not_afk);\",\n \"events = categorize(events, [[\\\"Work\\\", {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"GitHub|Stack Overflow\\\"}]]);\",\n \"RETURN = events;\"\n ]\n}"
+ },
+ {
+ "simStepId": "e91513ab-13ec-4eea-9942-9620dbe3b92b",
+ "diagramNodeId": "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1",
+ "simStepLabel": "Backend: Receive Query Request",
+ "simStepDescription": "The `aw-server-rust` (or the Python equivalent `aw-server`) receives the POST request. The `/api/0/query` endpoint deserializes the JSON body into a `Query` struct containing the query statements and time intervals.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "9",
+ "endLine": "23",
+ "relevantVariables": [
+ "query"
+ ]
+ },
+ "inputDataExample": "{\n \"timeperiods\": [\n \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n ],\n \"query\": [\n \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\",\n \"not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\",\n \"not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\",\n \"events = filter_period_intersect(events, not_afk);\",\n \"RETURN = events;\"\n ]\n}",
+ "outputDataExample": "{\n \"query_code\": \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\\nnot_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\\n...\",\n \"intervals\": [\n \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n ]\n}"
+ },
+ {
+ "simStepId": "a7b6aefb-1401-4756-bfa1-1eb9a76cde07",
+ "diagramNodeId": "c8403507-4895-4695-84b5-9305afdc3c9f",
+ "simStepLabel": "API Endpoint -> Query Engine",
+ "simStepDescription": "The API endpoint joins the query lines into a single string and passes it, along with the time interval and a datastore reference, to the `aw_query::query` function for execution.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "16",
+ "endLine": "16",
+ "relevantVariables": [
+ "aw_query::query"
+ ]
+ },
+ "inputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_my-desktop\\\"); RETURN = events;\",\n \"interval\": \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n}",
+ "outputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_my-desktop\\\"); RETURN = events;\",\n \"interval\": \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n}"
+ },
+ {
+ "simStepId": "3291e01a-482d-401b-98b5-759573be65ca",
+ "diagramNodeId": "a9279dbc-8fda-434c-bc5a-4eefaca0df56",
+ "simStepLabel": "Query Engine: Parse and Interpret",
+ "simStepDescription": "The `aw_query::query` function orchestrates the execution. It first uses a lexer to tokenize the query string, then a parser to build an Abstract Syntax Tree (AST). Finally, it invokes the interpreter to execute the AST.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/lib.rs",
+ "startLine": "53",
+ "endLine": "64",
+ "relevantVariables": [
+ "query",
+ "lexer::Lexer",
+ "parser::parse",
+ "interpret::interpret_prog"
+ ]
+ },
+ "inputDataExample": "{\n \"code\": \"events = query_bucket(\\\"aw-watcher-window_my-desktop\\\"); RETURN = events;\",\n \"ti\": \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n}",
+ "outputDataExample": "{\n \"program\": {\n \"stmts\": [\n {\n \"node\": \"Assign(\\\"events\\\", Function(\\\"query_bucket\\\", List([String(\\\"aw-watcher-window_my-desktop\\\")])))\"\n },\n {\n \"node\": \"Return(Var(\\\"events\\\"))\"\n }\n ]\n }\n}"
+ },
+ {
+ "simStepId": "00784ae1-bb99-494c-bf46-fe5947de5066",
+ "diagramNodeId": "8f8d2c55-63c0-48ec-b931-f848e245688f",
+ "simStepLabel": "Interpreter -> `query_bucket`",
+ "simStepDescription": "While traversing the AST, the interpreter encounters the `query_bucket` function call. It resolves this function from its environment of built-in functions and prepares to execute it.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/interpret.rs",
+ "startLine": "213",
+ "endLine": "226",
+ "relevantVariables": [
+ "Function(fname, e)",
+ "fun(args, env, ds)"
+ ]
+ },
+ "inputDataExample": "{\n \"functionName\": \"query_bucket\",\n \"args\": [\n \"aw-watcher-window_my-desktop\"\n ]\n}",
+ "outputDataExample": "{\n \"functionName\": \"query_bucket\",\n \"args\": [\n \"aw-watcher-window_my-desktop\"\n ]\n}"
+ },
+ {
+ "simStepId": "475886bc-26d3-4528-84ae-2f9c8e1dfcf9",
+ "diagramNodeId": "be2c99a2-8b27-487f-9c8f-e1d1836613cc",
+ "simStepLabel": "Execute `query_bucket`",
+ "simStepDescription": "The `query_bucket` function is executed. It reads the time interval from its environment and makes a call to the datastore's `get_events` method to fetch raw event data from the specified bucket.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/functions.rs",
+ "startLine": "139",
+ "endLine": "168",
+ "relevantVariables": [
+ "qfunctions::query_bucket",
+ "ds.get_events"
+ ]
+ },
+ "inputDataExample": "{\n \"args\": [\n \"aw-watcher-window_my-desktop\"\n ],\n \"env\": {\n \"TIMEINTERVAL\": \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n }\n}",
+ "outputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"startTime\": \"2023-10-26T00:00:00Z\",\n \"endTime\": \"2023-10-27T00:00:00Z\"\n}"
+ },
+ {
+ "simStepId": "e1bf9f3c-e763-4e75-8c62-1a8d739d53cc",
+ "diagramNodeId": "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
+ "simStepLabel": "`query_bucket` -> Datastore",
+ "simStepDescription": "The call to `get_events` is sent to the datastore worker thread, which will translate it into a database query.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "startLine": "414",
+ "endLine": "430",
+ "relevantVariables": [
+ "get_events"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"starttime_opt\": \"2023-10-26T00:00:00Z\",\n \"endtime_opt\": \"2023-10-27T00:00:00Z\",\n \"limit_opt\": -1\n}",
+ "outputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"starttime_opt\": \"2023-10-26T00:00:00Z\",\n \"endtime_opt\": \"2023-10-27T00:00:00Z\",\n \"limit_opt\": -1\n}"
+ },
+ {
+ "simStepId": "ff017206-8323-4caa-9eca-4fc760c2470f",
+ "diagramNodeId": "48d1c5e2-32b3-4eaf-9005-dd0a65a77448",
+ "simStepLabel": "Datastore: Retrieve Events from SQLite",
+ "simStepDescription": "The `aw-datastore` component executes a `SELECT` query against its SQLite database. It retrieves all events from the `aw-watcher-window_my-desktop` bucket that fall within the specified time range.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "startLine": "700",
+ "endLine": "797",
+ "relevantVariables": [
+ "get_events",
+ "stmt.query_map"
+ ]
+ },
+ "inputDataExample": "{\n \"sql\": \"SELECT id, starttime, endtime, datastr FROM events WHERE bucketrow = (SELECT rowid FROM buckets WHERE id = ?) AND endtime >= ? AND starttime <= ? ORDER BY starttime DESC LIMIT ?\",\n \"params\": [\n 1,\n 1698278400000000000,\n 1698364800000000000,\n -1\n ]\n}",
+ "outputDataExample": "{\n \"rows\": [\n {\n \"id\": 101,\n \"timestamp\": \"2023-10-26T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\"app\": \"Code\", \"title\": \"README.md\"}\n },\n {\n \"id\": 102,\n \"timestamp\": \"2023-10-26T10:05:00Z\",\n \"duration\": 600,\n \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch Documentation\"}\n }\n ]\n}"
+ },
+ {
+ "simStepId": "f7dfb334-099f-4750-a893-cd96b1c46278",
+ "diagramNodeId": "7a14a4d3-a453-4e33-9b10-fb192e40e34e",
+ "simStepLabel": "Datastore -> Query Engine",
+ "simStepDescription": "The raw event data is returned from the datastore, through the `query_bucket` function, and back to the interpreter as a list of `DataType::Event`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/functions.rs",
+ "startLine": "163",
+ "endLine": "167",
+ "relevantVariables": [
+ "ret"
+ ]
+ },
+ "inputDataExample": "[\n {\n \"id\": 101,\n \"timestamp\": \"2023-10-26T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\"app\": \"Code\", \"title\": \"README.md\"}\n },\n {\n \"id\": 102,\n \"timestamp\": \"2023-10-26T10:05:00Z\",\n \"duration\": 600,\n \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch Documentation\"}\n }\n]",
+ "outputDataExample": "[\n {\n \"id\": 101,\n \"timestamp\": \"2023-10-26T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\"app\": \"Code\", \"title\": \"README.md\"}\n },\n {\n \"id\": 102,\n \"timestamp\": \"2023-10-26T10:05:00Z\",\n \"duration\": 600,\n \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch Documentation\"}\n }\n]"
+ },
+ {
+ "simStepId": "50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10",
+ "diagramNodeId": "48a7e119-b25c-4b9f-9a95-bd649493ff48",
+ "simStepLabel": "Transform: Filter AFK Periods",
+ "simStepDescription": "The interpreter continues executing the query, calling transformation functions like `filter_period_intersect`. This function takes the window activity events and intersects them with the 'not-afk' events, effectively removing any time the user was away from the keyboard.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-transform/src/filter_period.rs",
+ "startLine": "20",
+ "endLine": "69",
+ "relevantVariables": [
+ "filter_period_intersect"
+ ]
+ },
+ "inputDataExample": "{\n \"events\": [\n {\"timestamp\": \"2023-10-26T10:00:00Z\", \"duration\": 1200, \"data\": {\"app\": \"Code\"}}\n ],\n \"filter_events\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 600, \"data\": {\"status\": \"not-afk\"}}\n ]\n}",
+ "outputDataExample": "{\n \"filtered_events\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 600, \"data\": {\"app\": \"Code\"}}\n ]\n}"
+ },
+ {
+ "simStepId": "78aaa465-8377-43f1-9ba6-36ddcf9300cf",
+ "diagramNodeId": "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
+ "simStepLabel": "Return Transformed Data",
+ "simStepDescription": "The list of filtered, non-AFK events is returned to the interpreter. This data is then passed to subsequent transformation functions specified in the query, such as `categorize` or `merge_events_by_keys`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/interpret.rs",
+ "startLine": "36",
+ "endLine": "228",
+ "relevantVariables": [
+ "interpret_expr"
+ ]
+ },
+ "inputDataExample": "{\n \"filtered_events\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 600, \"data\": {\"app\": \"Code\"}}\n ]\n}",
+ "outputDataExample": "{\n \"filtered_events\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 600, \"data\": {\"app\": \"Code\"}}\n ]\n}"
+ },
+ {
+ "simStepId": "18492fe4-5b57-4749-a2e8-d18f3c546e89",
+ "diagramNodeId": "63ebaed0-610a-46cd-8a5b-392c2874aecb",
+ "simStepLabel": "Final Aggregation and Return",
+ "simStepDescription": "The interpreter completes the query by performing final aggregations like `merge_events_by_keys` and `sort_by_duration`. It assembles the results into a final dictionary structure as defined by the `RETURN` statement in the query script.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/interpret.rs",
+ "startLine": "30",
+ "endLine": "33",
+ "relevantVariables": [
+ "env.remove(\"RETURN\")"
+ ]
+ },
+ "inputDataExample": "{\n \"events_to_aggregate\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 300, \"data\": {\"app\": \"Code\", \"title\": \"File A\"}},\n {\"timestamp\": \"2023-10-26T10:10:00Z\", \"duration\": 300, \"data\": {\"app\": \"Code\", \"title\": \"File B\"}}\n ]\n}",
+ "outputDataExample": "{\n \"window\": {\n \"app_events\": [\n {\"data\": {\"app\": \"Code\"}, \"duration\": 600}\n ],\n \"duration\": 600\n }\n}"
+ },
+ {
+ "simStepId": "785d1355-bf16-42a7-846e-a2bf3ecbb35b",
+ "diagramNodeId": "889f0869-2c33-499b-a558-ede80ee18a54",
+ "simStepLabel": "API Response: Send Processed Data",
+ "simStepDescription": "The query engine returns the final aggregated data to the API endpoint. The endpoint serializes this data into a JSON format and sends it back to the web client as the HTTP response.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "28",
+ "endLine": "28",
+ "relevantVariables": [
+ "json!(results)"
+ ]
+ },
+ "inputDataExample": "{\n \"window\": {\n \"app_events\": [\n {\"data\": {\"app\": \"Code\", \"title\": \"...\"}, \"duration\": 1800}\n ],\n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\", \"Programming\"]}, \"duration\": 1800}\n ]\n }\n}",
+ "outputDataExample": "{\n \"window\": {\n \"app_events\": [\n {\"data\": {\"app\": \"Code\", \"title\": \"...\"}, \"duration\": 1800}\n ],\n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\", \"Programming\"]}, \"duration\": 1800}\n ]\n }\n}"
+ },
+ {
+ "simStepId": "9396ef3a-ed06-4635-bb1d-3b136660bcc4",
+ "diagramNodeId": "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd",
+ "simStepLabel": "Frontend: Render Dashboard",
+ "simStepDescription": "The `aw-webui` frontend receives the JSON data. Its JavaScript code then processes this data to render the various visualizations on the activity dashboard, such as the top applications and categories pie charts, and the activity timeline.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "README.md",
+ "startLine": "243",
+ "endLine": "250",
+ "relevantVariables": [
+ "The frontend (`aw-webui`) includes",
+ "Data visualization"
+ ]
+ },
+ "inputDataExample": "{\n \"window\": {\n \"app_events\": [\n {\"data\": {\"app\": \"Code\"}, \"duration\": 1800},\n {\"data\": {\"app\": \"Firefox\"}, \"duration\": 1200}\n ],\n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\", \"Programming\"]}, \"duration\": 1800},\n {\"data\": {\"$category\": [\"Media\", \"Video\"]}, \"duration\": 900}\n ]\n }\n}",
+ "outputDataExample": "{\n \"dashboardState\": {\n \"topApps\": [{\"label\": \"Code\", \"value\": 1800}, {\"label\": \"Firefox\", \"value\": 1200}],\n \"topCategories\": [{\"label\": \"Work > Programming\", \"value\": 1800}, {\"label\": \"Media > Video\", \"value\": 900}]\n }\n}"
+ }
+ ],
+ "description": "- The
aw-server is responsible for serving a web-based user interface, aw-webui - Users can access this interface, typically at
localhost:5600, to view their tracked data - The web UI sends API requests to the server, using the ActivityWatch Query Language to fetch and process data for display
- Key visualization features include a main activity dashboard showing top applications and categories, a detailed zoomable timeline of events, and a raw data browser
",
+ "simulationNodesAndEdges": {
+ "12f9554d-dd4e-4f66-bd20-8845b718ef19": {
+ "simStepIds": [
+ "81f31a9b-3434-4458-a7d3-bdcf610af75e"
+ ]
+ },
+ "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1": {
+ "simStepIds": [
+ "e91513ab-13ec-4eea-9942-9620dbe3b92b"
+ ]
+ },
+ "a9279dbc-8fda-434c-bc5a-4eefaca0df56": {
+ "simStepIds": [
+ "3291e01a-482d-401b-98b5-759573be65ca"
+ ]
+ },
+ "be2c99a2-8b27-487f-9c8f-e1d1836613cc": {
+ "simStepIds": [
+ "475886bc-26d3-4528-84ae-2f9c8e1dfcf9"
+ ]
+ },
+ "48d1c5e2-32b3-4eaf-9005-dd0a65a77448": {
+ "simStepIds": [
+ "ff017206-8323-4caa-9eca-4fc760c2470f"
+ ]
+ },
+ "48a7e119-b25c-4b9f-9a95-bd649493ff48": {
+ "simStepIds": [
+ "50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10"
+ ]
+ },
+ "63ebaed0-610a-46cd-8a5b-392c2874aecb": {
+ "simStepIds": [
+ "18492fe4-5b57-4749-a2e8-d18f3c546e89"
+ ]
+ },
+ "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd": {
+ "simStepIds": [
+ "9396ef3a-ed06-4635-bb1d-3b136660bcc4"
+ ]
+ },
+ "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f": {
+ "simStepIds": [
+ "c1a26d9b-d661-4a99-8275-39a414824ed6"
+ ]
+ },
+ "c8403507-4895-4695-84b5-9305afdc3c9f": {
+ "simStepIds": [
+ "a7b6aefb-1401-4756-bfa1-1eb9a76cde07"
+ ]
+ },
+ "8f8d2c55-63c0-48ec-b931-f848e245688f": {
+ "simStepIds": [
+ "00784ae1-bb99-494c-bf46-fe5947de5066"
+ ]
+ },
+ "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013": {
+ "simStepIds": [
+ "e1bf9f3c-e763-4e75-8c62-1a8d739d53cc"
+ ]
+ },
+ "7a14a4d3-a453-4e33-9b10-fb192e40e34e": {
+ "simStepIds": [
+ "f7dfb334-099f-4750-a893-cd96b1c46278"
+ ]
+ },
+ "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa": {
+ "simStepIds": [
+ "78aaa465-8377-43f1-9ba6-36ddcf9300cf"
+ ]
+ },
+ "889f0869-2c33-499b-a558-ede80ee18a54": {
+ "simStepIds": [
+ "785d1355-bf16-42a7-846e-a2bf3ecbb35b"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "aw-webui, aw-server, query, timeline, dashboard",
+ "generationPrompt": "How activity data visualization works",
+ "generationKeywords": "aw-webui, aw-server, query, timeline, dashboard",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 12,
+ "promptTokenCount": 8319,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 123,
+ "promptTokenCount": 96744,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 72,
+ "promptTokenCount": 53807,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": [
+ {
+ "path": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "container": "server",
+ "triggerType": "http",
+ "identifier": "application/json"
+ }
+ ]
+ },
+ "crossLayerTriggers": [
+ {
+ "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "identifier": "application/json",
+ "type": "http",
+ "matchedTargets": [
+ ".github/workflows/test.yml",
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "aw-server-rust/aw-server/src/endpoints/import.rs"
+ ]
+ }
+ ]
+ }
+ },
+ "How activity categorization works": {
+ "name": "How activity categorization works",
+ "simSteps": [
+ {
+ "simStepId": "1b40cfa3-9cf5-4dc3-830f-74cb1d476d50",
+ "diagramNodeId": "49029598-25ad-4498-b744-e2180f404fe5",
+ "simStepLabel": "Query Construction",
+ "simStepDescription": "A client application or script constructs a query to fetch and categorize events. The `canonicalEvents` function is often used, which includes a `categorize` step. The categorization rules (classes) can be provided directly or fetched from the server's settings.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/queries.py",
+ "startLine": "84",
+ "endLine": "151",
+ "relevantVariables": [
+ "canonicalEvents",
+ "params",
+ "classes_str",
+ "categorize"
+ ]
+ },
+ "inputDataExample": "{\n \"params\": {\n \"bid_window\": \"aw-watcher-window_my-pc\",\n \"bid_afk\": \"aw-watcher-afk_my-pc\",\n \"classes\": [\n [\n [\"Work\", \"Programming\"],\n {\"type\": \"regex\", \"regex\": \"Visual Studio Code|Sublime Text\", \"ignore_case\": true}\n ],\n [\n [\"Work\", \"Programming\", \"Rust\"],\n {\"type\": \"regex\", \"regex\": \"\\\\.rs|cargo\", \"ignore_case\": true}\n ]\n ]\n }\n}",
+ "outputDataExample": "{\n \"query\": \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-pc\\\")));\\nnot_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-pc\\\")));\\nnot_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\\nevents = filter_period_intersect(events, not_afk);\\nevents = categorize(events, [[\\\"Work\\\",\\\"Programming\\\"],{\\\"type\\\":\\\"regex\\\",\\\"regex\\\":\\\"Visual Studio Code|Sublime Text\\\",\\\"ignore_case\\\":true}],[\\\"Work\\\",\\\"Programming\\\",\\\"Rust\\\"],{\\\"type\\\":\\\"regex\\\",\\\"regex\\\":\\\"\\\\\\\\.rs|cargo\\\",\\\"ignore_case\\\":true}]]);\"\n}"
+ },
+ {
+ "simStepId": "9eeb592f-5c44-4ce1-a7a0-261bc6d6b679",
+ "diagramNodeId": "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
+ "simStepLabel": "API Call: Execute Query",
+ "simStepDescription": "The client sends the constructed query string to the ActivityWatch server's API endpoint for execution.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "119",
+ "endLine": "131",
+ "relevantVariables": [
+ "self.post"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": \"... events = categorize(events, [[\\\"Work\\\",\\\"Programming\\\"],{\\\"type\\\":\\\"regex\\\",\\\"regex\\\":\\\"Visual Studio Code|Sublime Text\\\",\\\"ignore_case\\\":true}]]); ...\",\n \"timeperiods\": [\"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"]\n}",
+ "outputDataExample": "{\n \"query\": \"... events = categorize(events, [[\\\"Work\\\",\\\"Programming\\\"],{\\\"type\\\":\\\"regex\\\",\\\"regex\\\":\\\"Visual Studio Code|Sublime Text\\\",\\\"ignore_case\\\":true}]]); ...\",\n \"timeperiods\": [\"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"]\n}"
+ },
+ {
+ "simStepId": "af6c51b2-ee18-406c-acc6-6e5d9588d012",
+ "diagramNodeId": "ff986e21-7050-4c3d-ae40-3a678f46221d",
+ "simStepLabel": "Query Engine: Function Invocation",
+ "simStepDescription": "The `aw-server-rust` query engine parses the query, recognizes the `categorize` function call, and invokes its registered implementation, passing the fetched events and rules as arguments.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/functions.rs",
+ "startLine": "278",
+ "endLine": "295",
+ "relevantVariables": [
+ "categorize",
+ "aw_transform::classify::categorize"
+ ]
+ },
+ "inputDataExample": "{\n \"args\": [\n {\n \"DataType::List\": [\"Event(...)\", \"Event(...)\"]\n },\n {\n \"DataType::List\": [\n [\n [\"Work\", \"Programming\"],\n {\"type\": \"regex\", \"regex\": \"Visual Studio Code\"}\n ]\n ]\n }\n ]\n}",
+ "outputDataExample": "{\n \"DataType::List\": [\"Event(categorized)\", \"Event(categorized)\"]\n}"
+ },
+ {
+ "simStepId": "e598a658-8e0e-4a76-9310-af0d60ec5828",
+ "diagramNodeId": "79c14e32-8192-488e-ab72-b9c4c6edb346",
+ "simStepLabel": "Data Transformation: Convert Rules",
+ "simStepDescription": "Before executing the core logic, the query engine converts the rule definitions from the generic `DataType::Dict` format into the strongly-typed `Rule` struct that the transform function expects.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/datatype.rs",
+ "startLine": "272",
+ "endLine": "346",
+ "relevantVariables": [
+ "TryFrom<&DataType> for Rule",
+ "RegexRule::new"
+ ]
+ },
+ "inputDataExample": "{\n \"DataType::Dict\": {\n \"type\": \"regex\",\n \"regex\": \"Visual Studio Code\",\n \"ignore_case\": true\n }\n}",
+ "outputDataExample": "{\n \"Rule::Regex\": {\n \"regex\": \"(?i)Visual Studio Code\"\n }\n}"
+ },
+ {
+ "simStepId": "55815d72-39f6-4201-ad99-6ebd57d0eece",
+ "diagramNodeId": "e99fcabc-934a-46cd-8823-d3e04ceea63c",
+ "simStepLabel": "Categorization Core Logic",
+ "simStepDescription": "The main `categorize` function iterates through each event and applies the list of rules to it by calling `categorize_one`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-transform/src/classify.rs",
+ "startLine": "70",
+ "endLine": "76",
+ "relevantVariables": [
+ "categorize",
+ "categorize_one"
+ ]
+ },
+ "inputDataExample": "{\n \"events\": [\n {\n \"timestamp\": \"2023-10-27T10:00:00Z\",\n \"duration\": 60,\n \"data\": {\"app\": \"Code\", \"title\": \"classify.rs - aw-server-rust\"}\n }\n ],\n \"rules\": [\n [\n [\"Work\", \"Programming\", \"Rust\"],\n {\"regex\": \"(?i)\\\\.rs|cargo\"}\n ]\n ]\n}",
+ "outputDataExample": "{\n \"classified_events\": [\n {\n \"timestamp\": \"2023-10-27T10:00:00Z\",\n \"duration\": 60,\n \"data\": {\n \"app\": \"Code\",\n \"title\": \"classify.rs - aw-server-rust\",\n \"$category\": [\"Work\", \"Programming\", \"Rust\"]\n }\n }\n ]\n}"
+ },
+ {
+ "simStepId": "9f7f50e4-03c6-4d7c-95c8-3317d37115eb",
+ "diagramNodeId": "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
+ "simStepLabel": "Event-Rule Matching",
+ "simStepDescription": "For each event, the system iterates through all provided rules and invokes the `matches` method to check if the rule's regex pattern can be found within any of the event's data fields.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-transform/src/classify.rs",
+ "startLine": "49",
+ "endLine": "57",
+ "relevantVariables": [
+ "RuleTrait for RegexRule",
+ "matches",
+ "self.regex.is_match"
+ ]
+ },
+ "inputDataExample": "{\n \"event\": {\n \"data\": {\"app\": \"Code\", \"title\": \"classify.rs - aw-server-rust\"}\n },\n \"rule\": {\n \"regex\": \"(?i)\\\\.rs|cargo\"\n }\n}",
+ "outputDataExample": "{\n \"event\": {\n \"data\": {\"app\": \"Code\", \"title\": \"classify.rs - aw-server-rust\"}\n },\n \"rule\": {\n \"regex\": \"(?i)\\\\.rs|cargo\"\n }\n}"
+ },
+ {
+ "simStepId": "e863b0b1-c3ce-4b13-ad7d-a7438f650035",
+ "diagramNodeId": "294c7beb-b479-47e2-bd3c-6d616497ecd2",
+ "simStepLabel": "Select Highest-Ranking Category",
+ "simStepDescription": "If an event matches multiple categories, this function selects the most specific one. Specificity is determined by the depth of the category hierarchy (e.g., `['Work', 'Programming', 'Rust']` is deeper than `['Work', 'Programming']`). If no rules match, a default category of `['Uncategorized']` is assigned.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-transform/src/classify.rs",
+ "startLine": "116",
+ "endLine": "122",
+ "relevantVariables": [
+ "_pick_highest_ranking_category"
+ ]
+ },
+ "inputDataExample": "{\n \"current_best_category\": [\"Work\", \"Programming\"],\n \"new_matching_category\": [\"Work\", \"Programming\", \"Rust\"]\n}",
+ "outputDataExample": "{\n \"chosen_category\": [\"Work\", \"Programming\", \"Rust\"]\n}"
+ },
+ {
+ "simStepId": "ebd328dc-4cdf-452d-b4aa-10b65e9c354d",
+ "diagramNodeId": "b4391f38-d9ee-4377-8568-efca87206124",
+ "simStepLabel": "Return Categorized Events",
+ "simStepDescription": "After processing all events, the modified list, now with a `$category` field in each event's data, is returned to the query engine. The server then serializes this as JSON and sends it back to the client.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-transform/src/classify.rs",
+ "startLine": "85",
+ "endLine": "88",
+ "relevantVariables": [
+ "event.data.insert"
+ ]
+ },
+ "inputDataExample": "{\n \"classified_events\": [\n {\n \"timestamp\": \"2023-10-27T10:00:00Z\",\n \"duration\": 60,\n \"data\": {\n \"app\": \"Code\",\n \"title\": \"classify.rs - aw-server-rust\",\n \"$category\": [\"Work\", \"Programming\", \"Rust\"]\n }\n }\n ]\n}",
+ "outputDataExample": "{\n \"classified_events\": [\n {\n \"timestamp\": \"2023-10-27T10:00:00Z\",\n \"duration\": 60,\n \"data\": {\n \"app\": \"Code\",\n \"title\": \"classify.rs - aw-server-rust\",\n \"$category\": [\"Work\", \"Programming\", \"Rust\"]\n }\n }\n ]\n}"
+ },
+ {
+ "simStepId": "2108914e-2569-47bf-aa87-af337de03f8c",
+ "diagramNodeId": "9847b0a7-39f2-44f8-ae14-73eab42d8894",
+ "simStepLabel": "Client Consumes Categorized Data",
+ "simStepDescription": "The client application receives the categorized events. It can then use the `$category` field to perform aggregations and generate reports, such as calculating the total time spent in each top-level category for the day.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "123",
+ "endLine": "130",
+ "relevantVariables": [
+ "cat_time",
+ "e[\"data\"][\"$category\"][0]"
+ ]
+ },
+ "inputDataExample": "{\n \"cat_events\": [\n {\n \"data\": {\"$category\": [\"Work\", \"Programming\", \"Rust\"]},\n \"duration\": 3600\n },\n {\n \"data\": {\"$category\": [\"Work\", \"Meetings\"]},\n \"duration\": 1800\n },\n {\n \"data\": {\"$category\": [\"Media\", \"Video\"]},\n \"duration\": 1200\n }\n ]\n}",
+ "outputDataExample": "{\n \"aggregated_time\": {\n \"Work\": \"1h 30m\",\n \"Media\": \"20m\"\n }\n}"
+ }
+ ],
+ "description": "- ActivityWatch allows users to transform raw data into meaningful insights through categorization
- This is achieved by defining rules, typically using regular expressions (
regex), that match against event data like window titles or application names - The
categorize function, used within the query language, applies these rules to events and assigns them to a category (e - g
- ,
Work, Programming) - These categories are then used in the web UI to generate aggregated reports, helping users understand how they spend their time across different life areas
",
+ "simulationNodesAndEdges": {
+ "49029598-25ad-4498-b744-e2180f404fe5": {
+ "simStepIds": [
+ "1b40cfa3-9cf5-4dc3-830f-74cb1d476d50"
+ ]
+ },
+ "ff986e21-7050-4c3d-ae40-3a678f46221d": {
+ "simStepIds": [
+ "af6c51b2-ee18-406c-acc6-6e5d9588d012"
+ ]
+ },
+ "e99fcabc-934a-46cd-8823-d3e04ceea63c": {
+ "simStepIds": [
+ "55815d72-39f6-4201-ad99-6ebd57d0eece"
+ ]
+ },
+ "294c7beb-b479-47e2-bd3c-6d616497ecd2": {
+ "simStepIds": [
+ "e863b0b1-c3ce-4b13-ad7d-a7438f650035"
+ ]
+ },
+ "9847b0a7-39f2-44f8-ae14-73eab42d8894": {
+ "simStepIds": [
+ "2108914e-2569-47bf-aa87-af337de03f8c"
+ ]
+ },
+ "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661": {
+ "simStepIds": [
+ "9eeb592f-5c44-4ce1-a7a0-261bc6d6b679"
+ ]
+ },
+ "79c14e32-8192-488e-ab72-b9c4c6edb346": {
+ "simStepIds": [
+ "e598a658-8e0e-4a76-9310-af0d60ec5828"
+ ]
+ },
+ "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8": {
+ "simStepIds": [
+ "9f7f50e4-03c6-4d7c-95c8-3317d37115eb"
+ ]
+ },
+ "b4391f38-d9ee-4377-8568-efca87206124": {
+ "simStepIds": [
+ "ebd328dc-4cdf-452d-b4aa-10b65e9c354d"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "categorize, Rule, regex, category, aw_transform/classify.py",
+ "generationPrompt": "How activity categorization works",
+ "generationKeywords": "categorize, Rule, regex, category, aw_transform/classify.py",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 11,
+ "promptTokenCount": 6843,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 13,
+ "promptTokenCount": 13255,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 16,
+ "promptTokenCount": 10044,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": []
+ }
+ }
+ },
+ "How the data query language works": {
+ "name": "How the data query language works",
+ "simSteps": [
+ {
+ "simStepId": "06f7c9e7-1c78-4114-867b-3dbb20dcc427",
+ "diagramNodeId": "5540d168-0892-4d44-a835-530768fbad09",
+ "simStepLabel": "Python Flow: Client Initiates API Query",
+ "simStepDescription": "A client application, using the `aw-client` library, constructs a query to fetch data from the ActivityWatch server. It specifies the query string and the time periods to analyze.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "305",
+ "endLine": "338",
+ "relevantVariables": [
+ "query",
+ "timeperiods",
+ "endpoint",
+ "data"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');\\nRETURN = events;\",\n \"timeperiods\": [\n {\n \"start\": \"2023-01-01T00:00:00Z\",\n \"end\": \"2023-01-02T00:00:00Z\"\n }\n ]\n}",
+ "outputDataExample": "{\n \"endpoint\": \"query/\",\n \"data\": {\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ]\n }\n}"
+ },
+ {
+ "simStepId": "5dc6bd77-15d2-44c3-b665-8de88288c314",
+ "diagramNodeId": "71408ae2-19e6-4327-bab9-8918af09c855",
+ "simStepLabel": "API Call: Transmit Query to Python Server",
+ "simStepDescription": "The client sends an HTTP POST request to the `/api/0/query/` endpoint of the `aw-server` (Python implementation), with the query and time periods in the request body.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "115",
+ "endLine": "127",
+ "relevantVariables": [
+ "_post"
+ ]
+ },
+ "inputDataExample": "{\n \"endpoint\": \"query/\",\n \"data\": {\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ]\n }\n}",
+ "outputDataExample": "{\n \"endpoint\": \"query/\",\n \"data\": {\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ]\n }\n}"
+ },
+ {
+ "simStepId": "671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7",
+ "diagramNodeId": "abf45adb-988a-4613-ab4a-acb8cef0c90a",
+ "simStepLabel": "Python Flow: API Endpoint Receives Request",
+ "simStepDescription": "The Flask-based `aw-server` receives the incoming POST request. The `/api/0/query/` route is handled by the `QueryResource`, which extracts the query payload from the request.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "310",
+ "endLine": "326",
+ "relevantVariables": [
+ "QueryResource",
+ "post",
+ "request",
+ "current_app.api.query2"
+ ]
+ },
+ "inputDataExample": "{\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ]\n}",
+ "outputDataExample": "{\n \"name\": \"\",\n \"query\": {\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ]\n },\n \"cache\": false\n}"
+ },
+ {
+ "simStepId": "5a0d9b17-b09a-4aa5-9234-c01cb2aadef4",
+ "diagramNodeId": "891bfe3a-f22a-4998-acea-aa6d0c362821",
+ "simStepLabel": "Data Flow: Pass Query to API Logic",
+ "simStepDescription": "The parsed query data is passed from the REST endpoint layer to the `ServerAPI` business logic layer for processing.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "320",
+ "endLine": "323",
+ "relevantVariables": [
+ "current_app.api.query2"
+ ]
+ },
+ "inputDataExample": "{\n \"name\": \"\",\n \"query\": {\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ]\n },\n \"cache\": false\n}",
+ "outputDataExample": "{\n \"name\": \"\",\n \"query\": {\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ]\n },\n \"cache\": false\n}"
+ },
+ {
+ "simStepId": "a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31",
+ "diagramNodeId": "96c3be58-d96a-4b11-b4f3-e778387f76b8",
+ "simStepLabel": "Python Flow: ServerAPI Orchestrates Query",
+ "simStepDescription": "The `ServerAPI.query2` method iterates through each specified time period and invokes the core query engine (`query2.query`) from `aw-core` for each one.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "339",
+ "endLine": "349",
+ "relevantVariables": [
+ "query2",
+ "timeperiods",
+ "starttime",
+ "endtime",
+ "query2.query"
+ ]
+ },
+ "inputDataExample": "{\n \"name\": \"\",\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"cache\": false\n}",
+ "outputDataExample": "{\n \"name\": \"\",\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');RETURN = events;\",\n \"starttime\": \"2023-01-01T00:00:00+00:00\",\n \"endtime\": \"2023-01-02T00:00:00+00:00\",\n \"datastore\": \"\"\n}"
+ },
+ {
+ "simStepId": "833f0f0f-ec00-4960-b1f9-46d8a8530a01",
+ "diagramNodeId": "b79b67f9-1be1-48f1-920a-9ebdd4417272",
+ "simStepLabel": "Data Flow: Pass Query to Interpreter",
+ "simStepDescription": "The raw query string, along with the time range and a datastore instance, is passed to the `query` function in `aw-core/aw_query/query2.py`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "348",
+ "endLine": "348",
+ "relevantVariables": [
+ "query2.query"
+ ]
+ },
+ "inputDataExample": "{\n \"name\": \"\",\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');RETURN = events;\",\n \"starttime\": \"2023-01-01T00:00:00+00:00\",\n \"endtime\": \"2023-01-02T00:00:00+00:00\",\n \"datastore\": \"\"\n}",
+ "outputDataExample": "{\n \"name\": \"\",\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');RETURN = events;\",\n \"starttime\": \"2023-01-01T00:00:00+00:00\",\n \"endtime\": \"2023-01-02T00:00:00+00:00\",\n \"datastore\": \"\"\n}"
+ },
+ {
+ "simStepId": "5f7b6985-edf0-42eb-8822-847d0d7b8e9b",
+ "diagramNodeId": "c0a28353-be8d-4bc8-a1be-2879961fc4df",
+ "simStepLabel": "Python Flow: Parse and Interpret Query",
+ "simStepDescription": "The `query` function in `aw-core/aw_query/query2.py` acts as the interpreter. It splits the query into individual statements, parses each one into tokens (like variables and function calls), and then interprets them chronologically. Function calls are resolved by looking them up in the `functions` dictionary, which is populated by functions in `aw-core/aw_query/functions.py`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_query/query2.py",
+ "startLine": "404",
+ "endLine": "418",
+ "relevantVariables": [
+ "query",
+ "parse",
+ "interpret"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');\\nRETURN = events;\"\n}",
+ "outputDataExample": "{\n \"statement\": \"events = query_bucket('aw-watcher-window_test-host')\",\n \"var\": \"\",\n \"val\": \"\"\n}"
+ },
+ {
+ "simStepId": "7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6",
+ "diagramNodeId": "4059fcbe-a1ee-41d0-b576-55a1d278bca0",
+ "simStepLabel": "Data Flow: Execute Query Function",
+ "simStepDescription": "During interpretation, a `QFunction` token for `query_bucket` is executed. The `interpret` method looks up `q2_query_bucket` in `aw-core/aw_query/functions.py` and calls it.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_query/query2.py",
+ "startLine": "133",
+ "endLine": "148",
+ "relevantVariables": [
+ "QFunction.interpret",
+ "functions"
+ ]
+ },
+ "inputDataExample": "{\n \"function_name\": \"query_bucket\",\n \"args\": [\n \"\",\n \"{'STARTTIME': '...', 'ENDTIME': '...'}\",\n \"aw-watcher-window_test-host\"\n ]\n}",
+ "outputDataExample": "{\n \"function_name\": \"query_bucket\",\n \"args\": [\n \"\",\n \"{'STARTTIME': '...', 'ENDTIME': '...'}\",\n \"aw-watcher-window_test-host\"\n ]\n}"
+ },
+ {
+ "simStepId": "6ea3ab36-027f-40b9-a0ba-9ede77ae1117",
+ "diagramNodeId": "fb0bcd2a-5999-47fc-bb41-11233e3544fa",
+ "simStepLabel": "Python Flow: Fetch Events from Datastore",
+ "simStepDescription": "The `q2_query_bucket` function interacts with the datastore to fetch events for the specified bucket and time range.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_query/functions.py",
+ "startLine": "151",
+ "endLine": "164",
+ "relevantVariables": [
+ "q2_query_bucket",
+ "datastore.get"
+ ]
+ },
+ "inputDataExample": "{\n \"bucketname\": \"aw-watcher-window_test-host\",\n \"starttime\": \"2023-01-01T00:00:00+00:00\",\n \"endtime\": \"2023-01-02T00:00:00+00:00\"\n}",
+ "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
+ },
+ {
+ "simStepId": "ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c",
+ "diagramNodeId": "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
+ "simStepLabel": "Data Flow: Return Events to Interpreter",
+ "simStepDescription": "The list of fetched events is returned from the datastore, through the `q2_query_bucket` function, and back to the `interpret` function.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_datastore/datastore.py",
+ "startLine": "88",
+ "endLine": "114",
+ "relevantVariables": [
+ "Bucket.get",
+ "self.ds.storage_strategy.get_events"
+ ]
+ },
+ "inputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
+ "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
+ },
+ {
+ "simStepId": "ab3fe2d5-9396-4241-b64e-2a187e97de75",
+ "diagramNodeId": "5eb14d26-499c-4ea4-8282-3f923646dbdb",
+ "simStepLabel": "Python Flow: Finalize and Return Result",
+ "simStepDescription": "The interpreter completes all statements. The `get_return` function is called to extract the final value assigned to the `RETURN` variable from the execution namespace.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_query/query2.py",
+ "startLine": "396",
+ "endLine": "401",
+ "relevantVariables": [
+ "get_return",
+ "namespace['RETURN']"
+ ]
+ },
+ "inputDataExample": "{\n \"namespace\": {\n \"STARTTIME\": \"...\",\n \"ENDTIME\": \"...\",\n \"events\": [{\"id\": 101, ...}],\n \"RETURN\": [{\"id\": 101, ...}]\n }\n}",
+ "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
+ },
+ {
+ "simStepId": "fe43857f-ef7d-455d-a9c4-37d54d12207a",
+ "diagramNodeId": "c4b6d403-d2a9-4cff-8a72-31189a53c0db",
+ "simStepLabel": "API Call: Send JSON Response",
+ "simStepDescription": "The final result is returned up the call stack to the `rest.py` endpoint, serialized into JSON, and sent back to the client as an HTTP response.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "323",
+ "endLine": "323",
+ "relevantVariables": [
+ "jsonify"
+ ]
+ },
+ "inputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
+ "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
+ },
+ {
+ "simStepId": "3118dc4c-d7ad-4996-aa81-a205ccdf6e72",
+ "diagramNodeId": "7ace16a3-9438-4e78-bcf9-79131079c89d",
+ "simStepLabel": "Rust Flow: Client Initiates API Query",
+ "simStepDescription": "A client application sends a query to the ActivityWatch server. This example uses the Rust client for consistency, but any HTTP client can be used.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-client-rust/src/blocking.rs",
+ "startLine": "64",
+ "endLine": "69",
+ "relevantVariables": [
+ "query"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\",\n \"timeperiods\": [\n {\n \"start\": \"2023-01-01T00:00:00Z\",\n \"end\": \"2023-01-02T00:00:00Z\"\n }\n ]\n}",
+ "outputDataExample": "{\n \"url\": \"http://127.0.0.1:5600/api/0/query\",\n \"body\": {\n \"query\": [\n \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00Z/2023-01-02T00:00:00Z\"\n ]\n }\n}"
+ },
+ {
+ "simStepId": "97542310-17cf-4c99-9ce9-a328dffa5f4c",
+ "diagramNodeId": "ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
+ "simStepLabel": "API Call: Transmit Query to Rust Server",
+ "simStepDescription": "The client sends an HTTP POST request to the `/api/0/query` endpoint of the `aw-server-rust` implementation, with the query and time periods in the request body.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-client-rust/src/lib.rs",
+ "startLine": "112",
+ "endLine": "137",
+ "relevantVariables": [
+ "query"
+ ]
+ },
+ "inputDataExample": "{\n \"url\": \"http://127.0.0.1:5600/api/0/query\",\n \"body\": {\n \"query\": [\n \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00Z/2023-01-02T00:00:00Z\"\n ]\n }\n}",
+ "outputDataExample": "{\n \"url\": \"http://127.0.0.1:5600/api/0/query\",\n \"body\": {\n \"query\": [\n \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00Z/2023-01-02T00:00:00Z\"\n ]\n }\n}"
+ },
+ {
+ "simStepId": "1c25a330-b713-4866-9440-8737c787ce33",
+ "diagramNodeId": "b93b83dd-fff3-44dc-ac22-3ea63117c222",
+ "simStepLabel": "Rust Flow: API Endpoint Receives Request",
+ "simStepDescription": "The Rocket-based `aw-server-rust` receives the request. The `query` endpoint in `endpoints/query.rs` deserializes the JSON payload into a `Query` struct and joins the query lines.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "9",
+ "endLine": "29",
+ "relevantVariables": [
+ "query",
+ "query_req",
+ "query_code",
+ "intervals"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": [\n \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00Z/2023-01-02T00:00:00Z\"\n ]\n}",
+ "outputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\",\n \"interval\": \"\"\n}"
+ },
+ {
+ "simStepId": "6eb126a9-5234-4495-9727-ec2741ce9660",
+ "diagramNodeId": "d3cb01a0-d8cd-4382-b122-d1234b0562bc",
+ "simStepLabel": "Data Flow: Pass Query to Core Engine",
+ "simStepDescription": "The query string and time interval are passed from the endpoint to the `aw_query::query` function, the entry point of the Rust query engine.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "16",
+ "endLine": "24",
+ "relevantVariables": [
+ "aw_query::query"
+ ]
+ },
+ "inputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\",\n \"interval\": \"\"\n}",
+ "outputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\",\n \"interval\": \"\"\n}"
+ },
+ {
+ "simStepId": "024a46d7-abc2-4c35-92d1-900d198f748c",
+ "diagramNodeId": "d8afb2b7-af24-431a-b206-828a8b7cef2a",
+ "simStepLabel": "Rust Flow: Lexing and Parsing",
+ "simStepDescription": "The `aw_query::query` function first uses a lexer (`lexer.rs`) to convert the query string into a stream of tokens. Then, a parser (`parser.rs`) consumes the tokens to build an Abstract Syntax Tree (AST) representing the query's structure.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/lib.rs",
+ "startLine": "53",
+ "endLine": "62",
+ "relevantVariables": [
+ "query",
+ "lexer::Lexer",
+ "parser::parse"
+ ]
+ },
+ "inputDataExample": "{\n \"code\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\"\n}",
+ "outputDataExample": "{\n \"program\": \"\"\n}"
+ },
+ {
+ "simStepId": "acc1ad56-50cb-41ab-9217-f8d15af6686c",
+ "diagramNodeId": "e72e1881-49ce-41ad-966a-90a26ca47453",
+ "simStepLabel": "Data Flow: Pass AST to Interpreter",
+ "simStepDescription": "The generated Abstract Syntax Tree (AST) is passed to the `interpret_prog` function for execution.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/lib.rs",
+ "startLine": "63",
+ "endLine": "63",
+ "relevantVariables": [
+ "interpret::interpret_prog"
+ ]
+ },
+ "inputDataExample": "{\n \"program\": \"\"\n}",
+ "outputDataExample": "{\n \"program\": \"\"\n}"
+ },
+ {
+ "simStepId": "e3204124-26ff-4799-8462-100305c27ae1",
+ "diagramNodeId": "630bda35-fbd5-40ec-b47d-37ad66379d94",
+ "simStepLabel": "Rust Flow: Interpret AST",
+ "simStepDescription": "The `interpret_prog` function in `interpret.rs` initializes an environment and recursively evaluates each expression (`Expr`) in the AST using `interpret_expr`. Function calls are resolved by looking up their names in the environment, which is pre-populated with built-in functions from `functions.rs`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/interpret.rs",
+ "startLine": "21",
+ "endLine": "34",
+ "relevantVariables": [
+ "interpret_prog",
+ "interpret_expr"
+ ]
+ },
+ "inputDataExample": "{\n \"expression\": \"Assign('events', Function('query_bucket', ...))\"\n}",
+ "outputDataExample": "{\n \"env\": {\n \"events\": \"\",\n \"query_bucket\": \"\"\n }\n}"
+ },
+ {
+ "simStepId": "f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5",
+ "diagramNodeId": "15dfaeb9-fb37-4296-972f-0188abd0b353",
+ "simStepLabel": "Data Flow: Execute Query Function",
+ "simStepDescription": "When interpreting a `Function` node, the corresponding function from the `qfunctions` module in `functions.rs` is executed. In this case, `query_bucket` is called.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/interpret.rs",
+ "startLine": "213",
+ "endLine": "226",
+ "relevantVariables": [
+ "Expr_::Function",
+ "fun"
+ ]
+ },
+ "inputDataExample": "{\n \"function_name\": \"query_bucket\",\n \"args\": [\n \"aw-watcher-window_test-host\"\n ]\n}",
+ "outputDataExample": "{\n \"function_name\": \"query_bucket\",\n \"args\": [\n \"aw-watcher-window_test-host\"\n ]\n}"
+ },
+ {
+ "simStepId": "06d75f72-3fc8-47d8-85ab-f7fa317f4de5",
+ "diagramNodeId": "eecd0f91-7c53-4352-8d85-05c3dd46bee1",
+ "simStepLabel": "Rust Flow: Fetch Events from Datastore",
+ "simStepDescription": "The `query_bucket` function calls the datastore's `get_events` method to retrieve events from the specified bucket within the given time interval.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/functions.rs",
+ "startLine": "139",
+ "endLine": "167",
+ "relevantVariables": [
+ "qfunctions::query_bucket",
+ "ds.get_events"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_test-host\",\n \"interval\": \"\"\n}",
+ "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
+ },
+ {
+ "simStepId": "f69e7df0-6666-4b48-a0a6-1000c8ccede0",
+ "diagramNodeId": "9792d1f0-08be-4f90-8e68-3caee0eb2498",
+ "simStepLabel": "Data Flow: Return Events to Interpreter",
+ "simStepDescription": "The datastore returns a `Vec`, which is then wrapped in a `DataType::List` and returned by the `query_bucket` function back to the interpreter.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "startLine": "700",
+ "endLine": "797",
+ "relevantVariables": [
+ "get_events"
+ ]
+ },
+ "inputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
+ "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
+ },
+ {
+ "simStepId": "9382ac29-7930-4f83-afdd-deb2bfc221e3",
+ "diagramNodeId": "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4",
+ "simStepLabel": "Rust Flow: Finalize and Return Result",
+ "simStepDescription": "After executing all statements (including handling the `Return` expression which sets the special `RETURN` variable in the environment), the `interpret_prog` function retrieves the final value from the environment.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/interpret.rs",
+ "startLine": "30",
+ "endLine": "33",
+ "relevantVariables": [
+ "env.remove(\"RETURN\")"
+ ]
+ },
+ "inputDataExample": "{\n \"env\": {\n \"TIMEINTERVAL\": \"...\",\n \"events\": \"\",\n \"RETURN\": \"\"\n }\n}",
+ "outputDataExample": "[\n {\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n },\n \"duration\": 300.0,\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\"\n }\n]"
+ },
+ {
+ "simStepId": "2f510957-0fdb-4253-a4fb-4122a252fc1e",
+ "diagramNodeId": "",
+ "simStepLabel": "API Call: Send JSON Response",
+ "simStepDescription": "The final result is returned up the call stack to the `endpoints/query.rs` endpoint, serialized into a JSON `Value`, and sent back to the client as an HTTP response.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "28",
+ "endLine": "28",
+ "relevantVariables": [
+ "json!"
+ ]
+ },
+ "inputDataExample": "[\n {\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n },\n \"duration\": 300.0,\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\"\n }\n]",
+ "outputDataExample": "[\n {\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n },\n \"duration\": 300.0,\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\"\n }\n]"
+ }
+ ],
+ "description": "- ActivityWatch features a powerful custom query language for advanced data analysis and transformation
- Queries are scripts composed of function calls and variable assignments that process event data fetched from the datastore
- It includes a rich library of transformation functions like
filter_keyvals, merge_events_by_keys, sum_durations, and categorize - The
aw-server parses and executes these queries, returning the final value assigned to the RETURN variable - Users can run custom queries through the Web UI's Query Explorer or programmatically via the API
",
+ "simulationNodesAndEdges": {
+ "5540d168-0892-4d44-a835-530768fbad09": {
+ "simStepIds": [
+ "06f7c9e7-1c78-4114-867b-3dbb20dcc427"
+ ]
+ },
+ "abf45adb-988a-4613-ab4a-acb8cef0c90a": {
+ "simStepIds": [
+ "671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7"
+ ]
+ },
+ "96c3be58-d96a-4b11-b4f3-e778387f76b8": {
+ "simStepIds": [
+ "a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31"
+ ]
+ },
+ "c0a28353-be8d-4bc8-a1be-2879961fc4df": {
+ "simStepIds": [
+ "5f7b6985-edf0-42eb-8822-847d0d7b8e9b"
+ ]
+ },
+ "fb0bcd2a-5999-47fc-bb41-11233e3544fa": {
+ "simStepIds": [
+ "6ea3ab36-027f-40b9-a0ba-9ede77ae1117"
+ ]
+ },
+ "5eb14d26-499c-4ea4-8282-3f923646dbdb": {
+ "simStepIds": [
+ "ab3fe2d5-9396-4241-b64e-2a187e97de75"
+ ]
+ },
+ "7ace16a3-9438-4e78-bcf9-79131079c89d": {
+ "simStepIds": [
+ "3118dc4c-d7ad-4996-aa81-a205ccdf6e72"
+ ]
+ },
+ "b93b83dd-fff3-44dc-ac22-3ea63117c222": {
+ "simStepIds": [
+ "1c25a330-b713-4866-9440-8737c787ce33"
+ ]
+ },
+ "d8afb2b7-af24-431a-b206-828a8b7cef2a": {
+ "simStepIds": [
+ "024a46d7-abc2-4c35-92d1-900d198f748c"
+ ]
+ },
+ "630bda35-fbd5-40ec-b47d-37ad66379d94": {
+ "simStepIds": [
+ "e3204124-26ff-4799-8462-100305c27ae1"
+ ]
+ },
+ "eecd0f91-7c53-4352-8d85-05c3dd46bee1": {
+ "simStepIds": [
+ "06d75f72-3fc8-47d8-85ab-f7fa317f4de5"
+ ]
+ },
+ "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4": {
+ "simStepIds": [
+ "9382ac29-7930-4f83-afdd-deb2bfc221e3"
+ ]
+ },
+ "71408ae2-19e6-4327-bab9-8918af09c855": {
+ "simStepIds": [
+ "5dc6bd77-15d2-44c3-b665-8de88288c314"
+ ]
+ },
+ "891bfe3a-f22a-4998-acea-aa6d0c362821": {
+ "simStepIds": [
+ "5a0d9b17-b09a-4aa5-9234-c01cb2aadef4"
+ ]
+ },
+ "b79b67f9-1be1-48f1-920a-9ebdd4417272": {
+ "simStepIds": [
+ "833f0f0f-ec00-4960-b1f9-46d8a8530a01"
+ ]
+ },
+ "4059fcbe-a1ee-41d0-b576-55a1d278bca0": {
+ "simStepIds": [
+ "7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6"
+ ]
+ },
+ "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4": {
+ "simStepIds": [
+ "ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c"
+ ]
+ },
+ "c4b6d403-d2a9-4cff-8a72-31189a53c0db": {
+ "simStepIds": [
+ "fe43857f-ef7d-455d-a9c4-37d54d12207a"
+ ]
+ },
+ "ed18dcc0-5e4a-44fb-b661-f746f1e893f1": {
+ "simStepIds": [
+ "97542310-17cf-4c99-9ce9-a328dffa5f4c"
+ ]
+ },
+ "d3cb01a0-d8cd-4382-b122-d1234b0562bc": {
+ "simStepIds": [
+ "6eb126a9-5234-4495-9727-ec2741ce9660"
+ ]
+ },
+ "e72e1881-49ce-41ad-966a-90a26ca47453": {
+ "simStepIds": [
+ "acc1ad56-50cb-41ab-9217-f8d15af6686c"
+ ]
+ },
+ "15dfaeb9-fb37-4296-972f-0188abd0b353": {
+ "simStepIds": [
+ "f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5"
+ ]
+ },
+ "9792d1f0-08be-4f90-8e68-3caee0eb2498": {
+ "simStepIds": [
+ "f69e7df0-6666-4b48-a0a6-1000c8ccede0"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "query2, aw_query, QFunction, interpret, RETURN",
+ "generationPrompt": "How the data query language works",
+ "generationKeywords": "query2, aw_query, QFunction, interpret, RETURN",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 14,
+ "promptTokenCount": 9352,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 123,
+ "promptTokenCount": 88309,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 54,
+ "promptTokenCount": 34979,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": [
+ {
+ "path": ".github/workflows/test.yml",
+ "container": "shared",
+ "triggerType": "http",
+ "identifier": "application/json"
+ }
+ ]
+ },
+ "crossLayerTriggers": [
+ {
+ "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "identifier": "application/json",
+ "type": "http",
+ "matchedTargets": [
+ ".github/workflows/test.yml",
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "aw-server-rust/aw-server/src/endpoints/import.rs"
+ ]
+ }
+ ]
+ }
+ },
+ "How AFK (Away From Keyboard) detection works": {
+ "name": "How AFK (Away From Keyboard) detection works",
+ "simSteps": [
+ {
+ "simStepId": "8ffbcadf-f26a-483a-9902-95e5a761de64",
+ "diagramNodeId": "ba27c535-e0e5-44ae-b9f0-2827227ebfe2",
+ "simStepLabel": "AFK Watcher Entrypoint",
+ "simStepDescription": "The `aw-watcher-afk` process is started. The `main` function is called, which parses command-line arguments, sets up logging, and initializes the `AFKWatcher`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/__main__.py",
+ "startLine": "7",
+ "endLine": "21",
+ "relevantVariables": [
+ "main",
+ "parse_args",
+ "setup_logging",
+ "AFKWatcher",
+ "watcher.run"
+ ]
+ },
+ "inputDataExample": "null",
+ "outputDataExample": "{\"testing\": false, \"verbose\": false, \"host\": null, \"port\": null, \"timeout\": 180.0, \"poll_time\": 5.0}"
+ },
+ {
+ "simStepId": "60e1002f-9782-4c8d-b104-f4bb172e2c91",
+ "diagramNodeId": "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
+ "simStepLabel": "Initialize Watcher",
+ "simStepDescription": "The parsed arguments and testing flag are passed to the `AFKWatcher` constructor.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/__main__.py",
+ "startLine": "20",
+ "endLine": "20",
+ "relevantVariables": [
+ "AFKWatcher"
+ ]
+ },
+ "inputDataExample": "{\"testing\": false, \"verbose\": false, \"host\": null, \"port\": null, \"timeout\": 180.0, \"poll_time\": 5.0}",
+ "outputDataExample": "{\"testing\": false, \"verbose\": false, \"host\": null, \"port\": null, \"timeout\": 180.0, \"poll_time\": 5.0}"
+ },
+ {
+ "simStepId": "daeeac12-287a-4144-9028-6ea841b196c4",
+ "diagramNodeId": "79468b99-a4de-48b7-bb67-506dc0dcb41c",
+ "simStepLabel": "Load Configuration",
+ "simStepDescription": "The `AFKWatcher` constructor loads its configuration, setting the `timeout` (time of inactivity to be considered AFK) and `poll_time` (how often to check for activity). It also initializes the `ActivityWatchClient` to communicate with the server.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "42",
+ "endLine": "53",
+ "relevantVariables": [
+ "AFKWatcher.__init__",
+ "Settings",
+ "load_config",
+ "ActivityWatchClient"
+ ]
+ },
+ "inputDataExample": "{\"args\": {\"timeout\": 180.0, \"poll_time\": 5.0, \"host\": null, \"port\": null}, \"testing\": false}",
+ "outputDataExample": "{\"settings\": {\"timeout\": 180, \"poll_time\": 5}, \"client\": \"\", \"bucketname\": \"aw-watcher-afk_my-laptop\"}"
+ },
+ {
+ "simStepId": "1422a5f8-ad2e-4b32-8955-ee6bb3053286",
+ "diagramNodeId": "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
+ "simStepLabel": "Start Main Loop",
+ "simStepDescription": "After initialization, the `run` method is called, which creates the necessary data bucket on the server and then starts the main `heartbeat_loop`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "71",
+ "endLine": "72",
+ "relevantVariables": [
+ "self.client",
+ "self.heartbeat_loop"
+ ]
+ },
+ "inputDataExample": "null",
+ "outputDataExample": "null"
+ },
+ {
+ "simStepId": "6579f587-817d-4d23-a9df-86abc54273ae",
+ "diagramNodeId": "6b45de30-296e-4896-915c-371f09843599",
+ "simStepLabel": "Check User Activity",
+ "simStepDescription": "Inside the `heartbeat_loop`, the watcher calls `seconds_since_last_input()` to get the time elapsed since the last keyboard or mouse activity from the operating system.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "86",
+ "endLine": "86",
+ "relevantVariables": [
+ "seconds_since_last_input"
+ ]
+ },
+ "inputDataExample": "null",
+ "outputDataExample": "{\"seconds_since_input\": 185.3}"
+ },
+ {
+ "simStepId": "2588211c-b086-4768-8a87-a86764c7e5cd",
+ "diagramNodeId": "e514d9e2-e803-4041-b693-65878401b214",
+ "simStepLabel": "Platform-Specific Call",
+ "simStepDescription": "The `seconds_since_last_input` call is dispatched to the appropriate platform-specific implementation (Windows, macOS, or Unix).",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "14",
+ "endLine": "24",
+ "relevantVariables": [
+ "system",
+ "seconds_since_last_input"
+ ]
+ },
+ "inputDataExample": "null",
+ "outputDataExample": "null"
+ },
+ {
+ "simStepId": "4d2c85c7-0754-429a-8a55-c64d4da0d37c",
+ "diagramNodeId": "b7321a6c-302b-4701-9ea5-5c05c6d3e71b",
+ "simStepLabel": "Get Idle Time (Unix Example)",
+ "simStepDescription": "On Unix-like systems, listeners for mouse and keyboard events are checked. If a new event has occurred since the last check, the `last_activity` timestamp is updated. The function then returns the total seconds between now and the last recorded activity.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/unix.py",
+ "startLine": "21",
+ "endLine": "31",
+ "relevantVariables": [
+ "LastInputUnix.seconds_since_last_input",
+ "self.mouseListener.has_new_event",
+ "self.keyboardListener.has_new_event"
+ ]
+ },
+ "inputDataExample": "null",
+ "outputDataExample": "185.3"
+ },
+ {
+ "simStepId": "9195e582-b3fa-4848-b151-0236a8a5d176",
+ "diagramNodeId": "eeb9224a-fff6-4652-b733-ea430b820a2c",
+ "simStepLabel": "Return Idle Time",
+ "simStepDescription": "The idle time in seconds is returned to the `heartbeat_loop`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "86",
+ "endLine": "86",
+ "relevantVariables": [
+ "seconds_since_input"
+ ]
+ },
+ "inputDataExample": "185.3",
+ "outputDataExample": "185.3"
+ },
+ {
+ "simStepId": "3e0e033c-c32f-4d0d-aa65-a278d77e80c7",
+ "diagramNodeId": "faab8465-be29-479d-890a-7936dc5cfbdd",
+ "simStepLabel": "Detect State Change: User Becomes AFK",
+ "simStepDescription": "The watcher compares the idle time with the configured timeout. Since the user was previously not AFK (`afk=False`) and the idle time (`185.3s`) is greater than the timeout (`180s`), the user's state changes to AFK.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "98",
+ "endLine": "105",
+ "relevantVariables": [
+ "afk",
+ "seconds_since_input",
+ "self.settings.timeout",
+ "self.ping"
+ ]
+ },
+ "inputDataExample": "{\"afk\": false, \"seconds_since_input\": 185.3, \"timeout\": 180}",
+ "outputDataExample": "{\"afk\": true}"
+ },
+ {
+ "simStepId": "78d78341-ced8-4fc6-bc93-ce4a62c8adf6",
+ "diagramNodeId": "196358b9-6ae9-4f52-ad78-ff88b4a49403",
+ "simStepLabel": "Send Final 'not-afk' Heartbeat",
+ "simStepDescription": "Before officially changing the state, a final `not-afk` heartbeat is sent to accurately mark the end of the active period.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "100",
+ "endLine": "100",
+ "relevantVariables": [
+ "self.ping"
+ ]
+ },
+ "inputDataExample": "{\"afk\": false, \"timestamp\": \"2023-10-27T10:27:15.123456+00:00\"}",
+ "outputDataExample": "{\"afk\": false, \"timestamp\": \"2023-10-27T10:27:15.123456+00:00\"}"
+ },
+ {
+ "simStepId": "dc58bc3e-b09e-4df2-870b-76419e78dd3d",
+ "diagramNodeId": "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5",
+ "simStepLabel": "Prepare Event for Server",
+ "simStepDescription": "The `ping` method constructs an `Event` object containing the user's status. It then calls the client's `heartbeat` method to send this event to the `aw-server`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "55",
+ "endLine": "59",
+ "relevantVariables": [
+ "ping",
+ "Event",
+ "self.client.heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"afk\": false, \"timestamp\": \"2023-10-27T10:27:15.123456+00:00\", \"duration\": 0}",
+ "outputDataExample": "{\"timestamp\": \"2023-10-27T10:27:15.123Z\", \"duration\": 0.0, \"data\": {\"status\": \"not-afk\"}}"
+ },
+ {
+ "simStepId": "c9a127c1-afd0-4def-a0fe-c490c9b64039",
+ "diagramNodeId": "b520b088-6f6f-4b32-afba-5ef244691c44",
+ "simStepLabel": "Send First 'afk' Heartbeat",
+ "simStepDescription": "After the state change, the first `afk` heartbeat is sent to mark the beginning of the idle period.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "103",
+ "endLine": "105",
+ "relevantVariables": [
+ "self.ping"
+ ]
+ },
+ "inputDataExample": "{\"afk\": true, \"timestamp\": \"2023-10-27T10:27:15.124456+00:00\", \"duration\": 185.3}",
+ "outputDataExample": "{\"afk\": true, \"timestamp\": \"2023-10-27T10:27:15.124456+00:00\", \"duration\": 185.3}"
+ },
+ {
+ "simStepId": "7357e239-3712-4b55-a94c-2165ea1f3255",
+ "diagramNodeId": "c27977fb-af8a-4779-8f78-a99b40221157",
+ "simStepLabel": "Server Receives and Processes Heartbeat",
+ "simStepDescription": "The `aw-server` receives the heartbeat event. The `heartbeat` method in the API layer checks if the new event's data is the same as the last event. Since the status changed from 'not-afk' to 'afk', it will not merge them and will instead insert a new event.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "268",
+ "endLine": "276",
+ "relevantVariables": [
+ "heartbeat",
+ "last_event",
+ "heartbeat_merge",
+ "self.db[bucket_id].insert"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-afk_my-laptop\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:27:15.124Z\", \"duration\": 185.3, \"data\": {\"status\": \"afk\"}}, \"pulsetime\": 185.0}",
+ "outputDataExample": "{\"id\": 102, \"timestamp\": \"2023-10-27T10:27:15.124Z\", \"duration\": 185.3, \"data\": {\"status\": \"afk\"}}"
+ },
+ {
+ "simStepId": "9fde1b44-5dbf-4530-88e2-ca54c220b462",
+ "diagramNodeId": "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
+ "simStepLabel": "Pause for Poll Time",
+ "simStepDescription": "After processing the current state and sending heartbeats, the loop pauses for the configured `poll_time` before the next check.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "119",
+ "endLine": "119",
+ "relevantVariables": [
+ "sleep",
+ "self.settings.poll_time"
+ ]
+ },
+ "inputDataExample": "{\"poll_time\": 5}",
+ "outputDataExample": "{\"poll_time\": 5}"
+ },
+ {
+ "simStepId": "1e5ad77f-aeff-49b6-9634-65e52f011a83",
+ "diagramNodeId": "802c1941-09e1-4038-a0bf-bd4e553ff6f6",
+ "simStepLabel": "Loop Repeats",
+ "simStepDescription": "The process repeats. The watcher continues to send `afk` heartbeats on each poll interval as long as the user remains idle. When activity resumes, the condition `afk and seconds_since_input < self.settings.timeout` will trigger, sending a `not-afk` event and resetting the state.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "startLine": "76",
+ "endLine": "76",
+ "relevantVariables": [
+ "while True"
+ ]
+ },
+ "inputDataExample": "null",
+ "outputDataExample": "null"
+ }
+ ],
+ "description": "- The
aw-watcher-afk module monitors user presence by tracking keyboard and mouse activity - It periodically queries the operating system for the time elapsed since the last input event
- If this time exceeds a configurable timeout, the watcher sends an
afk status event - When activity resumes, it sends a
not-afk event - This AFK data is crucial for accurately measuring active screen time, as it allows queries to filter out periods when the user was idle
",
+ "simulationNodesAndEdges": {
+ "ba27c535-e0e5-44ae-b9f0-2827227ebfe2": {
+ "simStepIds": [
+ "8ffbcadf-f26a-483a-9902-95e5a761de64"
+ ]
+ },
+ "79468b99-a4de-48b7-bb67-506dc0dcb41c": {
+ "simStepIds": [
+ "daeeac12-287a-4144-9028-6ea841b196c4"
+ ]
+ },
+ "6b45de30-296e-4896-915c-371f09843599": {
+ "simStepIds": [
+ "6579f587-817d-4d23-a9df-86abc54273ae"
+ ]
+ },
+ "b7321a6c-302b-4701-9ea5-5c05c6d3e71b": {
+ "simStepIds": [
+ "4d2c85c7-0754-429a-8a55-c64d4da0d37c"
+ ]
+ },
+ "faab8465-be29-479d-890a-7936dc5cfbdd": {
+ "simStepIds": [
+ "3e0e033c-c32f-4d0d-aa65-a278d77e80c7"
+ ]
+ },
+ "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5": {
+ "simStepIds": [
+ "dc58bc3e-b09e-4df2-870b-76419e78dd3d"
+ ]
+ },
+ "c27977fb-af8a-4779-8f78-a99b40221157": {
+ "simStepIds": [
+ "7357e239-3712-4b55-a94c-2165ea1f3255"
+ ]
+ },
+ "802c1941-09e1-4038-a0bf-bd4e553ff6f6": {
+ "simStepIds": [
+ "1e5ad77f-aeff-49b6-9634-65e52f011a83"
+ ]
+ },
+ "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250": {
+ "simStepIds": [
+ "60e1002f-9782-4c8d-b104-f4bb172e2c91"
+ ]
+ },
+ "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838": {
+ "simStepIds": [
+ "1422a5f8-ad2e-4b32-8955-ee6bb3053286"
+ ]
+ },
+ "e514d9e2-e803-4041-b693-65878401b214": {
+ "simStepIds": [
+ "2588211c-b086-4768-8a87-a86764c7e5cd"
+ ]
+ },
+ "eeb9224a-fff6-4652-b733-ea430b820a2c": {
+ "simStepIds": [
+ "9195e582-b3fa-4848-b151-0236a8a5d176"
+ ]
+ },
+ "196358b9-6ae9-4f52-ad78-ff88b4a49403": {
+ "simStepIds": [
+ "78d78341-ced8-4fc6-bc93-ce4a62c8adf6"
+ ]
+ },
+ "b520b088-6f6f-4b32-afba-5ef244691c44": {
+ "simStepIds": [
+ "c9a127c1-afd0-4def-a0fe-c490c9b64039"
+ ]
+ },
+ "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0": {
+ "simStepIds": [
+ "9fde1b44-5dbf-4530-88e2-ca54c220b462"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "aw-watcher-afk, seconds_since_last_input, afk, not-afk, heartbeat_loop",
+ "generationPrompt": "How AFK (Away From Keyboard) detection works",
+ "generationKeywords": "aw-watcher-afk, seconds_since_last_input, afk, not-afk, heartbeat_loop",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 8,
+ "promptTokenCount": 4269,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 9,
+ "promptTokenCount": 7504,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 77,
+ "promptTokenCount": 69327,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": []
+ }
+ }
+ },
+ "How the heartbeat API enables efficient tracking works": {
+ "name": "How the heartbeat API enables efficient tracking works",
+ "simSteps": [
+ {
+ "simStepId": "46ccc29e-b251-435a-8768-4304d477261a",
+ "diagramNodeId": "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c",
+ "simStepLabel": "[Python Flow - Watcher] Detect Active Window Change",
+ "simStepDescription": "The `aw-watcher-window` process on macOS, implemented in Swift, detects a change in the active window or its title. An observer callback function like `windowTitleChanged` is triggered, which captures the application name (`app`) and the window title (`title`).",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "startLine": "306",
+ "endLine": "375",
+ "relevantVariables": [
+ "windowTitleChanged",
+ "frontmost",
+ "data",
+ "heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"axObserver\": \"\", \"axElement\": \"\", \"notification\": \"kAXTitleChangedNotification\"}",
+ "outputDataExample": "{\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}"
+ },
+ {
+ "simStepId": "b6456941-3a8f-452d-a4eb-67915b00d5b3",
+ "diagramNodeId": "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
+ "simStepLabel": "Data Transmission: Pass Event Data for Heartbeat",
+ "simStepDescription": "The captured window data is packaged into a `Heartbeat` object and passed to the `sendHeartbeat` function to be sent to the server.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "startLine": "373",
+ "endLine": "374",
+ "relevantVariables": [
+ "heartbeat",
+ "sendHeartbeat"
+ ]
+ },
+ "inputDataExample": "{\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}",
+ "outputDataExample": "{\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}"
+ },
+ {
+ "simStepId": "e873b3e2-2ebd-43ee-8f97-e02f869578f7",
+ "diagramNodeId": "67a89dcc-93fc-413d-aa21-eca0b7227bc2",
+ "simStepLabel": "[Python Flow - Watcher] Send Heartbeat API Request",
+ "simStepDescription": "The `sendHeartbeatSingle` function constructs an HTTP POST request. It sets the URL to the heartbeat endpoint, including the bucket name and a calculated `pulsetime` as a query parameter. The heartbeat data is JSON-encoded and sent as the request body.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "startLine": "253",
+ "endLine": "268",
+ "relevantVariables": [
+ "sendHeartbeatSingle",
+ "urlRequest",
+ "URLSession.shared.upload"
+ ]
+ },
+ "inputDataExample": "{\"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"url\": \"http://localhost:5600/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"method\": \"POST\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}"
+ },
+ {
+ "simStepId": "02717bea-6ee3-48ef-8c41-0c9f3e9d9a58",
+ "diagramNodeId": "a676f81f-8c68-4fc8-94b7-583bada02d70",
+ "simStepLabel": "API Call: Watcher -> Python Server",
+ "simStepDescription": "The watcher sends the HTTP POST request containing the heartbeat event to the `aw-server` (Python) instance.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "272",
+ "endLine": "272",
+ "relevantVariables": [
+ "HeartbeatResource"
+ ]
+ },
+ "inputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}",
+ "outputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}"
+ },
+ {
+ "simStepId": "e98f7509-f28f-4534-8f2a-f525edc73f69",
+ "diagramNodeId": "9de5f1e4-764e-4be7-90a1-65fa23ca0dea",
+ "simStepLabel": "[Python Server] Handle Heartbeat Endpoint",
+ "simStepDescription": "The `aw-server` (Flask) routes the incoming request to the `post` method of the `HeartbeatResource`. This method parses the JSON body into an `Event` object and extracts the `pulsetime` from the URL parameters.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "283",
+ "endLine": "304",
+ "relevantVariables": [
+ "HeartbeatResource",
+ "post",
+ "heartbeat",
+ "pulsetime",
+ "current_app.api.heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"request_json\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
+ },
+ {
+ "simStepId": "d57d2bf7-916c-44cd-844d-b1900c276925",
+ "diagramNodeId": "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
+ "simStepLabel": "Data Transmission: REST -> API Logic",
+ "simStepDescription": "The REST controller passes the parsed heartbeat event, bucket ID, and pulsetime to the core API logic for processing.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "300",
+ "endLine": "300",
+ "relevantVariables": [
+ "current_app.api.heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
+ },
+ {
+ "simStepId": "bb678fe2-e6e3-472b-8ae4-95e362d4bdaf",
+ "diagramNodeId": "7c02469d-20a7-415d-940e-fbd82d0fc997",
+ "simStepLabel": "[Python Server] Process Heartbeat Event",
+ "simStepDescription": "The `ServerAPI.heartbeat` method retrieves the last event from the specified bucket, either from an in-memory cache (`self.last_event`) or the database. It then compares the data of the new heartbeat with the last event. If the data is the same, it calls `heartbeat_merge` to attempt a merge.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "254",
+ "endLine": "337",
+ "relevantVariables": [
+ "heartbeat",
+ "last_event",
+ "heartbeat_merge"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"merged_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}"
+ },
+ {
+ "simStepId": "40b16e25-734b-44d2-86cd-7c301723ff5f",
+ "diagramNodeId": "9aec4875-5718-4c38-a57c-1d3053c38ba5",
+ "simStepLabel": "Data Transmission: Pass Events to Merge Function",
+ "simStepDescription": "The last recorded event, the new heartbeat event, and the pulsetime are passed to the `heartbeat_merge` utility function to determine if they can be combined.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "305",
+ "endLine": "305",
+ "relevantVariables": [
+ "heartbeat_merge"
+ ]
+ },
+ "inputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
+ },
+ {
+ "simStepId": "d2eac5dc-58f7-408c-beba-c1711beec25a",
+ "diagramNodeId": "dc7a3836-03e1-4a54-9817-b62f36466ec0",
+ "simStepLabel": "[Python Server] Core Merge Logic",
+ "simStepDescription": "The `heartbeat_merge` function checks if the event data is identical and if the new heartbeat's timestamp is within the `pulsetime` window of the last event's end time. If both conditions are met, it creates a new merged event by extending the duration of the last event to cover the time up to the new heartbeat. Otherwise, it returns `None`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_transform/heartbeats.py",
+ "startLine": "26",
+ "endLine": "56",
+ "relevantVariables": [
+ "heartbeat_merge",
+ "last_event",
+ "heartbeat",
+ "pulsetime",
+ "within_pulsetime_window",
+ "new_duration"
+ ]
+ },
+ "inputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}"
+ },
+ {
+ "simStepId": "9f918447-9e45-4c3b-b34f-658f58d35495",
+ "diagramNodeId": "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
+ "simStepLabel": "Data Transmission: Return Merged Event",
+ "simStepDescription": "The `heartbeat_merge` function returns the newly created merged event (or `None`) back to the `ServerAPI.heartbeat` method.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-core/aw_transform/heartbeats.py",
+ "startLine": "54",
+ "endLine": "56",
+ "relevantVariables": [
+ "last_event",
+ "None"
+ ]
+ },
+ "inputDataExample": "{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}",
+ "outputDataExample": "{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}"
+ },
+ {
+ "simStepId": "976cfbd0-8946-4157-81b0-0ae6dffa43e1",
+ "diagramNodeId": "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f",
+ "simStepLabel": "[Python Server] Update Database",
+ "simStepDescription": "If a merged event was returned, the `ServerAPI.heartbeat` method updates its local cache (`self.last_event`) and calls `self.db[bucket_id].replace_last(merged)` to persist the change in the database. This replaces the previous event with the new, longer-duration event. If no merged event was returned, it inserts a new event instead.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "313",
+ "endLine": "315",
+ "relevantVariables": [
+ "self.last_event",
+ "self.db[bucket_id].replace_last"
+ ]
+ },
+ "inputDataExample": "{\"merged_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}",
+ "outputDataExample": "{\"success\": true}"
+ },
+ {
+ "simStepId": "8420fd6c-dba4-41c0-b11d-7280a428ab36",
+ "diagramNodeId": "b3da175e-36b5-4025-ba15-6c54e1d850dd",
+ "simStepLabel": "[Rust Flow - Watcher] Detect and Send Heartbeat",
+ "simStepDescription": "This step marks the beginning of the alternative `aw-server-rust` implementation flow. The process is initiated in the same way as the Python flow: a watcher detects an activity change and prepares a heartbeat event. The Swift-based watcher is implementation-agnostic and sends the same HTTP request regardless of the server.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "startLine": "203",
+ "endLine": "268",
+ "relevantVariables": [
+ "sendHeartbeat",
+ "sendHeartbeatSingle"
+ ]
+ },
+ "inputDataExample": "{\"axObserver\": \"\", \"axElement\": \"\", \"notification\": \"kAXTitleChangedNotification\"}",
+ "outputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}"
+ },
+ {
+ "simStepId": "7e361c3d-a5a9-45f3-a83d-98e39ff45675",
+ "diagramNodeId": "2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
+ "simStepLabel": "API Call: Watcher -> Rust Server",
+ "simStepDescription": "The watcher sends the HTTP POST request containing the heartbeat event to the `aw-server-rust` instance.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "startLine": "145",
+ "endLine": "149",
+ "relevantVariables": [
+ "bucket_events_heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}",
+ "outputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}"
+ },
+ {
+ "simStepId": "41b8b1d6-f9fe-47ad-851e-574e804f7171",
+ "diagramNodeId": "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926",
+ "simStepLabel": "[Rust Server] Handle Heartbeat Endpoint",
+ "simStepDescription": "The `aw-server-rust` (Rocket) routes the incoming request to the `bucket_events_heartbeat` function. This function parses the JSON body and pulsetime, then calls the `datastore.heartbeat` method to process the event.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "startLine": "150",
+ "endLine": "162",
+ "relevantVariables": [
+ "bucket_events_heartbeat",
+ "heartbeat_json",
+ "pulsetime",
+ "state.datastore"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat_json\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
+ },
+ {
+ "simStepId": "bfcc2f87-9167-4784-a3b3-f71d6e7a6e71",
+ "diagramNodeId": "4a4afbdf-0303-4d84-bbf8-5121c74965a0",
+ "simStepLabel": "Data Transmission: Endpoint -> Datastore",
+ "simStepDescription": "The endpoint function passes the heartbeat data to the datastore worker layer for processing.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "startLine": "158",
+ "endLine": "158",
+ "relevantVariables": [
+ "datastore.heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
+ },
+ {
+ "simStepId": "b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3",
+ "diagramNodeId": "b6b4c8cb-741a-4e38-b800-61273375cd64",
+ "simStepLabel": "[Rust Server] Queue Heartbeat Command",
+ "simStepDescription": "The `Datastore::heartbeat` method in `worker.rs` creates a `Command::Heartbeat` enum variant and sends it to the datastore worker thread through a multi-producer, single-consumer (mpsc) channel. This decouples API handling from database operations.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "startLine": "385",
+ "endLine": "399",
+ "relevantVariables": [
+ "heartbeat",
+ "Command::Heartbeat",
+ "self.requester.request"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"Command::Heartbeat\": {\"bucket_id\": \"aw-watcher-window_my-mac\", \"event\": {...}, \"pulsetime\": 61.0}}"
+ },
+ {
+ "simStepId": "eefd671a-3b08-4336-bd26-cb6eb04070ec",
+ "diagramNodeId": "21d1c973-0f67-4aca-9d1b-eade3b5d347b",
+ "simStepLabel": "Data Transmission: Command Channel",
+ "simStepDescription": "The heartbeat command is sent over the mpsc channel to the dedicated datastore worker thread.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "startLine": "167",
+ "endLine": "175",
+ "relevantVariables": [
+ "self.responder.poll"
+ ]
+ },
+ "inputDataExample": "{\"Command::Heartbeat\": {\"bucket_id\": \"aw-watcher-window_my-mac\", \"event\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}}",
+ "outputDataExample": "{\"Command::Heartbeat\": {\"bucket_id\": \"aw-watcher-window_my-mac\", \"event\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}}"
+ },
+ {
+ "simStepId": "a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb",
+ "diagramNodeId": "f0e92638-21d1-4b7e-9f2e-17b67a33ef78",
+ "simStepLabel": "[Rust Server] Process Heartbeat in Worker",
+ "simStepDescription": "The `DatastoreWorker::handle_request` method receives the command, matches it to `Command::Heartbeat`, and calls the `heartbeat` method on the `DatastoreInstance`, which directly interacts with the SQLite database connection.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "startLine": "240",
+ "endLine": "248",
+ "relevantVariables": [
+ "handle_request",
+ "ds.heartbeat",
+ "self.last_heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"Command::Heartbeat\": {\"bucket_id\": \"aw-watcher-window_my-mac\", \"event\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}}",
+ "outputDataExample": "{\"Response::Event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.123, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}"
+ },
+ {
+ "simStepId": "9750ac2c-c0fb-4fe5-815f-398886fc827b",
+ "diagramNodeId": "959b342e-eb44-4255-8176-1600a5fa17ac",
+ "simStepLabel": "Data Transmission: Worker -> Datastore Instance",
+ "simStepDescription": "The worker thread calls the `heartbeat` method on the datastore instance, passing the event data.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
+ "startLine": "241",
+ "endLine": "241",
+ "relevantVariables": [
+ "ds.heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
+ },
+ {
+ "simStepId": "c59f4b10-f6c9-4fd8-ba70-ea60667a01e8",
+ "diagramNodeId": "b0093d22-e8cc-4e9e-8711-7e698b537efc",
+ "simStepLabel": "[Rust Server] Core Merge Logic",
+ "simStepDescription": "The `DatastoreInstance::heartbeat` method retrieves the last event and calls `aw_transform::heartbeat`. This function checks for data equality and pulsetime. If successful, it returns a `Some(merged_event)`. If not, `None`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "startLine": "600",
+ "endLine": "642",
+ "relevantVariables": [
+ "heartbeat",
+ "last_event",
+ "aw_transform::heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"Some(merged_heartbeat)\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.123, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}"
+ },
+ {
+ "simStepId": "7b396541-e74f-4baf-9b1b-c1f7a914ba7a",
+ "diagramNodeId": "0fe644bb-a583-40d8-9377-3641c90c4f62",
+ "simStepLabel": "Data Transmission: Pass Events to Merge Function",
+ "simStepDescription": "The last event, new heartbeat, and pulsetime are passed to the `aw_transform::heartbeat` function for the merge calculation.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "startLine": "628",
+ "endLine": "628",
+ "relevantVariables": [
+ "aw_transform::heartbeat"
+ ]
+ },
+ "inputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
+ "outputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
+ },
+ {
+ "simStepId": "da146aa5-e96f-4db6-a36f-b405b1a11255",
+ "diagramNodeId": "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8",
+ "simStepLabel": "[Rust Server] Update Database",
+ "simStepDescription": "Based on the result from `aw_transform::heartbeat`, the `DatastoreInstance::heartbeat` method either calls `self.replace_last_event` to update the last event in the database with the merged one, or `self.insert_events` to create a new event. The merged or new event is then cached and returned.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "startLine": "628",
+ "endLine": "639",
+ "relevantVariables": [
+ "replace_last_event",
+ "insert_events"
+ ]
+ },
+ "inputDataExample": "{\"merged_heartbeat\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.123, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}",
+ "outputDataExample": "{\"success\": true}"
+ }
+ ],
+ "description": "- Watchers use a
heartbeat mechanism to efficiently report continuous states, such as the currently active window - Instead of sending events with long durations, watchers send frequent, zero-duration
heartbeat events - The
aw-server receives these heartbeats and, if the new event's data is identical to the previous one and arrives within a pulsetime window, it merges them by extending the duration of the last event - This approach significantly reduces the amount of data that needs to be stored and transmitted, making the tracking process highly efficient
- If the data changes (e
- g
- , the user switches windows), a new event is created, starting a new continuous period
",
+ "simulationNodesAndEdges": {
+ "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c": {
+ "simStepIds": [
+ "46ccc29e-b251-435a-8768-4304d477261a"
+ ]
+ },
+ "67a89dcc-93fc-413d-aa21-eca0b7227bc2": {
+ "simStepIds": [
+ "e873b3e2-2ebd-43ee-8f97-e02f869578f7"
+ ]
+ },
+ "9de5f1e4-764e-4be7-90a1-65fa23ca0dea": {
+ "simStepIds": [
+ "e98f7509-f28f-4534-8f2a-f525edc73f69"
+ ]
+ },
+ "7c02469d-20a7-415d-940e-fbd82d0fc997": {
+ "simStepIds": [
+ "bb678fe2-e6e3-472b-8ae4-95e362d4bdaf"
+ ]
+ },
+ "dc7a3836-03e1-4a54-9817-b62f36466ec0": {
+ "simStepIds": [
+ "d2eac5dc-58f7-408c-beba-c1711beec25a"
+ ]
+ },
+ "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f": {
+ "simStepIds": [
+ "976cfbd0-8946-4157-81b0-0ae6dffa43e1"
+ ]
+ },
+ "b3da175e-36b5-4025-ba15-6c54e1d850dd": {
+ "simStepIds": [
+ "8420fd6c-dba4-41c0-b11d-7280a428ab36"
+ ]
+ },
+ "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926": {
+ "simStepIds": [
+ "41b8b1d6-f9fe-47ad-851e-574e804f7171"
+ ]
+ },
+ "b6b4c8cb-741a-4e38-b800-61273375cd64": {
+ "simStepIds": [
+ "b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3"
+ ]
+ },
+ "f0e92638-21d1-4b7e-9f2e-17b67a33ef78": {
+ "simStepIds": [
+ "a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb"
+ ]
+ },
+ "b0093d22-e8cc-4e9e-8711-7e698b537efc": {
+ "simStepIds": [
+ "c59f4b10-f6c9-4fd8-ba70-ea60667a01e8"
+ ]
+ },
+ "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8": {
+ "simStepIds": [
+ "da146aa5-e96f-4db6-a36f-b405b1a11255"
+ ]
+ },
+ "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f": {
+ "simStepIds": [
+ "b6456941-3a8f-452d-a4eb-67915b00d5b3"
+ ]
+ },
+ "a676f81f-8c68-4fc8-94b7-583bada02d70": {
+ "simStepIds": [
+ "02717bea-6ee3-48ef-8c41-0c9f3e9d9a58"
+ ]
+ },
+ "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75": {
+ "simStepIds": [
+ "d57d2bf7-916c-44cd-844d-b1900c276925"
+ ]
+ },
+ "9aec4875-5718-4c38-a57c-1d3053c38ba5": {
+ "simStepIds": [
+ "40b16e25-734b-44d2-86cd-7c301723ff5f"
+ ]
+ },
+ "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0": {
+ "simStepIds": [
+ "9f918447-9e45-4c3b-b34f-658f58d35495"
+ ]
+ },
+ "2df6b81e-6b59-4aec-92c7-e9d9f2332be6": {
+ "simStepIds": [
+ "7e361c3d-a5a9-45f3-a83d-98e39ff45675"
+ ]
+ },
+ "4a4afbdf-0303-4d84-bbf8-5121c74965a0": {
+ "simStepIds": [
+ "bfcc2f87-9167-4784-a3b3-f71d6e7a6e71"
+ ]
+ },
+ "21d1c973-0f67-4aca-9d1b-eade3b5d347b": {
+ "simStepIds": [
+ "eefd671a-3b08-4336-bd26-cb6eb04070ec"
+ ]
+ },
+ "959b342e-eb44-4255-8176-1600a5fa17ac": {
+ "simStepIds": [
+ "9750ac2c-c0fb-4fe5-815f-398886fc827b"
+ ]
+ },
+ "0fe644bb-a583-40d8-9377-3641c90c4f62": {
+ "simStepIds": [
+ "7b396541-e74f-4baf-9b1b-c1f7a914ba7a"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "heartbeat, heartbeat_merge, pulsetime, aw-server/api.py, aw_transform/heartbeats.py",
+ "generationPrompt": "How the heartbeat API enables efficient tracking works",
+ "generationKeywords": "heartbeat, heartbeat_merge, pulsetime, aw-server/api.py, aw_transform/heartbeats.py",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 5,
+ "promptTokenCount": 2654,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 123,
+ "promptTokenCount": 103244,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 62,
+ "promptTokenCount": 64640,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": [
+ {
+ "path": "aw-server-rust/aw-server/src/endpoints/import.rs",
+ "container": "server",
+ "triggerType": "http",
+ "identifier": "application/json"
+ }
+ ]
+ },
+ "crossLayerTriggers": [
+ {
+ "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "identifier": "application/json",
+ "type": "http",
+ "matchedTargets": [
+ ".github/workflows/test.yml",
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "aw-server-rust/aw-server/src/endpoints/import.rs"
+ ]
+ }
+ ]
+ }
+ },
+ "How the module manager and tray icon works": {
+ "name": "How the module manager and tray icon works",
+ "simSteps": [
+ {
+ "simStepId": "61d1a03e-ed06-496d-8495-36419b9c8607",
+ "diagramNodeId": "d1bb4e12-29b6-4f70-9931-321214e3ea2a",
+ "simStepLabel": "Application Entrypoint",
+ "simStepDescription": "The `aw-qt` application is launched. It parses command-line arguments, sets up logging, loads configuration, and initializes the `Manager`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/main.py",
+ "startLine": "41",
+ "endLine": "53",
+ "relevantVariables": [
+ "main",
+ "testing",
+ "verbose",
+ "autostart_modules"
+ ]
+ },
+ "inputDataExample": "{\n \"command\": \"aw-qt --testing\"\n}",
+ "outputDataExample": "{\n \"testing\": true,\n \"verbose\": false,\n \"autostart_modules\": null,\n \"no_gui\": false,\n \"interactive_cli\": false\n}"
+ },
+ {
+ "simStepId": "6084ca69-514e-4bde-b2c0-1d33b26203e8",
+ "diagramNodeId": "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
+ "simStepLabel": "Load Autostart Config",
+ "simStepDescription": "The application triggers the loading of autostart module settings based on the `testing` flag.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/main.py",
+ "startLine": "70",
+ "endLine": "70",
+ "relevantVariables": [
+ "AwQtSettings"
+ ]
+ },
+ "inputDataExample": "{\n \"testing\": true\n}",
+ "outputDataExample": "{\n \"testing\": true\n}"
+ },
+ {
+ "simStepId": "c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a",
+ "diagramNodeId": "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc",
+ "simStepLabel": "Read Configuration File",
+ "simStepDescription": "The `AwQtSettings` class reads the `aw-qt.toml` configuration file to determine which modules to autostart.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/config.py",
+ "startLine": "16",
+ "endLine": "24",
+ "relevantVariables": [
+ "AwQtSettings",
+ "load_config_toml",
+ "autostart_modules"
+ ]
+ },
+ "inputDataExample": "{\n \"testing\": true\n}",
+ "outputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}"
+ },
+ {
+ "simStepId": "540119c2-b541-4342-aa59-233b4f0f8db5",
+ "diagramNodeId": "030668a5-a377-4710-b39f-95efb5fa4768",
+ "simStepLabel": "Pass Config to Manager",
+ "simStepDescription": "The list of modules to autostart is passed from the main function to the `Manager` instance during its initialization and autostart sequence.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/main.py",
+ "startLine": "77",
+ "endLine": "78",
+ "relevantVariables": [
+ "manager",
+ "Manager",
+ "autostart"
+ ]
+ },
+ "inputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}",
+ "outputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}"
+ },
+ {
+ "simStepId": "e716abbb-c96e-4613-bca2-0c094e8df129",
+ "diagramNodeId": "cae37571-f0ba-4abe-aefd-53e49f26137f",
+ "simStepLabel": "Discover Modules",
+ "simStepDescription": "The `Manager` class is instantiated and discovers all available `aw-*` executables. It searches for bundled modules within its own directory structure and for system-wide modules in the user's PATH.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/manager.py",
+ "startLine": "241",
+ "endLine": "250",
+ "relevantVariables": [
+ "discover_modules",
+ "_discover_modules_bundled",
+ "_discover_modules_system",
+ "filter_modules"
+ ]
+ },
+ "inputDataExample": "{\n \"testing\": true\n}",
+ "outputDataExample": "{\n \"modules\": [\n {\n \"name\": \"aw-server\",\n \"path\": \"/path/to/aw-server\",\n \"type\": \"bundled\"\n },\n {\n \"name\": \"aw-watcher-afk\",\n \"path\": \"/path/to/aw-watcher-afk\",\n \"type\": \"bundled\"\n },\n {\n \"name\": \"aw-watcher-window\",\n \"path\": \"/path/to/aw-watcher-window\",\n \"type\": \"system\"\n }\n ]\n}"
+ },
+ {
+ "simStepId": "9aeaf443-6741-4557-9671-67d596f456b3",
+ "diagramNodeId": "1fb5a75e-9c49-490d-b412-04ac1c7205fa",
+ "simStepLabel": "Initiate Autostart Sequence",
+ "simStepDescription": "With the list of discovered modules and the autostart configuration, the `Manager` begins the startup sequence for each required module.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/manager.py",
+ "startLine": "276",
+ "endLine": "286",
+ "relevantVariables": [
+ "autostart",
+ "start"
+ ]
+ },
+ "inputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}",
+ "outputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}"
+ },
+ {
+ "simStepId": "8be10173-751a-4da9-99a9-321c23e71aaa",
+ "diagramNodeId": "8f981b6f-7bed-4d9a-8486-79f85b06d904",
+ "simStepLabel": "Spawn Module Process",
+ "simStepDescription": "For each module designated for autostart, the `Module.start` method is called. This method constructs the execution command and uses `subprocess.Popen` to launch the module as a new, independent process. `aw-server` is started first.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/manager.py",
+ "startLine": "147",
+ "endLine": "172",
+ "relevantVariables": [
+ "Module.start",
+ "subprocess.Popen",
+ "exec_cmd",
+ "_process",
+ "started"
+ ]
+ },
+ "inputDataExample": "{\n \"module_name\": \"aw-server\",\n \"testing\": true\n}",
+ "outputDataExample": "{\n \"process_id\": 12345\n}"
+ },
+ {
+ "simStepId": "f968357d-53c4-41e8-b71f-c581c08b52e6",
+ "diagramNodeId": "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
+ "simStepLabel": "Module Process Running",
+ "simStepDescription": "The `aw-server` module process is now running independently. Control returns to the `aw-qt` main process, which proceeds to start other modules and initialize the GUI.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/manager.py",
+ "startLine": "169",
+ "endLine": "171",
+ "relevantVariables": [
+ "_process"
+ ]
+ },
+ "inputDataExample": "{\n \"module\": \"aw-server\",\n \"status\": \"started\"\n}",
+ "outputDataExample": "{\n \"module\": \"aw-server\",\n \"status\": \"started\"\n}"
+ },
+ {
+ "simStepId": "6ae15f2e-5331-4153-b9d2-2a297b65c55f",
+ "diagramNodeId": "4d657da7-6757-4d72-9324-765a991f73d7",
+ "simStepLabel": "Initialize Tray Icon",
+ "simStepDescription": "After attempting to start all autostart modules, the `trayicon.run` function is called. This initializes the PyQt application and creates the system tray icon, making ActivityWatch accessible to the user.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "207",
+ "endLine": "211",
+ "relevantVariables": [
+ "run",
+ "app",
+ "QApplication"
+ ]
+ },
+ "inputDataExample": "{\n \"manager\": \"\",\n \"testing\": true\n}",
+ "outputDataExample": "{\n \"app_exit_code\": 0\n}"
+ },
+ {
+ "simStepId": "03fd319d-4ffe-47cf-bf39-ac388da80fa7",
+ "diagramNodeId": "dfaa3fc8-eca8-4c67-b926-87798f511adb",
+ "simStepLabel": "Create Tray Icon Instance",
+ "simStepDescription": "The `run` function creates an instance of the `TrayIcon` class, passing the `manager` object which holds the state of all modules.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "259",
+ "endLine": "260",
+ "relevantVariables": [
+ "TrayIcon",
+ "manager"
+ ]
+ },
+ "inputDataExample": "{\n \"manager\": \"\"\n}",
+ "outputDataExample": "{\n \"manager\": \"\"\n}"
+ },
+ {
+ "simStepId": "08d88f03-4133-41d6-9cbb-0df16703b864",
+ "diagramNodeId": "05bd0955-8e55-4657-80ee-f6389995db6d",
+ "simStepLabel": "Build Tray Menu",
+ "simStepDescription": "The `TrayIcon` constructor builds the context menu. It creates a 'Modules' submenu by iterating through the modules discovered by the manager. Each module is represented as a checkable menu item, with its initial state reflecting whether it's currently running.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "174",
+ "endLine": "193",
+ "relevantVariables": [
+ "_build_modulemenu",
+ "add_module_menuitem",
+ "module.is_alive"
+ ]
+ },
+ "inputDataExample": "{\n \"modules_bundled\": [\n \"aw-server\"\n ],\n \"modules_system\": [\n \"aw-watcher-window\"\n ]\n}",
+ "outputDataExample": "{\n \"menu_actions\": {\n \"aw-server\": {\n \"checked\": true\n },\n \"aw-watcher-window\": {\n \"checked\": true\n }\n }\n}"
+ },
+ {
+ "simStepId": "8e583414-7b87-42c9-bdb2-e56259be4cdf",
+ "diagramNodeId": "d9e460b6-432d-49c8-8e76-0d8750aa2c10",
+ "simStepLabel": "User Toggles Module",
+ "simStepDescription": "The user clicks on a module in the tray menu, triggering the associated lambda function which calls `module.toggle()`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "179",
+ "endLine": "179",
+ "relevantVariables": [
+ "module.toggle"
+ ]
+ },
+ "inputDataExample": "{\n \"user_action\": \"click\",\n \"menu_item\": \"aw-server\"\n}",
+ "outputDataExample": "{\n \"user_action\": \"click\",\n \"menu_item\": \"aw-server\"\n}"
+ },
+ {
+ "simStepId": "520ab3f2-ef6c-4334-89fc-280f6d86d14b",
+ "diagramNodeId": "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b",
+ "simStepLabel": "Toggle Module State",
+ "simStepDescription": "The `toggle` method in the `Module` class checks if the module is currently started. If it is, it calls `stop()`; otherwise, it calls `start()`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/manager.py",
+ "startLine": "202",
+ "endLine": "206",
+ "relevantVariables": [
+ "toggle",
+ "self.started",
+ "self.stop",
+ "self.start"
+ ]
+ },
+ "inputDataExample": "{\n \"module_name\": \"aw-server\",\n \"current_state\": \"started\"\n}",
+ "outputDataExample": "{\n \"action_taken\": \"stop\"\n}"
+ },
+ {
+ "simStepId": "fdff8ecd-12b9-4bc0-ba7b-9402d26b1737",
+ "diagramNodeId": "9d4dee50-64ef-459a-98fa-839761e16813",
+ "simStepLabel": "Send Termination Signal",
+ "simStepDescription": "The `stop()` method sends a SIGTERM signal to the module's subprocess to gracefully shut it down.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/manager.py",
+ "startLine": "191",
+ "endLine": "191",
+ "relevantVariables": [
+ "_process.terminate"
+ ]
+ },
+ "inputDataExample": "{\n \"process_id\": 12345\n}",
+ "outputDataExample": "{\n \"process_id\": 12345\n}"
+ },
+ {
+ "simStepId": "01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9",
+ "diagramNodeId": "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5",
+ "simStepLabel": "Periodic Status Check",
+ "simStepDescription": "A recurring timer in `TrayIcon` triggers `rebuild_modules_menu` every 2 seconds. This function updates the checkmarks in the 'Modules' menu to reflect the current running status of each module.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "149",
+ "endLine": "158",
+ "relevantVariables": [
+ "rebuild_modules_menu",
+ "QtCore.QTimer.singleShot"
+ ]
+ },
+ "inputDataExample": "{}",
+ "outputDataExample": "{\n \"menu_updates\": [\n {\n \"module\": \"aw-server\",\n \"is_alive\": false\n }\n ]\n}"
+ },
+ {
+ "simStepId": "c0115129-b34b-4d27-9f73-cf2dc142ea81",
+ "diagramNodeId": "f704019b-d227-47ad-8761-9a2ea01516cb",
+ "simStepLabel": "Query Module Process State",
+ "simStepDescription": "To update the menu, `rebuild_modules_menu` calls `module.is_alive()` for each module's menu action.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "153",
+ "endLine": "153",
+ "relevantVariables": [
+ "module.is_alive"
+ ]
+ },
+ "inputDataExample": "{\n \"module_name\": \"aw-server\"\n}",
+ "outputDataExample": "{\n \"module_name\": \"aw-server\"\n}"
+ },
+ {
+ "simStepId": "899b57ba-4a68-4620-977a-80981d089e85",
+ "diagramNodeId": "421b1687-98a6-4773-a7dc-cdc564be5f8e",
+ "simStepLabel": "Check if Module Process is Alive",
+ "simStepDescription": "The `is_alive` method polls the subprocess to check its status. It returns `True` if the process is running and `False` otherwise.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/manager.py",
+ "startLine": "208",
+ "endLine": "214",
+ "relevantVariables": [
+ "is_alive",
+ "_process.poll",
+ "_process.returncode"
+ ]
+ },
+ "inputDataExample": "{\n \"_process\": \"\"\n}",
+ "outputDataExample": "{\n \"is_alive\": false\n}"
+ },
+ {
+ "simStepId": "7775ac80-c954-464e-b230-b233216ee5e3",
+ "diagramNodeId": "ba9e605d-98a7-4b50-979a-05bf7213c681",
+ "simStepLabel": "Check for Unexpected Stops",
+ "simStepDescription": "A separate periodic timer calls `check_module_status`, which in turn calls `manager.get_unexpected_stops()` to detect if any managed modules have crashed.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "163",
+ "endLine": "163",
+ "relevantVariables": [
+ "self.manager.get_unexpected_stops"
+ ]
+ },
+ "inputDataExample": "{}",
+ "outputDataExample": "{}"
+ },
+ {
+ "simStepId": "6173a9e1-ecfa-4dd9-9f82-f80579406011",
+ "diagramNodeId": "5dd0e28d-e0e9-4433-8db9-e8de93de1abe",
+ "simStepLabel": "Identify Unexpectedly Stopped Modules",
+ "simStepDescription": "The `get_unexpected_stops` method filters the list of all modules, returning those that are marked as `started` but are no longer `alive`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/manager.py",
+ "startLine": "252",
+ "endLine": "253",
+ "relevantVariables": [
+ "get_unexpected_stops",
+ "x.started",
+ "x.is_alive"
+ ]
+ },
+ "inputDataExample": "{\n \"modules\": [\n {\n \"name\": \"aw-watcher-afk\",\n \"started\": true,\n \"is_alive\": false\n }\n ]\n}",
+ "outputDataExample": "{\n \"unexpected_stops\": [\n {\n \"name\": \"aw-watcher-afk\",\n \"started\": true,\n \"is_alive\": false\n }\n ]\n}"
+ },
+ {
+ "simStepId": "1ed5cd16-b593-41cf-84f2-233a8d64a227",
+ "diagramNodeId": "2298c4b5-17de-487f-b592-2ac0f95eca84",
+ "simStepLabel": "Trigger Failure Notification",
+ "simStepDescription": "If any modules are identified as having stopped unexpectedly, the `show_module_failed_dialog` function is called for each one.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "166",
+ "endLine": "166",
+ "relevantVariables": [
+ "show_module_failed_dialog"
+ ]
+ },
+ "inputDataExample": "{\n \"failed_module\": \"\"\n}",
+ "outputDataExample": "{\n \"failed_module\": \"\"\n}"
+ },
+ {
+ "simStepId": "a71f6cd0-490a-40b5-8a05-1c873f208882",
+ "diagramNodeId": "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc",
+ "simStepLabel": "Display Failure Dialog",
+ "simStepDescription": "A `QMessageBox` is displayed to the user, informing them that a module has quit unexpectedly. The dialog includes the module's logs and provides a button to restart the module.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-qt/aw_qt/trayicon.py",
+ "startLine": "136",
+ "endLine": "147",
+ "relevantVariables": [
+ "show_module_failed_dialog",
+ "QMessageBox",
+ "module.read_log",
+ "module.start"
+ ]
+ },
+ "inputDataExample": "{\n \"module_name\": \"aw-watcher-afk\",\n \"log_content\": \"ERROR: Something went wrong...\"\n}",
+ "outputDataExample": "{\n \"user_choice\": \"Restart\"\n}"
+ }
+ ],
+ "description": "- The
aw-qt application provides a system tray icon that acts as a central control panel for ActivityWatch - It discovers and manages all the runnable modules, such as the server and various watchers
- From the tray menu, users can start and stop individual modules, check their status, and access the web UI
- The manager handles the autostarting of configured modules on system login, ensuring that time tracking is always active without manual intervention
",
+ "simulationNodesAndEdges": {
+ "d1bb4e12-29b6-4f70-9931-321214e3ea2a": {
+ "simStepIds": [
+ "61d1a03e-ed06-496d-8495-36419b9c8607"
+ ]
+ },
+ "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc": {
+ "simStepIds": [
+ "c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a"
+ ]
+ },
+ "cae37571-f0ba-4abe-aefd-53e49f26137f": {
+ "simStepIds": [
+ "e716abbb-c96e-4613-bca2-0c094e8df129"
+ ]
+ },
+ "8f981b6f-7bed-4d9a-8486-79f85b06d904": {
+ "simStepIds": [
+ "8be10173-751a-4da9-99a9-321c23e71aaa"
+ ]
+ },
+ "4d657da7-6757-4d72-9324-765a991f73d7": {
+ "simStepIds": [
+ "6ae15f2e-5331-4153-b9d2-2a297b65c55f"
+ ]
+ },
+ "05bd0955-8e55-4657-80ee-f6389995db6d": {
+ "simStepIds": [
+ "08d88f03-4133-41d6-9cbb-0df16703b864"
+ ]
+ },
+ "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b": {
+ "simStepIds": [
+ "520ab3f2-ef6c-4334-89fc-280f6d86d14b"
+ ]
+ },
+ "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5": {
+ "simStepIds": [
+ "01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9"
+ ]
+ },
+ "421b1687-98a6-4773-a7dc-cdc564be5f8e": {
+ "simStepIds": [
+ "899b57ba-4a68-4620-977a-80981d089e85"
+ ]
+ },
+ "5dd0e28d-e0e9-4433-8db9-e8de93de1abe": {
+ "simStepIds": [
+ "6173a9e1-ecfa-4dd9-9f82-f80579406011"
+ ]
+ },
+ "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc": {
+ "simStepIds": [
+ "a71f6cd0-490a-40b5-8a05-1c873f208882"
+ ]
+ },
+ "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7": {
+ "simStepIds": [
+ "6084ca69-514e-4bde-b2c0-1d33b26203e8"
+ ]
+ },
+ "030668a5-a377-4710-b39f-95efb5fa4768": {
+ "simStepIds": [
+ "540119c2-b541-4342-aa59-233b4f0f8db5"
+ ]
+ },
+ "1fb5a75e-9c49-490d-b412-04ac1c7205fa": {
+ "simStepIds": [
+ "9aeaf443-6741-4557-9671-67d596f456b3"
+ ]
+ },
+ "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9": {
+ "simStepIds": [
+ "f968357d-53c4-41e8-b71f-c581c08b52e6"
+ ]
+ },
+ "dfaa3fc8-eca8-4c67-b926-87798f511adb": {
+ "simStepIds": [
+ "03fd319d-4ffe-47cf-bf39-ac388da80fa7"
+ ]
+ },
+ "d9e460b6-432d-49c8-8e76-0d8750aa2c10": {
+ "simStepIds": [
+ "8e583414-7b87-42c9-bdb2-e56259be4cdf"
+ ]
+ },
+ "9d4dee50-64ef-459a-98fa-839761e16813": {
+ "simStepIds": [
+ "fdff8ecd-12b9-4bc0-ba7b-9402d26b1737"
+ ]
+ },
+ "f704019b-d227-47ad-8761-9a2ea01516cb": {
+ "simStepIds": [
+ "c0115129-b34b-4d27-9f73-cf2dc142ea81"
+ ]
+ },
+ "ba9e605d-98a7-4b50-979a-05bf7213c681": {
+ "simStepIds": [
+ "7775ac80-c954-464e-b230-b233216ee5e3"
+ ]
+ },
+ "2298c4b5-17de-487f-b592-2ac0f95eca84": {
+ "simStepIds": [
+ "1ed5cd16-b593-41cf-84f2-233a8d64a227"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "aw-qt, Manager, Module, autostart, start",
+ "generationPrompt": "How the module manager and tray icon works",
+ "generationKeywords": "aw-qt, Manager, Module, autostart, start",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 11,
+ "promptTokenCount": 10004,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 124,
+ "promptTokenCount": 89898,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 47,
+ "promptTokenCount": 40704,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": [
+ {
+ "path": "aw-server-rust/aw-server/src/endpoints/import.rs",
+ "container": "server",
+ "triggerType": "http",
+ "identifier": "application/json"
+ }
+ ]
+ },
+ "crossLayerTriggers": [
+ {
+ "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "identifier": "application/json",
+ "type": "http",
+ "matchedTargets": [
+ ".github/workflows/test.yml",
+ "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "aw-server-rust/aw-server/src/endpoints/import.rs"
+ ]
+ }
+ ]
+ }
+ },
+ "How time-based notifications work": {
+ "name": "How time-based notifications work",
+ "simSteps": [
+ {
+ "simStepId": "9b9a0f90-d7a7-40fb-8573-53b470ecf85d",
+ "diagramNodeId": "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1",
+ "simStepLabel": "Start Notification Service",
+ "simStepDescription": "The `aw-notify` service is started from the command line, which calls the `main` function. `main` in turn invokes the `start` function to begin the notification service.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "340",
+ "endLine": "360",
+ "relevantVariables": [
+ "main",
+ "start"
+ ]
+ },
+ "inputDataExample": "{\n \"command\": \"aw-notify start\"\n}",
+ "outputDataExample": "{\n \"status\": \"Service starting...\"\n}"
+ },
+ {
+ "simStepId": "3c977159-c34d-4907-9004-e5aaff3f3bdc",
+ "diagramNodeId": "f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
+ "simStepLabel": "Initialize Client and Get Hostname",
+ "simStepDescription": "The `start` function initializes the `ActivityWatchClient` to communicate with the `aw-server` and retrieves the local hostname.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "368",
+ "endLine": "370",
+ "relevantVariables": [
+ "aw_client.ActivityWatchClient",
+ "aw.get_info"
+ ]
+ },
+ "inputDataExample": "{\n \"testing\": false,\n \"port\": null\n}",
+ "outputDataExample": "{\n \"testing\": false,\n \"port\": null\n}"
+ },
+ {
+ "simStepId": "f636bdd6-a8e3-47ec-9f9d-986b21a81868",
+ "diagramNodeId": "553f1437-5c34-4d6d-8226-417014259fc5",
+ "simStepLabel": "Initialize Threshold Alerts",
+ "simStepDescription": "The `threshold_alerts` function is called, which creates a list of `CategoryAlert` objects. Each object is configured with a specific category to monitor (e.g., 'Work', 'Twitter'), a list of time thresholds, and a display label.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "380",
+ "endLine": "392",
+ "relevantVariables": [
+ "threshold_alerts",
+ "CategoryAlert",
+ "alerts"
+ ]
+ },
+ "inputDataExample": "{}",
+ "outputDataExample": "{\n \"alerts\": [\n {\n \"category\": \"Work\",\n \"label\": \"💼 Work\",\n \"thresholds\": [900, 1800, 3600, 7200, 14400]\n },\n {\n \"category\": \"Twitter\",\n \"label\": \"🐦 Twitter\",\n \"thresholds\": [900, 1800, 3600]\n }\n ]\n}"
+ },
+ {
+ "simStepId": "7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b",
+ "diagramNodeId": "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
+ "simStepLabel": "Enter Main Loop",
+ "simStepDescription": "The service enters an infinite `while True` loop to periodically check activity against the defined thresholds. The loop starts by calling `alert.update()` for each configured alert.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "400",
+ "endLine": "401",
+ "relevantVariables": [
+ "alerts",
+ "alert.update"
+ ]
+ },
+ "inputDataExample": "{\n \"alert_object\": {\n \"category\": \"Work\",\n \"label\": \"💼 Work\",\n \"thresholds\": [900, 1800, 3600, 7200, 14400],\n \"time_spent\": 0\n }\n}",
+ "outputDataExample": "{\n \"alert_object\": {\n \"category\": \"Work\",\n \"label\": \"💼 Work\",\n \"thresholds\": [900, 1800, 3600, 7200, 14400],\n \"time_spent\": 0\n }\n}"
+ },
+ {
+ "simStepId": "945e3312-c7c9-4722-953b-94dc0feee249",
+ "diagramNodeId": "1de089eb-60a7-4d7f-bfb5-3f7f23315873",
+ "simStepLabel": "Update Category Time",
+ "simStepDescription": "The `update` method of a `CategoryAlert` instance is called. It checks if enough time has passed to warrant a new query to the server. If so, it calls `get_time()` to fetch the latest activity duration for its category.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "262",
+ "endLine": "276",
+ "relevantVariables": [
+ "update",
+ "time_to_next_threshold",
+ "get_time"
+ ]
+ },
+ "inputDataExample": "{\n \"self.category\": \"Work\",\n \"self.time_to_next_threshold\": \"900s\",\n \"self.last_check\": \"1970-01-01T00:00:00Z\"\n}",
+ "outputDataExample": "{\n \"status\": \"Time to update, calling get_time()\"\n}"
+ },
+ {
+ "simStepId": "f20bb756-15f3-4a7c-914b-aa61470cc435",
+ "diagramNodeId": "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
+ "simStepLabel": "API Call: Query Server for Activity Data",
+ "simStepDescription": "The `get_time` function constructs a query to summarize activity data and sends it to the `aw-server` via an HTTP POST request to the `/api/0/query` endpoint.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "120",
+ "endLine": "120",
+ "relevantVariables": [
+ "aw.query",
+ "query",
+ "timeperiods"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": \"...canonicalEvents... cat_events = sort_by_duration(merge_events_by_keys(events, [\\\"$category\\\"])); ...\",\n \"timeperiods\": [\"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"]\n}",
+ "outputDataExample": "{\n \"query\": \"...canonicalEvents... cat_events = sort_by_duration(merge_events_by_keys(events, [\\\"$category\\\"])); ...\",\n \"timeperiods\": [\"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"]\n}"
+ },
+ {
+ "simStepId": "868edfd6-1f03-416e-88dc-7b09d05e4ba5",
+ "diagramNodeId": "e567d898-2785-43f6-98ef-f4b6d1232620",
+ "simStepLabel": "Server: Receive and Process Query",
+ "simStepDescription": "The `aw-server-rust` instance receives the POST request at the `/api/0/query` endpoint. The request body, containing the query and time periods, is deserialized.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "9",
+ "endLine": "12",
+ "relevantVariables": [
+ "query",
+ "query_req"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": [\"...query string...\"],\n \"timeperiods\": [\"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"]\n}",
+ "outputDataExample": "{\n \"query_code\": \"...query string...\",\n \"intervals\": [\"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"]\n}"
+ },
+ {
+ "simStepId": "b835d5e0-434d-4469-94fe-d309114a9ef1",
+ "diagramNodeId": "8f02d20c-25fe-4a28-99de-3e8908d0a66f",
+ "simStepLabel": "Server: Execute Query",
+ "simStepDescription": "The server's query endpoint passes the parsed query string and time interval to the `aw_query` library for execution against the datastore.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "16",
+ "endLine": "16",
+ "relevantVariables": [
+ "aw_query::query"
+ ]
+ },
+ "inputDataExample": "{\n \"query_code\": \"...query string...\",\n \"interval\": \"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"\n}",
+ "outputDataExample": "{\n \"query_code\": \"...query string...\",\n \"interval\": \"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"\n}"
+ },
+ {
+ "simStepId": "cc5cfecf-cee9-4582-aa6c-b74787a11da8",
+ "diagramNodeId": "44016962-bb6d-4a70-b13c-4538926a02a4",
+ "simStepLabel": "Server: Fetch Events from Datastore",
+ "simStepDescription": "The query interpreter executes the `query_bucket` function from the query string. This function calls `ds.get_events` on the datastore to retrieve all relevant raw events within the specified time interval from the SQLite database.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/functions.rs",
+ "startLine": "150",
+ "endLine": "162",
+ "relevantVariables": [
+ "query_bucket",
+ "ds.get_events"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-hostname\",\n \"interval\": {\n \"start\": \"2023-10-27T04:00:00Z\",\n \"end\": \"2023-10-28T04:00:00Z\"\n }\n}",
+ "outputDataExample": "{\n \"events\": [\n {\"id\": 1, \"timestamp\": \"2023-10-27T10:00:00Z\", \"duration\": 300, \"data\": {\"app\": \"Code\", \"title\": \"main.py\"}},\n {\"id\": 2, \"timestamp\": \"2023-10-27T10:05:00Z\", \"duration\": 600, \"data\": {\"app\": \"Firefox\", \"title\": \"Stack Overflow\"}}\n ]\n}"
+ },
+ {
+ "simStepId": "027140c6-aa16-4070-89d3-3b553168e65e",
+ "diagramNodeId": "5595958a-cf9d-4894-9824-ecc89e5cf956",
+ "simStepLabel": "Server: Transform Raw Events",
+ "simStepDescription": "The raw events are passed through a series of transform functions as defined in the query, such as `merge_events_by_keys` to group events by category and `sort_by_duration` to order them.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "115",
+ "endLine": "115",
+ "relevantVariables": [
+ "merge_events_by_keys",
+ "sort_by_duration"
+ ]
+ },
+ "inputDataExample": "{\n \"transform_function\": \"merge_events_by_keys\",\n \"events\": [{\"id\": 1, \"data\": {\"$category\": [\"Work\"]}}, ...]\n}",
+ "outputDataExample": "{\n \"transform_function\": \"merge_events_by_keys\",\n \"events\": [{\"id\": 1, \"data\": {\"$category\": [\"Work\"]}}, ...]\n}"
+ },
+ {
+ "simStepId": "f52d6bfa-55fe-49ee-9f20-60bf296c76f4",
+ "diagramNodeId": "fd5d1362-e41b-43af-bfd8-7f7c344c9849",
+ "simStepLabel": "Server: Send Query Result",
+ "simStepDescription": "After all transformations are complete, the query engine returns the final processed data. The server serializes this data into a JSON array and sends it back as the HTTP response.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "28",
+ "endLine": "28",
+ "relevantVariables": [
+ "json!",
+ "results"
+ ]
+ },
+ "inputDataExample": "{\n \"results_to_serialize\": [\n {\n \"events\": [], \n \"duration\": 5400, \n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\"]}, \"duration\": 3600},\n {\"data\": {\"$category\": [\"Social Media\"]}, \"duration\": 1800}\n ]\n }\n ]\n}",
+ "outputDataExample": "{\n \"status\": 200,\n \"body\": \"[{\\\"events\\\":[],\\\"duration\\\":5400,\\\"cat_events\\\":[{\\\"data\\\":{\\\"$category\\\":[\\\"Work\\\"]},\\\"duration\\\":3600},{\\\"data\\\":{\\\"$category\\\":[\\\"Social Media\\\"]},\\\"duration\\\":1800}]}]\"\n}"
+ },
+ {
+ "simStepId": "92487214-03b7-430e-aab5-b5a5fb85b2cb",
+ "diagramNodeId": "1b9dc1d5-e6a7-4069-8473-2156853d662e",
+ "simStepLabel": "Data Flow: Receive and Parse Server Response",
+ "simStepDescription": "The `aw-notify` client receives the HTTP response. The `get_time` function parses the JSON body to extract the categorized event durations.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "120",
+ "endLine": "120",
+ "relevantVariables": [
+ "aw.query"
+ ]
+ },
+ "inputDataExample": "{\n \"response_body\": \"[{\\\"cat_events\\\":[{\\\"data\\\":{\\\"$category\\\":[\\\"Work\\\"]},\\\"duration\\\":3600}, {\\\"data\\\":{\\\"$category\\\":[\\\"All\\\"]},\\\"duration\\\":5400}]}]\"\n}",
+ "outputDataExample": "{\n \"response_body\": \"[{\\\"cat_events\\\":[{\\\"data\\\":{\\\"$category\\\":[\\\"Work\\\"]},\\\"duration\\\":3600}, {\\\"data\\\":{\\\"$category\\\":[\\\"All\\\"]},\\\"duration\\\":5400}]}]\"\n}"
+ },
+ {
+ "simStepId": "9c0b3f20-5c18-418a-82f7-78b04ebda9b5",
+ "diagramNodeId": "a01b5cc8-f12f-447b-9879-6b55bda0ef87",
+ "simStepLabel": "Process Query Result and Update State",
+ "simStepDescription": "The `get_time` function processes the server response, creating a dictionary mapping each category to its total duration. This dictionary is returned to the `update` method, which then updates the `time_spent` attribute of the `CategoryAlert` instance.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "123",
+ "endLine": "130",
+ "relevantVariables": [
+ "cat_time",
+ "res"
+ ]
+ },
+ "inputDataExample": "{\n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\"]}, \"duration\": 3660},\n {\"data\": {\"$category\": [\"All\"]}, \"duration\": 5430}\n ]\n}",
+ "outputDataExample": "{\n \"self.time_spent\": \"3660s\"\n}"
+ },
+ {
+ "simStepId": "c8b0fe19-76a8-458d-9923-c2f270e306b3",
+ "diagramNodeId": "08e05622-d948-47eb-a56d-3d6782d638c0",
+ "simStepLabel": "Check for Threshold Breach",
+ "simStepDescription": "After updating the time spent, the main loop calls the `check` method on the `CategoryAlert` instance. This method iterates through its configured thresholds to see if any have been met or exceeded by the new `time_spent` value.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "402",
+ "endLine": "402",
+ "relevantVariables": [
+ "alert.check"
+ ]
+ },
+ "inputDataExample": "{\n \"self.time_spent\": \"3660s\",\n \"self.thresholds_untriggered\": [3600, 7200, 14400]\n}",
+ "outputDataExample": "{\n \"self.time_spent\": \"3660s\",\n \"self.thresholds_untriggered\": [3600, 7200, 14400]\n}"
+ },
+ {
+ "simStepId": "a66f8ebc-93f8-4f9c-8f19-03bd951d1e98",
+ "diagramNodeId": "30303464-f5f8-4155-87e9-b81dda8175d9",
+ "simStepLabel": "Trigger Desktop Notification",
+ "simStepDescription": "A threshold has been reached (e.g., time spent on 'Work' exceeds 1 hour). The `check` method calls the `notify` function, passing it a title and a formatted message to be displayed to the user.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "281",
+ "endLine": "297",
+ "relevantVariables": [
+ "check",
+ "thres",
+ "self.time_spent",
+ "notify"
+ ]
+ },
+ "inputDataExample": "{\n \"thres\": 3600,\n \"self.time_spent\": 3660,\n \"self.label\": \"💼 Work\"\n}",
+ "outputDataExample": "{\n \"title\": \"Goal reached!\",\n \"msg\": \"💼 Work: 1h (1h 1m)\"\n}"
+ },
+ {
+ "simStepId": "e46653da-3493-419e-8f9c-397be83fe894",
+ "diagramNodeId": "17c4cd6c-69f5-4df8-ac77-6955a0518939",
+ "simStepLabel": "Render Notification",
+ "simStepDescription": "The `notify` function uses the `desktop-notifier` library to send the notification to the operating system's notification center.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "161",
+ "endLine": "177",
+ "relevantVariables": [
+ "notifier.send"
+ ]
+ },
+ "inputDataExample": "{\n \"title\": \"Goal reached!\",\n \"msg\": \"💼 Work: 1h (1h 1m)\"\n}",
+ "outputDataExample": "{\n \"title\": \"Goal reached!\",\n \"msg\": \"💼 Work: 1h (1h 1m)\"\n}"
+ },
+ {
+ "simStepId": "21533839-7ba4-4cfa-864a-2f67198cad68",
+ "diagramNodeId": "445477ac-c52d-4053-a45e-8c81da805c88",
+ "simStepLabel": "User sees notification",
+ "simStepDescription": "The operating system displays a native notification on the user's desktop with the message '💼 Work: 1h'.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "149",
+ "endLine": "184",
+ "relevantVariables": [
+ "notify"
+ ]
+ },
+ "inputDataExample": "{\n \"notification_payload\": {\n \"title\": \"Goal reached!\",\n \"message\": \"💼 Work: 1h (1h 1m)\"\n }\n}",
+ "outputDataExample": "null"
+ },
+ {
+ "simStepId": "8702751d-5f93-4a07-9f11-b22c5e109d8a",
+ "diagramNodeId": "",
+ "simStepLabel": "Wait for Next Cycle",
+ "simStepDescription": "After checking all alerts, the main loop pauses for 10 seconds before starting the next iteration.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-notify/aw_notify/main.py",
+ "startLine": "409",
+ "endLine": "409",
+ "relevantVariables": [
+ "sleep"
+ ]
+ },
+ "inputDataExample": "{}",
+ "outputDataExample": "{}"
+ }
+ ],
+ "description": "- The
aw-notify module provides proactive alerts based on a user's activity - It runs as a background service, periodically querying the
aw-server to get summaries of time spent in different categories - Users can configure thresholds for specific categories (e
- g
- , 'notify after 30 minutes on Social Media')
- When a threshold is reached,
aw-notify sends a native desktop notification to the user - It can also provide daily summary notifications and alerts about the server's status
",
+ "simulationNodesAndEdges": {
+ "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1": {
+ "simStepIds": [
+ "9b9a0f90-d7a7-40fb-8573-53b470ecf85d"
+ ]
+ },
+ "553f1437-5c34-4d6d-8226-417014259fc5": {
+ "simStepIds": [
+ "f636bdd6-a8e3-47ec-9f9d-986b21a81868"
+ ]
+ },
+ "1de089eb-60a7-4d7f-bfb5-3f7f23315873": {
+ "simStepIds": [
+ "945e3312-c7c9-4722-953b-94dc0feee249"
+ ]
+ },
+ "e567d898-2785-43f6-98ef-f4b6d1232620": {
+ "simStepIds": [
+ "868edfd6-1f03-416e-88dc-7b09d05e4ba5"
+ ]
+ },
+ "44016962-bb6d-4a70-b13c-4538926a02a4": {
+ "simStepIds": [
+ "cc5cfecf-cee9-4582-aa6c-b74787a11da8"
+ ]
+ },
+ "fd5d1362-e41b-43af-bfd8-7f7c344c9849": {
+ "simStepIds": [
+ "f52d6bfa-55fe-49ee-9f20-60bf296c76f4"
+ ]
+ },
+ "a01b5cc8-f12f-447b-9879-6b55bda0ef87": {
+ "simStepIds": [
+ "9c0b3f20-5c18-418a-82f7-78b04ebda9b5"
+ ]
+ },
+ "30303464-f5f8-4155-87e9-b81dda8175d9": {
+ "simStepIds": [
+ "a66f8ebc-93f8-4f9c-8f19-03bd951d1e98"
+ ]
+ },
+ "445477ac-c52d-4053-a45e-8c81da805c88": {
+ "simStepIds": [
+ "21533839-7ba4-4cfa-864a-2f67198cad68"
+ ]
+ },
+ "f9ddc0fb-c342-4a4a-baec-53c6a2581b80": {
+ "simStepIds": [
+ "3c977159-c34d-4907-9004-e5aaff3f3bdc"
+ ]
+ },
+ "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e": {
+ "simStepIds": [
+ "7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b"
+ ]
+ },
+ "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd": {
+ "simStepIds": [
+ "f20bb756-15f3-4a7c-914b-aa61470cc435"
+ ]
+ },
+ "8f02d20c-25fe-4a28-99de-3e8908d0a66f": {
+ "simStepIds": [
+ "b835d5e0-434d-4469-94fe-d309114a9ef1"
+ ]
+ },
+ "5595958a-cf9d-4894-9824-ecc89e5cf956": {
+ "simStepIds": [
+ "027140c6-aa16-4070-89d3-3b553168e65e"
+ ]
+ },
+ "1b9dc1d5-e6a7-4069-8473-2156853d662e": {
+ "simStepIds": [
+ "92487214-03b7-430e-aab5-b5a5fb85b2cb"
+ ]
+ },
+ "08e05622-d948-47eb-a56d-3d6782d638c0": {
+ "simStepIds": [
+ "c8b0fe19-76a8-458d-9923-c2f270e306b3"
+ ]
+ },
+ "17c4cd6c-69f5-4df8-ac77-6955a0518939": {
+ "simStepIds": [
+ "e46653da-3493-419e-8f9c-397be83fe894"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "aw-notify, CategoryAlert, DesktopNotifier, thresholds, get_time",
+ "generationPrompt": "How time-based notifications work",
+ "generationKeywords": "aw-notify, CategoryAlert, DesktopNotifier, thresholds, get_time",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 123,
+ "promptTokenCount": 142893,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 62,
+ "promptTokenCount": 64061,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": []
+ }
+ }
+ },
+ "How data export and import works": {
+ "name": "How data export and import works",
+ "simSteps": [
+ {
+ "simStepId": "8739f5eb-aec2-47f1-b1e6-a05a2bb65acd",
+ "diagramNodeId": "a1e562ae-ea06-4c6a-ab92-fa78417115f6",
+ "simStepLabel": "Export Flow: Client Initiates Data Export",
+ "simStepDescription": "A client application, using `aw-client`, calls the `export_all` method to begin the process of exporting all user data from the ActivityWatch server.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "291",
+ "endLine": "292",
+ "relevantVariables": [
+ "export_all"
+ ]
+ },
+ "inputDataExample": "{}",
+ "outputDataExample": "{}"
+ },
+ {
+ "simStepId": "8efaf2e1-7c6d-4820-90a5-2abb80bf65ed",
+ "diagramNodeId": "5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
+ "simStepLabel": "Export Flow: API Call to Export Endpoint",
+ "simStepDescription": "The `aw-client` sends an HTTP GET request to the `/api/0/export` endpoint on the `aw-server` to fetch all bucket and event data.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "292",
+ "endLine": "292",
+ "relevantVariables": [
+ "_get"
+ ]
+ },
+ "inputDataExample": "{\"method\": \"GET\", \"endpoint\": \"/api/0/export\"}",
+ "outputDataExample": "{\"method\": \"GET\", \"endpoint\": \"/api/0/export\"}"
+ },
+ {
+ "simStepId": "7bdce779-492f-4dee-a68d-4e6d28dc079a",
+ "diagramNodeId": "07e4d089-e23f-4030-8c10-7dbdbd00e1c7",
+ "simStepLabel": "Export Flow: Server Handles Export Request",
+ "simStepDescription": "The `aw-server` (Flask application) receives the GET request and routes it to the `get` method of the `ExportAllResource` class, which is responsible for handling data exports.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "332",
+ "endLine": "344",
+ "relevantVariables": [
+ "ExportAllResource",
+ "get"
+ ]
+ },
+ "inputDataExample": "{\"request\": \"GET /api/0/export\"}",
+ "outputDataExample": "{}"
+ },
+ {
+ "simStepId": "6449735d-8c85-4d49-bb8c-c2b1f9918ffc",
+ "diagramNodeId": "8515a29c-385b-4ec5-886c-ba3a3a48518e",
+ "simStepLabel": "Export Flow: Call to API Layer for Export Logic",
+ "simStepDescription": "The REST endpoint handler calls the `export_all` method within the `ServerAPI` class to orchestrate the data aggregation process.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "337",
+ "endLine": "337",
+ "relevantVariables": [
+ "current_app.api.export_all"
+ ]
+ },
+ "inputDataExample": "{}",
+ "outputDataExample": "{}"
+ },
+ {
+ "simStepId": "d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6",
+ "diagramNodeId": "19faa606-15ad-4c47-a983-692a1f30a667",
+ "simStepLabel": "Export Flow: Aggregate All Buckets and Events",
+ "simStepDescription": "The `export_all` method in the `ServerAPI` class begins by fetching all existing buckets. It then iterates through each bucket to export its metadata and all associated events.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "97",
+ "endLine": "103",
+ "relevantVariables": [
+ "export_all",
+ "get_buckets",
+ "export_bucket"
+ ]
+ },
+ "inputDataExample": "{}",
+ "outputDataExample": "{\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\"}}"
+ },
+ {
+ "simStepId": "60764034-1b94-4c15-9015-09e8b775f736",
+ "diagramNodeId": "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
+ "simStepLabel": "Export Flow: Fetching Events for a Bucket",
+ "simStepDescription": "For each bucket, the `export_bucket` function calls `get_events` to retrieve all events associated with that bucket from the datastore.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "91",
+ "endLine": "91",
+ "relevantVariables": [
+ "get_events"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"limit\": -1}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"limit\": -1}"
+ },
+ {
+ "simStepId": "5fb7b7d5-1759-43dc-a711-b2b0b5df3893",
+ "diagramNodeId": "e590d109-3712-4d3d-9241-ba9cd9a7eeaa",
+ "simStepLabel": "Export Flow: Datastore Retrieves Events",
+ "simStepDescription": "The `get_events` function in the API layer queries the datastore, which fetches the corresponding events from the underlying database (e.g., SQLite).",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "214",
+ "endLine": "228",
+ "relevantVariables": [
+ "get_events",
+ "self.db[bucket_id].get"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"limit\": -1, \"start\": null, \"end\": null}",
+ "outputDataExample": "[{\"id\": 1, \"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180.0, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"id\": 2, \"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120.0, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]"
+ },
+ {
+ "simStepId": "7a5f8838-8ed9-47b3-907f-077efeedaa10",
+ "diagramNodeId": "272a1088-1b0c-43f9-8335-d7055539c813",
+ "simStepLabel": "Export Flow: Returning Exported Data to REST Layer",
+ "simStepDescription": "After collecting and formatting all buckets and their events (and scrubbing event IDs), the `export_all` method returns the complete data structure to the REST resource.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "103",
+ "endLine": "103",
+ "relevantVariables": [
+ "exported_buckets"
+ ]
+ },
+ "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\", \"last_updated\": \"2023-10-27T10:05:00.000Z\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]}}}",
+ "outputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\", \"last_updated\": \"2023-10-27T10:05:00.000Z\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]}}}"
+ },
+ {
+ "simStepId": "cfd637bd-f6b2-44cf-8330-7b2c59c0658b",
+ "diagramNodeId": "6e7e85b1-9708-4f64-ac9e-efc54338c444",
+ "simStepLabel": "Export Flow: Server Sends JSON File Response",
+ "simStepDescription": "The `ExportAllResource` constructs a final JSON payload and creates an HTTP response with a `Content-Disposition` header, prompting the client to download the data as `aw-buckets-export.json`.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "336",
+ "endLine": "344",
+ "relevantVariables": [
+ "buckets_export",
+ "payload",
+ "response"
+ ]
+ },
+ "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\", \"last_updated\": \"2023-10-27T10:05:00.000Z\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]}}}",
+ "outputDataExample": "HTTP Response with JSON file and headers: {\"Content-Disposition\": \"attachment; filename=aw-buckets-export.json\"}"
+ },
+ {
+ "simStepId": "ea6d2274-023a-4d5f-abf4-0414c6c7f68d",
+ "diagramNodeId": "e60e25ae-e9aa-4497-8555-7e3d99a4049f",
+ "simStepLabel": "Import Flow: Client Initiates Data Import",
+ "simStepDescription": "A client application, such as a script using `aw-client`, calls a method like `import_bucket` to start the data import process. This example shows a single bucket import, but the server supports importing multiple buckets at once.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "297",
+ "endLine": "299",
+ "relevantVariables": [
+ "import_bucket"
+ ]
+ },
+ "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]}}}",
+ "outputDataExample": "{}"
+ },
+ {
+ "simStepId": "f5c06885-1138-4c13-ae70-10b9d409be5b",
+ "diagramNodeId": "ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
+ "simStepLabel": "Import Flow: API Call to Import Endpoint",
+ "simStepDescription": "The client sends an HTTP POST request to the `/api/0/import` endpoint, with the JSON data containing buckets and events in the request body.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "299",
+ "endLine": "299",
+ "relevantVariables": [
+ "_post"
+ ]
+ },
+ "inputDataExample": "{\"method\": \"POST\", \"endpoint\": \"/api/0/import\", \"payload\": {\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}}",
+ "outputDataExample": "{\"method\": \"POST\", \"endpoint\": \"/api/0/import\", \"payload\": {\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}}"
+ },
+ {
+ "simStepId": "3e1decf0-1329-4da8-a7c7-870ffe960a54",
+ "diagramNodeId": "12725c25-974e-4363-bb91-c61c8745ed75",
+ "simStepLabel": "Import Flow: Server Handles Import Request",
+ "simStepDescription": "The `aw-server` receives the POST request and routes it to the `post` method of the `ImportAllResource` class. This method extracts the `buckets` data from the request.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "129",
+ "endLine": "341",
+ "relevantVariables": [
+ "ImportAllResource",
+ "post",
+ "buckets"
+ ]
+ },
+ "inputDataExample": "{\"request\": \"POST /api/0/import\", \"payload\": {\"buckets\": {}}}",
+ "outputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}"
+ },
+ {
+ "simStepId": "988adf58-e1be-4352-be66-4f02188fc28a",
+ "diagramNodeId": "0614b31f-64d9-4e85-a5f5-6304f0702bd7",
+ "simStepLabel": "Import Flow: Call to API Layer for Import Logic",
+ "simStepDescription": "The REST endpoint handler calls the `import_all` method in the `ServerAPI` to process the imported data.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "129",
+ "endLine": "341",
+ "relevantVariables": [
+ "current_app.api.import_all"
+ ]
+ },
+ "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}",
+ "outputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}"
+ },
+ {
+ "simStepId": "4050248c-1638-452c-8826-677a7a2fece8",
+ "diagramNodeId": "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570",
+ "simStepLabel": "Import Flow: Iterate and Import Each Bucket",
+ "simStepDescription": "The `import_all` method loops through each bucket from the input data and calls `import_bucket` to process them individually.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "133",
+ "endLine": "135",
+ "relevantVariables": [
+ "import_all",
+ "import_bucket"
+ ]
+ },
+ "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\"}"
+ },
+ {
+ "simStepId": "7e01821d-906c-4518-a1e0-6b71be84291a",
+ "diagramNodeId": "941b8c57-be7c-49cd-ba2a-d2237f8f129b",
+ "simStepLabel": "Import Flow: Create Bucket in Datastore",
+ "simStepDescription": "The `import_bucket` method calls `db.create_bucket` to create the new bucket with its metadata in the datastore.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "110",
+ "endLine": "120",
+ "relevantVariables": [
+ "self.db.create_bucket"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00.000Z\"}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00.000Z\"}"
+ },
+ {
+ "simStepId": "164ed08b-0873-499b-b945-e062cf362429",
+ "diagramNodeId": "07630c61-6df6-484b-81c3-0984379bfd68",
+ "simStepLabel": "Import Flow: Create and Insert Events",
+ "simStepDescription": "After creating the bucket, `import_bucket` calls `create_events`, which in turn calls the datastore's `insert` method to add all events from the imported data into the newly created bucket.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "128",
+ "endLine": "131",
+ "relevantVariables": [
+ "create_events"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\"}}]}",
+ "outputDataExample": "null"
+ },
+ {
+ "simStepId": "666a933a-7a74-4d90-be19-7610f7bd3d74",
+ "diagramNodeId": "1f7db50a-bc15-48d1-9f06-27ed743afa75",
+ "simStepLabel": "Import Flow: Persist Events to Database",
+ "simStepDescription": "The `create_events` method calls the datastore to persist the events to the database.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/api.py",
+ "startLine": "235",
+ "endLine": "235",
+ "relevantVariables": [
+ "self.db[bucket_id].insert"
+ ]
+ },
+ "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\"}}]}",
+ "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\"}}]}"
+ },
+ {
+ "simStepId": "3fd4d48c-e70c-4217-92c1-7554445cf03b",
+ "diagramNodeId": "ae563be0-ff29-4c20-8f6d-6771f04c8da3",
+ "simStepLabel": "Import Flow: Server Sends Success Response",
+ "simStepDescription": "After all buckets and events have been successfully imported, the `ImportAllResource` returns a 200 OK status to the client.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server/aw_server/rest.py",
+ "startLine": "129",
+ "endLine": "341",
+ "relevantVariables": []
+ },
+ "inputDataExample": "{}",
+ "outputDataExample": "{\"status_code\": 200, \"message\": \"OK\"}"
+ }
+ ],
+ "description": "- To ensure users have full control over their data,
aw-server provides API endpoints for data migration - The export feature allows a user to download all their tracked data, including bucket metadata and all associated events, into a single JSON file
- This file can be used for backups, analysis with external tools, or migration to another machine
- The import feature can read this JSON file to recreate the buckets and insert all the events, effectively restoring a user's complete history
",
+ "simulationNodesAndEdges": {
+ "a1e562ae-ea06-4c6a-ab92-fa78417115f6": {
+ "simStepIds": [
+ "8739f5eb-aec2-47f1-b1e6-a05a2bb65acd"
+ ]
+ },
+ "07e4d089-e23f-4030-8c10-7dbdbd00e1c7": {
+ "simStepIds": [
+ "7bdce779-492f-4dee-a68d-4e6d28dc079a"
+ ]
+ },
+ "19faa606-15ad-4c47-a983-692a1f30a667": {
+ "simStepIds": [
+ "d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6"
+ ]
+ },
+ "e590d109-3712-4d3d-9241-ba9cd9a7eeaa": {
+ "simStepIds": [
+ "5fb7b7d5-1759-43dc-a711-b2b0b5df3893"
+ ]
+ },
+ "6e7e85b1-9708-4f64-ac9e-efc54338c444": {
+ "simStepIds": [
+ "cfd637bd-f6b2-44cf-8330-7b2c59c0658b"
+ ]
+ },
+ "e60e25ae-e9aa-4497-8555-7e3d99a4049f": {
+ "simStepIds": [
+ "ea6d2274-023a-4d5f-abf4-0414c6c7f68d"
+ ]
+ },
+ "12725c25-974e-4363-bb91-c61c8745ed75": {
+ "simStepIds": [
+ "3e1decf0-1329-4da8-a7c7-870ffe960a54"
+ ]
+ },
+ "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570": {
+ "simStepIds": [
+ "4050248c-1638-452c-8826-677a7a2fece8"
+ ]
+ },
+ "07630c61-6df6-484b-81c3-0984379bfd68": {
+ "simStepIds": [
+ "164ed08b-0873-499b-b945-e062cf362429"
+ ]
+ },
+ "ae563be0-ff29-4c20-8f6d-6771f04c8da3": {
+ "simStepIds": [
+ "3fd4d48c-e70c-4217-92c1-7554445cf03b"
+ ]
+ },
+ "5fe912cd-a72c-4cc1-969b-b5eb6759ace9": {
+ "simStepIds": [
+ "8efaf2e1-7c6d-4820-90a5-2abb80bf65ed"
+ ]
+ },
+ "8515a29c-385b-4ec5-886c-ba3a3a48518e": {
+ "simStepIds": [
+ "6449735d-8c85-4d49-bb8c-c2b1f9918ffc"
+ ]
+ },
+ "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff": {
+ "simStepIds": [
+ "60764034-1b94-4c15-9015-09e8b775f736"
+ ]
+ },
+ "272a1088-1b0c-43f9-8335-d7055539c813": {
+ "simStepIds": [
+ "7a5f8838-8ed9-47b3-907f-077efeedaa10"
+ ]
+ },
+ "ebfbcf3c-bc57-4fe1-866e-fde1b860e633": {
+ "simStepIds": [
+ "f5c06885-1138-4c13-ae70-10b9d409be5b"
+ ]
+ },
+ "0614b31f-64d9-4e85-a5f5-6304f0702bd7": {
+ "simStepIds": [
+ "988adf58-e1be-4352-be66-4f02188fc28a"
+ ]
+ },
+ "941b8c57-be7c-49cd-ba2a-d2237f8f129b": {
+ "simStepIds": [
+ "7e01821d-906c-4518-a1e0-6b71be84291a"
+ ]
+ },
+ "1f7db50a-bc15-48d1-9f06-27ed743afa75": {
+ "simStepIds": [
+ "666a933a-7a74-4d90-be19-7610f7bd3d74"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "export_all, import_bucket, get_buckets, create_events, aw-server/api.py",
+ "generationPrompt": "How data export and import works",
+ "generationKeywords": "export_all, import_bucket, get_buckets, create_events, aw-server/api.py",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 6,
+ "promptTokenCount": 4701,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 123,
+ "promptTokenCount": 104218,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 58,
+ "promptTokenCount": 57795,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": []
+ }
+ }
+ },
+ "How custom scripting with the client library works": {
+ "name": "How custom scripting with the client library works",
+ "simSteps": [
+ {
+ "simStepId": "e90cee0c-3a20-498b-97b9-2086a61dc02b",
+ "diagramNodeId": "237e712f-0c66-4488-b6e9-1ef8c3b71b51",
+ "simStepLabel": "Start Script Execution",
+ "simStepDescription": "The user executes the `working_hours.py` script to calculate work time. The script defines a regex for 'Work' activities and sets up time periods to query.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/examples/working_hours.py",
+ "startLine": "91",
+ "endLine": "115",
+ "relevantVariables": [
+ "main",
+ "query"
+ ]
+ },
+ "inputDataExample": "null",
+ "outputDataExample": "{\n \"regex\": \"Google Docs|libreoffice|ReText|GitHub|Stack Overflow|BitBucket|Gitlab|vim|Spyder|kate|Ghidra|Scite|ActivityWatch|aw-\",\n \"hostname\": \"my-laptop\",\n \"timeperiods\": [\n [\"2023-10-26T04:00:00+00:00\", \"2023-10-27T04:00:00+00:00\"],\n [\"2023-10-27T04:00:00+00:00\", \"2023-10-28T04:00:00+00:00\"]\n ]\n}"
+ },
+ {
+ "simStepId": "5aa97ae5-7e30-4d15-8f12-05942f2e75c9",
+ "diagramNodeId": "aecc1e90-5e71-43f4-a5b8-757de329fe3a",
+ "simStepLabel": "Invoke AW Client Query",
+ "simStepDescription": "The script constructs a query string using helper functions from `aw_client.queries` and then calls the `aw.query()` method to execute it against the ActivityWatch server.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/examples/working_hours.py",
+ "startLine": "86",
+ "endLine": "86",
+ "relevantVariables": [
+ "aw.query"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": \"\\n events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-laptop\\\")));\\n not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-laptop\\\")));\\n not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\\n events = filter_period_intersect(events, not_afk);\\n events = categorize(events, [[\\\"Work\\\"], {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"Google Docs|libreoffice|ReText|GitHub|Stack Overflow|BitBucket|Gitlab|vim|Spyder|kate|Ghidra|Scite|ActivityWatch|aw-\\\", \\\"ignore_case\\\": true}]);\\n events = filter_keyvals(events, \\\"$category\\\", [[\\\"Work\\\"]]);\\n duration = sum_durations(events);\\n RETURN = {\\\"events\\\": events, \\\"duration\\\": duration};\\n \",\n \"timeperiods\": [\n [\"2023-10-26T04:00:00+00:00\", \"2023-10-27T04:00:00+00:00\"],\n [\"2023-10-27T04:00:00+00:00\", \"2023-10-28T04:00:00+00:00\"]\n ]\n}",
+ "outputDataExample": "{\n \"query\": \"\\n events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-laptop\\\")));\\n not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-laptop\\\")));\\n not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\\n events = filter_period_intersect(events, not_afk);\\n events = categorize(events, [[\\\"Work\\\"], {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"Google Docs|libreoffice|ReText|GitHub|Stack Overflow|BitBucket|Gitlab|vim|Spyder|kate|Ghidra|Scite|ActivityWatch|aw-\\\", \\\"ignore_case\\\": true}]);\\n events = filter_keyvals(events, \\\"$category\\\", [[\\\"Work\\\"]]);\\n duration = sum_durations(events);\\n RETURN = {\\\"events\\\": events, \\\"duration\\\": duration};\\n \",\n \"timeperiods\": [\n [\"2023-10-26T04:00:00+00:00\", \"2023-10-27T04:00:00+00:00\"],\n [\"2023-10-27T04:00:00+00:00\", \"2023-10-28T04:00:00+00:00\"]\n ]\n}"
+ },
+ {
+ "simStepId": "0d34430a-af81-407b-8817-672288674005",
+ "diagramNodeId": "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c",
+ "simStepLabel": "Prepare API Request",
+ "simStepDescription": "The `ActivityWatchClient.query` method formats the time periods into ISO 8601 interval strings and packages the query and time periods into a JSON payload for the HTTP POST request.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "305",
+ "endLine": "339",
+ "relevantVariables": [
+ "query",
+ "_post"
+ ]
+ },
+ "inputDataExample": "{\n \"query\": \"...query string...\",\n \"timeperiods\": [[\"2023-10-26T04:00:00+00:00\", \"2023-10-27T04:00:00+00:00\"]]\n}",
+ "outputDataExample": "{\n \"endpoint\": \"query/\",\n \"data\": {\n \"timeperiods\": [\"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"],\n \"query\": [\"...statement1...\", \"...statement2...\"]\n }\n}"
+ },
+ {
+ "simStepId": "834b7dbc-5efe-41ac-b75b-e43ad32141df",
+ "diagramNodeId": "62388ee6-67f4-4adc-b08e-90deeb10efd4",
+ "simStepLabel": "API Call: POST /api/0/query/",
+ "simStepDescription": "The client sends the formatted JSON payload as an HTTP POST request to the `/api/0/query/` endpoint on the `aw-server`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "122",
+ "endLine": "127",
+ "relevantVariables": [
+ "req.post"
+ ]
+ },
+ "inputDataExample": "{\n \"timeperiods\": [\"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"],\n \"query\": [\"events = query_bucket(...)\", \"RETURN = events;\"]\n}",
+ "outputDataExample": "{\n \"timeperiods\": [\"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"],\n \"query\": [\"events = query_bucket(...)\", \"RETURN = events;\"]\n}"
+ },
+ {
+ "simStepId": "c988a25d-05ad-4c19-87ac-362c79af1d00",
+ "diagramNodeId": "73994797-596f-4b60-a36e-5f45cba1fcd3",
+ "simStepLabel": "Receive Query Request (aw-server-rust)",
+ "simStepDescription": "The Rust-based `aw-server` receives the POST request at the `/api/0/query` endpoint. It parses the JSON body into a `Query` struct and prepares to execute the query against the datastore.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "10",
+ "endLine": "23",
+ "relevantVariables": [
+ "query",
+ "query_req",
+ "aw_query::query"
+ ]
+ },
+ "inputDataExample": "{\n \"timeperiods\": [\"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"],\n \"query\": [\"events = query_bucket(...)\", \"RETURN = events;\"]\n}",
+ "outputDataExample": "{\n \"query_code\": \"events = query_bucket(...)\\nRETURN = events;\",\n \"interval\": \"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"\n}"
+ },
+ {
+ "simStepId": "98777081-df05-4b5c-89f6-5076fab00e92",
+ "diagramNodeId": "31b60323-3a65-4184-a42f-f577f3a958ff",
+ "simStepLabel": "Execute Query",
+ "simStepDescription": "The endpoint handler passes the raw query string, time interval, and a datastore reference to the `aw_query::query` function, which is the entry point for the query engine.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "16",
+ "endLine": "16",
+ "relevantVariables": [
+ "aw_query::query"
+ ]
+ },
+ "inputDataExample": "{\n \"code\": \"events = query_bucket(\\\"aw-watcher-window_my-laptop\\\"); RETURN = events;\",\n \"ti\": \"2023-10-26T04:00:00Z/2023-10-27T04:00:00Z\",\n \"ds\": \"Datastore object\"\n}",
+ "outputDataExample": "{\n \"code\": \"events = query_bucket(\\\"aw-watcher-window_my-laptop\\\"); RETURN = events;\",\n \"ti\": \"2023-10-26T04:00:00Z/2023-10-27T04:00:00Z\",\n \"ds\": \"Datastore object\"\n}"
+ },
+ {
+ "simStepId": "b482a39f-e520-4d4d-8b2f-d1298922763f",
+ "diagramNodeId": "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b",
+ "simStepLabel": "Parse and Interpret Query",
+ "simStepDescription": "The `aw_query` library's main function takes the query string, tokenizes it with a lexer, parses it into an Abstract Syntax Tree (AST), and then interprets the AST to execute the query logic.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/lib.rs",
+ "startLine": "53",
+ "endLine": "64",
+ "relevantVariables": [
+ "query",
+ "lexer::Lexer",
+ "parser::parse",
+ "interpret::interpret_prog"
+ ]
+ },
+ "inputDataExample": "{\n \"code\": \"events = query_bucket(...); RETURN = events;\"\n}",
+ "outputDataExample": "{\n \"program\": \"AST representation of the query\"\n}"
+ },
+ {
+ "simStepId": "914107de-b38a-4307-ab2c-e257ed3d2fb5",
+ "diagramNodeId": "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
+ "simStepLabel": "Data Fetch: `query_bucket`",
+ "simStepDescription": "During interpretation, the `query_bucket` function is called. This function requests all events for a given bucket ID within the specified time interval from the datastore.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/functions.rs",
+ "startLine": "139",
+ "endLine": "168",
+ "relevantVariables": [
+ "query_bucket",
+ "ds.get_events"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-laptop\",\n \"interval\": \"2023-10-26T04:00:00Z/2023-10-27T04:00:00Z\"\n}",
+ "outputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-laptop\",\n \"interval\": \"2023-10-26T04:00:00Z/2023-10-27T04:00:00Z\"\n}"
+ },
+ {
+ "simStepId": "04bbbe33-e9de-4c5f-b925-27196d20ef1d",
+ "diagramNodeId": "0b3e80ff-b4c9-42db-b067-1a9ba48e9218",
+ "simStepLabel": "Database Query",
+ "simStepDescription": "The datastore worker receives the request and executes a SQL `SELECT` statement against the SQLite database to retrieve the raw event data for the specified bucket and time range.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "startLine": "700",
+ "endLine": "797",
+ "relevantVariables": [
+ "get_events",
+ "conn.prepare"
+ ]
+ },
+ "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-laptop\",\n \"starttime_opt\": \"2023-10-26T04:00:00Z\",\n \"endtime_opt\": \"2023-10-27T04:00:00Z\",\n \"limit_opt\": null\n}",
+ "outputDataExample": "{\n \"rows\": [\n [1, 1698307200000000000, 1698307260000000000, \"{\\\"app\\\":\\\"Firefox\\\",\\\"title\\\":\\\"ActivityWatch - GitHub\\\"}\"]\n ]\n}"
+ },
+ {
+ "simStepId": "5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619",
+ "diagramNodeId": "561eebea-ee66-4251-a29c-64c2e3aae490",
+ "simStepLabel": "Return Raw Event Data",
+ "simStepDescription": "The raw rows from the SQLite query are returned to the datastore layer for processing.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "startLine": "748",
+ "endLine": "788",
+ "relevantVariables": [
+ "rows"
+ ]
+ },
+ "inputDataExample": "{\n \"rows\": [\n [1, 1698307200000000000, 1698307260000000000, \"{\\\"app\\\":\\\"Firefox\\\",\\\"title\\\":\\\"ActivityWatch - GitHub\\\"}\"]\n ]\n}",
+ "outputDataExample": "{\n \"rows\": [\n [1, 1698307200000000000, 1698307260000000000, \"{\\\"app\\\":\\\"Firefox\\\",\\\"title\\\":\\\"ActivityWatch - GitHub\\\"}\"]\n ]\n}"
+ },
+ {
+ "simStepId": "1b3cdf02-5dad-411c-a35e-9250c8aafc9d",
+ "diagramNodeId": "60a529b9-b262-4c7f-9baf-5beb50025a86",
+ "simStepLabel": "Deserialize Events",
+ "simStepDescription": "The datastore layer deserializes the raw database rows into structured `Event` objects.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "startLine": "755",
+ "endLine": "780",
+ "relevantVariables": [
+ "Event"
+ ]
+ },
+ "inputDataExample": "{\n \"row\": [1, 1698307200000000000, 1698307260000000000, \"{\\\"app\\\":\\\"Firefox\\\",\\\"title\\\":\\\"ActivityWatch - GitHub\\\"}\"]\n}",
+ "outputDataExample": "{\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 60.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}"
+ },
+ {
+ "simStepId": "d78663e6-a6d4-4ba7-a922-436bd075e457",
+ "diagramNodeId": "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
+ "simStepLabel": "Return Deserialized Events",
+ "simStepDescription": "A vector of `Event` objects is returned from the datastore up to the query engine.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/functions.rs",
+ "startLine": "167",
+ "endLine": "167",
+ "relevantVariables": [
+ "ret"
+ ]
+ },
+ "inputDataExample": "[{\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 60.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
+ "outputDataExample": "[{\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 60.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
+ },
+ {
+ "simStepId": "f7c58723-a402-45d1-8070-59c196e20fb2",
+ "diagramNodeId": "06ecdf3e-50eb-4bf3-9c56-183f98a3186b",
+ "simStepLabel": "Perform Query Transformations",
+ "simStepDescription": "The query interpreter continues executing the AST. It applies a series of transformations to the fetched events, such as `flood`, `filter_period_intersect`, `categorize`, `merge_events_by_keys`, and `sum_durations`, as defined in the query string.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-query/src/interpret.rs",
+ "startLine": "213",
+ "endLine": "226",
+ "relevantVariables": [
+ "interpret_expr",
+ "fun"
+ ]
+ },
+ "inputDataExample": "[{\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 60.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
+ "outputDataExample": "{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}"
+ },
+ {
+ "simStepId": "633d97c2-762a-45cb-8900-308ab124d526",
+ "diagramNodeId": "3f00132f-3930-4b99-82cf-1ca7f818661b",
+ "simStepLabel": "Return Final Query Result",
+ "simStepDescription": "The final computed result, as specified by the `RETURN` statement in the query, is passed from the query engine back to the API endpoint handler.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "16",
+ "endLine": "25",
+ "relevantVariables": [
+ "result"
+ ]
+ },
+ "inputDataExample": "{\n \"events\": [{\"id\":1, ...}],\n \"duration\": 55.0\n}",
+ "outputDataExample": "{\n \"events\": [{\"id\":1, ...}],\n \"duration\": 55.0\n}"
+ },
+ {
+ "simStepId": "72197f38-6e3b-432c-be11-ce5fbb94efb9",
+ "diagramNodeId": "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500",
+ "simStepLabel": "Serialize and Send Response",
+ "simStepDescription": "The Rocket endpoint handler serializes the query result into a JSON string and sends it as the HTTP response.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "startLine": "28",
+ "endLine": "28",
+ "relevantVariables": [
+ "json!"
+ ]
+ },
+ "inputDataExample": "{\n \"events\": [{\"id\":1, ...}],\n \"duration\": 55.0\n}",
+ "outputDataExample": "[{\n \"events\": [{\"id\":1, ...}],\n \"duration\": 55.0\n}]"
+ },
+ {
+ "simStepId": "33e5b4e9-bd66-45f5-ab0f-543737810b99",
+ "diagramNodeId": "ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
+ "simStepLabel": "HTTP Response",
+ "simStepDescription": "The `aw-server` sends the JSON response back to the `aw-client`.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "337",
+ "endLine": "338",
+ "relevantVariables": [
+ "response"
+ ]
+ },
+ "inputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]",
+ "outputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]"
+ },
+ {
+ "simStepId": "642425c3-abd7-45fe-b5a9-a76bf90a9477",
+ "diagramNodeId": "7057dbee-ccfe-43f8-9014-90812018a849",
+ "simStepLabel": "Process Response in Client",
+ "simStepDescription": "The `ActivityWatchClient` receives the HTTP response, checks for errors, and parses the JSON body into a Python list of dictionaries.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/aw_client/client.py",
+ "startLine": "338",
+ "endLine": "338",
+ "relevantVariables": [
+ "response.json()"
+ ]
+ },
+ "inputDataExample": "HTTP Response with JSON body: `[{\"events\": [...], \"duration\": 55.0}]`",
+ "outputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]"
+ },
+ {
+ "simStepId": "65443293-5e86-4e71-9e8d-19d61bd162d9",
+ "diagramNodeId": "c8cbde86-13c0-4232-898e-104d815a805c",
+ "simStepLabel": "Return Result to Script",
+ "simStepDescription": "The parsed data is returned from the `aw.query()` method call back to the `working_hours.py` script.",
+ "isEdge": 1,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/examples/working_hours.py",
+ "startLine": "86",
+ "endLine": "86",
+ "relevantVariables": [
+ "res"
+ ]
+ },
+ "inputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]",
+ "outputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]"
+ },
+ {
+ "simStepId": "e38db73e-b347-4786-8efd-1e7cab44f73f",
+ "diagramNodeId": "e985450d-2666-412f-acf5-988a5c0c7de5",
+ "simStepLabel": "Process and Display Results",
+ "simStepDescription": "The `working_hours.py` script receives the processed data, calculates total durations using `generous_approx` (which applies flooding), formats the output, and prints a tabulated summary to the console. It also saves the raw event data to a JSON file.",
+ "isEdge": 0,
+ "sourceCodeMapping": {
+ "filePath": "aw-client/examples/working_hours.py",
+ "startLine": "113",
+ "endLine": "120",
+ "relevantVariables": [
+ "_print",
+ "generous_approx",
+ "json.dump"
+ ]
+ },
+ "inputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]",
+ "outputDataExample": "Console Output:\n| Date | Duration | Events |\n|------------|------------|--------|\n| 2023-10-26 | 0:00:55 | 1 |\n\nTotal: 0:00:55"
+ }
+ ],
+ "description": "- The
aw-client library provides a high-level Python interface for interacting with the aw-server REST API - It empowers developers and power users to build custom scripts, new watchers, or data analysis tools
- The library handles API authentication, request queuing for offline support, and data serialization
- The
examples directory showcases common use cases, such as calculating daily active time, generating custom reports, and exporting data to a pandas DataFrame for further analysis
",
+ "simulationNodesAndEdges": {
+ "237e712f-0c66-4488-b6e9-1ef8c3b71b51": {
+ "simStepIds": [
+ "e90cee0c-3a20-498b-97b9-2086a61dc02b"
+ ]
+ },
+ "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c": {
+ "simStepIds": [
+ "0d34430a-af81-407b-8817-672288674005"
+ ]
+ },
+ "73994797-596f-4b60-a36e-5f45cba1fcd3": {
+ "simStepIds": [
+ "c988a25d-05ad-4c19-87ac-362c79af1d00"
+ ]
+ },
+ "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b": {
+ "simStepIds": [
+ "b482a39f-e520-4d4d-8b2f-d1298922763f"
+ ]
+ },
+ "0b3e80ff-b4c9-42db-b067-1a9ba48e9218": {
+ "simStepIds": [
+ "04bbbe33-e9de-4c5f-b925-27196d20ef1d"
+ ]
+ },
+ "60a529b9-b262-4c7f-9baf-5beb50025a86": {
+ "simStepIds": [
+ "1b3cdf02-5dad-411c-a35e-9250c8aafc9d"
+ ]
+ },
+ "06ecdf3e-50eb-4bf3-9c56-183f98a3186b": {
+ "simStepIds": [
+ "f7c58723-a402-45d1-8070-59c196e20fb2"
+ ]
+ },
+ "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500": {
+ "simStepIds": [
+ "72197f38-6e3b-432c-be11-ce5fbb94efb9"
+ ]
+ },
+ "7057dbee-ccfe-43f8-9014-90812018a849": {
+ "simStepIds": [
+ "642425c3-abd7-45fe-b5a9-a76bf90a9477"
+ ]
+ },
+ "e985450d-2666-412f-acf5-988a5c0c7de5": {
+ "simStepIds": [
+ "e38db73e-b347-4786-8efd-1e7cab44f73f"
+ ]
+ },
+ "aecc1e90-5e71-43f4-a5b8-757de329fe3a": {
+ "simStepIds": [
+ "5aa97ae5-7e30-4d15-8f12-05942f2e75c9"
+ ]
+ },
+ "62388ee6-67f4-4adc-b08e-90deeb10efd4": {
+ "simStepIds": [
+ "834b7dbc-5efe-41ac-b75b-e43ad32141df"
+ ]
+ },
+ "31b60323-3a65-4184-a42f-f577f3a958ff": {
+ "simStepIds": [
+ "98777081-df05-4b5c-89f6-5076fab00e92"
+ ]
+ },
+ "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f": {
+ "simStepIds": [
+ "914107de-b38a-4307-ab2c-e257ed3d2fb5"
+ ]
+ },
+ "561eebea-ee66-4251-a29c-64c2e3aae490": {
+ "simStepIds": [
+ "5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619"
+ ]
+ },
+ "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe": {
+ "simStepIds": [
+ "d78663e6-a6d4-4ba7-a922-436bd075e457"
+ ]
+ },
+ "3f00132f-3930-4b99-82cf-1ca7f818661b": {
+ "simStepIds": [
+ "633d97c2-762a-45cb-8900-308ab124d526"
+ ]
+ },
+ "ec5d6b90-2f5f-4a07-b0e8-da3610035a92": {
+ "simStepIds": [
+ "33e5b4e9-bd66-45f5-ab0f-543737810b99"
+ ]
+ },
+ "c8cbde86-13c0-4232-898e-104d815a805c": {
+ "simStepIds": [
+ "65443293-5e86-4e71-9e8d-19d61bd162d9"
+ ]
+ }
+ },
+ "isAIGenerated": true,
+ "keywords": "aw_client, ActivityWatchClient, insert_events, query, aw-client/examples",
+ "generationPrompt": "How custom scripting with the client library works",
+ "generationKeywords": "aw_client, ActivityWatchClient, insert_events, query, aw-client/examples",
+ "meta": {
+ "containerCoverage": {
+ "perContainerTotals": {
+ "frontend": {
+ "promptFileCount": 18,
+ "promptTokenCount": 9716,
+ "suggestedFileCount": 5
+ },
+ "server": {
+ "promptFileCount": 123,
+ "promptTokenCount": 94957,
+ "suggestedFileCount": 7
+ },
+ "drawio": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ },
+ "shared": {
+ "promptFileCount": 67,
+ "promptTokenCount": 54942,
+ "suggestedFileCount": 17
+ },
+ "unknown": {
+ "promptFileCount": 0,
+ "promptTokenCount": 0,
+ "suggestedFileCount": 0
+ }
+ },
+ "missingContainers": [],
+ "addedFiles": []
+ }
+ }
+ }
+ },
+ "cellToPath": {
+ "02d954ad-e1f5-4853-9860-a553ea21245b": "aw-watcher-window",
+ "900d6121-1844-48ba-9a18-db1ec6ea9793": "aw-client",
+ "efb8048c-455c-4e7a-aa18-9e8b04779b71": "aw-server",
+ "1eed769a-5d0a-443c-9cc3-4e8f59c84abb": "aw-core",
+ "306c9af9-c4b4-4bea-85d2-fc4830dedc4c": "aw-watcher-window/aw_watcher_window",
+ "48103d9a-f009-4555-bb82-435f417b0644": "aw-client/aw_client",
+ "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49": "aw-server/aw_server",
+ "5093a30d-28ac-4c2b-811d-65c61efc0882": "aw-core/aw_datastore",
+ "1bbc4c76-4066-4521-a1d8-0248c1418060": "aw-watcher-window/aw_watcher_window/main.py",
+ "f55ac327-589c-4d8a-ac08-6db49ae00e75": "aw-watcher-window/aw_watcher_window/lib.py",
+ "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2": "aw-client/aw_client/client.py",
+ "7f67f305-e40b-496e-87a4-97725d0636a0": "aw-server/aw_server/rest.py",
+ "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc": "aw-server/aw_server/api.py",
+ "aba7852e-7836-4343-ae26-5ecb9a02d42d": "aw-core/aw_datastore/datastore.py",
+ "b2eb5c59-4162-4dea-ac74-511f22996f00": "aw-core/aw_datastore/storages",
+ "a63cc090-4355-47fb-8b22-62cd1b842ddb": "aw-core/aw_datastore/storages/peewee.py",
+ "638a5f20-935f-4345-8eaf-dfcd2aa6efb4": "aw-watcher-window/aw_watcher_window/main.py-simstep-caf92190-4958-42b9-b962-d21c9ff6c62d",
+ "89c12f0e-0649-4963-8e57-d7fd7da30bc4": "aw-watcher-window/aw_watcher_window/lib.py-simstep-3e57e810-18fe-461f-a33c-f3eb0773ecf5",
+ "30328419-4cc4-4ea2-a7fb-1728782b23aa": "aw-watcher-window/aw_watcher_window/main.py-simstep-706e836d-c3e2-4048-9eae-95e761ca9ffa",
+ "82482fcc-b698-4f91-a27c-a4110d012d99": "aw-client/aw_client/client.py-simstep-432d1978-befd-4dfd-979b-fe28821d4e00",
+ "2217c8ca-4cbb-4721-acb9-1057b3b16d69": "aw-server/aw_server/api.py-simstep-addb33f5-b815-49f0-9b54-a8ee3fb3b87b",
+ "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a": "aw-core/aw_datastore/datastore.py-simstep-5573707d-aa48-4a66-a3dc-25c841986d39",
+ "6d9c0750-fa20-47af-9135-6cc6444cb6b0": "generated-edge-simstep-39835fd9-a301-482d-8b6d-9d16abbbaa29-6d9c0750-fa20-47af-9135-6cc6444cb6b0",
+ "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26": "generated-edge-simstep-81f5cf5a-47ed-4fce-9c97-27559b1c7976-3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
+ "78766ca9-9103-486a-8755-f57a09e7f5a7": "generated-edge-simstep-11bc8b75-0103-4652-9fec-e55af41400a0-78766ca9-9103-486a-8755-f57a09e7f5a7",
+ "5a7fba44-6d4d-4836-bc13-ed69518c9d45": "generated-edge-simstep-97f58e0a-cbeb-4895-b613-d8e9fd129a42-5a7fba44-6d4d-4836-bc13-ed69518c9d45",
+ "6a5be6b6-e11d-460d-8193-427f3a9e42ac": "generated-edge-simstep-cd6c54a5-c0bd-4b99-9446-ea921ee876a6-6a5be6b6-e11d-460d-8193-427f3a9e42ac",
+ "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0": "aw-server-rust",
+ "d4939ae3-d0c2-44b2-90c5-9a7791e083b5": "README.md",
+ "e4fd3d3d-801a-4bc3-8891-9fdd6222369c": "aw-server-rust/aw-server",
+ "d70684b2-06ba-4f18-9c40-80de0778c035": "aw-server-rust/aw-query",
+ "a542ca3c-9d99-490f-89de-186bb284b0fe": "aw-server-rust/aw-datastore",
+ "6d2ab9ea-9e77-402f-a726-95d44e0f23c8": "aw-server-rust/aw-transform",
+ "941d7da8-a28d-4d5e-806f-3b546909f74e": "aw-client/aw_client/queries.py",
+ "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e": "aw-server-rust/aw-server/src",
+ "e6b26caf-0857-4e8d-8f29-124af90c1966": "aw-server-rust/aw-query/src",
+ "234cf403-9edd-4f7e-96eb-81e90587bbdc": "aw-server-rust/aw-datastore/src",
+ "7e71e7fe-f8aa-4693-a92e-4c3b664c1528": "aw-server-rust/aw-transform/src",
+ "11799249-188d-43b3-b410-54dcff47aeba": "aw-server-rust/aw-server/src/endpoints",
+ "d020e6ae-765b-4374-947a-57f7ad4a9237": "aw-server-rust/aw-query/src/lib.rs",
+ "9b5e1d70-af70-4de3-9b35-73b774a50c3c": "aw-server-rust/aw-query/src/interpret.rs",
+ "bf649fa4-66cc-4975-8549-aa2f1db4a11e": "aw-server-rust/aw-query/src/functions.rs",
+ "c3bb8632-e3d6-4b2f-86ea-2472e155f19e": "aw-server-rust/aw-datastore/src/worker.rs",
+ "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f": "aw-server-rust/aw-datastore/src/datastore.rs",
+ "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca": "aw-server-rust/aw-transform/src/filter_period.rs",
+ "873444c7-80ea-4a0b-8620-92fc96cce006": "aw-server-rust/aw-server/src/endpoints/query.rs",
+ "12f9554d-dd4e-4f66-bd20-8845b718ef19": "aw-client/aw_client/queries.py-simstep-81f31a9b-3434-4458-a7d3-bdcf610af75e",
+ "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-e91513ab-13ec-4eea-9942-9620dbe3b92b",
+ "a9279dbc-8fda-434c-bc5a-4eefaca0df56": "aw-server-rust/aw-query/src/lib.rs-simstep-3291e01a-482d-401b-98b5-759573be65ca",
+ "be2c99a2-8b27-487f-9c8f-e1d1836613cc": "aw-server-rust/aw-query/src/functions.rs-simstep-475886bc-26d3-4528-84ae-2f9c8e1dfcf9",
+ "48d1c5e2-32b3-4eaf-9005-dd0a65a77448": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-ff017206-8323-4caa-9eca-4fc760c2470f",
+ "48a7e119-b25c-4b9f-9a95-bd649493ff48": "aw-server-rust/aw-transform/src/filter_period.rs-simstep-50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10",
+ "63ebaed0-610a-46cd-8a5b-392c2874aecb": "aw-server-rust/aw-query/src/interpret.rs-simstep-18492fe4-5b57-4749-a2e8-d18f3c546e89",
+ "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd": "README.md-simstep-9396ef3a-ed06-4635-bb1d-3b136660bcc4",
+ "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f": "generated-edge-simstep-c1a26d9b-d661-4a99-8275-39a414824ed6-6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
+ "c8403507-4895-4695-84b5-9305afdc3c9f": "generated-edge-simstep-a7b6aefb-1401-4756-bfa1-1eb9a76cde07-c8403507-4895-4695-84b5-9305afdc3c9f",
+ "8f8d2c55-63c0-48ec-b931-f848e245688f": "generated-edge-simstep-00784ae1-bb99-494c-bf46-fe5947de5066-8f8d2c55-63c0-48ec-b931-f848e245688f",
+ "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013": "generated-edge-simstep-e1bf9f3c-e763-4e75-8c62-1a8d739d53cc-5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
+ "7a14a4d3-a453-4e33-9b10-fb192e40e34e": "generated-edge-simstep-f7dfb334-099f-4750-a893-cd96b1c46278-7a14a4d3-a453-4e33-9b10-fb192e40e34e",
+ "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa": "generated-edge-simstep-78aaa465-8377-43f1-9ba6-36ddcf9300cf-8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
+ "889f0869-2c33-499b-a558-ede80ee18a54": "generated-edge-simstep-785d1355-bf16-42a7-846e-a2bf3ecbb35b-889f0869-2c33-499b-a558-ede80ee18a54",
+ "0b23a1ca-091a-4f70-b49e-95910c8179bf": "aw-notify",
+ "4d835cac-01b7-4b3d-a7f5-189f89fda1c7": "aw-notify/aw_notify",
+ "954ebccb-39ec-4c50-aca4-0ac8c09e6358": "aw-notify/aw_notify/main.py",
+ "60cb37da-078e-4380-88f0-e6746007277d": "aw-server-rust/aw-query/src/datatype.rs",
+ "22d8d360-9b15-49db-bc15-de087f960e23": "aw-server-rust/aw-transform/src/classify.rs",
+ "49029598-25ad-4498-b744-e2180f404fe5": "aw-client/aw_client/queries.py-simstep-1b40cfa3-9cf5-4dc3-830f-74cb1d476d50",
+ "ff986e21-7050-4c3d-ae40-3a678f46221d": "aw-server-rust/aw-query/src/functions.rs-simstep-af6c51b2-ee18-406c-acc6-6e5d9588d012",
+ "e99fcabc-934a-46cd-8823-d3e04ceea63c": "aw-server-rust/aw-transform/src/classify.rs-simstep-55815d72-39f6-4201-ad99-6ebd57d0eece",
+ "294c7beb-b479-47e2-bd3c-6d616497ecd2": "aw-server-rust/aw-transform/src/classify.rs-simstep-e863b0b1-c3ce-4b13-ad7d-a7438f650035",
+ "9847b0a7-39f2-44f8-ae14-73eab42d8894": "aw-notify/aw_notify/main.py-simstep-2108914e-2569-47bf-aa87-af337de03f8c",
+ "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661": "generated-edge-simstep-9eeb592f-5c44-4ce1-a7a0-261bc6d6b679-e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
+ "79c14e32-8192-488e-ab72-b9c4c6edb346": "generated-edge-simstep-e598a658-8e0e-4a76-9310-af0d60ec5828-79c14e32-8192-488e-ab72-b9c4c6edb346",
+ "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8": "generated-edge-simstep-9f7f50e4-03c6-4d7c-95c8-3317d37115eb-341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
+ "b4391f38-d9ee-4377-8568-efca87206124": "generated-edge-simstep-ebd328dc-4cdf-452d-b4aa-10b65e9c354d-b4391f38-d9ee-4377-8568-efca87206124",
+ "701d49bd-2670-4a9f-8ffd-52f62726ddc0": "aw-core/aw_query",
+ "22692aea-cd7a-4c08-8c76-c16bb5499546": "aw-server-rust/aw-client-rust",
+ "0fb8ce44-e9ea-4e8a-a049-33211b003d20": "aw-core/aw_query/query2.py",
+ "e1b937af-2584-42ee-8281-e1bffda373ae": "aw-core/aw_query/functions.py",
+ "08296022-1e80-4653-821d-b48d9cf30c68": "aw-server-rust/aw-client-rust/src",
+ "8dafeb60-1305-46f7-baac-4153d6d18539": "aw-server-rust/aw-client-rust/src/blocking.rs",
+ "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf": "aw-server-rust/aw-client-rust/src/lib.rs",
+ "5540d168-0892-4d44-a835-530768fbad09": "aw-client/aw_client/client.py-simstep-06f7c9e7-1c78-4114-867b-3dbb20dcc427",
+ "abf45adb-988a-4613-ab4a-acb8cef0c90a": "aw-server/aw_server/rest.py-simstep-671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7",
+ "96c3be58-d96a-4b11-b4f3-e778387f76b8": "aw-server/aw_server/api.py-simstep-a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31",
+ "c0a28353-be8d-4bc8-a1be-2879961fc4df": "aw-core/aw_query/query2.py-simstep-5f7b6985-edf0-42eb-8822-847d0d7b8e9b",
+ "fb0bcd2a-5999-47fc-bb41-11233e3544fa": "aw-core/aw_query/functions.py-simstep-6ea3ab36-027f-40b9-a0ba-9ede77ae1117",
+ "5eb14d26-499c-4ea4-8282-3f923646dbdb": "aw-core/aw_query/query2.py-simstep-ab3fe2d5-9396-4241-b64e-2a187e97de75",
+ "7ace16a3-9438-4e78-bcf9-79131079c89d": "aw-server-rust/aw-client-rust/src/blocking.rs-simstep-3118dc4c-d7ad-4996-aa81-a205ccdf6e72",
+ "b93b83dd-fff3-44dc-ac22-3ea63117c222": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-1c25a330-b713-4866-9440-8737c787ce33",
+ "d8afb2b7-af24-431a-b206-828a8b7cef2a": "aw-server-rust/aw-query/src/lib.rs-simstep-024a46d7-abc2-4c35-92d1-900d198f748c",
+ "630bda35-fbd5-40ec-b47d-37ad66379d94": "aw-server-rust/aw-query/src/interpret.rs-simstep-e3204124-26ff-4799-8462-100305c27ae1",
+ "eecd0f91-7c53-4352-8d85-05c3dd46bee1": "aw-server-rust/aw-query/src/functions.rs-simstep-06d75f72-3fc8-47d8-85ab-f7fa317f4de5",
+ "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4": "aw-server-rust/aw-query/src/interpret.rs-simstep-9382ac29-7930-4f83-afdd-deb2bfc221e3",
+ "71408ae2-19e6-4327-bab9-8918af09c855": "generated-edge-simstep-5dc6bd77-15d2-44c3-b665-8de88288c314-71408ae2-19e6-4327-bab9-8918af09c855",
+ "891bfe3a-f22a-4998-acea-aa6d0c362821": "generated-edge-simstep-5a0d9b17-b09a-4aa5-9234-c01cb2aadef4-891bfe3a-f22a-4998-acea-aa6d0c362821",
+ "b79b67f9-1be1-48f1-920a-9ebdd4417272": "generated-edge-simstep-833f0f0f-ec00-4960-b1f9-46d8a8530a01-b79b67f9-1be1-48f1-920a-9ebdd4417272",
+ "4059fcbe-a1ee-41d0-b576-55a1d278bca0": "generated-edge-simstep-7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6-4059fcbe-a1ee-41d0-b576-55a1d278bca0",
+ "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4": "generated-edge-simstep-ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c-e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
+ "c4b6d403-d2a9-4cff-8a72-31189a53c0db": "generated-edge-simstep-fe43857f-ef7d-455d-a9c4-37d54d12207a-c4b6d403-d2a9-4cff-8a72-31189a53c0db",
+ "ed18dcc0-5e4a-44fb-b661-f746f1e893f1": "generated-edge-simstep-97542310-17cf-4c99-9ce9-a328dffa5f4c-ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
+ "d3cb01a0-d8cd-4382-b122-d1234b0562bc": "generated-edge-simstep-6eb126a9-5234-4495-9727-ec2741ce9660-d3cb01a0-d8cd-4382-b122-d1234b0562bc",
+ "e72e1881-49ce-41ad-966a-90a26ca47453": "generated-edge-simstep-acc1ad56-50cb-41ab-9217-f8d15af6686c-e72e1881-49ce-41ad-966a-90a26ca47453",
+ "15dfaeb9-fb37-4296-972f-0188abd0b353": "generated-edge-simstep-f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5-15dfaeb9-fb37-4296-972f-0188abd0b353",
+ "9792d1f0-08be-4f90-8e68-3caee0eb2498": "generated-edge-simstep-f69e7df0-6666-4b48-a0a6-1000c8ccede0-9792d1f0-08be-4f90-8e68-3caee0eb2498",
+ "7ee7b20f-9df9-4269-8f41-bc7e191503bd": "aw-watcher-afk",
+ "8f0b906e-fb77-4a52-aee5-1f494bec596c": "aw-watcher-afk/aw_watcher_afk",
+ "d242d1ad-7cdf-414b-812a-f3e5af153562": "aw-watcher-afk/aw_watcher_afk/__main__.py",
+ "c443335f-7f08-4436-8862-5aab2adcf7e0": "aw-watcher-afk/aw_watcher_afk/afk.py",
+ "72e53989-6741-4b0d-b49c-f58d0333cdd1": "aw-watcher-afk/aw_watcher_afk/unix.py",
+ "ba27c535-e0e5-44ae-b9f0-2827227ebfe2": "aw-watcher-afk/aw_watcher_afk/__main__.py-simstep-8ffbcadf-f26a-483a-9902-95e5a761de64",
+ "79468b99-a4de-48b7-bb67-506dc0dcb41c": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-daeeac12-287a-4144-9028-6ea841b196c4",
+ "6b45de30-296e-4896-915c-371f09843599": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-6579f587-817d-4d23-a9df-86abc54273ae",
+ "b7321a6c-302b-4701-9ea5-5c05c6d3e71b": "aw-watcher-afk/aw_watcher_afk/unix.py-simstep-4d2c85c7-0754-429a-8a55-c64d4da0d37c",
+ "faab8465-be29-479d-890a-7936dc5cfbdd": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-3e0e033c-c32f-4d0d-aa65-a278d77e80c7",
+ "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-dc58bc3e-b09e-4df2-870b-76419e78dd3d",
+ "c27977fb-af8a-4779-8f78-a99b40221157": "aw-server/aw_server/api.py-simstep-7357e239-3712-4b55-a94c-2165ea1f3255",
+ "802c1941-09e1-4038-a0bf-bd4e553ff6f6": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-1e5ad77f-aeff-49b6-9634-65e52f011a83",
+ "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250": "generated-edge-simstep-60e1002f-9782-4c8d-b104-f4bb172e2c91-7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
+ "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838": "generated-edge-simstep-1422a5f8-ad2e-4b32-8955-ee6bb3053286-1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
+ "e514d9e2-e803-4041-b693-65878401b214": "generated-edge-simstep-2588211c-b086-4768-8a87-a86764c7e5cd-e514d9e2-e803-4041-b693-65878401b214",
+ "eeb9224a-fff6-4652-b733-ea430b820a2c": "generated-edge-simstep-9195e582-b3fa-4848-b151-0236a8a5d176-eeb9224a-fff6-4652-b733-ea430b820a2c",
+ "196358b9-6ae9-4f52-ad78-ff88b4a49403": "generated-edge-simstep-78d78341-ced8-4fc6-bc93-ce4a62c8adf6-196358b9-6ae9-4f52-ad78-ff88b4a49403",
+ "b520b088-6f6f-4b32-afba-5ef244691c44": "generated-edge-simstep-c9a127c1-afd0-4def-a0fe-c490c9b64039-b520b088-6f6f-4b32-afba-5ef244691c44",
+ "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0": "generated-edge-simstep-9fde1b44-5dbf-4530-88e2-ca54c220b462-f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
+ "34f5debb-c898-419f-9c17-186d2a5f6e85": "aw-core/aw_transform",
+ "40ad45bd-b0eb-4f2c-a091-f933962a90b8": "aw-watcher-window/aw_watcher_window/macos.swift",
+ "6860aa38-bc11-4d81-9260-87eba1c02581": "aw-core/aw_transform/heartbeats.py",
+ "0f86982d-c1d5-4ceb-8574-3e19c2db7159": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
+ "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-46ccc29e-b251-435a-8768-4304d477261a",
+ "67a89dcc-93fc-413d-aa21-eca0b7227bc2": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-e873b3e2-2ebd-43ee-8f97-e02f869578f7",
+ "9de5f1e4-764e-4be7-90a1-65fa23ca0dea": "aw-server/aw_server/rest.py-simstep-e98f7509-f28f-4534-8f2a-f525edc73f69",
+ "7c02469d-20a7-415d-940e-fbd82d0fc997": "aw-server/aw_server/api.py-simstep-bb678fe2-e6e3-472b-8ae4-95e362d4bdaf",
+ "dc7a3836-03e1-4a54-9817-b62f36466ec0": "aw-core/aw_transform/heartbeats.py-simstep-d2eac5dc-58f7-408c-beba-c1711beec25a",
+ "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f": "aw-server/aw_server/api.py-simstep-976cfbd0-8946-4157-81b0-0ae6dffa43e1",
+ "b3da175e-36b5-4025-ba15-6c54e1d850dd": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-8420fd6c-dba4-41c0-b11d-7280a428ab36",
+ "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926": "aw-server-rust/aw-server/src/endpoints/bucket.rs-simstep-41b8b1d6-f9fe-47ad-851e-574e804f7171",
+ "b6b4c8cb-741a-4e38-b800-61273375cd64": "aw-server-rust/aw-datastore/src/worker.rs-simstep-b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3",
+ "f0e92638-21d1-4b7e-9f2e-17b67a33ef78": "aw-server-rust/aw-datastore/src/worker.rs-simstep-a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb",
+ "b0093d22-e8cc-4e9e-8711-7e698b537efc": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-c59f4b10-f6c9-4fd8-ba70-ea60667a01e8",
+ "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-da146aa5-e96f-4db6-a36f-b405b1a11255",
+ "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f": "generated-edge-simstep-b6456941-3a8f-452d-a4eb-67915b00d5b3-4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
+ "a676f81f-8c68-4fc8-94b7-583bada02d70": "generated-edge-simstep-02717bea-6ee3-48ef-8c41-0c9f3e9d9a58-a676f81f-8c68-4fc8-94b7-583bada02d70",
+ "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75": "generated-edge-simstep-d57d2bf7-916c-44cd-844d-b1900c276925-a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
+ "9aec4875-5718-4c38-a57c-1d3053c38ba5": "generated-edge-simstep-40b16e25-734b-44d2-86cd-7c301723ff5f-9aec4875-5718-4c38-a57c-1d3053c38ba5",
+ "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0": "generated-edge-simstep-9f918447-9e45-4c3b-b34f-658f58d35495-31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
+ "2df6b81e-6b59-4aec-92c7-e9d9f2332be6": "generated-edge-simstep-7e361c3d-a5a9-45f3-a83d-98e39ff45675-2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
+ "4a4afbdf-0303-4d84-bbf8-5121c74965a0": "generated-edge-simstep-bfcc2f87-9167-4784-a3b3-f71d6e7a6e71-4a4afbdf-0303-4d84-bbf8-5121c74965a0",
+ "21d1c973-0f67-4aca-9d1b-eade3b5d347b": "generated-edge-simstep-eefd671a-3b08-4336-bd26-cb6eb04070ec-21d1c973-0f67-4aca-9d1b-eade3b5d347b",
+ "959b342e-eb44-4255-8176-1600a5fa17ac": "generated-edge-simstep-9750ac2c-c0fb-4fe5-815f-398886fc827b-959b342e-eb44-4255-8176-1600a5fa17ac",
+ "0fe644bb-a583-40d8-9377-3641c90c4f62": "generated-edge-simstep-7b396541-e74f-4baf-9b1b-c1f7a914ba7a-0fe644bb-a583-40d8-9377-3641c90c4f62",
+ "315afad3-54aa-4009-bbe4-8e17ade01ec1": "aw-qt",
+ "52098e1d-ea54-42f8-9e69-f6bd54686e33": "aw-qt/aw_qt",
+ "9d82da70-d3bc-4199-9292-8dd7e71ab15d": "aw-qt/aw_qt/main.py",
+ "f47c0efe-5fd2-488b-b325-b2965448260a": "aw-qt/aw_qt/config.py",
+ "f2489cff-231c-4352-baac-95f17e0f6395": "aw-qt/aw_qt/manager.py",
+ "38fbe4ec-4658-4084-864e-b163e0540497": "aw-qt/aw_qt/trayicon.py",
+ "d1bb4e12-29b6-4f70-9931-321214e3ea2a": "aw-qt/aw_qt/main.py-simstep-61d1a03e-ed06-496d-8495-36419b9c8607",
+ "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc": "aw-qt/aw_qt/config.py-simstep-c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a",
+ "cae37571-f0ba-4abe-aefd-53e49f26137f": "aw-qt/aw_qt/manager.py-simstep-e716abbb-c96e-4613-bca2-0c094e8df129",
+ "8f981b6f-7bed-4d9a-8486-79f85b06d904": "aw-qt/aw_qt/manager.py-simstep-8be10173-751a-4da9-99a9-321c23e71aaa",
+ "4d657da7-6757-4d72-9324-765a991f73d7": "aw-qt/aw_qt/trayicon.py-simstep-6ae15f2e-5331-4153-b9d2-2a297b65c55f",
+ "05bd0955-8e55-4657-80ee-f6389995db6d": "aw-qt/aw_qt/trayicon.py-simstep-08d88f03-4133-41d6-9cbb-0df16703b864",
+ "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b": "aw-qt/aw_qt/manager.py-simstep-520ab3f2-ef6c-4334-89fc-280f6d86d14b",
+ "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5": "aw-qt/aw_qt/trayicon.py-simstep-01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9",
+ "421b1687-98a6-4773-a7dc-cdc564be5f8e": "aw-qt/aw_qt/manager.py-simstep-899b57ba-4a68-4620-977a-80981d089e85",
+ "5dd0e28d-e0e9-4433-8db9-e8de93de1abe": "aw-qt/aw_qt/manager.py-simstep-6173a9e1-ecfa-4dd9-9f82-f80579406011",
+ "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc": "aw-qt/aw_qt/trayicon.py-simstep-a71f6cd0-490a-40b5-8a05-1c873f208882",
+ "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7": "generated-edge-simstep-6084ca69-514e-4bde-b2c0-1d33b26203e8-1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
+ "030668a5-a377-4710-b39f-95efb5fa4768": "generated-edge-simstep-540119c2-b541-4342-aa59-233b4f0f8db5-030668a5-a377-4710-b39f-95efb5fa4768",
+ "1fb5a75e-9c49-490d-b412-04ac1c7205fa": "generated-edge-simstep-9aeaf443-6741-4557-9671-67d596f456b3-1fb5a75e-9c49-490d-b412-04ac1c7205fa",
+ "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9": "generated-edge-simstep-f968357d-53c4-41e8-b71f-c581c08b52e6-a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
+ "dfaa3fc8-eca8-4c67-b926-87798f511adb": "generated-edge-simstep-03fd319d-4ffe-47cf-bf39-ac388da80fa7-dfaa3fc8-eca8-4c67-b926-87798f511adb",
+ "d9e460b6-432d-49c8-8e76-0d8750aa2c10": "generated-edge-simstep-8e583414-7b87-42c9-bdb2-e56259be4cdf-d9e460b6-432d-49c8-8e76-0d8750aa2c10",
+ "9d4dee50-64ef-459a-98fa-839761e16813": "generated-edge-simstep-fdff8ecd-12b9-4bc0-ba7b-9402d26b1737-9d4dee50-64ef-459a-98fa-839761e16813",
+ "f704019b-d227-47ad-8761-9a2ea01516cb": "generated-edge-simstep-c0115129-b34b-4d27-9f73-cf2dc142ea81-f704019b-d227-47ad-8761-9a2ea01516cb",
+ "ba9e605d-98a7-4b50-979a-05bf7213c681": "generated-edge-simstep-7775ac80-c954-464e-b230-b233216ee5e3-ba9e605d-98a7-4b50-979a-05bf7213c681",
+ "2298c4b5-17de-487f-b592-2ac0f95eca84": "generated-edge-simstep-1ed5cd16-b593-41cf-84f2-233a8d64a227-2298c4b5-17de-487f-b592-2ac0f95eca84",
+ "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1": "aw-notify/aw_notify/main.py-simstep-9b9a0f90-d7a7-40fb-8573-53b470ecf85d",
+ "553f1437-5c34-4d6d-8226-417014259fc5": "aw-notify/aw_notify/main.py-simstep-f636bdd6-a8e3-47ec-9f9d-986b21a81868",
+ "1de089eb-60a7-4d7f-bfb5-3f7f23315873": "aw-notify/aw_notify/main.py-simstep-945e3312-c7c9-4722-953b-94dc0feee249",
+ "e567d898-2785-43f6-98ef-f4b6d1232620": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-868edfd6-1f03-416e-88dc-7b09d05e4ba5",
+ "44016962-bb6d-4a70-b13c-4538926a02a4": "aw-server-rust/aw-query/src/functions.rs-simstep-cc5cfecf-cee9-4582-aa6c-b74787a11da8",
+ "fd5d1362-e41b-43af-bfd8-7f7c344c9849": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-f52d6bfa-55fe-49ee-9f20-60bf296c76f4",
+ "a01b5cc8-f12f-447b-9879-6b55bda0ef87": "aw-notify/aw_notify/main.py-simstep-9c0b3f20-5c18-418a-82f7-78b04ebda9b5",
+ "30303464-f5f8-4155-87e9-b81dda8175d9": "aw-notify/aw_notify/main.py-simstep-a66f8ebc-93f8-4f9c-8f19-03bd951d1e98",
+ "445477ac-c52d-4053-a45e-8c81da805c88": "aw-notify/aw_notify/main.py-simstep-21533839-7ba4-4cfa-864a-2f67198cad68",
+ "f9ddc0fb-c342-4a4a-baec-53c6a2581b80": "generated-edge-simstep-3c977159-c34d-4907-9004-e5aaff3f3bdc-f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
+ "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e": "generated-edge-simstep-7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b-22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
+ "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd": "generated-edge-simstep-f20bb756-15f3-4a7c-914b-aa61470cc435-5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
+ "8f02d20c-25fe-4a28-99de-3e8908d0a66f": "generated-edge-simstep-b835d5e0-434d-4469-94fe-d309114a9ef1-8f02d20c-25fe-4a28-99de-3e8908d0a66f",
+ "5595958a-cf9d-4894-9824-ecc89e5cf956": "generated-edge-simstep-027140c6-aa16-4070-89d3-3b553168e65e-5595958a-cf9d-4894-9824-ecc89e5cf956",
+ "1b9dc1d5-e6a7-4069-8473-2156853d662e": "generated-edge-simstep-92487214-03b7-430e-aab5-b5a5fb85b2cb-1b9dc1d5-e6a7-4069-8473-2156853d662e",
+ "08e05622-d948-47eb-a56d-3d6782d638c0": "generated-edge-simstep-c8b0fe19-76a8-458d-9923-c2f270e306b3-08e05622-d948-47eb-a56d-3d6782d638c0",
+ "17c4cd6c-69f5-4df8-ac77-6955a0518939": "generated-edge-simstep-e46653da-3493-419e-8f9c-397be83fe894-17c4cd6c-69f5-4df8-ac77-6955a0518939",
+ "a1e562ae-ea06-4c6a-ab92-fa78417115f6": "aw-client/aw_client/client.py-simstep-8739f5eb-aec2-47f1-b1e6-a05a2bb65acd",
+ "07e4d089-e23f-4030-8c10-7dbdbd00e1c7": "aw-server/aw_server/rest.py-simstep-7bdce779-492f-4dee-a68d-4e6d28dc079a",
+ "19faa606-15ad-4c47-a983-692a1f30a667": "aw-server/aw_server/api.py-simstep-d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6",
+ "e590d109-3712-4d3d-9241-ba9cd9a7eeaa": "aw-server/aw_server/api.py-simstep-5fb7b7d5-1759-43dc-a711-b2b0b5df3893",
+ "6e7e85b1-9708-4f64-ac9e-efc54338c444": "aw-server/aw_server/rest.py-simstep-cfd637bd-f6b2-44cf-8330-7b2c59c0658b",
+ "e60e25ae-e9aa-4497-8555-7e3d99a4049f": "aw-client/aw_client/client.py-simstep-ea6d2274-023a-4d5f-abf4-0414c6c7f68d",
+ "12725c25-974e-4363-bb91-c61c8745ed75": "aw-server/aw_server/rest.py-simstep-3e1decf0-1329-4da8-a7c7-870ffe960a54",
+ "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570": "aw-server/aw_server/api.py-simstep-4050248c-1638-452c-8826-677a7a2fece8",
+ "07630c61-6df6-484b-81c3-0984379bfd68": "aw-server/aw_server/api.py-simstep-164ed08b-0873-499b-b945-e062cf362429",
+ "ae563be0-ff29-4c20-8f6d-6771f04c8da3": "aw-server/aw_server/rest.py-simstep-3fd4d48c-e70c-4217-92c1-7554445cf03b",
+ "5fe912cd-a72c-4cc1-969b-b5eb6759ace9": "generated-edge-simstep-8efaf2e1-7c6d-4820-90a5-2abb80bf65ed-5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
+ "8515a29c-385b-4ec5-886c-ba3a3a48518e": "generated-edge-simstep-6449735d-8c85-4d49-bb8c-c2b1f9918ffc-8515a29c-385b-4ec5-886c-ba3a3a48518e",
+ "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff": "generated-edge-simstep-60764034-1b94-4c15-9015-09e8b775f736-ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
+ "272a1088-1b0c-43f9-8335-d7055539c813": "generated-edge-simstep-7a5f8838-8ed9-47b3-907f-077efeedaa10-272a1088-1b0c-43f9-8335-d7055539c813",
+ "ebfbcf3c-bc57-4fe1-866e-fde1b860e633": "generated-edge-simstep-f5c06885-1138-4c13-ae70-10b9d409be5b-ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
+ "0614b31f-64d9-4e85-a5f5-6304f0702bd7": "generated-edge-simstep-988adf58-e1be-4352-be66-4f02188fc28a-0614b31f-64d9-4e85-a5f5-6304f0702bd7",
+ "941b8c57-be7c-49cd-ba2a-d2237f8f129b": "generated-edge-simstep-7e01821d-906c-4518-a1e0-6b71be84291a-941b8c57-be7c-49cd-ba2a-d2237f8f129b",
+ "1f7db50a-bc15-48d1-9f06-27ed743afa75": "generated-edge-simstep-666a933a-7a74-4d90-be19-7610f7bd3d74-1f7db50a-bc15-48d1-9f06-27ed743afa75",
+ "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c": "aw-client/examples",
+ "9b8f28aa-5406-437c-8363-bcfe0f788580": "aw-client/examples/working_hours.py",
+ "237e712f-0c66-4488-b6e9-1ef8c3b71b51": "aw-client/examples/working_hours.py-simstep-e90cee0c-3a20-498b-97b9-2086a61dc02b",
+ "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c": "aw-client/aw_client/client.py-simstep-0d34430a-af81-407b-8817-672288674005",
+ "73994797-596f-4b60-a36e-5f45cba1fcd3": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-c988a25d-05ad-4c19-87ac-362c79af1d00",
+ "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b": "aw-server-rust/aw-query/src/lib.rs-simstep-b482a39f-e520-4d4d-8b2f-d1298922763f",
+ "0b3e80ff-b4c9-42db-b067-1a9ba48e9218": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-04bbbe33-e9de-4c5f-b925-27196d20ef1d",
+ "60a529b9-b262-4c7f-9baf-5beb50025a86": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-1b3cdf02-5dad-411c-a35e-9250c8aafc9d",
+ "06ecdf3e-50eb-4bf3-9c56-183f98a3186b": "aw-server-rust/aw-query/src/interpret.rs-simstep-f7c58723-a402-45d1-8070-59c196e20fb2",
+ "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-72197f38-6e3b-432c-be11-ce5fbb94efb9",
+ "7057dbee-ccfe-43f8-9014-90812018a849": "aw-client/aw_client/client.py-simstep-642425c3-abd7-45fe-b5a9-a76bf90a9477",
+ "e985450d-2666-412f-acf5-988a5c0c7de5": "aw-client/examples/working_hours.py-simstep-e38db73e-b347-4786-8efd-1e7cab44f73f",
+ "aecc1e90-5e71-43f4-a5b8-757de329fe3a": "generated-edge-simstep-5aa97ae5-7e30-4d15-8f12-05942f2e75c9-aecc1e90-5e71-43f4-a5b8-757de329fe3a",
+ "62388ee6-67f4-4adc-b08e-90deeb10efd4": "generated-edge-simstep-834b7dbc-5efe-41ac-b75b-e43ad32141df-62388ee6-67f4-4adc-b08e-90deeb10efd4",
+ "31b60323-3a65-4184-a42f-f577f3a958ff": "generated-edge-simstep-98777081-df05-4b5c-89f6-5076fab00e92-31b60323-3a65-4184-a42f-f577f3a958ff",
+ "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f": "generated-edge-simstep-914107de-b38a-4307-ab2c-e257ed3d2fb5-9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
+ "561eebea-ee66-4251-a29c-64c2e3aae490": "generated-edge-simstep-5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619-561eebea-ee66-4251-a29c-64c2e3aae490",
+ "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe": "generated-edge-simstep-d78663e6-a6d4-4ba7-a922-436bd075e457-2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
+ "3f00132f-3930-4b99-82cf-1ca7f818661b": "generated-edge-simstep-633d97c2-762a-45cb-8900-308ab124d526-3f00132f-3930-4b99-82cf-1ca7f818661b",
+ "ec5d6b90-2f5f-4a07-b0e8-da3610035a92": "generated-edge-simstep-33e5b4e9-bd66-45f5-ab0f-543737810b99-ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
+ "c8cbde86-13c0-4232-898e-104d815a805c": "generated-edge-simstep-65443293-5e86-4e71-9e8d-19d61bd162d9-c8cbde86-13c0-4232-898e-104d815a805c"
+ }
+}
\ No newline at end of file
From b923054d6ff5afe0aa8912bb89555923308b02ba Mon Sep 17 00:00:00 2001
From: Nasser <42423897+Abdulnaser97@users.noreply.github.com>
Date: Fri, 14 Nov 2025 22:19:36 -0500
Subject: [PATCH 2/5] Add CodeCanvas diagram to README
---
README.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/README.md b/README.md
index 883c741a..a1402ad0 100644
--- a/README.md
+++ b/README.md
@@ -218,6 +218,15 @@ class A,B,C,D,E,G darkMode;
%% linkStyle 1 stroke:#1ABC9C, stroke-width:2px;
```
+### How does `activitywatch` work under the hood?
+
+Check out this interactive walkthrough of the `activitywatch` codebase on CodeCanvas [here](https://www.code-canvas.com/?session=unauthenticatedGithub&repo=activitywatch&owner=ActivityWatch&branch=master&OnboardingTutorial=true).
+
+To refine existing dataflow simulation or create new ones, follow the quick tutorial [here](https://docs.code-canvas.com/updating-diagram).
+
+
+
+
## About this repository
This repo is a bundle of the core components and official modules of ActivityWatch (managed with `git submodule`). Its primary use is as a meta-package providing all the components in one repo; enabling easier packaging and installation. It is also where releases of the full suite are published (see [releases](https://github.com/ActivityWatch/activitywatch/releases)).
From 7d1ac0fe5590a488696e680465488d425751ce37 Mon Sep 17 00:00:00 2001
From: Nasser <42423897+Abdulnaser97@users.noreply.github.com>
Date: Fri, 14 Nov 2025 22:24:31 -0500
Subject: [PATCH 3/5] Replaced codecanvas screenshot
---
README.md | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/README.md b/README.md
index a1402ad0..389a444f 100644
--- a/README.md
+++ b/README.md
@@ -222,9 +222,7 @@ class A,B,C,D,E,G darkMode;
Check out this interactive walkthrough of the `activitywatch` codebase on CodeCanvas [here](https://www.code-canvas.com/?session=unauthenticatedGithub&repo=activitywatch&owner=ActivityWatch&branch=master&OnboardingTutorial=true).
-To refine existing dataflow simulation or create new ones, follow the quick tutorial [here](https://docs.code-canvas.com/updating-diagram).
-
-
+
## About this repository
From bb2c62a3044d1e102f606eba1ac61fadefe93614 Mon Sep 17 00:00:00 2001
From: Nasser <42423897+Abdulnaser97@users.noreply.github.com>
Date: Sat, 15 Nov 2025 19:15:37 -0500
Subject: [PATCH 4/5] Revise interactive tutorial section in README
Updated the section title and link for the interactive tutorial.
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 389a444f..fbb28e4e 100644
--- a/README.md
+++ b/README.md
@@ -218,9 +218,9 @@ class A,B,C,D,E,G darkMode;
%% linkStyle 1 stroke:#1ABC9C, stroke-width:2px;
```
-### How does `activitywatch` work under the hood?
+### Interactive `activitywatch` Architecture Tutorial with CodeCanvas
-Check out this interactive walkthrough of the `activitywatch` codebase on CodeCanvas [here](https://www.code-canvas.com/?session=unauthenticatedGithub&repo=activitywatch&owner=ActivityWatch&branch=master&OnboardingTutorial=true).
+Check out this interactive walkthrough of the `activitywatch` codebase on CodeCanvas [here](https://www.code-canvas.com/?session=unauthenticatedGithub&repo=activitywatch&owner=Abdulnaser97&branch=master&OnboardingTutorial=true).
From 2c809b37d54539b5ed985289a49212c3fc06a7af Mon Sep 17 00:00:00 2001
From: Nasser <42423897+Abdulnaser97@users.noreply.github.com>
Date: Sat, 15 Nov 2025 19:19:42 -0500
Subject: [PATCH 5/5] Delete activitywatch.CodeCanvas
---
activitywatch.CodeCanvas | 10199 -------------------------------------
1 file changed, 10199 deletions(-)
delete mode 100644 activitywatch.CodeCanvas
diff --git a/activitywatch.CodeCanvas b/activitywatch.CodeCanvas
deleted file mode 100644
index b8f3e8ca..00000000
--- a/activitywatch.CodeCanvas
+++ /dev/null
@@ -1,10199 +0,0 @@
-{
- "drawioXML": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n",
- "fileName": "activitywatch.CodeCanvas",
- "fileURL": "github",
- "diagramTemplateVersion": 0.2,
- "filePath": "activitywatch.CodeCanvas",
- "repoData": {
- "README.md": {
- "path": "README.md",
- "fileName": "README.md",
- "cellName": "README.md",
- "cellId": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5",
- "visible": true,
- "children": [
- "README.md-simstep-9396ef3a-ed06-4635-bb1d-3b136660bcc4"
- ]
- },
- "aw-client": {
- "path": "aw-client",
- "fileName": "aw-client",
- "cellName": "aw-client",
- "cellId": "900d6121-1844-48ba-9a18-db1ec6ea9793",
- "visible": true,
- "children": [
- "aw-client/aw_client",
- "aw-client/examples"
- ]
- },
- "aw-client/aw_client": {
- "path": "aw-client/aw_client",
- "fileName": "aw_client",
- "cellName": "aw_client",
- "cellId": "48103d9a-f009-4555-bb82-435f417b0644",
- "visible": true,
- "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793",
- "children": [
- "aw-client/aw_client/client.py",
- "aw-client/aw_client/queries.py"
- ]
- },
- "aw-client/aw_client/client.py": {
- "path": "aw-client/aw_client/client.py",
- "fileName": "client.py",
- "cellName": "client.py",
- "cellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "visible": true,
- "parentCellId": "48103d9a-f009-4555-bb82-435f417b0644",
- "children": [
- "aw-client/aw_client/client.py-simstep-432d1978-befd-4dfd-979b-fe28821d4e00",
- "generated-edge-simstep-11bc8b75-0103-4652-9fec-e55af41400a0-78766ca9-9103-486a-8755-f57a09e7f5a7",
- "generated-edge-simstep-c1a26d9b-d661-4a99-8275-39a414824ed6-6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
- "generated-edge-simstep-9eeb592f-5c44-4ce1-a7a0-261bc6d6b679-e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
- "aw-client/aw_client/client.py-simstep-06f7c9e7-1c78-4114-867b-3dbb20dcc427",
- "generated-edge-simstep-5dc6bd77-15d2-44c3-b665-8de88288c314-71408ae2-19e6-4327-bab9-8918af09c855",
- "aw-client/aw_client/client.py-simstep-8739f5eb-aec2-47f1-b1e6-a05a2bb65acd",
- "aw-client/aw_client/client.py-simstep-ea6d2274-023a-4d5f-abf4-0414c6c7f68d",
- "generated-edge-simstep-8efaf2e1-7c6d-4820-90a5-2abb80bf65ed-5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
- "generated-edge-simstep-f5c06885-1138-4c13-ae70-10b9d409be5b-ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
- "aw-client/aw_client/client.py-simstep-0d34430a-af81-407b-8817-672288674005",
- "aw-client/aw_client/client.py-simstep-642425c3-abd7-45fe-b5a9-a76bf90a9477",
- "generated-edge-simstep-834b7dbc-5efe-41ac-b75b-e43ad32141df-62388ee6-67f4-4adc-b08e-90deeb10efd4",
- "generated-edge-simstep-33e5b4e9-bd66-45f5-ab0f-543737810b99-ec5d6b90-2f5f-4a07-b0e8-da3610035a92"
- ]
- },
- "aw-client/aw_client/queries.py": {
- "path": "aw-client/aw_client/queries.py",
- "fileName": "queries.py",
- "cellName": "queries.py",
- "cellId": "941d7da8-a28d-4d5e-806f-3b546909f74e",
- "visible": true,
- "parentCellId": "48103d9a-f009-4555-bb82-435f417b0644",
- "children": [
- "aw-client/aw_client/queries.py-simstep-81f31a9b-3434-4458-a7d3-bdcf610af75e",
- "aw-client/aw_client/queries.py-simstep-1b40cfa3-9cf5-4dc3-830f-74cb1d476d50"
- ]
- },
- "aw-client/examples": {
- "path": "aw-client/examples",
- "fileName": "examples",
- "cellName": "examples",
- "cellId": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c",
- "visible": true,
- "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793",
- "children": [
- "aw-client/examples/working_hours.py"
- ]
- },
- "aw-client/examples/working_hours.py": {
- "path": "aw-client/examples/working_hours.py",
- "fileName": "working_hours.py",
- "cellName": "working_hours.py",
- "cellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
- "visible": true,
- "parentCellId": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c",
- "children": [
- "aw-client/examples/working_hours.py-simstep-e90cee0c-3a20-498b-97b9-2086a61dc02b",
- "aw-client/examples/working_hours.py-simstep-e38db73e-b347-4786-8efd-1e7cab44f73f",
- "generated-edge-simstep-5aa97ae5-7e30-4d15-8f12-05942f2e75c9-aecc1e90-5e71-43f4-a5b8-757de329fe3a",
- "generated-edge-simstep-65443293-5e86-4e71-9e8d-19d61bd162d9-c8cbde86-13c0-4232-898e-104d815a805c"
- ]
- },
- "aw-core": {
- "path": "aw-core",
- "fileName": "aw-core",
- "cellName": "aw-core",
- "cellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
- "visible": true,
- "children": [
- "aw-core/aw_datastore",
- "aw-core/aw_query",
- "aw-core/aw_transform"
- ]
- },
- "aw-core/aw_datastore": {
- "path": "aw-core/aw_datastore",
- "fileName": "aw_datastore",
- "cellName": "aw_datastore",
- "cellId": "5093a30d-28ac-4c2b-811d-65c61efc0882",
- "visible": true,
- "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
- "children": [
- "aw-core/aw_datastore/datastore.py",
- "aw-core/aw_datastore/storages"
- ]
- },
- "aw-core/aw_datastore/datastore.py": {
- "path": "aw-core/aw_datastore/datastore.py",
- "fileName": "datastore.py",
- "cellName": "datastore.py",
- "cellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
- "visible": true,
- "parentCellId": "5093a30d-28ac-4c2b-811d-65c61efc0882",
- "children": [
- "aw-core/aw_datastore/datastore.py-simstep-5573707d-aa48-4a66-a3dc-25c841986d39",
- "generated-edge-simstep-ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c-e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4"
- ]
- },
- "aw-core/aw_datastore/storages": {
- "path": "aw-core/aw_datastore/storages",
- "fileName": "storages",
- "cellName": "storages",
- "cellId": "b2eb5c59-4162-4dea-ac74-511f22996f00",
- "visible": true,
- "parentCellId": "5093a30d-28ac-4c2b-811d-65c61efc0882",
- "children": [
- "aw-core/aw_datastore/storages/peewee.py"
- ]
- },
- "aw-core/aw_datastore/storages/peewee.py": {
- "path": "aw-core/aw_datastore/storages/peewee.py",
- "fileName": "peewee.py",
- "cellName": "peewee.py",
- "cellId": "a63cc090-4355-47fb-8b22-62cd1b842ddb",
- "visible": true,
- "parentCellId": "b2eb5c59-4162-4dea-ac74-511f22996f00"
- },
- "aw-core/aw_query": {
- "path": "aw-core/aw_query",
- "fileName": "aw_query",
- "cellName": "aw_query",
- "cellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
- "visible": true,
- "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
- "children": [
- "aw-core/aw_query/query2.py",
- "aw-core/aw_query/functions.py"
- ]
- },
- "aw-core/aw_query/functions.py": {
- "path": "aw-core/aw_query/functions.py",
- "fileName": "functions.py",
- "cellName": "functions.py",
- "cellId": "e1b937af-2584-42ee-8281-e1bffda373ae",
- "visible": true,
- "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
- "children": [
- "aw-core/aw_query/functions.py-simstep-6ea3ab36-027f-40b9-a0ba-9ede77ae1117"
- ]
- },
- "aw-core/aw_query/query2.py": {
- "path": "aw-core/aw_query/query2.py",
- "fileName": "query2.py",
- "cellName": "query2.py",
- "cellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
- "visible": true,
- "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
- "children": [
- "aw-core/aw_query/query2.py-simstep-5f7b6985-edf0-42eb-8822-847d0d7b8e9b",
- "aw-core/aw_query/query2.py-simstep-ab3fe2d5-9396-4241-b64e-2a187e97de75",
- "generated-edge-simstep-7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6-4059fcbe-a1ee-41d0-b576-55a1d278bca0"
- ]
- },
- "aw-core/aw_transform": {
- "path": "aw-core/aw_transform",
- "fileName": "aw_transform",
- "cellName": "aw_transform",
- "cellId": "34f5debb-c898-419f-9c17-186d2a5f6e85",
- "visible": true,
- "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
- "children": [
- "aw-core/aw_transform/heartbeats.py"
- ]
- },
- "aw-core/aw_transform/heartbeats.py": {
- "path": "aw-core/aw_transform/heartbeats.py",
- "fileName": "heartbeats.py",
- "cellName": "heartbeats.py",
- "cellId": "6860aa38-bc11-4d81-9260-87eba1c02581",
- "visible": true,
- "parentCellId": "34f5debb-c898-419f-9c17-186d2a5f6e85",
- "children": [
- "aw-core/aw_transform/heartbeats.py-simstep-d2eac5dc-58f7-408c-beba-c1711beec25a",
- "generated-edge-simstep-9f918447-9e45-4c3b-b34f-658f58d35495-31cd2b01-8df9-4d95-9a91-d4c3aa153eb0"
- ]
- },
- "aw-notify": {
- "path": "aw-notify",
- "fileName": "aw-notify",
- "cellName": "aw-notify",
- "cellId": "0b23a1ca-091a-4f70-b49e-95910c8179bf",
- "visible": true,
- "children": [
- "aw-notify/aw_notify"
- ]
- },
- "aw-notify/aw_notify": {
- "path": "aw-notify/aw_notify",
- "fileName": "aw_notify",
- "cellName": "aw_notify",
- "cellId": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7",
- "visible": true,
- "parentCellId": "0b23a1ca-091a-4f70-b49e-95910c8179bf",
- "children": [
- "aw-notify/aw_notify/main.py"
- ]
- },
- "aw-notify/aw_notify/main.py": {
- "path": "aw-notify/aw_notify/main.py",
- "fileName": "main.py",
- "cellName": "main.py",
- "cellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "visible": true,
- "parentCellId": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7",
- "children": [
- "aw-notify/aw_notify/main.py-simstep-2108914e-2569-47bf-aa87-af337de03f8c",
- "aw-notify/aw_notify/main.py-simstep-9b9a0f90-d7a7-40fb-8573-53b470ecf85d",
- "aw-notify/aw_notify/main.py-simstep-f636bdd6-a8e3-47ec-9f9d-986b21a81868",
- "aw-notify/aw_notify/main.py-simstep-945e3312-c7c9-4722-953b-94dc0feee249",
- "aw-notify/aw_notify/main.py-simstep-9c0b3f20-5c18-418a-82f7-78b04ebda9b5",
- "aw-notify/aw_notify/main.py-simstep-a66f8ebc-93f8-4f9c-8f19-03bd951d1e98",
- "aw-notify/aw_notify/main.py-simstep-21533839-7ba4-4cfa-864a-2f67198cad68",
- "generated-edge-simstep-3c977159-c34d-4907-9004-e5aaff3f3bdc-f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
- "generated-edge-simstep-7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b-22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
- "generated-edge-simstep-f20bb756-15f3-4a7c-914b-aa61470cc435-5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
- "generated-edge-simstep-027140c6-aa16-4070-89d3-3b553168e65e-5595958a-cf9d-4894-9824-ecc89e5cf956",
- "generated-edge-simstep-92487214-03b7-430e-aab5-b5a5fb85b2cb-1b9dc1d5-e6a7-4069-8473-2156853d662e",
- "generated-edge-simstep-c8b0fe19-76a8-458d-9923-c2f270e306b3-08e05622-d948-47eb-a56d-3d6782d638c0",
- "generated-edge-simstep-e46653da-3493-419e-8f9c-397be83fe894-17c4cd6c-69f5-4df8-ac77-6955a0518939"
- ]
- },
- "aw-qt": {
- "path": "aw-qt",
- "fileName": "aw-qt",
- "cellName": "aw-qt",
- "cellId": "315afad3-54aa-4009-bbe4-8e17ade01ec1",
- "visible": true,
- "children": [
- "aw-qt/aw_qt"
- ]
- },
- "aw-qt/aw_qt": {
- "path": "aw-qt/aw_qt",
- "fileName": "aw_qt",
- "cellName": "aw_qt",
- "cellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
- "visible": true,
- "parentCellId": "315afad3-54aa-4009-bbe4-8e17ade01ec1",
- "children": [
- "aw-qt/aw_qt/main.py",
- "aw-qt/aw_qt/config.py",
- "aw-qt/aw_qt/manager.py",
- "aw-qt/aw_qt/trayicon.py"
- ]
- },
- "aw-qt/aw_qt/config.py": {
- "path": "aw-qt/aw_qt/config.py",
- "fileName": "config.py",
- "cellName": "config.py",
- "cellId": "f47c0efe-5fd2-488b-b325-b2965448260a",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
- "children": [
- "aw-qt/aw_qt/config.py-simstep-c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a"
- ]
- },
- "aw-qt/aw_qt/main.py": {
- "path": "aw-qt/aw_qt/main.py",
- "fileName": "main.py",
- "cellName": "main.py",
- "cellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
- "children": [
- "aw-qt/aw_qt/main.py-simstep-61d1a03e-ed06-496d-8495-36419b9c8607",
- "generated-edge-simstep-6084ca69-514e-4bde-b2c0-1d33b26203e8-1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
- "generated-edge-simstep-540119c2-b541-4342-aa59-233b4f0f8db5-030668a5-a377-4710-b39f-95efb5fa4768"
- ]
- },
- "aw-qt/aw_qt/manager.py": {
- "path": "aw-qt/aw_qt/manager.py",
- "fileName": "manager.py",
- "cellName": "manager.py",
- "cellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
- "children": [
- "aw-qt/aw_qt/manager.py-simstep-e716abbb-c96e-4613-bca2-0c094e8df129",
- "aw-qt/aw_qt/manager.py-simstep-8be10173-751a-4da9-99a9-321c23e71aaa",
- "aw-qt/aw_qt/manager.py-simstep-520ab3f2-ef6c-4334-89fc-280f6d86d14b",
- "aw-qt/aw_qt/manager.py-simstep-899b57ba-4a68-4620-977a-80981d089e85",
- "aw-qt/aw_qt/manager.py-simstep-6173a9e1-ecfa-4dd9-9f82-f80579406011",
- "generated-edge-simstep-9aeaf443-6741-4557-9671-67d596f456b3-1fb5a75e-9c49-490d-b412-04ac1c7205fa",
- "generated-edge-simstep-f968357d-53c4-41e8-b71f-c581c08b52e6-a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
- "generated-edge-simstep-fdff8ecd-12b9-4bc0-ba7b-9402d26b1737-9d4dee50-64ef-459a-98fa-839761e16813"
- ]
- },
- "aw-qt/aw_qt/trayicon.py": {
- "path": "aw-qt/aw_qt/trayicon.py",
- "fileName": "trayicon.py",
- "cellName": "trayicon.py",
- "cellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
- "children": [
- "aw-qt/aw_qt/trayicon.py-simstep-6ae15f2e-5331-4153-b9d2-2a297b65c55f",
- "aw-qt/aw_qt/trayicon.py-simstep-08d88f03-4133-41d6-9cbb-0df16703b864",
- "aw-qt/aw_qt/trayicon.py-simstep-01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9",
- "aw-qt/aw_qt/trayicon.py-simstep-a71f6cd0-490a-40b5-8a05-1c873f208882",
- "generated-edge-simstep-03fd319d-4ffe-47cf-bf39-ac388da80fa7-dfaa3fc8-eca8-4c67-b926-87798f511adb",
- "generated-edge-simstep-8e583414-7b87-42c9-bdb2-e56259be4cdf-d9e460b6-432d-49c8-8e76-0d8750aa2c10",
- "generated-edge-simstep-c0115129-b34b-4d27-9f73-cf2dc142ea81-f704019b-d227-47ad-8761-9a2ea01516cb",
- "generated-edge-simstep-7775ac80-c954-464e-b230-b233216ee5e3-ba9e605d-98a7-4b50-979a-05bf7213c681",
- "generated-edge-simstep-1ed5cd16-b593-41cf-84f2-233a8d64a227-2298c4b5-17de-487f-b592-2ac0f95eca84"
- ]
- },
- "aw-server": {
- "path": "aw-server",
- "fileName": "aw-server",
- "cellName": "aw-server",
- "cellId": "efb8048c-455c-4e7a-aa18-9e8b04779b71",
- "visible": true,
- "children": [
- "aw-server/aw_server"
- ]
- },
- "aw-server/aw_server": {
- "path": "aw-server/aw_server",
- "fileName": "aw_server",
- "cellName": "aw_server",
- "cellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
- "visible": true,
- "parentCellId": "efb8048c-455c-4e7a-aa18-9e8b04779b71",
- "children": [
- "aw-server/aw_server/rest.py",
- "aw-server/aw_server/api.py"
- ]
- },
- "aw-server/aw_server/api.py": {
- "path": "aw-server/aw_server/api.py",
- "fileName": "api.py",
- "cellName": "api.py",
- "cellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
- "children": [
- "aw-server/aw_server/api.py-simstep-addb33f5-b815-49f0-9b54-a8ee3fb3b87b",
- "generated-edge-simstep-cd6c54a5-c0bd-4b99-9446-ea921ee876a6-6a5be6b6-e11d-460d-8193-427f3a9e42ac",
- "aw-server/aw_server/api.py-simstep-a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31",
- "generated-edge-simstep-833f0f0f-ec00-4960-b1f9-46d8a8530a01-b79b67f9-1be1-48f1-920a-9ebdd4417272",
- "aw-server/aw_server/api.py-simstep-7357e239-3712-4b55-a94c-2165ea1f3255",
- "aw-server/aw_server/api.py-simstep-bb678fe2-e6e3-472b-8ae4-95e362d4bdaf",
- "aw-server/aw_server/api.py-simstep-976cfbd0-8946-4157-81b0-0ae6dffa43e1",
- "generated-edge-simstep-40b16e25-734b-44d2-86cd-7c301723ff5f-9aec4875-5718-4c38-a57c-1d3053c38ba5",
- "aw-server/aw_server/api.py-simstep-d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6",
- "aw-server/aw_server/api.py-simstep-5fb7b7d5-1759-43dc-a711-b2b0b5df3893",
- "aw-server/aw_server/api.py-simstep-4050248c-1638-452c-8826-677a7a2fece8",
- "aw-server/aw_server/api.py-simstep-164ed08b-0873-499b-b945-e062cf362429",
- "generated-edge-simstep-60764034-1b94-4c15-9015-09e8b775f736-ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
- "generated-edge-simstep-7a5f8838-8ed9-47b3-907f-077efeedaa10-272a1088-1b0c-43f9-8335-d7055539c813",
- "generated-edge-simstep-7e01821d-906c-4518-a1e0-6b71be84291a-941b8c57-be7c-49cd-ba2a-d2237f8f129b",
- "generated-edge-simstep-666a933a-7a74-4d90-be19-7610f7bd3d74-1f7db50a-bc15-48d1-9f06-27ed743afa75"
- ]
- },
- "aw-server/aw_server/rest.py": {
- "path": "aw-server/aw_server/rest.py",
- "fileName": "rest.py",
- "cellName": "rest.py",
- "cellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
- "children": [
- "generated-edge-simstep-97f58e0a-cbeb-4895-b613-d8e9fd129a42-5a7fba44-6d4d-4836-bc13-ed69518c9d45",
- "aw-server/aw_server/rest.py-simstep-671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7",
- "generated-edge-simstep-5a0d9b17-b09a-4aa5-9234-c01cb2aadef4-891bfe3a-f22a-4998-acea-aa6d0c362821",
- "generated-edge-simstep-fe43857f-ef7d-455d-a9c4-37d54d12207a-c4b6d403-d2a9-4cff-8a72-31189a53c0db",
- "aw-server/aw_server/rest.py-simstep-e98f7509-f28f-4534-8f2a-f525edc73f69",
- "generated-edge-simstep-02717bea-6ee3-48ef-8c41-0c9f3e9d9a58-a676f81f-8c68-4fc8-94b7-583bada02d70",
- "generated-edge-simstep-d57d2bf7-916c-44cd-844d-b1900c276925-a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
- "aw-server/aw_server/rest.py-simstep-7bdce779-492f-4dee-a68d-4e6d28dc079a",
- "aw-server/aw_server/rest.py-simstep-cfd637bd-f6b2-44cf-8330-7b2c59c0658b",
- "aw-server/aw_server/rest.py-simstep-3e1decf0-1329-4da8-a7c7-870ffe960a54",
- "aw-server/aw_server/rest.py-simstep-3fd4d48c-e70c-4217-92c1-7554445cf03b",
- "generated-edge-simstep-6449735d-8c85-4d49-bb8c-c2b1f9918ffc-8515a29c-385b-4ec5-886c-ba3a3a48518e",
- "generated-edge-simstep-988adf58-e1be-4352-be66-4f02188fc28a-0614b31f-64d9-4e85-a5f5-6304f0702bd7"
- ]
- },
- "aw-server-rust": {
- "path": "aw-server-rust",
- "fileName": "aw-server-rust",
- "cellName": "aw-server-rust",
- "cellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
- "visible": true,
- "children": [
- "aw-server-rust/aw-server",
- "aw-server-rust/aw-query",
- "aw-server-rust/aw-datastore",
- "aw-server-rust/aw-transform",
- "aw-server-rust/aw-client-rust"
- ]
- },
- "aw-server-rust/aw-client-rust": {
- "path": "aw-server-rust/aw-client-rust",
- "fileName": "aw-client-rust",
- "cellName": "aw-client-rust",
- "cellId": "22692aea-cd7a-4c08-8c76-c16bb5499546",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
- "children": [
- "aw-server-rust/aw-client-rust/src"
- ]
- },
- "aw-server-rust/aw-client-rust/src": {
- "path": "aw-server-rust/aw-client-rust/src",
- "fileName": "src",
- "cellName": "src",
- "cellId": "08296022-1e80-4653-821d-b48d9cf30c68",
- "visible": true,
- "parentCellId": "22692aea-cd7a-4c08-8c76-c16bb5499546",
- "children": [
- "aw-server-rust/aw-client-rust/src/blocking.rs",
- "aw-server-rust/aw-client-rust/src/lib.rs"
- ]
- },
- "aw-server-rust/aw-client-rust/src/blocking.rs": {
- "path": "aw-server-rust/aw-client-rust/src/blocking.rs",
- "fileName": "blocking.rs",
- "cellName": "blocking.rs",
- "cellId": "8dafeb60-1305-46f7-baac-4153d6d18539",
- "visible": true,
- "parentCellId": "08296022-1e80-4653-821d-b48d9cf30c68",
- "children": [
- "aw-server-rust/aw-client-rust/src/blocking.rs-simstep-3118dc4c-d7ad-4996-aa81-a205ccdf6e72"
- ]
- },
- "aw-server-rust/aw-client-rust/src/lib.rs": {
- "path": "aw-server-rust/aw-client-rust/src/lib.rs",
- "fileName": "lib.rs",
- "cellName": "lib.rs",
- "cellId": "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf",
- "visible": true,
- "parentCellId": "08296022-1e80-4653-821d-b48d9cf30c68",
- "children": [
- "generated-edge-simstep-97542310-17cf-4c99-9ce9-a328dffa5f4c-ed18dcc0-5e4a-44fb-b661-f746f1e893f1"
- ]
- },
- "aw-server-rust/aw-datastore": {
- "path": "aw-server-rust/aw-datastore",
- "fileName": "aw-datastore",
- "cellName": "aw-datastore",
- "cellId": "a542ca3c-9d99-490f-89de-186bb284b0fe",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
- "children": [
- "aw-server-rust/aw-datastore/src"
- ]
- },
- "aw-server-rust/aw-datastore/src": {
- "path": "aw-server-rust/aw-datastore/src",
- "fileName": "src",
- "cellName": "src",
- "cellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
- "visible": true,
- "parentCellId": "a542ca3c-9d99-490f-89de-186bb284b0fe",
- "children": [
- "aw-server-rust/aw-datastore/src/worker.rs",
- "aw-server-rust/aw-datastore/src/datastore.rs"
- ]
- },
- "aw-server-rust/aw-datastore/src/datastore.rs": {
- "path": "aw-server-rust/aw-datastore/src/datastore.rs",
- "fileName": "datastore.rs",
- "cellName": "datastore.rs",
- "cellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "visible": true,
- "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
- "children": [
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-ff017206-8323-4caa-9eca-4fc760c2470f",
- "generated-edge-simstep-f69e7df0-6666-4b48-a0a6-1000c8ccede0-9792d1f0-08be-4f90-8e68-3caee0eb2498",
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-c59f4b10-f6c9-4fd8-ba70-ea60667a01e8",
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-da146aa5-e96f-4db6-a36f-b405b1a11255",
- "generated-edge-simstep-7b396541-e74f-4baf-9b1b-c1f7a914ba7a-0fe644bb-a583-40d8-9377-3641c90c4f62",
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-04bbbe33-e9de-4c5f-b925-27196d20ef1d",
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-1b3cdf02-5dad-411c-a35e-9250c8aafc9d",
- "generated-edge-simstep-5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619-561eebea-ee66-4251-a29c-64c2e3aae490"
- ]
- },
- "aw-server-rust/aw-datastore/src/worker.rs": {
- "path": "aw-server-rust/aw-datastore/src/worker.rs",
- "fileName": "worker.rs",
- "cellName": "worker.rs",
- "cellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
- "visible": true,
- "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
- "children": [
- "generated-edge-simstep-e1bf9f3c-e763-4e75-8c62-1a8d739d53cc-5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
- "aw-server-rust/aw-datastore/src/worker.rs-simstep-b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3",
- "aw-server-rust/aw-datastore/src/worker.rs-simstep-a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb",
- "generated-edge-simstep-eefd671a-3b08-4336-bd26-cb6eb04070ec-21d1c973-0f67-4aca-9d1b-eade3b5d347b",
- "generated-edge-simstep-9750ac2c-c0fb-4fe5-815f-398886fc827b-959b342e-eb44-4255-8176-1600a5fa17ac"
- ]
- },
- "aw-server-rust/aw-query": {
- "path": "aw-server-rust/aw-query",
- "fileName": "aw-query",
- "cellName": "aw-query",
- "cellId": "d70684b2-06ba-4f18-9c40-80de0778c035",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
- "children": [
- "aw-server-rust/aw-query/src"
- ]
- },
- "aw-server-rust/aw-query/src": {
- "path": "aw-server-rust/aw-query/src",
- "fileName": "src",
- "cellName": "src",
- "cellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
- "visible": true,
- "parentCellId": "d70684b2-06ba-4f18-9c40-80de0778c035",
- "children": [
- "aw-server-rust/aw-query/src/lib.rs",
- "aw-server-rust/aw-query/src/interpret.rs",
- "aw-server-rust/aw-query/src/functions.rs",
- "aw-server-rust/aw-query/src/datatype.rs"
- ]
- },
- "aw-server-rust/aw-query/src/datatype.rs": {
- "path": "aw-server-rust/aw-query/src/datatype.rs",
- "fileName": "datatype.rs",
- "cellName": "datatype.rs",
- "cellId": "60cb37da-078e-4380-88f0-e6746007277d",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
- "children": [
- "generated-edge-simstep-e598a658-8e0e-4a76-9310-af0d60ec5828-79c14e32-8192-488e-ab72-b9c4c6edb346"
- ]
- },
- "aw-server-rust/aw-query/src/functions.rs": {
- "path": "aw-server-rust/aw-query/src/functions.rs",
- "fileName": "functions.rs",
- "cellName": "functions.rs",
- "cellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
- "children": [
- "aw-server-rust/aw-query/src/functions.rs-simstep-475886bc-26d3-4528-84ae-2f9c8e1dfcf9",
- "generated-edge-simstep-f7dfb334-099f-4750-a893-cd96b1c46278-7a14a4d3-a453-4e33-9b10-fb192e40e34e",
- "aw-server-rust/aw-query/src/functions.rs-simstep-af6c51b2-ee18-406c-acc6-6e5d9588d012",
- "aw-server-rust/aw-query/src/functions.rs-simstep-06d75f72-3fc8-47d8-85ab-f7fa317f4de5",
- "aw-server-rust/aw-query/src/functions.rs-simstep-cc5cfecf-cee9-4582-aa6c-b74787a11da8",
- "generated-edge-simstep-914107de-b38a-4307-ab2c-e257ed3d2fb5-9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
- "generated-edge-simstep-d78663e6-a6d4-4ba7-a922-436bd075e457-2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe"
- ]
- },
- "aw-server-rust/aw-query/src/interpret.rs": {
- "path": "aw-server-rust/aw-query/src/interpret.rs",
- "fileName": "interpret.rs",
- "cellName": "interpret.rs",
- "cellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
- "children": [
- "aw-server-rust/aw-query/src/interpret.rs-simstep-18492fe4-5b57-4749-a2e8-d18f3c546e89",
- "generated-edge-simstep-00784ae1-bb99-494c-bf46-fe5947de5066-8f8d2c55-63c0-48ec-b931-f848e245688f",
- "generated-edge-simstep-78aaa465-8377-43f1-9ba6-36ddcf9300cf-8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
- "aw-server-rust/aw-query/src/interpret.rs-simstep-e3204124-26ff-4799-8462-100305c27ae1",
- "aw-server-rust/aw-query/src/interpret.rs-simstep-9382ac29-7930-4f83-afdd-deb2bfc221e3",
- "generated-edge-simstep-f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5-15dfaeb9-fb37-4296-972f-0188abd0b353",
- "aw-server-rust/aw-query/src/interpret.rs-simstep-f7c58723-a402-45d1-8070-59c196e20fb2"
- ]
- },
- "aw-server-rust/aw-query/src/lib.rs": {
- "path": "aw-server-rust/aw-query/src/lib.rs",
- "fileName": "lib.rs",
- "cellName": "lib.rs",
- "cellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
- "children": [
- "aw-server-rust/aw-query/src/lib.rs-simstep-3291e01a-482d-401b-98b5-759573be65ca",
- "aw-server-rust/aw-query/src/lib.rs-simstep-024a46d7-abc2-4c35-92d1-900d198f748c",
- "generated-edge-simstep-acc1ad56-50cb-41ab-9217-f8d15af6686c-e72e1881-49ce-41ad-966a-90a26ca47453",
- "aw-server-rust/aw-query/src/lib.rs-simstep-b482a39f-e520-4d4d-8b2f-d1298922763f"
- ]
- },
- "aw-server-rust/aw-server": {
- "path": "aw-server-rust/aw-server",
- "fileName": "aw-server",
- "cellName": "aw-server",
- "cellId": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
- "children": [
- "aw-server-rust/aw-server/src"
- ]
- },
- "aw-server-rust/aw-server/src": {
- "path": "aw-server-rust/aw-server/src",
- "fileName": "src",
- "cellName": "src",
- "cellId": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e",
- "visible": true,
- "parentCellId": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c",
- "children": [
- "aw-server-rust/aw-server/src/endpoints"
- ]
- },
- "aw-server-rust/aw-server/src/endpoints": {
- "path": "aw-server-rust/aw-server/src/endpoints",
- "fileName": "endpoints",
- "cellName": "endpoints",
- "cellId": "11799249-188d-43b3-b410-54dcff47aeba",
- "visible": true,
- "parentCellId": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e",
- "children": [
- "aw-server-rust/aw-server/src/endpoints/query.rs",
- "aw-server-rust/aw-server/src/endpoints/bucket.rs"
- ]
- },
- "aw-server-rust/aw-server/src/endpoints/bucket.rs": {
- "path": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "fileName": "bucket.rs",
- "cellName": "bucket.rs",
- "cellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
- "visible": true,
- "parentCellId": "11799249-188d-43b3-b410-54dcff47aeba",
- "children": [
- "aw-server-rust/aw-server/src/endpoints/bucket.rs-simstep-41b8b1d6-f9fe-47ad-851e-574e804f7171",
- "generated-edge-simstep-7e361c3d-a5a9-45f3-a83d-98e39ff45675-2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
- "generated-edge-simstep-bfcc2f87-9167-4784-a3b3-f71d6e7a6e71-4a4afbdf-0303-4d84-bbf8-5121c74965a0"
- ]
- },
- "aw-server-rust/aw-server/src/endpoints/query.rs": {
- "path": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "fileName": "query.rs",
- "cellName": "query.rs",
- "cellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "visible": true,
- "parentCellId": "11799249-188d-43b3-b410-54dcff47aeba",
- "children": [
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-e91513ab-13ec-4eea-9942-9620dbe3b92b",
- "generated-edge-simstep-a7b6aefb-1401-4756-bfa1-1eb9a76cde07-c8403507-4895-4695-84b5-9305afdc3c9f",
- "generated-edge-simstep-785d1355-bf16-42a7-846e-a2bf3ecbb35b-889f0869-2c33-499b-a558-ede80ee18a54",
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-1c25a330-b713-4866-9440-8737c787ce33",
- "generated-edge-simstep-6eb126a9-5234-4495-9727-ec2741ce9660-d3cb01a0-d8cd-4382-b122-d1234b0562bc",
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-868edfd6-1f03-416e-88dc-7b09d05e4ba5",
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-f52d6bfa-55fe-49ee-9f20-60bf296c76f4",
- "generated-edge-simstep-b835d5e0-434d-4469-94fe-d309114a9ef1-8f02d20c-25fe-4a28-99de-3e8908d0a66f",
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-c988a25d-05ad-4c19-87ac-362c79af1d00",
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-72197f38-6e3b-432c-be11-ce5fbb94efb9",
- "generated-edge-simstep-98777081-df05-4b5c-89f6-5076fab00e92-31b60323-3a65-4184-a42f-f577f3a958ff",
- "generated-edge-simstep-633d97c2-762a-45cb-8900-308ab124d526-3f00132f-3930-4b99-82cf-1ca7f818661b"
- ]
- },
- "aw-server-rust/aw-transform": {
- "path": "aw-server-rust/aw-transform",
- "fileName": "aw-transform",
- "cellName": "aw-transform",
- "cellId": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
- "children": [
- "aw-server-rust/aw-transform/src"
- ]
- },
- "aw-server-rust/aw-transform/src": {
- "path": "aw-server-rust/aw-transform/src",
- "fileName": "src",
- "cellName": "src",
- "cellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
- "visible": true,
- "parentCellId": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8",
- "children": [
- "aw-server-rust/aw-transform/src/filter_period.rs",
- "aw-server-rust/aw-transform/src/classify.rs"
- ]
- },
- "aw-server-rust/aw-transform/src/classify.rs": {
- "path": "aw-server-rust/aw-transform/src/classify.rs",
- "fileName": "classify.rs",
- "cellName": "classify.rs",
- "cellId": "22d8d360-9b15-49db-bc15-de087f960e23",
- "visible": true,
- "parentCellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
- "children": [
- "aw-server-rust/aw-transform/src/classify.rs-simstep-55815d72-39f6-4201-ad99-6ebd57d0eece",
- "aw-server-rust/aw-transform/src/classify.rs-simstep-e863b0b1-c3ce-4b13-ad7d-a7438f650035",
- "generated-edge-simstep-9f7f50e4-03c6-4d7c-95c8-3317d37115eb-341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
- "generated-edge-simstep-ebd328dc-4cdf-452d-b4aa-10b65e9c354d-b4391f38-d9ee-4377-8568-efca87206124"
- ]
- },
- "aw-server-rust/aw-transform/src/filter_period.rs": {
- "path": "aw-server-rust/aw-transform/src/filter_period.rs",
- "fileName": "filter_period.rs",
- "cellName": "filter_period.rs",
- "cellId": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca",
- "visible": true,
- "parentCellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
- "children": [
- "aw-server-rust/aw-transform/src/filter_period.rs-simstep-50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10"
- ]
- },
- "aw-watcher-afk": {
- "path": "aw-watcher-afk",
- "fileName": "aw-watcher-afk",
- "cellName": "aw-watcher-afk",
- "cellId": "7ee7b20f-9df9-4269-8f41-bc7e191503bd",
- "visible": true,
- "children": [
- "aw-watcher-afk/aw_watcher_afk"
- ]
- },
- "aw-watcher-afk/aw_watcher_afk": {
- "path": "aw-watcher-afk/aw_watcher_afk",
- "fileName": "aw_watcher_afk",
- "cellName": "aw_watcher_afk",
- "cellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
- "visible": true,
- "parentCellId": "7ee7b20f-9df9-4269-8f41-bc7e191503bd",
- "children": [
- "aw-watcher-afk/aw_watcher_afk/__main__.py",
- "aw-watcher-afk/aw_watcher_afk/afk.py",
- "aw-watcher-afk/aw_watcher_afk/unix.py"
- ]
- },
- "aw-watcher-afk/aw_watcher_afk/__main__.py": {
- "path": "aw-watcher-afk/aw_watcher_afk/__main__.py",
- "fileName": "__main__.py",
- "cellName": "__main__.py",
- "cellId": "d242d1ad-7cdf-414b-812a-f3e5af153562",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
- "children": [
- "aw-watcher-afk/aw_watcher_afk/__main__.py-simstep-8ffbcadf-f26a-483a-9902-95e5a761de64",
- "generated-edge-simstep-60e1002f-9782-4c8d-b104-f4bb172e2c91-7c2f1d5b-706c-4dd2-9d8c-62b3e6886250"
- ]
- },
- "aw-watcher-afk/aw_watcher_afk/afk.py": {
- "path": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "fileName": "afk.py",
- "cellName": "afk.py",
- "cellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
- "children": [
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-daeeac12-287a-4144-9028-6ea841b196c4",
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-6579f587-817d-4d23-a9df-86abc54273ae",
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-3e0e033c-c32f-4d0d-aa65-a278d77e80c7",
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-dc58bc3e-b09e-4df2-870b-76419e78dd3d",
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-1e5ad77f-aeff-49b6-9634-65e52f011a83",
- "generated-edge-simstep-1422a5f8-ad2e-4b32-8955-ee6bb3053286-1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
- "generated-edge-simstep-2588211c-b086-4768-8a87-a86764c7e5cd-e514d9e2-e803-4041-b693-65878401b214",
- "generated-edge-simstep-9195e582-b3fa-4848-b151-0236a8a5d176-eeb9224a-fff6-4652-b733-ea430b820a2c",
- "generated-edge-simstep-78d78341-ced8-4fc6-bc93-ce4a62c8adf6-196358b9-6ae9-4f52-ad78-ff88b4a49403",
- "generated-edge-simstep-c9a127c1-afd0-4def-a0fe-c490c9b64039-b520b088-6f6f-4b32-afba-5ef244691c44",
- "generated-edge-simstep-9fde1b44-5dbf-4530-88e2-ca54c220b462-f0e34997-66ab-4bc2-9a5e-1f00b40d47b0"
- ]
- },
- "aw-watcher-afk/aw_watcher_afk/unix.py": {
- "path": "aw-watcher-afk/aw_watcher_afk/unix.py",
- "fileName": "unix.py",
- "cellName": "unix.py",
- "cellId": "72e53989-6741-4b0d-b49c-f58d0333cdd1",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
- "children": [
- "aw-watcher-afk/aw_watcher_afk/unix.py-simstep-4d2c85c7-0754-429a-8a55-c64d4da0d37c"
- ]
- },
- "aw-watcher-window": {
- "path": "aw-watcher-window",
- "fileName": "aw-watcher-window",
- "cellName": "aw-watcher-window",
- "cellId": "02d954ad-e1f5-4853-9860-a553ea21245b",
- "visible": true,
- "children": [
- "aw-watcher-window/aw_watcher_window"
- ]
- },
- "aw-watcher-window/aw_watcher_window": {
- "path": "aw-watcher-window/aw_watcher_window",
- "fileName": "aw_watcher_window",
- "cellName": "aw_watcher_window",
- "cellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
- "visible": true,
- "parentCellId": "02d954ad-e1f5-4853-9860-a553ea21245b",
- "children": [
- "aw-watcher-window/aw_watcher_window/main.py",
- "aw-watcher-window/aw_watcher_window/lib.py",
- "aw-watcher-window/aw_watcher_window/macos.swift"
- ]
- },
- "aw-watcher-window/aw_watcher_window/lib.py": {
- "path": "aw-watcher-window/aw_watcher_window/lib.py",
- "fileName": "lib.py",
- "cellName": "lib.py",
- "cellId": "f55ac327-589c-4d8a-ac08-6db49ae00e75",
- "visible": true,
- "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
- "children": [
- "aw-watcher-window/aw_watcher_window/lib.py-simstep-3e57e810-18fe-461f-a33c-f3eb0773ecf5"
- ]
- },
- "aw-watcher-window/aw_watcher_window/macos.swift": {
- "path": "aw-watcher-window/aw_watcher_window/macos.swift",
- "fileName": "macos.swift",
- "cellName": "macos.swift",
- "cellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
- "visible": true,
- "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
- "children": [
- "aw-watcher-window/aw_watcher_window/macos.swift-simstep-46ccc29e-b251-435a-8768-4304d477261a",
- "aw-watcher-window/aw_watcher_window/macos.swift-simstep-e873b3e2-2ebd-43ee-8f97-e02f869578f7",
- "aw-watcher-window/aw_watcher_window/macos.swift-simstep-8420fd6c-dba4-41c0-b11d-7280a428ab36",
- "generated-edge-simstep-b6456941-3a8f-452d-a4eb-67915b00d5b3-4d96dbc5-cd5e-4ef9-8733-721776e8fb8f"
- ]
- },
- "aw-watcher-window/aw_watcher_window/main.py": {
- "path": "aw-watcher-window/aw_watcher_window/main.py",
- "fileName": "main.py",
- "cellName": "main.py",
- "cellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
- "visible": true,
- "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
- "children": [
- "aw-watcher-window/aw_watcher_window/main.py-simstep-caf92190-4958-42b9-b962-d21c9ff6c62d",
- "aw-watcher-window/aw_watcher_window/main.py-simstep-706e836d-c3e2-4048-9eae-95e761ca9ffa",
- "generated-edge-simstep-39835fd9-a301-482d-8b6d-9d16abbbaa29-6d9c0750-fa20-47af-9135-6cc6444cb6b0",
- "generated-edge-simstep-81f5cf5a-47ed-4fce-9c97-27559b1c7976-3fe51be8-fc72-4a07-8a11-bef3ffb6dd26"
- ]
- },
- "02d954ad-e1f5-4853-9860-a553ea21245b": {
- "path": "02d954ad-e1f5-4853-9860-a553ea21245b",
- "cellName": "aw-watcher-window",
- "cellId": "02d954ad-e1f5-4853-9860-a553ea21245b",
- "visible": true
- },
- "900d6121-1844-48ba-9a18-db1ec6ea9793": {
- "path": "900d6121-1844-48ba-9a18-db1ec6ea9793",
- "cellName": "aw-client",
- "cellId": "900d6121-1844-48ba-9a18-db1ec6ea9793",
- "visible": true
- },
- "efb8048c-455c-4e7a-aa18-9e8b04779b71": {
- "path": "efb8048c-455c-4e7a-aa18-9e8b04779b71",
- "cellName": "aw-server",
- "cellId": "efb8048c-455c-4e7a-aa18-9e8b04779b71",
- "visible": true
- },
- "1eed769a-5d0a-443c-9cc3-4e8f59c84abb": {
- "path": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
- "cellName": "aw-core",
- "cellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb",
- "visible": true
- },
- "306c9af9-c4b4-4bea-85d2-fc4830dedc4c": {
- "path": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
- "cellName": "aw_watcher_window",
- "cellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c",
- "visible": true,
- "parentCellId": "02d954ad-e1f5-4853-9860-a553ea21245b"
- },
- "48103d9a-f009-4555-bb82-435f417b0644": {
- "path": "48103d9a-f009-4555-bb82-435f417b0644",
- "cellName": "aw_client",
- "cellId": "48103d9a-f009-4555-bb82-435f417b0644",
- "visible": true,
- "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793"
- },
- "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49": {
- "path": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
- "cellName": "aw_server",
- "cellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49",
- "visible": true,
- "parentCellId": "efb8048c-455c-4e7a-aa18-9e8b04779b71"
- },
- "5093a30d-28ac-4c2b-811d-65c61efc0882": {
- "path": "5093a30d-28ac-4c2b-811d-65c61efc0882",
- "cellName": "aw_datastore",
- "cellId": "5093a30d-28ac-4c2b-811d-65c61efc0882",
- "visible": true,
- "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb"
- },
- "1bbc4c76-4066-4521-a1d8-0248c1418060": {
- "path": "1bbc4c76-4066-4521-a1d8-0248c1418060",
- "cellName": "main.py",
- "cellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
- "visible": true,
- "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
- },
- "f55ac327-589c-4d8a-ac08-6db49ae00e75": {
- "path": "f55ac327-589c-4d8a-ac08-6db49ae00e75",
- "cellName": "lib.py",
- "cellId": "f55ac327-589c-4d8a-ac08-6db49ae00e75",
- "visible": true,
- "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
- },
- "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2": {
- "path": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "cellName": "client.py",
- "cellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "visible": true,
- "parentCellId": "48103d9a-f009-4555-bb82-435f417b0644"
- },
- "7f67f305-e40b-496e-87a4-97725d0636a0": {
- "path": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "cellName": "rest.py",
- "cellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
- },
- "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc": {
- "path": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "cellName": "api.py",
- "cellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
- },
- "aba7852e-7836-4343-ae26-5ecb9a02d42d": {
- "path": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
- "cellName": "datastore.py",
- "cellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
- "visible": true,
- "parentCellId": "5093a30d-28ac-4c2b-811d-65c61efc0882"
- },
- "b2eb5c59-4162-4dea-ac74-511f22996f00": {
- "path": "b2eb5c59-4162-4dea-ac74-511f22996f00",
- "cellName": "storages",
- "cellId": "b2eb5c59-4162-4dea-ac74-511f22996f00",
- "visible": true,
- "parentCellId": "5093a30d-28ac-4c2b-811d-65c61efc0882"
- },
- "a63cc090-4355-47fb-8b22-62cd1b842ddb": {
- "path": "a63cc090-4355-47fb-8b22-62cd1b842ddb",
- "cellName": "peewee.py",
- "cellId": "a63cc090-4355-47fb-8b22-62cd1b842ddb",
- "visible": true,
- "parentCellId": "b2eb5c59-4162-4dea-ac74-511f22996f00"
- },
- "638a5f20-935f-4345-8eaf-dfcd2aa6efb4": {
- "path": "638a5f20-935f-4345-8eaf-dfcd2aa6efb4",
- "cellName": "Watcher Initialization - main.py:L62-69",
- "cellId": "638a5f20-935f-4345-8eaf-dfcd2aa6efb4",
- "visible": true,
- "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060"
- },
- "aw-watcher-window/aw_watcher_window/main.py-simstep-caf92190-4958-42b9-b962-d21c9ff6c62d": {
- "path": "aw-watcher-window/aw_watcher_window/main.py-simstep-caf92190-4958-42b9-b962-d21c9ff6c62d",
- "fileName": "main.py",
- "wiki": "The `aw-watcher-window` process starts. It parses arguments, sets up logging, and initializes the `ActivityWatchClient`. It also ensures a bucket for storing window activity exists on the server.",
- "cellName": "Watcher Initialization - main.py:L62-69",
- "cellId": "638a5f20-935f-4345-8eaf-dfcd2aa6efb4",
- "visible": true,
- "startLine": 62,
- "endLine": 69,
- "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
- "parentPath": "aw-watcher-window/aw_watcher_window/main.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "caf92190-4958-42b9-b962-d21c9ff6c62d"
- }
- ]
- },
- "89c12f0e-0649-4963-8e57-d7fd7da30bc4": {
- "path": "89c12f0e-0649-4963-8e57-d7fd7da30bc4",
- "cellName": "Get Current Window Information - lib.py:L58-73",
- "cellId": "89c12f0e-0649-4963-8e57-d7fd7da30bc4",
- "visible": true,
- "parentCellId": "f55ac327-589c-4d8a-ac08-6db49ae00e75"
- },
- "aw-watcher-window/aw_watcher_window/lib.py-simstep-3e57e810-18fe-461f-a33c-f3eb0773ecf5": {
- "path": "aw-watcher-window/aw_watcher_window/lib.py-simstep-3e57e810-18fe-461f-a33c-f3eb0773ecf5",
- "fileName": "lib.py",
- "wiki": "Inside the loop, the `get_current_window` function is called. This function acts as a dispatcher, calling the appropriate OS-specific implementation to get the currently focused application and window title.",
- "cellName": "Get Current Window Information - lib.py:L58-73",
- "cellId": "89c12f0e-0649-4963-8e57-d7fd7da30bc4",
- "visible": true,
- "startLine": 58,
- "endLine": 73,
- "parentCellId": "f55ac327-589c-4d8a-ac08-6db49ae00e75",
- "parentPath": "aw-watcher-window/aw_watcher_window/lib.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "3e57e810-18fe-461f-a33c-f3eb0773ecf5"
- }
- ]
- },
- "30328419-4cc4-4ea2-a7fb-1728782b23aa": {
- "path": "30328419-4cc4-4ea2-a7fb-1728782b23aa",
- "cellName": "Send Heartbeat via Client - main.py:L160-162",
- "cellId": "30328419-4cc4-4ea2-a7fb-1728782b23aa",
- "visible": true,
- "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060"
- },
- "aw-watcher-window/aw_watcher_window/main.py-simstep-706e836d-c3e2-4048-9eae-95e761ca9ffa": {
- "path": "aw-watcher-window/aw_watcher_window/main.py-simstep-706e836d-c3e2-4048-9eae-95e761ca9ffa",
- "fileName": "main.py",
- "wiki": "The created event is sent as a heartbeat to the `aw-server` using the `ActivityWatchClient`. The `queued=True` parameter enables local event merging and a persistent queue for offline robustness.",
- "cellName": "Send Heartbeat via Client - main.py:L160-162",
- "cellId": "30328419-4cc4-4ea2-a7fb-1728782b23aa",
- "visible": true,
- "startLine": 160,
- "endLine": 162,
- "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
- "parentPath": "aw-watcher-window/aw_watcher_window/main.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "706e836d-c3e2-4048-9eae-95e761ca9ffa"
- }
- ]
- },
- "82482fcc-b698-4f91-a27c-a4110d012d99": {
- "path": "82482fcc-b698-4f91-a27c-a4110d012d99",
- "cellName": "Queue and Dispatch Request - client.py:L531-533",
- "cellId": "82482fcc-b698-4f91-a27c-a4110d012d99",
- "visible": true,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
- },
- "aw-client/aw_client/client.py-simstep-432d1978-befd-4dfd-979b-fe28821d4e00": {
- "path": "aw-client/aw_client/client.py-simstep-432d1978-befd-4dfd-979b-fe28821d4e00",
- "fileName": "client.py",
- "wiki": "The `RequestQueue` thread picks up the heartbeat request. It formats an HTTP POST request to the server's heartbeat API endpoint: `/api/0/buckets/{bucket_id}/heartbeat`.",
- "cellName": "Queue and Dispatch Request - client.py:L531-533",
- "cellId": "82482fcc-b698-4f91-a27c-a4110d012d99",
- "visible": true,
- "startLine": 531,
- "endLine": 533,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "432d1978-befd-4dfd-979b-fe28821d4e00"
- }
- ]
- },
- "2217c8ca-4cbb-4721-acb9-1057b3b16d69": {
- "path": "2217c8ca-4cbb-4721-acb9-1057b3b16d69",
- "cellName": "Server-Side Heartbeat Logic - api.py:L254-337",
- "cellId": "2217c8ca-4cbb-4721-acb9-1057b3b16d69",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-addb33f5-b815-49f0-9b54-a8ee3fb3b87b": {
- "path": "aw-server/aw_server/api.py-simstep-addb33f5-b815-49f0-9b54-a8ee3fb3b87b",
- "fileName": "api.py",
- "wiki": "The `HeartbeatResource`'s `post` method calls the `api.heartbeat` function, which contains the main server-side logic. It fetches the last event from the bucket and determines if the new heartbeat should be merged with it (by extending its duration) or if a new event should be created.",
- "cellName": "Server-Side Heartbeat Logic - api.py:L254-337",
- "cellId": "2217c8ca-4cbb-4721-acb9-1057b3b16d69",
- "visible": true,
- "startLine": 254,
- "endLine": 337,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "addb33f5-b815-49f0-9b54-a8ee3fb3b87b"
- }
- ]
- },
- "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a": {
- "path": "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a",
- "cellName": "Persist Event to Database - datastore.py:L127-188",
- "cellId": "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a",
- "visible": true,
- "parentCellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d"
- },
- "aw-core/aw_datastore/datastore.py-simstep-5573707d-aa48-4a66-a3dc-25c841986d39": {
- "path": "aw-core/aw_datastore/datastore.py-simstep-5573707d-aa48-4a66-a3dc-25c841986d39",
- "fileName": "datastore.py",
- "wiki": "The `datastore`'s `Bucket` object calls the appropriate method on the configured storage strategy (e.g., `PeeweeStorage`). If merging, `replace_last` is used to update the last event. If it's a new event, `insert` is used.",
- "cellName": "Persist Event to Database - datastore.py:L127-188",
- "cellId": "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a",
- "visible": true,
- "startLine": 127,
- "endLine": 188,
- "parentCellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
- "parentPath": "aw-core/aw_datastore/datastore.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "5573707d-aa48-4a66-a3dc-25c841986d39"
- }
- ]
- },
- "6d9c0750-fa20-47af-9135-6cc6444cb6b0": {
- "path": "6d9c0750-fa20-47af-9135-6cc6444cb6b0",
- "cellName": "Start Heartbeat\nLoop",
- "cellId": "6d9c0750-fa20-47af-9135-6cc6444cb6b0",
- "visible": true,
- "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
- },
- "generated-edge-simstep-39835fd9-a301-482d-8b6d-9d16abbbaa29-6d9c0750-fa20-47af-9135-6cc6444cb6b0": {
- "path": "generated-edge-simstep-39835fd9-a301-482d-8b6d-9d16abbbaa29-6d9c0750-fa20-47af-9135-6cc6444cb6b0",
- "fileName": "main.py",
- "cellName": "Start Heartbeat Loop",
- "cellId": "6d9c0750-fa20-47af-9135-6cc6444cb6b0",
- "visible": true,
- "startLine": 98,
- "endLine": 109,
- "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
- "parentPath": "aw-watcher-window/aw_watcher_window/main.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "39835fd9-a301-482d-8b6d-9d16abbbaa29"
- }
- ]
- },
- "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26": {
- "path": "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
- "cellName": "Create Window\nEvent",
- "cellId": "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
- "visible": true,
- "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
- },
- "generated-edge-simstep-81f5cf5a-47ed-4fce-9c97-27559b1c7976-3fe51be8-fc72-4a07-8a11-bef3ffb6dd26": {
- "path": "generated-edge-simstep-81f5cf5a-47ed-4fce-9c97-27559b1c7976-3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
- "fileName": "main.py",
- "cellName": "Create Window Event",
- "cellId": "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
- "visible": true,
- "startLine": 154,
- "endLine": 155,
- "parentCellId": "1bbc4c76-4066-4521-a1d8-0248c1418060",
- "parentPath": "aw-watcher-window/aw_watcher_window/main.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "81f5cf5a-47ed-4fce-9c97-27559b1c7976"
- }
- ]
- },
- "78766ca9-9103-486a-8755-f57a09e7f5a7": {
- "path": "78766ca9-9103-486a-8755-f57a09e7f5a7",
- "cellName": "Local Heartbeat\nPre-Merging",
- "cellId": "78766ca9-9103-486a-8755-f57a09e7f5a7",
- "visible": true
- },
- "generated-edge-simstep-11bc8b75-0103-4652-9fec-e55af41400a0-78766ca9-9103-486a-8755-f57a09e7f5a7": {
- "path": "generated-edge-simstep-11bc8b75-0103-4652-9fec-e55af41400a0-78766ca9-9103-486a-8755-f57a09e7f5a7",
- "fileName": "client.py",
- "cellName": "Local Heartbeat Pre-Merging",
- "cellId": "78766ca9-9103-486a-8755-f57a09e7f5a7",
- "visible": true,
- "startLine": 244,
- "endLine": 259,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "11bc8b75-0103-4652-9fec-e55af41400a0"
- }
- ]
- },
- "5a7fba44-6d4d-4836-bc13-ed69518c9d45": {
- "path": "5a7fba44-6d4d-4836-bc13-ed69518c9d45",
- "cellName": "API Call:\nHeartbeat Received",
- "cellId": "5a7fba44-6d4d-4836-bc13-ed69518c9d45",
- "visible": true
- },
- "generated-edge-simstep-97f58e0a-cbeb-4895-b613-d8e9fd129a42-5a7fba44-6d4d-4836-bc13-ed69518c9d45": {
- "path": "generated-edge-simstep-97f58e0a-cbeb-4895-b613-d8e9fd129a42-5a7fba44-6d4d-4836-bc13-ed69518c9d45",
- "fileName": "rest.py",
- "cellName": "API Call: Heartbeat Received",
- "cellId": "5a7fba44-6d4d-4836-bc13-ed69518c9d45",
- "visible": true,
- "startLine": 272,
- "endLine": 276,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "97f58e0a-cbeb-4895-b613-d8e9fd129a42"
- }
- ]
- },
- "6a5be6b6-e11d-460d-8193-427f3a9e42ac": {
- "path": "6a5be6b6-e11d-460d-8193-427f3a9e42ac",
- "cellName": "Data to\nDatastore",
- "cellId": "6a5be6b6-e11d-460d-8193-427f3a9e42ac",
- "visible": true
- },
- "generated-edge-simstep-cd6c54a5-c0bd-4b99-9446-ea921ee876a6-6a5be6b6-e11d-460d-8193-427f3a9e42ac": {
- "path": "generated-edge-simstep-cd6c54a5-c0bd-4b99-9446-ea921ee876a6-6a5be6b6-e11d-460d-8193-427f3a9e42ac",
- "fileName": "api.py",
- "cellName": "Data to Datastore",
- "cellId": "6a5be6b6-e11d-460d-8193-427f3a9e42ac",
- "visible": true,
- "startLine": 314,
- "endLine": 335,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How automated application and window time tracking works",
- "simStepId": "cd6c54a5-c0bd-4b99-9446-ea921ee876a6"
- }
- ]
- },
- "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0": {
- "path": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
- "cellName": "aw-server-rust",
- "cellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0",
- "visible": true
- },
- "d4939ae3-d0c2-44b2-90c5-9a7791e083b5": {
- "path": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5",
- "cellName": "README.md",
- "cellId": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5",
- "visible": true
- },
- "e4fd3d3d-801a-4bc3-8891-9fdd6222369c": {
- "path": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c",
- "cellName": "aw-server",
- "cellId": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "d70684b2-06ba-4f18-9c40-80de0778c035": {
- "path": "d70684b2-06ba-4f18-9c40-80de0778c035",
- "cellName": "aw-query",
- "cellId": "d70684b2-06ba-4f18-9c40-80de0778c035",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "a542ca3c-9d99-490f-89de-186bb284b0fe": {
- "path": "a542ca3c-9d99-490f-89de-186bb284b0fe",
- "cellName": "aw-datastore",
- "cellId": "a542ca3c-9d99-490f-89de-186bb284b0fe",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "6d2ab9ea-9e77-402f-a726-95d44e0f23c8": {
- "path": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8",
- "cellName": "aw-transform",
- "cellId": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "941d7da8-a28d-4d5e-806f-3b546909f74e": {
- "path": "941d7da8-a28d-4d5e-806f-3b546909f74e",
- "cellName": "queries.py",
- "cellId": "941d7da8-a28d-4d5e-806f-3b546909f74e",
- "visible": true,
- "parentCellId": "48103d9a-f009-4555-bb82-435f417b0644"
- },
- "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e": {
- "path": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e",
- "cellName": "src",
- "cellId": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e",
- "visible": true,
- "parentCellId": "e4fd3d3d-801a-4bc3-8891-9fdd6222369c"
- },
- "e6b26caf-0857-4e8d-8f29-124af90c1966": {
- "path": "e6b26caf-0857-4e8d-8f29-124af90c1966",
- "cellName": "src",
- "cellId": "e6b26caf-0857-4e8d-8f29-124af90c1966",
- "visible": true,
- "parentCellId": "d70684b2-06ba-4f18-9c40-80de0778c035"
- },
- "234cf403-9edd-4f7e-96eb-81e90587bbdc": {
- "path": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
- "cellName": "src",
- "cellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc",
- "visible": true,
- "parentCellId": "a542ca3c-9d99-490f-89de-186bb284b0fe"
- },
- "7e71e7fe-f8aa-4693-a92e-4c3b664c1528": {
- "path": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
- "cellName": "src",
- "cellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528",
- "visible": true,
- "parentCellId": "6d2ab9ea-9e77-402f-a726-95d44e0f23c8"
- },
- "11799249-188d-43b3-b410-54dcff47aeba": {
- "path": "11799249-188d-43b3-b410-54dcff47aeba",
- "cellName": "endpoints",
- "cellId": "11799249-188d-43b3-b410-54dcff47aeba",
- "visible": true,
- "parentCellId": "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e"
- },
- "d020e6ae-765b-4374-947a-57f7ad4a9237": {
- "path": "d020e6ae-765b-4374-947a-57f7ad4a9237",
- "cellName": "lib.rs",
- "cellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
- },
- "9b5e1d70-af70-4de3-9b35-73b774a50c3c": {
- "path": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "cellName": "interpret.rs",
- "cellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
- },
- "bf649fa4-66cc-4975-8549-aa2f1db4a11e": {
- "path": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "cellName": "functions.rs",
- "cellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
- },
- "c3bb8632-e3d6-4b2f-86ea-2472e155f19e": {
- "path": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
- "cellName": "worker.rs",
- "cellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
- "visible": true,
- "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc"
- },
- "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f": {
- "path": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "cellName": "datastore.rs",
- "cellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "visible": true,
- "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc"
- },
- "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca": {
- "path": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca",
- "cellName": "filter_period.rs",
- "cellId": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca",
- "visible": true,
- "parentCellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528"
- },
- "873444c7-80ea-4a0b-8620-92fc96cce006": {
- "path": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "cellName": "query.rs",
- "cellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "visible": true,
- "parentCellId": "11799249-188d-43b3-b410-54dcff47aeba"
- },
- "12f9554d-dd4e-4f66-bd20-8845b718ef19": {
- "path": "12f9554d-dd4e-4f66-bd20-8845b718ef19",
- "cellName": "Client-side: Construct Activity Query - queries.py:L243-301",
- "cellId": "12f9554d-dd4e-4f66-bd20-8845b718ef19",
- "visible": true,
- "parentCellId": "941d7da8-a28d-4d5e-806f-3b546909f74e"
- },
- "aw-client/aw_client/queries.py-simstep-81f31a9b-3434-4458-a7d3-bdcf610af75e": {
- "path": "aw-client/aw_client/queries.py-simstep-81f31a9b-3434-4458-a7d3-bdcf610af75e",
- "fileName": "queries.py",
- "wiki": "The user accesses the ActivityWatch web UI. The frontend constructs a query using the ActivityWatch Query Language to fetch and process data for the main dashboard visualization. This query is designed to get window and AFK (Away From Keyboard) events, filter out AFK periods, categorize activities based on rules, and aggregate the results.",
- "cellName": "Client-side: Construct Activity Query - queries.py:L243-301",
- "cellId": "12f9554d-dd4e-4f66-bd20-8845b718ef19",
- "visible": true,
- "startLine": 243,
- "endLine": 301,
- "parentCellId": "941d7da8-a28d-4d5e-806f-3b546909f74e",
- "parentPath": "aw-client/aw_client/queries.py",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "81f31a9b-3434-4458-a7d3-bdcf610af75e"
- }
- ]
- },
- "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1": {
- "path": "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1",
- "cellName": "Backend: Receive Query Request - query.rs:L9-23",
- "cellId": "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1",
- "visible": true,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
- },
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-e91513ab-13ec-4eea-9942-9620dbe3b92b": {
- "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-e91513ab-13ec-4eea-9942-9620dbe3b92b",
- "fileName": "query.rs",
- "wiki": "The `aw-server-rust` (or the Python equivalent `aw-server`) receives the POST request. The `/api/0/query` endpoint deserializes the JSON body into a `Query` struct containing the query statements and time intervals.",
- "cellName": "Backend: Receive Query Request - query.rs:L9-23",
- "cellId": "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1",
- "visible": true,
- "startLine": 9,
- "endLine": 23,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "e91513ab-13ec-4eea-9942-9620dbe3b92b"
- }
- ]
- },
- "a9279dbc-8fda-434c-bc5a-4eefaca0df56": {
- "path": "a9279dbc-8fda-434c-bc5a-4eefaca0df56",
- "cellName": "Query Engine: Parse and Interpret - lib.rs:L53-64",
- "cellId": "a9279dbc-8fda-434c-bc5a-4eefaca0df56",
- "visible": true,
- "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237"
- },
- "aw-server-rust/aw-query/src/lib.rs-simstep-3291e01a-482d-401b-98b5-759573be65ca": {
- "path": "aw-server-rust/aw-query/src/lib.rs-simstep-3291e01a-482d-401b-98b5-759573be65ca",
- "fileName": "lib.rs",
- "wiki": "The `aw_query::query` function orchestrates the execution. It first uses a lexer to tokenize the query string, then a parser to build an Abstract Syntax Tree (AST). Finally, it invokes the interpreter to execute the AST.",
- "cellName": "Query Engine: Parse and Interpret - lib.rs:L53-64",
- "cellId": "a9279dbc-8fda-434c-bc5a-4eefaca0df56",
- "visible": true,
- "startLine": 53,
- "endLine": 64,
- "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
- "parentPath": "aw-server-rust/aw-query/src/lib.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "3291e01a-482d-401b-98b5-759573be65ca"
- }
- ]
- },
- "be2c99a2-8b27-487f-9c8f-e1d1836613cc": {
- "path": "be2c99a2-8b27-487f-9c8f-e1d1836613cc",
- "cellName": "Execute `query_bucket` - functions.rs:L139-168",
- "cellId": "be2c99a2-8b27-487f-9c8f-e1d1836613cc",
- "visible": true,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e"
- },
- "aw-server-rust/aw-query/src/functions.rs-simstep-475886bc-26d3-4528-84ae-2f9c8e1dfcf9": {
- "path": "aw-server-rust/aw-query/src/functions.rs-simstep-475886bc-26d3-4528-84ae-2f9c8e1dfcf9",
- "fileName": "functions.rs",
- "wiki": "The `query_bucket` function is executed. It reads the time interval from its environment and makes a call to the datastore's `get_events` method to fetch raw event data from the specified bucket.",
- "cellName": "Execute `query_bucket` - functions.rs:L139-168",
- "cellId": "be2c99a2-8b27-487f-9c8f-e1d1836613cc",
- "visible": true,
- "startLine": 139,
- "endLine": 168,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "parentPath": "aw-server-rust/aw-query/src/functions.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "475886bc-26d3-4528-84ae-2f9c8e1dfcf9"
- }
- ]
- },
- "48d1c5e2-32b3-4eaf-9005-dd0a65a77448": {
- "path": "48d1c5e2-32b3-4eaf-9005-dd0a65a77448",
- "cellName": "Datastore: Retrieve Events from SQLite - datastore.rs:L700-797",
- "cellId": "48d1c5e2-32b3-4eaf-9005-dd0a65a77448",
- "visible": true,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
- },
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-ff017206-8323-4caa-9eca-4fc760c2470f": {
- "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-ff017206-8323-4caa-9eca-4fc760c2470f",
- "fileName": "datastore.rs",
- "wiki": "The `aw-datastore` component executes a `SELECT` query against its SQLite database. It retrieves all events from the `aw-watcher-window_my-desktop` bucket that fall within the specified time range.",
- "cellName": "Datastore: Retrieve Events from SQLite - datastore.rs:L700-797",
- "cellId": "48d1c5e2-32b3-4eaf-9005-dd0a65a77448",
- "visible": true,
- "startLine": 700,
- "endLine": 797,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "ff017206-8323-4caa-9eca-4fc760c2470f"
- }
- ]
- },
- "48a7e119-b25c-4b9f-9a95-bd649493ff48": {
- "path": "48a7e119-b25c-4b9f-9a95-bd649493ff48",
- "cellName": "Transform: Filter AFK Periods - filter_period.rs:L20-69",
- "cellId": "48a7e119-b25c-4b9f-9a95-bd649493ff48",
- "visible": true,
- "parentCellId": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca"
- },
- "aw-server-rust/aw-transform/src/filter_period.rs-simstep-50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10": {
- "path": "aw-server-rust/aw-transform/src/filter_period.rs-simstep-50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10",
- "fileName": "filter_period.rs",
- "wiki": "The interpreter continues executing the query, calling transformation functions like `filter_period_intersect`. This function takes the window activity events and intersects them with the 'not-afk' events, effectively removing any time the user was away from the keyboard.",
- "cellName": "Transform: Filter AFK Periods - filter_period.rs:L20-69",
- "cellId": "48a7e119-b25c-4b9f-9a95-bd649493ff48",
- "visible": true,
- "startLine": 20,
- "endLine": 69,
- "parentCellId": "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca",
- "parentPath": "aw-server-rust/aw-transform/src/filter_period.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10"
- }
- ]
- },
- "63ebaed0-610a-46cd-8a5b-392c2874aecb": {
- "path": "63ebaed0-610a-46cd-8a5b-392c2874aecb",
- "cellName": "Final Aggregation and Return - interpret.rs:L30-33",
- "cellId": "63ebaed0-610a-46cd-8a5b-392c2874aecb",
- "visible": true,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c"
- },
- "aw-server-rust/aw-query/src/interpret.rs-simstep-18492fe4-5b57-4749-a2e8-d18f3c546e89": {
- "path": "aw-server-rust/aw-query/src/interpret.rs-simstep-18492fe4-5b57-4749-a2e8-d18f3c546e89",
- "fileName": "interpret.rs",
- "wiki": "The interpreter completes the query by performing final aggregations like `merge_events_by_keys` and `sort_by_duration`. It assembles the results into a final dictionary structure as defined by the `RETURN` statement in the query script.",
- "cellName": "Final Aggregation and Return - interpret.rs:L30-33",
- "cellId": "63ebaed0-610a-46cd-8a5b-392c2874aecb",
- "visible": true,
- "startLine": 30,
- "endLine": 33,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "18492fe4-5b57-4749-a2e8-d18f3c546e89"
- }
- ]
- },
- "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd": {
- "path": "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd",
- "cellName": "Frontend: Render Dashboard - README.md:L243-250",
- "cellId": "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd",
- "visible": true,
- "parentCellId": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5"
- },
- "README.md-simstep-9396ef3a-ed06-4635-bb1d-3b136660bcc4": {
- "path": "README.md-simstep-9396ef3a-ed06-4635-bb1d-3b136660bcc4",
- "fileName": "README.md",
- "wiki": "The `aw-webui` frontend receives the JSON data. Its JavaScript code then processes this data to render the various visualizations on the activity dashboard, such as the top applications and categories pie charts, and the activity timeline.",
- "cellName": "Frontend: Render Dashboard - README.md:L243-250",
- "cellId": "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd",
- "visible": true,
- "startLine": 243,
- "endLine": 250,
- "parentCellId": "d4939ae3-d0c2-44b2-90c5-9a7791e083b5",
- "parentPath": "README.md",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "9396ef3a-ed06-4635-bb1d-3b136660bcc4"
- }
- ]
- },
- "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f": {
- "path": "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
- "cellName": "API Call:\nPOST /api/0/query/",
- "cellId": "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
- "visible": true
- },
- "generated-edge-simstep-c1a26d9b-d661-4a99-8275-39a414824ed6-6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f": {
- "path": "generated-edge-simstep-c1a26d9b-d661-4a99-8275-39a414824ed6-6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
- "fileName": "client.py",
- "cellName": "API Call: POST /api/0/query/",
- "cellId": "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
- "visible": true,
- "startLine": 305,
- "endLine": 339,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "c1a26d9b-d661-4a99-8275-39a414824ed6"
- }
- ]
- },
- "c8403507-4895-4695-84b5-9305afdc3c9f": {
- "path": "c8403507-4895-4695-84b5-9305afdc3c9f",
- "cellName": "API Endpoint\n-> Query\nEngine",
- "cellId": "c8403507-4895-4695-84b5-9305afdc3c9f",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-a7b6aefb-1401-4756-bfa1-1eb9a76cde07-c8403507-4895-4695-84b5-9305afdc3c9f": {
- "path": "generated-edge-simstep-a7b6aefb-1401-4756-bfa1-1eb9a76cde07-c8403507-4895-4695-84b5-9305afdc3c9f",
- "fileName": "query.rs",
- "cellName": "API Endpoint -> Query Engine",
- "cellId": "c8403507-4895-4695-84b5-9305afdc3c9f",
- "visible": true,
- "startLine": 16,
- "endLine": 16,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "a7b6aefb-1401-4756-bfa1-1eb9a76cde07"
- }
- ]
- },
- "8f8d2c55-63c0-48ec-b931-f848e245688f": {
- "path": "8f8d2c55-63c0-48ec-b931-f848e245688f",
- "cellName": "Interpreter ->\n`query_bucket`",
- "cellId": "8f8d2c55-63c0-48ec-b931-f848e245688f",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
- },
- "generated-edge-simstep-00784ae1-bb99-494c-bf46-fe5947de5066-8f8d2c55-63c0-48ec-b931-f848e245688f": {
- "path": "generated-edge-simstep-00784ae1-bb99-494c-bf46-fe5947de5066-8f8d2c55-63c0-48ec-b931-f848e245688f",
- "fileName": "interpret.rs",
- "cellName": "Interpreter -> `query_bucket`",
- "cellId": "8f8d2c55-63c0-48ec-b931-f848e245688f",
- "visible": true,
- "startLine": 213,
- "endLine": 226,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "00784ae1-bb99-494c-bf46-fe5947de5066"
- }
- ]
- },
- "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013": {
- "path": "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
- "cellName": "`query_bucket` ->\nDatastore",
- "cellId": "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-e1bf9f3c-e763-4e75-8c62-1a8d739d53cc-5f0c5a39-ef1b-43eb-8332-3fc7e3b98013": {
- "path": "generated-edge-simstep-e1bf9f3c-e763-4e75-8c62-1a8d739d53cc-5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
- "fileName": "worker.rs",
- "cellName": "`query_bucket` -> Datastore",
- "cellId": "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
- "visible": true,
- "startLine": 414,
- "endLine": 430,
- "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
- "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "e1bf9f3c-e763-4e75-8c62-1a8d739d53cc"
- }
- ]
- },
- "7a14a4d3-a453-4e33-9b10-fb192e40e34e": {
- "path": "7a14a4d3-a453-4e33-9b10-fb192e40e34e",
- "cellName": "Datastore ->\nQuery Engine",
- "cellId": "7a14a4d3-a453-4e33-9b10-fb192e40e34e",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-f7dfb334-099f-4750-a893-cd96b1c46278-7a14a4d3-a453-4e33-9b10-fb192e40e34e": {
- "path": "generated-edge-simstep-f7dfb334-099f-4750-a893-cd96b1c46278-7a14a4d3-a453-4e33-9b10-fb192e40e34e",
- "fileName": "functions.rs",
- "cellName": "Datastore -> Query Engine",
- "cellId": "7a14a4d3-a453-4e33-9b10-fb192e40e34e",
- "visible": true,
- "startLine": 163,
- "endLine": 167,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "parentPath": "aw-server-rust/aw-query/src/functions.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "f7dfb334-099f-4750-a893-cd96b1c46278"
- }
- ]
- },
- "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa": {
- "path": "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
- "cellName": "Return Transformed\nData",
- "cellId": "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-78aaa465-8377-43f1-9ba6-36ddcf9300cf-8dd706f0-fb9b-496a-8ba8-26f289f0e2fa": {
- "path": "generated-edge-simstep-78aaa465-8377-43f1-9ba6-36ddcf9300cf-8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
- "fileName": "interpret.rs",
- "cellName": "Return Transformed Data",
- "cellId": "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
- "visible": true,
- "startLine": 36,
- "endLine": 228,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "78aaa465-8377-43f1-9ba6-36ddcf9300cf"
- }
- ]
- },
- "889f0869-2c33-499b-a558-ede80ee18a54": {
- "path": "889f0869-2c33-499b-a558-ede80ee18a54",
- "cellName": "API Response:\nSend Processed\nData",
- "cellId": "889f0869-2c33-499b-a558-ede80ee18a54",
- "visible": true
- },
- "generated-edge-simstep-785d1355-bf16-42a7-846e-a2bf3ecbb35b-889f0869-2c33-499b-a558-ede80ee18a54": {
- "path": "generated-edge-simstep-785d1355-bf16-42a7-846e-a2bf3ecbb35b-889f0869-2c33-499b-a558-ede80ee18a54",
- "fileName": "query.rs",
- "cellName": "API Response: Send Processed Data",
- "cellId": "889f0869-2c33-499b-a558-ede80ee18a54",
- "visible": true,
- "startLine": 28,
- "endLine": 28,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How activity data visualization works",
- "simStepId": "785d1355-bf16-42a7-846e-a2bf3ecbb35b"
- }
- ]
- },
- "0b23a1ca-091a-4f70-b49e-95910c8179bf": {
- "path": "0b23a1ca-091a-4f70-b49e-95910c8179bf",
- "cellName": "aw-notify",
- "cellId": "0b23a1ca-091a-4f70-b49e-95910c8179bf",
- "visible": true
- },
- "4d835cac-01b7-4b3d-a7f5-189f89fda1c7": {
- "path": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7",
- "cellName": "aw_notify",
- "cellId": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7",
- "visible": true,
- "parentCellId": "0b23a1ca-091a-4f70-b49e-95910c8179bf"
- },
- "954ebccb-39ec-4c50-aca4-0ac8c09e6358": {
- "path": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "cellName": "main.py",
- "cellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "visible": true,
- "parentCellId": "4d835cac-01b7-4b3d-a7f5-189f89fda1c7"
- },
- "60cb37da-078e-4380-88f0-e6746007277d": {
- "path": "60cb37da-078e-4380-88f0-e6746007277d",
- "cellName": "datatype.rs",
- "cellId": "60cb37da-078e-4380-88f0-e6746007277d",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
- },
- "22d8d360-9b15-49db-bc15-de087f960e23": {
- "path": "22d8d360-9b15-49db-bc15-de087f960e23",
- "cellName": "classify.rs",
- "cellId": "22d8d360-9b15-49db-bc15-de087f960e23",
- "visible": true,
- "parentCellId": "7e71e7fe-f8aa-4693-a92e-4c3b664c1528"
- },
- "49029598-25ad-4498-b744-e2180f404fe5": {
- "path": "49029598-25ad-4498-b744-e2180f404fe5",
- "cellName": "Query Construction - queries.py:L84-151",
- "cellId": "49029598-25ad-4498-b744-e2180f404fe5",
- "visible": true,
- "parentCellId": "941d7da8-a28d-4d5e-806f-3b546909f74e"
- },
- "aw-client/aw_client/queries.py-simstep-1b40cfa3-9cf5-4dc3-830f-74cb1d476d50": {
- "path": "aw-client/aw_client/queries.py-simstep-1b40cfa3-9cf5-4dc3-830f-74cb1d476d50",
- "fileName": "queries.py",
- "wiki": "A client application or script constructs a query to fetch and categorize events. The `canonicalEvents` function is often used, which includes a `categorize` step. The categorization rules (classes) can be provided directly or fetched from the server's settings.",
- "cellName": "Query Construction - queries.py:L84-151",
- "cellId": "49029598-25ad-4498-b744-e2180f404fe5",
- "visible": true,
- "startLine": 84,
- "endLine": 151,
- "parentCellId": "941d7da8-a28d-4d5e-806f-3b546909f74e",
- "parentPath": "aw-client/aw_client/queries.py",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "1b40cfa3-9cf5-4dc3-830f-74cb1d476d50"
- }
- ]
- },
- "ff986e21-7050-4c3d-ae40-3a678f46221d": {
- "path": "ff986e21-7050-4c3d-ae40-3a678f46221d",
- "cellName": "Query Engine: Function Invocation - functions.rs:L278-295",
- "cellId": "ff986e21-7050-4c3d-ae40-3a678f46221d",
- "visible": true,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e"
- },
- "aw-server-rust/aw-query/src/functions.rs-simstep-af6c51b2-ee18-406c-acc6-6e5d9588d012": {
- "path": "aw-server-rust/aw-query/src/functions.rs-simstep-af6c51b2-ee18-406c-acc6-6e5d9588d012",
- "fileName": "functions.rs",
- "wiki": "The `aw-server-rust` query engine parses the query, recognizes the `categorize` function call, and invokes its registered implementation, passing the fetched events and rules as arguments.",
- "cellName": "Query Engine: Function Invocation - functions.rs:L278-295",
- "cellId": "ff986e21-7050-4c3d-ae40-3a678f46221d",
- "visible": true,
- "startLine": 278,
- "endLine": 295,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "parentPath": "aw-server-rust/aw-query/src/functions.rs",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "af6c51b2-ee18-406c-acc6-6e5d9588d012"
- }
- ]
- },
- "e99fcabc-934a-46cd-8823-d3e04ceea63c": {
- "path": "e99fcabc-934a-46cd-8823-d3e04ceea63c",
- "cellName": "Categorization Core Logic - classify.rs:L70-76",
- "cellId": "e99fcabc-934a-46cd-8823-d3e04ceea63c",
- "visible": true,
- "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23"
- },
- "aw-server-rust/aw-transform/src/classify.rs-simstep-55815d72-39f6-4201-ad99-6ebd57d0eece": {
- "path": "aw-server-rust/aw-transform/src/classify.rs-simstep-55815d72-39f6-4201-ad99-6ebd57d0eece",
- "fileName": "classify.rs",
- "wiki": "The main `categorize` function iterates through each event and applies the list of rules to it by calling `categorize_one`.",
- "cellName": "Categorization Core Logic - classify.rs:L70-76",
- "cellId": "e99fcabc-934a-46cd-8823-d3e04ceea63c",
- "visible": true,
- "startLine": 70,
- "endLine": 76,
- "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23",
- "parentPath": "aw-server-rust/aw-transform/src/classify.rs",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "55815d72-39f6-4201-ad99-6ebd57d0eece"
- }
- ]
- },
- "294c7beb-b479-47e2-bd3c-6d616497ecd2": {
- "path": "294c7beb-b479-47e2-bd3c-6d616497ecd2",
- "cellName": "Select Highest-Ranking Category - classify.rs:L116-122",
- "cellId": "294c7beb-b479-47e2-bd3c-6d616497ecd2",
- "visible": true,
- "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23"
- },
- "aw-server-rust/aw-transform/src/classify.rs-simstep-e863b0b1-c3ce-4b13-ad7d-a7438f650035": {
- "path": "aw-server-rust/aw-transform/src/classify.rs-simstep-e863b0b1-c3ce-4b13-ad7d-a7438f650035",
- "fileName": "classify.rs",
- "wiki": "If an event matches multiple categories, this function selects the most specific one. Specificity is determined by the depth of the category hierarchy (e.g., `['Work', 'Programming', 'Rust']` is deeper than `['Work', 'Programming']`). If no rules match, a default category of `['Uncategorized']` is assigned.",
- "cellName": "Select Highest-Ranking Category - classify.rs:L116-122",
- "cellId": "294c7beb-b479-47e2-bd3c-6d616497ecd2",
- "visible": true,
- "startLine": 116,
- "endLine": 122,
- "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23",
- "parentPath": "aw-server-rust/aw-transform/src/classify.rs",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "e863b0b1-c3ce-4b13-ad7d-a7438f650035"
- }
- ]
- },
- "9847b0a7-39f2-44f8-ae14-73eab42d8894": {
- "path": "9847b0a7-39f2-44f8-ae14-73eab42d8894",
- "cellName": "Client Consumes Categorized Data - main.py:L123-130",
- "cellId": "9847b0a7-39f2-44f8-ae14-73eab42d8894",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "aw-notify/aw_notify/main.py-simstep-2108914e-2569-47bf-aa87-af337de03f8c": {
- "path": "aw-notify/aw_notify/main.py-simstep-2108914e-2569-47bf-aa87-af337de03f8c",
- "fileName": "main.py",
- "wiki": "The client application receives the categorized events. It can then use the `$category` field to perform aggregations and generate reports, such as calculating the total time spent in each top-level category for the day.",
- "cellName": "Client Consumes Categorized Data - main.py:L123-130",
- "cellId": "9847b0a7-39f2-44f8-ae14-73eab42d8894",
- "visible": true,
- "startLine": 123,
- "endLine": 130,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "2108914e-2569-47bf-aa87-af337de03f8c"
- }
- ]
- },
- "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661": {
- "path": "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
- "cellName": "API Call:\nExecute Query",
- "cellId": "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
- "visible": true
- },
- "generated-edge-simstep-9eeb592f-5c44-4ce1-a7a0-261bc6d6b679-e0c2455d-d2a0-4b88-bd3a-6f7b2472a661": {
- "path": "generated-edge-simstep-9eeb592f-5c44-4ce1-a7a0-261bc6d6b679-e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
- "fileName": "client.py",
- "cellName": "API Call: Execute Query",
- "cellId": "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
- "visible": true,
- "startLine": 119,
- "endLine": 131,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "9eeb592f-5c44-4ce1-a7a0-261bc6d6b679"
- }
- ]
- },
- "79c14e32-8192-488e-ab72-b9c4c6edb346": {
- "path": "79c14e32-8192-488e-ab72-b9c4c6edb346",
- "cellName": "Data Transformation:\nConvert Rules",
- "cellId": "79c14e32-8192-488e-ab72-b9c4c6edb346",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-e598a658-8e0e-4a76-9310-af0d60ec5828-79c14e32-8192-488e-ab72-b9c4c6edb346": {
- "path": "generated-edge-simstep-e598a658-8e0e-4a76-9310-af0d60ec5828-79c14e32-8192-488e-ab72-b9c4c6edb346",
- "fileName": "datatype.rs",
- "cellName": "Data Transformation: Convert Rules",
- "cellId": "79c14e32-8192-488e-ab72-b9c4c6edb346",
- "visible": true,
- "startLine": 272,
- "endLine": 346,
- "parentCellId": "60cb37da-078e-4380-88f0-e6746007277d",
- "parentPath": "aw-server-rust/aw-query/src/datatype.rs",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "e598a658-8e0e-4a76-9310-af0d60ec5828"
- }
- ]
- },
- "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8": {
- "path": "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
- "cellName": "Event-Rule Matching",
- "cellId": "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
- "visible": true,
- "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23"
- },
- "generated-edge-simstep-9f7f50e4-03c6-4d7c-95c8-3317d37115eb-341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8": {
- "path": "generated-edge-simstep-9f7f50e4-03c6-4d7c-95c8-3317d37115eb-341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
- "fileName": "classify.rs",
- "cellName": "Event-Rule Matching",
- "cellId": "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
- "visible": true,
- "startLine": 49,
- "endLine": 57,
- "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23",
- "parentPath": "aw-server-rust/aw-transform/src/classify.rs",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "9f7f50e4-03c6-4d7c-95c8-3317d37115eb"
- }
- ]
- },
- "b4391f38-d9ee-4377-8568-efca87206124": {
- "path": "b4391f38-d9ee-4377-8568-efca87206124",
- "cellName": "Return Categorized\nEvents",
- "cellId": "b4391f38-d9ee-4377-8568-efca87206124",
- "visible": true
- },
- "generated-edge-simstep-ebd328dc-4cdf-452d-b4aa-10b65e9c354d-b4391f38-d9ee-4377-8568-efca87206124": {
- "path": "generated-edge-simstep-ebd328dc-4cdf-452d-b4aa-10b65e9c354d-b4391f38-d9ee-4377-8568-efca87206124",
- "fileName": "classify.rs",
- "cellName": "Return Categorized Events",
- "cellId": "b4391f38-d9ee-4377-8568-efca87206124",
- "visible": true,
- "startLine": 85,
- "endLine": 88,
- "parentCellId": "22d8d360-9b15-49db-bc15-de087f960e23",
- "parentPath": "aw-server-rust/aw-transform/src/classify.rs",
- "simSteps": [
- {
- "simulationKey": "How activity categorization works",
- "simStepId": "ebd328dc-4cdf-452d-b4aa-10b65e9c354d"
- }
- ]
- },
- "701d49bd-2670-4a9f-8ffd-52f62726ddc0": {
- "path": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
- "cellName": "aw_query",
- "cellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0",
- "visible": true,
- "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb"
- },
- "22692aea-cd7a-4c08-8c76-c16bb5499546": {
- "path": "22692aea-cd7a-4c08-8c76-c16bb5499546",
- "cellName": "aw-client-rust",
- "cellId": "22692aea-cd7a-4c08-8c76-c16bb5499546",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "0fb8ce44-e9ea-4e8a-a049-33211b003d20": {
- "path": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
- "cellName": "query2.py",
- "cellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
- "visible": true,
- "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0"
- },
- "e1b937af-2584-42ee-8281-e1bffda373ae": {
- "path": "e1b937af-2584-42ee-8281-e1bffda373ae",
- "cellName": "functions.py",
- "cellId": "e1b937af-2584-42ee-8281-e1bffda373ae",
- "visible": true,
- "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0"
- },
- "08296022-1e80-4653-821d-b48d9cf30c68": {
- "path": "08296022-1e80-4653-821d-b48d9cf30c68",
- "cellName": "src",
- "cellId": "08296022-1e80-4653-821d-b48d9cf30c68",
- "visible": true,
- "parentCellId": "22692aea-cd7a-4c08-8c76-c16bb5499546"
- },
- "8dafeb60-1305-46f7-baac-4153d6d18539": {
- "path": "8dafeb60-1305-46f7-baac-4153d6d18539",
- "cellName": "blocking.rs",
- "cellId": "8dafeb60-1305-46f7-baac-4153d6d18539",
- "visible": true,
- "parentCellId": "08296022-1e80-4653-821d-b48d9cf30c68"
- },
- "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf": {
- "path": "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf",
- "cellName": "lib.rs",
- "cellId": "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf",
- "visible": true,
- "parentCellId": "08296022-1e80-4653-821d-b48d9cf30c68"
- },
- "5540d168-0892-4d44-a835-530768fbad09": {
- "path": "5540d168-0892-4d44-a835-530768fbad09",
- "cellName": "Python Flow: Client Initiates API Query - client.py:L305-338",
- "cellId": "5540d168-0892-4d44-a835-530768fbad09",
- "visible": true,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
- },
- "aw-client/aw_client/client.py-simstep-06f7c9e7-1c78-4114-867b-3dbb20dcc427": {
- "path": "aw-client/aw_client/client.py-simstep-06f7c9e7-1c78-4114-867b-3dbb20dcc427",
- "fileName": "client.py",
- "wiki": "A client application, using the `aw-client` library, constructs a query to fetch data from the ActivityWatch server. It specifies the query string and the time periods to analyze.",
- "cellName": "Python Flow: Client Initiates API Query - client.py:L305-338",
- "cellId": "5540d168-0892-4d44-a835-530768fbad09",
- "visible": true,
- "startLine": 305,
- "endLine": 338,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "06f7c9e7-1c78-4114-867b-3dbb20dcc427"
- }
- ]
- },
- "abf45adb-988a-4613-ab4a-acb8cef0c90a": {
- "path": "abf45adb-988a-4613-ab4a-acb8cef0c90a",
- "cellName": "Python Flow: API Endpoint Receives Request - rest.py:L310-326",
- "cellId": "abf45adb-988a-4613-ab4a-acb8cef0c90a",
- "visible": true,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
- },
- "aw-server/aw_server/rest.py-simstep-671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7": {
- "path": "aw-server/aw_server/rest.py-simstep-671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7",
- "fileName": "rest.py",
- "wiki": "The Flask-based `aw-server` receives the incoming POST request. The `/api/0/query/` route is handled by the `QueryResource`, which extracts the query payload from the request.",
- "cellName": "Python Flow: API Endpoint Receives Request - rest.py:L310-326",
- "cellId": "abf45adb-988a-4613-ab4a-acb8cef0c90a",
- "visible": true,
- "startLine": 310,
- "endLine": 326,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7"
- }
- ]
- },
- "96c3be58-d96a-4b11-b4f3-e778387f76b8": {
- "path": "96c3be58-d96a-4b11-b4f3-e778387f76b8",
- "cellName": "Python Flow: ServerAPI Orchestrates Query - api.py:L339-349",
- "cellId": "96c3be58-d96a-4b11-b4f3-e778387f76b8",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31": {
- "path": "aw-server/aw_server/api.py-simstep-a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31",
- "fileName": "api.py",
- "wiki": "The `ServerAPI.query2` method iterates through each specified time period and invokes the core query engine (`query2.query`) from `aw-core` for each one.",
- "cellName": "Python Flow: ServerAPI Orchestrates Query - api.py:L339-349",
- "cellId": "96c3be58-d96a-4b11-b4f3-e778387f76b8",
- "visible": true,
- "startLine": 339,
- "endLine": 349,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31"
- }
- ]
- },
- "c0a28353-be8d-4bc8-a1be-2879961fc4df": {
- "path": "c0a28353-be8d-4bc8-a1be-2879961fc4df",
- "cellName": "Python Flow: Parse and Interpret Query - query2.py:L404-418",
- "cellId": "c0a28353-be8d-4bc8-a1be-2879961fc4df",
- "visible": true,
- "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20"
- },
- "aw-core/aw_query/query2.py-simstep-5f7b6985-edf0-42eb-8822-847d0d7b8e9b": {
- "path": "aw-core/aw_query/query2.py-simstep-5f7b6985-edf0-42eb-8822-847d0d7b8e9b",
- "fileName": "query2.py",
- "wiki": "The `query` function in `aw-core/aw_query/query2.py` acts as the interpreter. It splits the query into individual statements, parses each one into tokens (like variables and function calls), and then interprets them chronologically. Function calls are resolved by looking them up in the `functions` dictionary, which is populated by functions in `aw-core/aw_query/functions.py`.",
- "cellName": "Python Flow: Parse and Interpret Query - query2.py:L404-418",
- "cellId": "c0a28353-be8d-4bc8-a1be-2879961fc4df",
- "visible": true,
- "startLine": 404,
- "endLine": 418,
- "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
- "parentPath": "aw-core/aw_query/query2.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "5f7b6985-edf0-42eb-8822-847d0d7b8e9b"
- }
- ]
- },
- "fb0bcd2a-5999-47fc-bb41-11233e3544fa": {
- "path": "fb0bcd2a-5999-47fc-bb41-11233e3544fa",
- "cellName": "Python Flow: Fetch Events from Datastore - functions.py:L151-164",
- "cellId": "fb0bcd2a-5999-47fc-bb41-11233e3544fa",
- "visible": true,
- "parentCellId": "e1b937af-2584-42ee-8281-e1bffda373ae"
- },
- "aw-core/aw_query/functions.py-simstep-6ea3ab36-027f-40b9-a0ba-9ede77ae1117": {
- "path": "aw-core/aw_query/functions.py-simstep-6ea3ab36-027f-40b9-a0ba-9ede77ae1117",
- "fileName": "functions.py",
- "wiki": "The `q2_query_bucket` function interacts with the datastore to fetch events for the specified bucket and time range.",
- "cellName": "Python Flow: Fetch Events from Datastore - functions.py:L151-164",
- "cellId": "fb0bcd2a-5999-47fc-bb41-11233e3544fa",
- "visible": true,
- "startLine": 151,
- "endLine": 164,
- "parentCellId": "e1b937af-2584-42ee-8281-e1bffda373ae",
- "parentPath": "aw-core/aw_query/functions.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "6ea3ab36-027f-40b9-a0ba-9ede77ae1117"
- }
- ]
- },
- "5eb14d26-499c-4ea4-8282-3f923646dbdb": {
- "path": "5eb14d26-499c-4ea4-8282-3f923646dbdb",
- "cellName": "Python Flow: Finalize and Return Result - query2.py:L396-401",
- "cellId": "5eb14d26-499c-4ea4-8282-3f923646dbdb",
- "visible": true,
- "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20"
- },
- "aw-core/aw_query/query2.py-simstep-ab3fe2d5-9396-4241-b64e-2a187e97de75": {
- "path": "aw-core/aw_query/query2.py-simstep-ab3fe2d5-9396-4241-b64e-2a187e97de75",
- "fileName": "query2.py",
- "wiki": "The interpreter completes all statements. The `get_return` function is called to extract the final value assigned to the `RETURN` variable from the execution namespace.",
- "cellName": "Python Flow: Finalize and Return Result - query2.py:L396-401",
- "cellId": "5eb14d26-499c-4ea4-8282-3f923646dbdb",
- "visible": true,
- "startLine": 396,
- "endLine": 401,
- "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
- "parentPath": "aw-core/aw_query/query2.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "ab3fe2d5-9396-4241-b64e-2a187e97de75"
- }
- ]
- },
- "7ace16a3-9438-4e78-bcf9-79131079c89d": {
- "path": "7ace16a3-9438-4e78-bcf9-79131079c89d",
- "cellName": "Rust Flow: Client Initiates API Query - blocking.rs:L64-69",
- "cellId": "7ace16a3-9438-4e78-bcf9-79131079c89d",
- "visible": true,
- "parentCellId": "8dafeb60-1305-46f7-baac-4153d6d18539"
- },
- "aw-server-rust/aw-client-rust/src/blocking.rs-simstep-3118dc4c-d7ad-4996-aa81-a205ccdf6e72": {
- "path": "aw-server-rust/aw-client-rust/src/blocking.rs-simstep-3118dc4c-d7ad-4996-aa81-a205ccdf6e72",
- "fileName": "blocking.rs",
- "wiki": "A client application sends a query to the ActivityWatch server. This example uses the Rust client for consistency, but any HTTP client can be used.",
- "cellName": "Rust Flow: Client Initiates API Query - blocking.rs:L64-69",
- "cellId": "7ace16a3-9438-4e78-bcf9-79131079c89d",
- "visible": true,
- "startLine": 64,
- "endLine": 69,
- "parentCellId": "8dafeb60-1305-46f7-baac-4153d6d18539",
- "parentPath": "aw-server-rust/aw-client-rust/src/blocking.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "3118dc4c-d7ad-4996-aa81-a205ccdf6e72"
- }
- ]
- },
- "b93b83dd-fff3-44dc-ac22-3ea63117c222": {
- "path": "b93b83dd-fff3-44dc-ac22-3ea63117c222",
- "cellName": "Rust Flow: API Endpoint Receives Request - query.rs:L9-29",
- "cellId": "b93b83dd-fff3-44dc-ac22-3ea63117c222",
- "visible": true,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
- },
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-1c25a330-b713-4866-9440-8737c787ce33": {
- "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-1c25a330-b713-4866-9440-8737c787ce33",
- "fileName": "query.rs",
- "wiki": "The Rocket-based `aw-server-rust` receives the request. The `query` endpoint in `endpoints/query.rs` deserializes the JSON payload into a `Query` struct and joins the query lines.",
- "cellName": "Rust Flow: API Endpoint Receives Request - query.rs:L9-29",
- "cellId": "b93b83dd-fff3-44dc-ac22-3ea63117c222",
- "visible": true,
- "startLine": 9,
- "endLine": 29,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "1c25a330-b713-4866-9440-8737c787ce33"
- }
- ]
- },
- "d8afb2b7-af24-431a-b206-828a8b7cef2a": {
- "path": "d8afb2b7-af24-431a-b206-828a8b7cef2a",
- "cellName": "Rust Flow: Lexing and Parsing - lib.rs:L53-62",
- "cellId": "d8afb2b7-af24-431a-b206-828a8b7cef2a",
- "visible": true,
- "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237"
- },
- "aw-server-rust/aw-query/src/lib.rs-simstep-024a46d7-abc2-4c35-92d1-900d198f748c": {
- "path": "aw-server-rust/aw-query/src/lib.rs-simstep-024a46d7-abc2-4c35-92d1-900d198f748c",
- "fileName": "lib.rs",
- "wiki": "The `aw_query::query` function first uses a lexer (`lexer.rs`) to convert the query string into a stream of tokens. Then, a parser (`parser.rs`) consumes the tokens to build an Abstract Syntax Tree (AST) representing the query's structure.",
- "cellName": "Rust Flow: Lexing and Parsing - lib.rs:L53-62",
- "cellId": "d8afb2b7-af24-431a-b206-828a8b7cef2a",
- "visible": true,
- "startLine": 53,
- "endLine": 62,
- "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
- "parentPath": "aw-server-rust/aw-query/src/lib.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "024a46d7-abc2-4c35-92d1-900d198f748c"
- }
- ]
- },
- "630bda35-fbd5-40ec-b47d-37ad66379d94": {
- "path": "630bda35-fbd5-40ec-b47d-37ad66379d94",
- "cellName": "Rust Flow: Interpret AST - interpret.rs:L21-34",
- "cellId": "630bda35-fbd5-40ec-b47d-37ad66379d94",
- "visible": true,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c"
- },
- "aw-server-rust/aw-query/src/interpret.rs-simstep-e3204124-26ff-4799-8462-100305c27ae1": {
- "path": "aw-server-rust/aw-query/src/interpret.rs-simstep-e3204124-26ff-4799-8462-100305c27ae1",
- "fileName": "interpret.rs",
- "wiki": "The `interpret_prog` function in `interpret.rs` initializes an environment and recursively evaluates each expression (`Expr`) in the AST using `interpret_expr`. Function calls are resolved by looking up their names in the environment, which is pre-populated with built-in functions from `functions.rs`.",
- "cellName": "Rust Flow: Interpret AST - interpret.rs:L21-34",
- "cellId": "630bda35-fbd5-40ec-b47d-37ad66379d94",
- "visible": true,
- "startLine": 21,
- "endLine": 34,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "e3204124-26ff-4799-8462-100305c27ae1"
- }
- ]
- },
- "eecd0f91-7c53-4352-8d85-05c3dd46bee1": {
- "path": "eecd0f91-7c53-4352-8d85-05c3dd46bee1",
- "cellName": "Rust Flow: Fetch Events from Datastore - functions.rs:L139-167",
- "cellId": "eecd0f91-7c53-4352-8d85-05c3dd46bee1",
- "visible": true,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e"
- },
- "aw-server-rust/aw-query/src/functions.rs-simstep-06d75f72-3fc8-47d8-85ab-f7fa317f4de5": {
- "path": "aw-server-rust/aw-query/src/functions.rs-simstep-06d75f72-3fc8-47d8-85ab-f7fa317f4de5",
- "fileName": "functions.rs",
- "wiki": "The `query_bucket` function calls the datastore's `get_events` method to retrieve events from the specified bucket within the given time interval.",
- "cellName": "Rust Flow: Fetch Events from Datastore - functions.rs:L139-167",
- "cellId": "eecd0f91-7c53-4352-8d85-05c3dd46bee1",
- "visible": true,
- "startLine": 139,
- "endLine": 167,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "parentPath": "aw-server-rust/aw-query/src/functions.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "06d75f72-3fc8-47d8-85ab-f7fa317f4de5"
- }
- ]
- },
- "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4": {
- "path": "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4",
- "cellName": "Rust Flow: Finalize and Return Result - interpret.rs:L30-33",
- "cellId": "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4",
- "visible": true,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c"
- },
- "aw-server-rust/aw-query/src/interpret.rs-simstep-9382ac29-7930-4f83-afdd-deb2bfc221e3": {
- "path": "aw-server-rust/aw-query/src/interpret.rs-simstep-9382ac29-7930-4f83-afdd-deb2bfc221e3",
- "fileName": "interpret.rs",
- "wiki": "After executing all statements (including handling the `Return` expression which sets the special `RETURN` variable in the environment), the `interpret_prog` function retrieves the final value from the environment.",
- "cellName": "Rust Flow: Finalize and Return Result - interpret.rs:L30-33",
- "cellId": "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4",
- "visible": true,
- "startLine": 30,
- "endLine": 33,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "9382ac29-7930-4f83-afdd-deb2bfc221e3"
- }
- ]
- },
- "71408ae2-19e6-4327-bab9-8918af09c855": {
- "path": "71408ae2-19e6-4327-bab9-8918af09c855",
- "cellName": "API Call:\nTransmit Query\nto Python\nServer",
- "cellId": "71408ae2-19e6-4327-bab9-8918af09c855",
- "visible": true
- },
- "generated-edge-simstep-5dc6bd77-15d2-44c3-b665-8de88288c314-71408ae2-19e6-4327-bab9-8918af09c855": {
- "path": "generated-edge-simstep-5dc6bd77-15d2-44c3-b665-8de88288c314-71408ae2-19e6-4327-bab9-8918af09c855",
- "fileName": "client.py",
- "cellName": "API Call: Transmit Query to Python Server",
- "cellId": "71408ae2-19e6-4327-bab9-8918af09c855",
- "visible": true,
- "startLine": 115,
- "endLine": 127,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "5dc6bd77-15d2-44c3-b665-8de88288c314"
- }
- ]
- },
- "891bfe3a-f22a-4998-acea-aa6d0c362821": {
- "path": "891bfe3a-f22a-4998-acea-aa6d0c362821",
- "cellName": "Data Flow:\nPass Query\nto API\nLogic",
- "cellId": "891bfe3a-f22a-4998-acea-aa6d0c362821",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
- },
- "generated-edge-simstep-5a0d9b17-b09a-4aa5-9234-c01cb2aadef4-891bfe3a-f22a-4998-acea-aa6d0c362821": {
- "path": "generated-edge-simstep-5a0d9b17-b09a-4aa5-9234-c01cb2aadef4-891bfe3a-f22a-4998-acea-aa6d0c362821",
- "fileName": "rest.py",
- "cellName": "Data Flow: Pass Query to API Logic",
- "cellId": "891bfe3a-f22a-4998-acea-aa6d0c362821",
- "visible": true,
- "startLine": 320,
- "endLine": 323,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "5a0d9b17-b09a-4aa5-9234-c01cb2aadef4"
- }
- ]
- },
- "b79b67f9-1be1-48f1-920a-9ebdd4417272": {
- "path": "b79b67f9-1be1-48f1-920a-9ebdd4417272",
- "cellName": "Data Flow:\nPass Query\nto Interpreter",
- "cellId": "b79b67f9-1be1-48f1-920a-9ebdd4417272",
- "visible": true
- },
- "generated-edge-simstep-833f0f0f-ec00-4960-b1f9-46d8a8530a01-b79b67f9-1be1-48f1-920a-9ebdd4417272": {
- "path": "generated-edge-simstep-833f0f0f-ec00-4960-b1f9-46d8a8530a01-b79b67f9-1be1-48f1-920a-9ebdd4417272",
- "fileName": "api.py",
- "cellName": "Data Flow: Pass Query to Interpreter",
- "cellId": "b79b67f9-1be1-48f1-920a-9ebdd4417272",
- "visible": true,
- "startLine": 348,
- "endLine": 348,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "833f0f0f-ec00-4960-b1f9-46d8a8530a01"
- }
- ]
- },
- "4059fcbe-a1ee-41d0-b576-55a1d278bca0": {
- "path": "4059fcbe-a1ee-41d0-b576-55a1d278bca0",
- "cellName": "Data Flow:\nExecute Query\nFunction",
- "cellId": "4059fcbe-a1ee-41d0-b576-55a1d278bca0",
- "visible": true,
- "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0"
- },
- "generated-edge-simstep-7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6-4059fcbe-a1ee-41d0-b576-55a1d278bca0": {
- "path": "generated-edge-simstep-7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6-4059fcbe-a1ee-41d0-b576-55a1d278bca0",
- "fileName": "query2.py",
- "cellName": "Data Flow: Execute Query Function",
- "cellId": "4059fcbe-a1ee-41d0-b576-55a1d278bca0",
- "visible": true,
- "startLine": 133,
- "endLine": 148,
- "parentCellId": "0fb8ce44-e9ea-4e8a-a049-33211b003d20",
- "parentPath": "aw-core/aw_query/query2.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6"
- }
- ]
- },
- "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4": {
- "path": "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
- "cellName": "Data Flow:\nReturn Events\nto Interpreter",
- "cellId": "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
- "visible": true,
- "parentCellId": "701d49bd-2670-4a9f-8ffd-52f62726ddc0"
- },
- "generated-edge-simstep-ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c-e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4": {
- "path": "generated-edge-simstep-ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c-e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
- "fileName": "datastore.py",
- "cellName": "Data Flow: Return Events to Interpreter",
- "cellId": "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
- "visible": true,
- "startLine": 88,
- "endLine": 114,
- "parentCellId": "aba7852e-7836-4343-ae26-5ecb9a02d42d",
- "parentPath": "aw-core/aw_datastore/datastore.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c"
- }
- ]
- },
- "c4b6d403-d2a9-4cff-8a72-31189a53c0db": {
- "path": "c4b6d403-d2a9-4cff-8a72-31189a53c0db",
- "cellName": "API Call:\nSend JSON\nResponse",
- "cellId": "c4b6d403-d2a9-4cff-8a72-31189a53c0db",
- "visible": true
- },
- "generated-edge-simstep-fe43857f-ef7d-455d-a9c4-37d54d12207a-c4b6d403-d2a9-4cff-8a72-31189a53c0db": {
- "path": "generated-edge-simstep-fe43857f-ef7d-455d-a9c4-37d54d12207a-c4b6d403-d2a9-4cff-8a72-31189a53c0db",
- "fileName": "rest.py",
- "cellName": "API Call: Send JSON Response",
- "cellId": "c4b6d403-d2a9-4cff-8a72-31189a53c0db",
- "visible": true,
- "startLine": 323,
- "endLine": 323,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "fe43857f-ef7d-455d-a9c4-37d54d12207a"
- }
- ]
- },
- "ed18dcc0-5e4a-44fb-b661-f746f1e893f1": {
- "path": "ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
- "cellName": "API Call:\nTransmit Query\nto Rust\nServer",
- "cellId": "ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-97542310-17cf-4c99-9ce9-a328dffa5f4c-ed18dcc0-5e4a-44fb-b661-f746f1e893f1": {
- "path": "generated-edge-simstep-97542310-17cf-4c99-9ce9-a328dffa5f4c-ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
- "fileName": "lib.rs",
- "cellName": "API Call: Transmit Query to Rust Server",
- "cellId": "ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
- "visible": true,
- "startLine": 112,
- "endLine": 137,
- "parentCellId": "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf",
- "parentPath": "aw-server-rust/aw-client-rust/src/lib.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "97542310-17cf-4c99-9ce9-a328dffa5f4c"
- }
- ]
- },
- "d3cb01a0-d8cd-4382-b122-d1234b0562bc": {
- "path": "d3cb01a0-d8cd-4382-b122-d1234b0562bc",
- "cellName": "Data Flow:\nPass Query\nto Core\nEngine",
- "cellId": "d3cb01a0-d8cd-4382-b122-d1234b0562bc",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-6eb126a9-5234-4495-9727-ec2741ce9660-d3cb01a0-d8cd-4382-b122-d1234b0562bc": {
- "path": "generated-edge-simstep-6eb126a9-5234-4495-9727-ec2741ce9660-d3cb01a0-d8cd-4382-b122-d1234b0562bc",
- "fileName": "query.rs",
- "cellName": "Data Flow: Pass Query to Core Engine",
- "cellId": "d3cb01a0-d8cd-4382-b122-d1234b0562bc",
- "visible": true,
- "startLine": 16,
- "endLine": 24,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "6eb126a9-5234-4495-9727-ec2741ce9660"
- }
- ]
- },
- "e72e1881-49ce-41ad-966a-90a26ca47453": {
- "path": "e72e1881-49ce-41ad-966a-90a26ca47453",
- "cellName": "Data Flow:\nPass AST\nto Interpreter",
- "cellId": "e72e1881-49ce-41ad-966a-90a26ca47453",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
- },
- "generated-edge-simstep-acc1ad56-50cb-41ab-9217-f8d15af6686c-e72e1881-49ce-41ad-966a-90a26ca47453": {
- "path": "generated-edge-simstep-acc1ad56-50cb-41ab-9217-f8d15af6686c-e72e1881-49ce-41ad-966a-90a26ca47453",
- "fileName": "lib.rs",
- "cellName": "Data Flow: Pass AST to Interpreter",
- "cellId": "e72e1881-49ce-41ad-966a-90a26ca47453",
- "visible": true,
- "startLine": 63,
- "endLine": 63,
- "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
- "parentPath": "aw-server-rust/aw-query/src/lib.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "acc1ad56-50cb-41ab-9217-f8d15af6686c"
- }
- ]
- },
- "15dfaeb9-fb37-4296-972f-0188abd0b353": {
- "path": "15dfaeb9-fb37-4296-972f-0188abd0b353",
- "cellName": "Data Flow:\nExecute Query\nFunction",
- "cellId": "15dfaeb9-fb37-4296-972f-0188abd0b353",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
- },
- "generated-edge-simstep-f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5-15dfaeb9-fb37-4296-972f-0188abd0b353": {
- "path": "generated-edge-simstep-f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5-15dfaeb9-fb37-4296-972f-0188abd0b353",
- "fileName": "interpret.rs",
- "cellName": "Data Flow: Execute Query Function",
- "cellId": "15dfaeb9-fb37-4296-972f-0188abd0b353",
- "visible": true,
- "startLine": 213,
- "endLine": 226,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5"
- }
- ]
- },
- "9792d1f0-08be-4f90-8e68-3caee0eb2498": {
- "path": "9792d1f0-08be-4f90-8e68-3caee0eb2498",
- "cellName": "Data Flow:\nReturn Events\nto Interpreter",
- "cellId": "9792d1f0-08be-4f90-8e68-3caee0eb2498",
- "visible": true,
- "parentCellId": "e6b26caf-0857-4e8d-8f29-124af90c1966"
- },
- "generated-edge-simstep-f69e7df0-6666-4b48-a0a6-1000c8ccede0-9792d1f0-08be-4f90-8e68-3caee0eb2498": {
- "path": "generated-edge-simstep-f69e7df0-6666-4b48-a0a6-1000c8ccede0-9792d1f0-08be-4f90-8e68-3caee0eb2498",
- "fileName": "datastore.rs",
- "cellName": "Data Flow: Return Events to Interpreter",
- "cellId": "9792d1f0-08be-4f90-8e68-3caee0eb2498",
- "visible": true,
- "startLine": 700,
- "endLine": 797,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "simSteps": [
- {
- "simulationKey": "How the data query language works",
- "simStepId": "f69e7df0-6666-4b48-a0a6-1000c8ccede0"
- }
- ]
- },
- "7ee7b20f-9df9-4269-8f41-bc7e191503bd": {
- "path": "7ee7b20f-9df9-4269-8f41-bc7e191503bd",
- "cellName": "aw-watcher-afk",
- "cellId": "7ee7b20f-9df9-4269-8f41-bc7e191503bd",
- "visible": true
- },
- "8f0b906e-fb77-4a52-aee5-1f494bec596c": {
- "path": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
- "cellName": "aw_watcher_afk",
- "cellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c",
- "visible": true,
- "parentCellId": "7ee7b20f-9df9-4269-8f41-bc7e191503bd"
- },
- "d242d1ad-7cdf-414b-812a-f3e5af153562": {
- "path": "d242d1ad-7cdf-414b-812a-f3e5af153562",
- "cellName": "__main__.py",
- "cellId": "d242d1ad-7cdf-414b-812a-f3e5af153562",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
- },
- "c443335f-7f08-4436-8862-5aab2adcf7e0": {
- "path": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "cellName": "afk.py",
- "cellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
- },
- "72e53989-6741-4b0d-b49c-f58d0333cdd1": {
- "path": "72e53989-6741-4b0d-b49c-f58d0333cdd1",
- "cellName": "unix.py",
- "cellId": "72e53989-6741-4b0d-b49c-f58d0333cdd1",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
- },
- "ba27c535-e0e5-44ae-b9f0-2827227ebfe2": {
- "path": "ba27c535-e0e5-44ae-b9f0-2827227ebfe2",
- "cellName": "AFK Watcher Entrypoint - __main__.py:L7-21",
- "cellId": "ba27c535-e0e5-44ae-b9f0-2827227ebfe2",
- "visible": true,
- "parentCellId": "d242d1ad-7cdf-414b-812a-f3e5af153562"
- },
- "aw-watcher-afk/aw_watcher_afk/__main__.py-simstep-8ffbcadf-f26a-483a-9902-95e5a761de64": {
- "path": "aw-watcher-afk/aw_watcher_afk/__main__.py-simstep-8ffbcadf-f26a-483a-9902-95e5a761de64",
- "fileName": "__main__.py",
- "wiki": "The `aw-watcher-afk` process is started. The `main` function is called, which parses command-line arguments, sets up logging, and initializes the `AFKWatcher`.",
- "cellName": "AFK Watcher Entrypoint - __main__.py:L7-21",
- "cellId": "ba27c535-e0e5-44ae-b9f0-2827227ebfe2",
- "visible": true,
- "startLine": 7,
- "endLine": 21,
- "parentCellId": "d242d1ad-7cdf-414b-812a-f3e5af153562",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/__main__.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "8ffbcadf-f26a-483a-9902-95e5a761de64"
- }
- ]
- },
- "79468b99-a4de-48b7-bb67-506dc0dcb41c": {
- "path": "79468b99-a4de-48b7-bb67-506dc0dcb41c",
- "cellName": "Load Configuration - afk.py:L42-53",
- "cellId": "79468b99-a4de-48b7-bb67-506dc0dcb41c",
- "visible": true,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
- },
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-daeeac12-287a-4144-9028-6ea841b196c4": {
- "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-daeeac12-287a-4144-9028-6ea841b196c4",
- "fileName": "afk.py",
- "wiki": "The `AFKWatcher` constructor loads its configuration, setting the `timeout` (time of inactivity to be considered AFK) and `poll_time` (how often to check for activity). It also initializes the `ActivityWatchClient` to communicate with the server.",
- "cellName": "Load Configuration - afk.py:L42-53",
- "cellId": "79468b99-a4de-48b7-bb67-506dc0dcb41c",
- "visible": true,
- "startLine": 42,
- "endLine": 53,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "daeeac12-287a-4144-9028-6ea841b196c4"
- }
- ]
- },
- "6b45de30-296e-4896-915c-371f09843599": {
- "path": "6b45de30-296e-4896-915c-371f09843599",
- "cellName": "Check User Activity - afk.py:L86",
- "cellId": "6b45de30-296e-4896-915c-371f09843599",
- "visible": true,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
- },
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-6579f587-817d-4d23-a9df-86abc54273ae": {
- "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-6579f587-817d-4d23-a9df-86abc54273ae",
- "fileName": "afk.py",
- "wiki": "Inside the `heartbeat_loop`, the watcher calls `seconds_since_last_input()` to get the time elapsed since the last keyboard or mouse activity from the operating system.",
- "cellName": "Check User Activity - afk.py:L86",
- "cellId": "6b45de30-296e-4896-915c-371f09843599",
- "visible": true,
- "startLine": 86,
- "endLine": 86,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "6579f587-817d-4d23-a9df-86abc54273ae"
- }
- ]
- },
- "b7321a6c-302b-4701-9ea5-5c05c6d3e71b": {
- "path": "b7321a6c-302b-4701-9ea5-5c05c6d3e71b",
- "cellName": "Get Idle Time (Unix Example) - unix.py:L21-31",
- "cellId": "b7321a6c-302b-4701-9ea5-5c05c6d3e71b",
- "visible": true,
- "parentCellId": "72e53989-6741-4b0d-b49c-f58d0333cdd1"
- },
- "aw-watcher-afk/aw_watcher_afk/unix.py-simstep-4d2c85c7-0754-429a-8a55-c64d4da0d37c": {
- "path": "aw-watcher-afk/aw_watcher_afk/unix.py-simstep-4d2c85c7-0754-429a-8a55-c64d4da0d37c",
- "fileName": "unix.py",
- "wiki": "On Unix-like systems, listeners for mouse and keyboard events are checked. If a new event has occurred since the last check, the `last_activity` timestamp is updated. The function then returns the total seconds between now and the last recorded activity.",
- "cellName": "Get Idle Time (Unix Example) - unix.py:L21-31",
- "cellId": "b7321a6c-302b-4701-9ea5-5c05c6d3e71b",
- "visible": true,
- "startLine": 21,
- "endLine": 31,
- "parentCellId": "72e53989-6741-4b0d-b49c-f58d0333cdd1",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/unix.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "4d2c85c7-0754-429a-8a55-c64d4da0d37c"
- }
- ]
- },
- "faab8465-be29-479d-890a-7936dc5cfbdd": {
- "path": "faab8465-be29-479d-890a-7936dc5cfbdd",
- "cellName": "Detect State Change: User Becomes AFK - afk.py:L98-105",
- "cellId": "faab8465-be29-479d-890a-7936dc5cfbdd",
- "visible": true,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
- },
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-3e0e033c-c32f-4d0d-aa65-a278d77e80c7": {
- "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-3e0e033c-c32f-4d0d-aa65-a278d77e80c7",
- "fileName": "afk.py",
- "wiki": "The watcher compares the idle time with the configured timeout. Since the user was previously not AFK (`afk=False`) and the idle time (`185.3s`) is greater than the timeout (`180s`), the user's state changes to AFK.",
- "cellName": "Detect State Change: User Becomes AFK - afk.py:L98-105",
- "cellId": "faab8465-be29-479d-890a-7936dc5cfbdd",
- "visible": true,
- "startLine": 98,
- "endLine": 105,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "3e0e033c-c32f-4d0d-aa65-a278d77e80c7"
- }
- ]
- },
- "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5": {
- "path": "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5",
- "cellName": "Prepare Event for Server - afk.py:L55-59",
- "cellId": "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5",
- "visible": true,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
- },
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-dc58bc3e-b09e-4df2-870b-76419e78dd3d": {
- "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-dc58bc3e-b09e-4df2-870b-76419e78dd3d",
- "fileName": "afk.py",
- "wiki": "The `ping` method constructs an `Event` object containing the user's status. It then calls the client's `heartbeat` method to send this event to the `aw-server`.",
- "cellName": "Prepare Event for Server - afk.py:L55-59",
- "cellId": "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5",
- "visible": true,
- "startLine": 55,
- "endLine": 59,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "dc58bc3e-b09e-4df2-870b-76419e78dd3d"
- }
- ]
- },
- "c27977fb-af8a-4779-8f78-a99b40221157": {
- "path": "c27977fb-af8a-4779-8f78-a99b40221157",
- "cellName": "Server Receives and Processes Heartbeat - api.py:L268-276",
- "cellId": "c27977fb-af8a-4779-8f78-a99b40221157",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-7357e239-3712-4b55-a94c-2165ea1f3255": {
- "path": "aw-server/aw_server/api.py-simstep-7357e239-3712-4b55-a94c-2165ea1f3255",
- "fileName": "api.py",
- "wiki": "The `aw-server` receives the heartbeat event. The `heartbeat` method in the API layer checks if the new event's data is the same as the last event. Since the status changed from 'not-afk' to 'afk', it will not merge them and will instead insert a new event.",
- "cellName": "Server Receives and Processes Heartbeat - api.py:L268-276",
- "cellId": "c27977fb-af8a-4779-8f78-a99b40221157",
- "visible": true,
- "startLine": 268,
- "endLine": 276,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "7357e239-3712-4b55-a94c-2165ea1f3255"
- }
- ]
- },
- "802c1941-09e1-4038-a0bf-bd4e553ff6f6": {
- "path": "802c1941-09e1-4038-a0bf-bd4e553ff6f6",
- "cellName": "Loop Repeats - afk.py:L76",
- "cellId": "802c1941-09e1-4038-a0bf-bd4e553ff6f6",
- "visible": true,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
- },
- "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-1e5ad77f-aeff-49b6-9634-65e52f011a83": {
- "path": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-1e5ad77f-aeff-49b6-9634-65e52f011a83",
- "fileName": "afk.py",
- "wiki": "The process repeats. The watcher continues to send `afk` heartbeats on each poll interval as long as the user remains idle. When activity resumes, the condition `afk and seconds_since_input < self.settings.timeout` will trigger, sending a `not-afk` event and resetting the state.",
- "cellName": "Loop Repeats - afk.py:L76",
- "cellId": "802c1941-09e1-4038-a0bf-bd4e553ff6f6",
- "visible": true,
- "startLine": 76,
- "endLine": 76,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "1e5ad77f-aeff-49b6-9634-65e52f011a83"
- }
- ]
- },
- "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250": {
- "path": "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
- "cellName": "Initialize Watcher",
- "cellId": "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
- },
- "generated-edge-simstep-60e1002f-9782-4c8d-b104-f4bb172e2c91-7c2f1d5b-706c-4dd2-9d8c-62b3e6886250": {
- "path": "generated-edge-simstep-60e1002f-9782-4c8d-b104-f4bb172e2c91-7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
- "fileName": "__main__.py",
- "cellName": "Initialize Watcher",
- "cellId": "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
- "visible": true,
- "startLine": 20,
- "endLine": 20,
- "parentCellId": "d242d1ad-7cdf-414b-812a-f3e5af153562",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/__main__.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "60e1002f-9782-4c8d-b104-f4bb172e2c91"
- }
- ]
- },
- "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838": {
- "path": "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
- "cellName": "Start Main\nLoop",
- "cellId": "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
- "visible": true,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
- },
- "generated-edge-simstep-1422a5f8-ad2e-4b32-8955-ee6bb3053286-1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838": {
- "path": "generated-edge-simstep-1422a5f8-ad2e-4b32-8955-ee6bb3053286-1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
- "fileName": "afk.py",
- "cellName": "Start Main Loop",
- "cellId": "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
- "visible": true,
- "startLine": 71,
- "endLine": 72,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "1422a5f8-ad2e-4b32-8955-ee6bb3053286"
- }
- ]
- },
- "e514d9e2-e803-4041-b693-65878401b214": {
- "path": "e514d9e2-e803-4041-b693-65878401b214",
- "cellName": "Platform-Specific Call",
- "cellId": "e514d9e2-e803-4041-b693-65878401b214",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
- },
- "generated-edge-simstep-2588211c-b086-4768-8a87-a86764c7e5cd-e514d9e2-e803-4041-b693-65878401b214": {
- "path": "generated-edge-simstep-2588211c-b086-4768-8a87-a86764c7e5cd-e514d9e2-e803-4041-b693-65878401b214",
- "fileName": "afk.py",
- "cellName": "Platform-Specific Call",
- "cellId": "e514d9e2-e803-4041-b693-65878401b214",
- "visible": true,
- "startLine": 14,
- "endLine": 24,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "2588211c-b086-4768-8a87-a86764c7e5cd"
- }
- ]
- },
- "eeb9224a-fff6-4652-b733-ea430b820a2c": {
- "path": "eeb9224a-fff6-4652-b733-ea430b820a2c",
- "cellName": "Return Idle\nTime",
- "cellId": "eeb9224a-fff6-4652-b733-ea430b820a2c",
- "visible": true,
- "parentCellId": "8f0b906e-fb77-4a52-aee5-1f494bec596c"
- },
- "generated-edge-simstep-9195e582-b3fa-4848-b151-0236a8a5d176-eeb9224a-fff6-4652-b733-ea430b820a2c": {
- "path": "generated-edge-simstep-9195e582-b3fa-4848-b151-0236a8a5d176-eeb9224a-fff6-4652-b733-ea430b820a2c",
- "fileName": "afk.py",
- "cellName": "Return Idle Time",
- "cellId": "eeb9224a-fff6-4652-b733-ea430b820a2c",
- "visible": true,
- "startLine": 86,
- "endLine": 86,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "9195e582-b3fa-4848-b151-0236a8a5d176"
- }
- ]
- },
- "196358b9-6ae9-4f52-ad78-ff88b4a49403": {
- "path": "196358b9-6ae9-4f52-ad78-ff88b4a49403",
- "cellName": "Send Final\n'not-afk' Heartbeat",
- "cellId": "196358b9-6ae9-4f52-ad78-ff88b4a49403",
- "visible": true,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0"
- },
- "generated-edge-simstep-78d78341-ced8-4fc6-bc93-ce4a62c8adf6-196358b9-6ae9-4f52-ad78-ff88b4a49403": {
- "path": "generated-edge-simstep-78d78341-ced8-4fc6-bc93-ce4a62c8adf6-196358b9-6ae9-4f52-ad78-ff88b4a49403",
- "fileName": "afk.py",
- "cellName": "Send Final 'not-afk' Heartbeat",
- "cellId": "196358b9-6ae9-4f52-ad78-ff88b4a49403",
- "visible": true,
- "startLine": 100,
- "endLine": 100,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "78d78341-ced8-4fc6-bc93-ce4a62c8adf6"
- }
- ]
- },
- "b520b088-6f6f-4b32-afba-5ef244691c44": {
- "path": "b520b088-6f6f-4b32-afba-5ef244691c44",
- "cellName": "Send First\n'afk' Heartbeat",
- "cellId": "b520b088-6f6f-4b32-afba-5ef244691c44",
- "visible": true
- },
- "generated-edge-simstep-c9a127c1-afd0-4def-a0fe-c490c9b64039-b520b088-6f6f-4b32-afba-5ef244691c44": {
- "path": "generated-edge-simstep-c9a127c1-afd0-4def-a0fe-c490c9b64039-b520b088-6f6f-4b32-afba-5ef244691c44",
- "fileName": "afk.py",
- "cellName": "Send First 'afk' Heartbeat",
- "cellId": "b520b088-6f6f-4b32-afba-5ef244691c44",
- "visible": true,
- "startLine": 103,
- "endLine": 105,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "c9a127c1-afd0-4def-a0fe-c490c9b64039"
- }
- ]
- },
- "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0": {
- "path": "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
- "cellName": "Pause for\nPoll Time",
- "cellId": "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
- "visible": true
- },
- "generated-edge-simstep-9fde1b44-5dbf-4530-88e2-ca54c220b462-f0e34997-66ab-4bc2-9a5e-1f00b40d47b0": {
- "path": "generated-edge-simstep-9fde1b44-5dbf-4530-88e2-ca54c220b462-f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
- "fileName": "afk.py",
- "cellName": "Pause for Poll Time",
- "cellId": "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
- "visible": true,
- "startLine": 119,
- "endLine": 119,
- "parentCellId": "c443335f-7f08-4436-8862-5aab2adcf7e0",
- "parentPath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "simSteps": [
- {
- "simulationKey": "How AFK (Away From Keyboard) detection works",
- "simStepId": "9fde1b44-5dbf-4530-88e2-ca54c220b462"
- }
- ]
- },
- "34f5debb-c898-419f-9c17-186d2a5f6e85": {
- "path": "34f5debb-c898-419f-9c17-186d2a5f6e85",
- "cellName": "aw_transform",
- "cellId": "34f5debb-c898-419f-9c17-186d2a5f6e85",
- "visible": true,
- "parentCellId": "1eed769a-5d0a-443c-9cc3-4e8f59c84abb"
- },
- "40ad45bd-b0eb-4f2c-a091-f933962a90b8": {
- "path": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
- "cellName": "macos.swift",
- "cellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
- "visible": true,
- "parentCellId": "306c9af9-c4b4-4bea-85d2-fc4830dedc4c"
- },
- "6860aa38-bc11-4d81-9260-87eba1c02581": {
- "path": "6860aa38-bc11-4d81-9260-87eba1c02581",
- "cellName": "heartbeats.py",
- "cellId": "6860aa38-bc11-4d81-9260-87eba1c02581",
- "visible": true,
- "parentCellId": "34f5debb-c898-419f-9c17-186d2a5f6e85"
- },
- "0f86982d-c1d5-4ceb-8574-3e19c2db7159": {
- "path": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
- "cellName": "bucket.rs",
- "cellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
- "visible": true,
- "parentCellId": "11799249-188d-43b3-b410-54dcff47aeba"
- },
- "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c": {
- "path": "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c",
- "cellName": "[Python Flow - Watcher] Detect Active Window Change - macos.swift:L306-375",
- "cellId": "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c",
- "visible": true,
- "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8"
- },
- "aw-watcher-window/aw_watcher_window/macos.swift-simstep-46ccc29e-b251-435a-8768-4304d477261a": {
- "path": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-46ccc29e-b251-435a-8768-4304d477261a",
- "fileName": "macos.swift",
- "wiki": "The `aw-watcher-window` process on macOS, implemented in Swift, detects a change in the active window or its title. An observer callback function like `windowTitleChanged` is triggered, which captures the application name (`app`) and the window title (`title`).",
- "cellName": "[Python Flow - Watcher] Detect Active Window Change - macos.swift:L306-375",
- "cellId": "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c",
- "visible": true,
- "startLine": 306,
- "endLine": 375,
- "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
- "parentPath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "46ccc29e-b251-435a-8768-4304d477261a"
- }
- ]
- },
- "67a89dcc-93fc-413d-aa21-eca0b7227bc2": {
- "path": "67a89dcc-93fc-413d-aa21-eca0b7227bc2",
- "cellName": "[Python Flow - Watcher] Send Heartbeat API Request - macos.swift:L253-268",
- "cellId": "67a89dcc-93fc-413d-aa21-eca0b7227bc2",
- "visible": true,
- "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8"
- },
- "aw-watcher-window/aw_watcher_window/macos.swift-simstep-e873b3e2-2ebd-43ee-8f97-e02f869578f7": {
- "path": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-e873b3e2-2ebd-43ee-8f97-e02f869578f7",
- "fileName": "macos.swift",
- "wiki": "The `sendHeartbeatSingle` function constructs an HTTP POST request. It sets the URL to the heartbeat endpoint, including the bucket name and a calculated `pulsetime` as a query parameter. The heartbeat data is JSON-encoded and sent as the request body.",
- "cellName": "[Python Flow - Watcher] Send Heartbeat API Request - macos.swift:L253-268",
- "cellId": "67a89dcc-93fc-413d-aa21-eca0b7227bc2",
- "visible": true,
- "startLine": 253,
- "endLine": 268,
- "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
- "parentPath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "e873b3e2-2ebd-43ee-8f97-e02f869578f7"
- }
- ]
- },
- "9de5f1e4-764e-4be7-90a1-65fa23ca0dea": {
- "path": "9de5f1e4-764e-4be7-90a1-65fa23ca0dea",
- "cellName": "[Python Server] Handle Heartbeat Endpoint - rest.py:L283-304",
- "cellId": "9de5f1e4-764e-4be7-90a1-65fa23ca0dea",
- "visible": true,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
- },
- "aw-server/aw_server/rest.py-simstep-e98f7509-f28f-4534-8f2a-f525edc73f69": {
- "path": "aw-server/aw_server/rest.py-simstep-e98f7509-f28f-4534-8f2a-f525edc73f69",
- "fileName": "rest.py",
- "wiki": "The `aw-server` (Flask) routes the incoming request to the `post` method of the `HeartbeatResource`. This method parses the JSON body into an `Event` object and extracts the `pulsetime` from the URL parameters.",
- "cellName": "[Python Server] Handle Heartbeat Endpoint - rest.py:L283-304",
- "cellId": "9de5f1e4-764e-4be7-90a1-65fa23ca0dea",
- "visible": true,
- "startLine": 283,
- "endLine": 304,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "e98f7509-f28f-4534-8f2a-f525edc73f69"
- }
- ]
- },
- "7c02469d-20a7-415d-940e-fbd82d0fc997": {
- "path": "7c02469d-20a7-415d-940e-fbd82d0fc997",
- "cellName": "[Python Server] Process Heartbeat Event - api.py:L254-337",
- "cellId": "7c02469d-20a7-415d-940e-fbd82d0fc997",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-bb678fe2-e6e3-472b-8ae4-95e362d4bdaf": {
- "path": "aw-server/aw_server/api.py-simstep-bb678fe2-e6e3-472b-8ae4-95e362d4bdaf",
- "fileName": "api.py",
- "wiki": "The `ServerAPI.heartbeat` method retrieves the last event from the specified bucket, either from an in-memory cache (`self.last_event`) or the database. It then compares the data of the new heartbeat with the last event. If the data is the same, it calls `heartbeat_merge` to attempt a merge.",
- "cellName": "[Python Server] Process Heartbeat Event - api.py:L254-337",
- "cellId": "7c02469d-20a7-415d-940e-fbd82d0fc997",
- "visible": true,
- "startLine": 254,
- "endLine": 337,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "bb678fe2-e6e3-472b-8ae4-95e362d4bdaf"
- }
- ]
- },
- "dc7a3836-03e1-4a54-9817-b62f36466ec0": {
- "path": "dc7a3836-03e1-4a54-9817-b62f36466ec0",
- "cellName": "[Python Server] Core Merge Logic - heartbeats.py:L26-56",
- "cellId": "dc7a3836-03e1-4a54-9817-b62f36466ec0",
- "visible": true,
- "parentCellId": "6860aa38-bc11-4d81-9260-87eba1c02581"
- },
- "aw-core/aw_transform/heartbeats.py-simstep-d2eac5dc-58f7-408c-beba-c1711beec25a": {
- "path": "aw-core/aw_transform/heartbeats.py-simstep-d2eac5dc-58f7-408c-beba-c1711beec25a",
- "fileName": "heartbeats.py",
- "wiki": "The `heartbeat_merge` function checks if the event data is identical and if the new heartbeat's timestamp is within the `pulsetime` window of the last event's end time. If both conditions are met, it creates a new merged event by extending the duration of the last event to cover the time up to the new heartbeat. Otherwise, it returns `None`.",
- "cellName": "[Python Server] Core Merge Logic - heartbeats.py:L26-56",
- "cellId": "dc7a3836-03e1-4a54-9817-b62f36466ec0",
- "visible": true,
- "startLine": 26,
- "endLine": 56,
- "parentCellId": "6860aa38-bc11-4d81-9260-87eba1c02581",
- "parentPath": "aw-core/aw_transform/heartbeats.py",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "d2eac5dc-58f7-408c-beba-c1711beec25a"
- }
- ]
- },
- "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f": {
- "path": "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f",
- "cellName": "[Python Server] Update Database - api.py:L313-315",
- "cellId": "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-976cfbd0-8946-4157-81b0-0ae6dffa43e1": {
- "path": "aw-server/aw_server/api.py-simstep-976cfbd0-8946-4157-81b0-0ae6dffa43e1",
- "fileName": "api.py",
- "wiki": "If a merged event was returned, the `ServerAPI.heartbeat` method updates its local cache (`self.last_event`) and calls `self.db[bucket_id].replace_last(merged)` to persist the change in the database. This replaces the previous event with the new, longer-duration event. If no merged event was returned, it inserts a new event instead.",
- "cellName": "[Python Server] Update Database - api.py:L313-315",
- "cellId": "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f",
- "visible": true,
- "startLine": 313,
- "endLine": 315,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "976cfbd0-8946-4157-81b0-0ae6dffa43e1"
- }
- ]
- },
- "b3da175e-36b5-4025-ba15-6c54e1d850dd": {
- "path": "b3da175e-36b5-4025-ba15-6c54e1d850dd",
- "cellName": "[Rust Flow - Watcher] Detect and Send Heartbeat - macos.swift:L203-268",
- "cellId": "b3da175e-36b5-4025-ba15-6c54e1d850dd",
- "visible": true,
- "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8"
- },
- "aw-watcher-window/aw_watcher_window/macos.swift-simstep-8420fd6c-dba4-41c0-b11d-7280a428ab36": {
- "path": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-8420fd6c-dba4-41c0-b11d-7280a428ab36",
- "fileName": "macos.swift",
- "wiki": "This step marks the beginning of the alternative `aw-server-rust` implementation flow. The process is initiated in the same way as the Python flow: a watcher detects an activity change and prepares a heartbeat event. The Swift-based watcher is implementation-agnostic and sends the same HTTP request regardless of the server.",
- "cellName": "[Rust Flow - Watcher] Detect and Send Heartbeat - macos.swift:L203-268",
- "cellId": "b3da175e-36b5-4025-ba15-6c54e1d850dd",
- "visible": true,
- "startLine": 203,
- "endLine": 268,
- "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
- "parentPath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "8420fd6c-dba4-41c0-b11d-7280a428ab36"
- }
- ]
- },
- "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926": {
- "path": "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926",
- "cellName": "[Rust Server] Handle Heartbeat Endpoint - bucket.rs:L150-162",
- "cellId": "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926",
- "visible": true,
- "parentCellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159"
- },
- "aw-server-rust/aw-server/src/endpoints/bucket.rs-simstep-41b8b1d6-f9fe-47ad-851e-574e804f7171": {
- "path": "aw-server-rust/aw-server/src/endpoints/bucket.rs-simstep-41b8b1d6-f9fe-47ad-851e-574e804f7171",
- "fileName": "bucket.rs",
- "wiki": "The `aw-server-rust` (Rocket) routes the incoming request to the `bucket_events_heartbeat` function. This function parses the JSON body and pulsetime, then calls the `datastore.heartbeat` method to process the event.",
- "cellName": "[Rust Server] Handle Heartbeat Endpoint - bucket.rs:L150-162",
- "cellId": "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926",
- "visible": true,
- "startLine": 150,
- "endLine": 162,
- "parentCellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "41b8b1d6-f9fe-47ad-851e-574e804f7171"
- }
- ]
- },
- "b6b4c8cb-741a-4e38-b800-61273375cd64": {
- "path": "b6b4c8cb-741a-4e38-b800-61273375cd64",
- "cellName": "[Rust Server] Queue Heartbeat Command - worker.rs:L385-399",
- "cellId": "b6b4c8cb-741a-4e38-b800-61273375cd64",
- "visible": true,
- "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e"
- },
- "aw-server-rust/aw-datastore/src/worker.rs-simstep-b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3": {
- "path": "aw-server-rust/aw-datastore/src/worker.rs-simstep-b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3",
- "fileName": "worker.rs",
- "wiki": "The `Datastore::heartbeat` method in `worker.rs` creates a `Command::Heartbeat` enum variant and sends it to the datastore worker thread through a multi-producer, single-consumer (mpsc) channel. This decouples API handling from database operations.",
- "cellName": "[Rust Server] Queue Heartbeat Command - worker.rs:L385-399",
- "cellId": "b6b4c8cb-741a-4e38-b800-61273375cd64",
- "visible": true,
- "startLine": 385,
- "endLine": 399,
- "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
- "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3"
- }
- ]
- },
- "f0e92638-21d1-4b7e-9f2e-17b67a33ef78": {
- "path": "f0e92638-21d1-4b7e-9f2e-17b67a33ef78",
- "cellName": "[Rust Server] Process Heartbeat in Worker - worker.rs:L240-248",
- "cellId": "f0e92638-21d1-4b7e-9f2e-17b67a33ef78",
- "visible": true,
- "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e"
- },
- "aw-server-rust/aw-datastore/src/worker.rs-simstep-a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb": {
- "path": "aw-server-rust/aw-datastore/src/worker.rs-simstep-a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb",
- "fileName": "worker.rs",
- "wiki": "The `DatastoreWorker::handle_request` method receives the command, matches it to `Command::Heartbeat`, and calls the `heartbeat` method on the `DatastoreInstance`, which directly interacts with the SQLite database connection.",
- "cellName": "[Rust Server] Process Heartbeat in Worker - worker.rs:L240-248",
- "cellId": "f0e92638-21d1-4b7e-9f2e-17b67a33ef78",
- "visible": true,
- "startLine": 240,
- "endLine": 248,
- "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
- "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb"
- }
- ]
- },
- "b0093d22-e8cc-4e9e-8711-7e698b537efc": {
- "path": "b0093d22-e8cc-4e9e-8711-7e698b537efc",
- "cellName": "[Rust Server] Core Merge Logic - datastore.rs:L600-642",
- "cellId": "b0093d22-e8cc-4e9e-8711-7e698b537efc",
- "visible": true,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
- },
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-c59f4b10-f6c9-4fd8-ba70-ea60667a01e8": {
- "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-c59f4b10-f6c9-4fd8-ba70-ea60667a01e8",
- "fileName": "datastore.rs",
- "wiki": "The `DatastoreInstance::heartbeat` method retrieves the last event and calls `aw_transform::heartbeat`. This function checks for data equality and pulsetime. If successful, it returns a `Some(merged_event)`. If not, `None`.",
- "cellName": "[Rust Server] Core Merge Logic - datastore.rs:L600-642",
- "cellId": "b0093d22-e8cc-4e9e-8711-7e698b537efc",
- "visible": true,
- "startLine": 600,
- "endLine": 642,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "c59f4b10-f6c9-4fd8-ba70-ea60667a01e8"
- }
- ]
- },
- "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8": {
- "path": "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8",
- "cellName": "[Rust Server] Update Database - datastore.rs:L628-639",
- "cellId": "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8",
- "visible": true,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
- },
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-da146aa5-e96f-4db6-a36f-b405b1a11255": {
- "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-da146aa5-e96f-4db6-a36f-b405b1a11255",
- "fileName": "datastore.rs",
- "wiki": "Based on the result from `aw_transform::heartbeat`, the `DatastoreInstance::heartbeat` method either calls `self.replace_last_event` to update the last event in the database with the merged one, or `self.insert_events` to create a new event. The merged or new event is then cached and returned.",
- "cellName": "[Rust Server] Update Database - datastore.rs:L628-639",
- "cellId": "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8",
- "visible": true,
- "startLine": 628,
- "endLine": 639,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "da146aa5-e96f-4db6-a36f-b405b1a11255"
- }
- ]
- },
- "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f": {
- "path": "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
- "cellName": "Data Transmission:\nPass Event\nData for\nHeartbeat",
- "cellId": "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
- "visible": true,
- "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8"
- },
- "generated-edge-simstep-b6456941-3a8f-452d-a4eb-67915b00d5b3-4d96dbc5-cd5e-4ef9-8733-721776e8fb8f": {
- "path": "generated-edge-simstep-b6456941-3a8f-452d-a4eb-67915b00d5b3-4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
- "fileName": "macos.swift",
- "cellName": "Data Transmission: Pass Event Data for Heartbeat",
- "cellId": "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
- "visible": true,
- "startLine": 373,
- "endLine": 374,
- "parentCellId": "40ad45bd-b0eb-4f2c-a091-f933962a90b8",
- "parentPath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "b6456941-3a8f-452d-a4eb-67915b00d5b3"
- }
- ]
- },
- "a676f81f-8c68-4fc8-94b7-583bada02d70": {
- "path": "a676f81f-8c68-4fc8-94b7-583bada02d70",
- "cellName": "API Call:\nWatcher ->\nPython Server",
- "cellId": "a676f81f-8c68-4fc8-94b7-583bada02d70",
- "visible": true
- },
- "generated-edge-simstep-02717bea-6ee3-48ef-8c41-0c9f3e9d9a58-a676f81f-8c68-4fc8-94b7-583bada02d70": {
- "path": "generated-edge-simstep-02717bea-6ee3-48ef-8c41-0c9f3e9d9a58-a676f81f-8c68-4fc8-94b7-583bada02d70",
- "fileName": "rest.py",
- "cellName": "API Call: Watcher -> Python Server",
- "cellId": "a676f81f-8c68-4fc8-94b7-583bada02d70",
- "visible": true,
- "startLine": 272,
- "endLine": 272,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "02717bea-6ee3-48ef-8c41-0c9f3e9d9a58"
- }
- ]
- },
- "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75": {
- "path": "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
- "cellName": "Data Transmission:\nREST ->\nAPI Logic",
- "cellId": "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
- },
- "generated-edge-simstep-d57d2bf7-916c-44cd-844d-b1900c276925-a1b18b07-52a9-4bfe-ad37-bdae87d5bd75": {
- "path": "generated-edge-simstep-d57d2bf7-916c-44cd-844d-b1900c276925-a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
- "fileName": "rest.py",
- "cellName": "Data Transmission: REST -> API Logic",
- "cellId": "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
- "visible": true,
- "startLine": 300,
- "endLine": 300,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "d57d2bf7-916c-44cd-844d-b1900c276925"
- }
- ]
- },
- "9aec4875-5718-4c38-a57c-1d3053c38ba5": {
- "path": "9aec4875-5718-4c38-a57c-1d3053c38ba5",
- "cellName": "Data Transmission:\nPass Events\nto Merge\nFunction",
- "cellId": "9aec4875-5718-4c38-a57c-1d3053c38ba5",
- "visible": true
- },
- "generated-edge-simstep-40b16e25-734b-44d2-86cd-7c301723ff5f-9aec4875-5718-4c38-a57c-1d3053c38ba5": {
- "path": "generated-edge-simstep-40b16e25-734b-44d2-86cd-7c301723ff5f-9aec4875-5718-4c38-a57c-1d3053c38ba5",
- "fileName": "api.py",
- "cellName": "Data Transmission: Pass Events to Merge Function",
- "cellId": "9aec4875-5718-4c38-a57c-1d3053c38ba5",
- "visible": true,
- "startLine": 305,
- "endLine": 305,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "40b16e25-734b-44d2-86cd-7c301723ff5f"
- }
- ]
- },
- "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0": {
- "path": "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
- "cellName": "Data Transmission:\nReturn Merged\nEvent",
- "cellId": "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
- "visible": true
- },
- "generated-edge-simstep-9f918447-9e45-4c3b-b34f-658f58d35495-31cd2b01-8df9-4d95-9a91-d4c3aa153eb0": {
- "path": "generated-edge-simstep-9f918447-9e45-4c3b-b34f-658f58d35495-31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
- "fileName": "heartbeats.py",
- "cellName": "Data Transmission: Return Merged Event",
- "cellId": "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
- "visible": true,
- "startLine": 54,
- "endLine": 56,
- "parentCellId": "6860aa38-bc11-4d81-9260-87eba1c02581",
- "parentPath": "aw-core/aw_transform/heartbeats.py",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "9f918447-9e45-4c3b-b34f-658f58d35495"
- }
- ]
- },
- "2df6b81e-6b59-4aec-92c7-e9d9f2332be6": {
- "path": "2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
- "cellName": "API Call:\nWatcher ->\nRust Server",
- "cellId": "2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
- "visible": true
- },
- "generated-edge-simstep-7e361c3d-a5a9-45f3-a83d-98e39ff45675-2df6b81e-6b59-4aec-92c7-e9d9f2332be6": {
- "path": "generated-edge-simstep-7e361c3d-a5a9-45f3-a83d-98e39ff45675-2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
- "fileName": "bucket.rs",
- "cellName": "API Call: Watcher -> Rust Server",
- "cellId": "2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
- "visible": true,
- "startLine": 145,
- "endLine": 149,
- "parentCellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "7e361c3d-a5a9-45f3-a83d-98e39ff45675"
- }
- ]
- },
- "4a4afbdf-0303-4d84-bbf8-5121c74965a0": {
- "path": "4a4afbdf-0303-4d84-bbf8-5121c74965a0",
- "cellName": "Data Transmission:\nEndpoint ->\nDatastore",
- "cellId": "4a4afbdf-0303-4d84-bbf8-5121c74965a0",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-bfcc2f87-9167-4784-a3b3-f71d6e7a6e71-4a4afbdf-0303-4d84-bbf8-5121c74965a0": {
- "path": "generated-edge-simstep-bfcc2f87-9167-4784-a3b3-f71d6e7a6e71-4a4afbdf-0303-4d84-bbf8-5121c74965a0",
- "fileName": "bucket.rs",
- "cellName": "Data Transmission: Endpoint -> Datastore",
- "cellId": "4a4afbdf-0303-4d84-bbf8-5121c74965a0",
- "visible": true,
- "startLine": 158,
- "endLine": 158,
- "parentCellId": "0f86982d-c1d5-4ceb-8574-3e19c2db7159",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "bfcc2f87-9167-4784-a3b3-f71d6e7a6e71"
- }
- ]
- },
- "21d1c973-0f67-4aca-9d1b-eade3b5d347b": {
- "path": "21d1c973-0f67-4aca-9d1b-eade3b5d347b",
- "cellName": "Data Transmission:\nCommand Channel",
- "cellId": "21d1c973-0f67-4aca-9d1b-eade3b5d347b",
- "visible": true,
- "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e"
- },
- "generated-edge-simstep-eefd671a-3b08-4336-bd26-cb6eb04070ec-21d1c973-0f67-4aca-9d1b-eade3b5d347b": {
- "path": "generated-edge-simstep-eefd671a-3b08-4336-bd26-cb6eb04070ec-21d1c973-0f67-4aca-9d1b-eade3b5d347b",
- "fileName": "worker.rs",
- "cellName": "Data Transmission: Command Channel",
- "cellId": "21d1c973-0f67-4aca-9d1b-eade3b5d347b",
- "visible": true,
- "startLine": 167,
- "endLine": 175,
- "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
- "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "eefd671a-3b08-4336-bd26-cb6eb04070ec"
- }
- ]
- },
- "959b342e-eb44-4255-8176-1600a5fa17ac": {
- "path": "959b342e-eb44-4255-8176-1600a5fa17ac",
- "cellName": "Data Transmission:\nWorker ->\nDatastore Instance",
- "cellId": "959b342e-eb44-4255-8176-1600a5fa17ac",
- "visible": true,
- "parentCellId": "234cf403-9edd-4f7e-96eb-81e90587bbdc"
- },
- "generated-edge-simstep-9750ac2c-c0fb-4fe5-815f-398886fc827b-959b342e-eb44-4255-8176-1600a5fa17ac": {
- "path": "generated-edge-simstep-9750ac2c-c0fb-4fe5-815f-398886fc827b-959b342e-eb44-4255-8176-1600a5fa17ac",
- "fileName": "worker.rs",
- "cellName": "Data Transmission: Worker -> Datastore Instance",
- "cellId": "959b342e-eb44-4255-8176-1600a5fa17ac",
- "visible": true,
- "startLine": 241,
- "endLine": 241,
- "parentCellId": "c3bb8632-e3d6-4b2f-86ea-2472e155f19e",
- "parentPath": "aw-server-rust/aw-datastore/src/worker.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "9750ac2c-c0fb-4fe5-815f-398886fc827b"
- }
- ]
- },
- "0fe644bb-a583-40d8-9377-3641c90c4f62": {
- "path": "0fe644bb-a583-40d8-9377-3641c90c4f62",
- "cellName": "Data Transmission:\nPass Events\nto Merge\nFunction",
- "cellId": "0fe644bb-a583-40d8-9377-3641c90c4f62",
- "visible": true,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
- },
- "generated-edge-simstep-7b396541-e74f-4baf-9b1b-c1f7a914ba7a-0fe644bb-a583-40d8-9377-3641c90c4f62": {
- "path": "generated-edge-simstep-7b396541-e74f-4baf-9b1b-c1f7a914ba7a-0fe644bb-a583-40d8-9377-3641c90c4f62",
- "fileName": "datastore.rs",
- "cellName": "Data Transmission: Pass Events to Merge Function",
- "cellId": "0fe644bb-a583-40d8-9377-3641c90c4f62",
- "visible": true,
- "startLine": 628,
- "endLine": 628,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "simSteps": [
- {
- "simulationKey": "How the heartbeat API enables efficient tracking works",
- "simStepId": "7b396541-e74f-4baf-9b1b-c1f7a914ba7a"
- }
- ]
- },
- "315afad3-54aa-4009-bbe4-8e17ade01ec1": {
- "path": "315afad3-54aa-4009-bbe4-8e17ade01ec1",
- "cellName": "aw-qt",
- "cellId": "315afad3-54aa-4009-bbe4-8e17ade01ec1",
- "visible": true
- },
- "52098e1d-ea54-42f8-9e69-f6bd54686e33": {
- "path": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
- "cellName": "aw_qt",
- "cellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33",
- "visible": true,
- "parentCellId": "315afad3-54aa-4009-bbe4-8e17ade01ec1"
- },
- "9d82da70-d3bc-4199-9292-8dd7e71ab15d": {
- "path": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
- "cellName": "main.py",
- "cellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "f47c0efe-5fd2-488b-b325-b2965448260a": {
- "path": "f47c0efe-5fd2-488b-b325-b2965448260a",
- "cellName": "config.py",
- "cellId": "f47c0efe-5fd2-488b-b325-b2965448260a",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "f2489cff-231c-4352-baac-95f17e0f6395": {
- "path": "f2489cff-231c-4352-baac-95f17e0f6395",
- "cellName": "manager.py",
- "cellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "38fbe4ec-4658-4084-864e-b163e0540497": {
- "path": "38fbe4ec-4658-4084-864e-b163e0540497",
- "cellName": "trayicon.py",
- "cellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "d1bb4e12-29b6-4f70-9931-321214e3ea2a": {
- "path": "d1bb4e12-29b6-4f70-9931-321214e3ea2a",
- "cellName": "Application Entrypoint - main.py:L41-53",
- "cellId": "d1bb4e12-29b6-4f70-9931-321214e3ea2a",
- "visible": true,
- "parentCellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d"
- },
- "aw-qt/aw_qt/main.py-simstep-61d1a03e-ed06-496d-8495-36419b9c8607": {
- "path": "aw-qt/aw_qt/main.py-simstep-61d1a03e-ed06-496d-8495-36419b9c8607",
- "fileName": "main.py",
- "wiki": "The `aw-qt` application is launched. It parses command-line arguments, sets up logging, loads configuration, and initializes the `Manager`.",
- "cellName": "Application Entrypoint - main.py:L41-53",
- "cellId": "d1bb4e12-29b6-4f70-9931-321214e3ea2a",
- "visible": true,
- "startLine": 41,
- "endLine": 53,
- "parentCellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
- "parentPath": "aw-qt/aw_qt/main.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "61d1a03e-ed06-496d-8495-36419b9c8607"
- }
- ]
- },
- "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc": {
- "path": "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc",
- "cellName": "Read Configuration File - config.py:L16-24",
- "cellId": "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc",
- "visible": true,
- "parentCellId": "f47c0efe-5fd2-488b-b325-b2965448260a"
- },
- "aw-qt/aw_qt/config.py-simstep-c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a": {
- "path": "aw-qt/aw_qt/config.py-simstep-c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a",
- "fileName": "config.py",
- "wiki": "The `AwQtSettings` class reads the `aw-qt.toml` configuration file to determine which modules to autostart.",
- "cellName": "Read Configuration File - config.py:L16-24",
- "cellId": "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc",
- "visible": true,
- "startLine": 16,
- "endLine": 24,
- "parentCellId": "f47c0efe-5fd2-488b-b325-b2965448260a",
- "parentPath": "aw-qt/aw_qt/config.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a"
- }
- ]
- },
- "cae37571-f0ba-4abe-aefd-53e49f26137f": {
- "path": "cae37571-f0ba-4abe-aefd-53e49f26137f",
- "cellName": "Discover Modules - manager.py:L241-250",
- "cellId": "cae37571-f0ba-4abe-aefd-53e49f26137f",
- "visible": true,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
- },
- "aw-qt/aw_qt/manager.py-simstep-e716abbb-c96e-4613-bca2-0c094e8df129": {
- "path": "aw-qt/aw_qt/manager.py-simstep-e716abbb-c96e-4613-bca2-0c094e8df129",
- "fileName": "manager.py",
- "wiki": "The `Manager` class is instantiated and discovers all available `aw-*` executables. It searches for bundled modules within its own directory structure and for system-wide modules in the user's PATH.",
- "cellName": "Discover Modules - manager.py:L241-250",
- "cellId": "cae37571-f0ba-4abe-aefd-53e49f26137f",
- "visible": true,
- "startLine": 241,
- "endLine": 250,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "parentPath": "aw-qt/aw_qt/manager.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "e716abbb-c96e-4613-bca2-0c094e8df129"
- }
- ]
- },
- "8f981b6f-7bed-4d9a-8486-79f85b06d904": {
- "path": "8f981b6f-7bed-4d9a-8486-79f85b06d904",
- "cellName": "Spawn Module Process - manager.py:L147-172",
- "cellId": "8f981b6f-7bed-4d9a-8486-79f85b06d904",
- "visible": true,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
- },
- "aw-qt/aw_qt/manager.py-simstep-8be10173-751a-4da9-99a9-321c23e71aaa": {
- "path": "aw-qt/aw_qt/manager.py-simstep-8be10173-751a-4da9-99a9-321c23e71aaa",
- "fileName": "manager.py",
- "wiki": "For each module designated for autostart, the `Module.start` method is called. This method constructs the execution command and uses `subprocess.Popen` to launch the module as a new, independent process. `aw-server` is started first.",
- "cellName": "Spawn Module Process - manager.py:L147-172",
- "cellId": "8f981b6f-7bed-4d9a-8486-79f85b06d904",
- "visible": true,
- "startLine": 147,
- "endLine": 172,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "parentPath": "aw-qt/aw_qt/manager.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "8be10173-751a-4da9-99a9-321c23e71aaa"
- }
- ]
- },
- "4d657da7-6757-4d72-9324-765a991f73d7": {
- "path": "4d657da7-6757-4d72-9324-765a991f73d7",
- "cellName": "Initialize Tray Icon - trayicon.py:L207-211",
- "cellId": "4d657da7-6757-4d72-9324-765a991f73d7",
- "visible": true,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
- },
- "aw-qt/aw_qt/trayicon.py-simstep-6ae15f2e-5331-4153-b9d2-2a297b65c55f": {
- "path": "aw-qt/aw_qt/trayicon.py-simstep-6ae15f2e-5331-4153-b9d2-2a297b65c55f",
- "fileName": "trayicon.py",
- "wiki": "After attempting to start all autostart modules, the `trayicon.run` function is called. This initializes the PyQt application and creates the system tray icon, making ActivityWatch accessible to the user.",
- "cellName": "Initialize Tray Icon - trayicon.py:L207-211",
- "cellId": "4d657da7-6757-4d72-9324-765a991f73d7",
- "visible": true,
- "startLine": 207,
- "endLine": 211,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "6ae15f2e-5331-4153-b9d2-2a297b65c55f"
- }
- ]
- },
- "05bd0955-8e55-4657-80ee-f6389995db6d": {
- "path": "05bd0955-8e55-4657-80ee-f6389995db6d",
- "cellName": "Build Tray Menu - trayicon.py:L174-193",
- "cellId": "05bd0955-8e55-4657-80ee-f6389995db6d",
- "visible": true,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
- },
- "aw-qt/aw_qt/trayicon.py-simstep-08d88f03-4133-41d6-9cbb-0df16703b864": {
- "path": "aw-qt/aw_qt/trayicon.py-simstep-08d88f03-4133-41d6-9cbb-0df16703b864",
- "fileName": "trayicon.py",
- "wiki": "The `TrayIcon` constructor builds the context menu. It creates a 'Modules' submenu by iterating through the modules discovered by the manager. Each module is represented as a checkable menu item, with its initial state reflecting whether it's currently running.",
- "cellName": "Build Tray Menu - trayicon.py:L174-193",
- "cellId": "05bd0955-8e55-4657-80ee-f6389995db6d",
- "visible": true,
- "startLine": 174,
- "endLine": 193,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "08d88f03-4133-41d6-9cbb-0df16703b864"
- }
- ]
- },
- "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b": {
- "path": "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b",
- "cellName": "Toggle Module State - manager.py:L202-206",
- "cellId": "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b",
- "visible": true,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
- },
- "aw-qt/aw_qt/manager.py-simstep-520ab3f2-ef6c-4334-89fc-280f6d86d14b": {
- "path": "aw-qt/aw_qt/manager.py-simstep-520ab3f2-ef6c-4334-89fc-280f6d86d14b",
- "fileName": "manager.py",
- "wiki": "The `toggle` method in the `Module` class checks if the module is currently started. If it is, it calls `stop()`; otherwise, it calls `start()`.",
- "cellName": "Toggle Module State - manager.py:L202-206",
- "cellId": "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b",
- "visible": true,
- "startLine": 202,
- "endLine": 206,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "parentPath": "aw-qt/aw_qt/manager.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "520ab3f2-ef6c-4334-89fc-280f6d86d14b"
- }
- ]
- },
- "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5": {
- "path": "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5",
- "cellName": "Periodic Status Check - trayicon.py:L149-158",
- "cellId": "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5",
- "visible": true,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
- },
- "aw-qt/aw_qt/trayicon.py-simstep-01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9": {
- "path": "aw-qt/aw_qt/trayicon.py-simstep-01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9",
- "fileName": "trayicon.py",
- "wiki": "A recurring timer in `TrayIcon` triggers `rebuild_modules_menu` every 2 seconds. This function updates the checkmarks in the 'Modules' menu to reflect the current running status of each module.",
- "cellName": "Periodic Status Check - trayicon.py:L149-158",
- "cellId": "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5",
- "visible": true,
- "startLine": 149,
- "endLine": 158,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9"
- }
- ]
- },
- "421b1687-98a6-4773-a7dc-cdc564be5f8e": {
- "path": "421b1687-98a6-4773-a7dc-cdc564be5f8e",
- "cellName": "Check if Module Process is Alive - manager.py:L208-214",
- "cellId": "421b1687-98a6-4773-a7dc-cdc564be5f8e",
- "visible": true,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
- },
- "aw-qt/aw_qt/manager.py-simstep-899b57ba-4a68-4620-977a-80981d089e85": {
- "path": "aw-qt/aw_qt/manager.py-simstep-899b57ba-4a68-4620-977a-80981d089e85",
- "fileName": "manager.py",
- "wiki": "The `is_alive` method polls the subprocess to check its status. It returns `True` if the process is running and `False` otherwise.",
- "cellName": "Check if Module Process is Alive - manager.py:L208-214",
- "cellId": "421b1687-98a6-4773-a7dc-cdc564be5f8e",
- "visible": true,
- "startLine": 208,
- "endLine": 214,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "parentPath": "aw-qt/aw_qt/manager.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "899b57ba-4a68-4620-977a-80981d089e85"
- }
- ]
- },
- "5dd0e28d-e0e9-4433-8db9-e8de93de1abe": {
- "path": "5dd0e28d-e0e9-4433-8db9-e8de93de1abe",
- "cellName": "Identify Unexpectedly Stopped Modules - manager.py:L252-253",
- "cellId": "5dd0e28d-e0e9-4433-8db9-e8de93de1abe",
- "visible": true,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
- },
- "aw-qt/aw_qt/manager.py-simstep-6173a9e1-ecfa-4dd9-9f82-f80579406011": {
- "path": "aw-qt/aw_qt/manager.py-simstep-6173a9e1-ecfa-4dd9-9f82-f80579406011",
- "fileName": "manager.py",
- "wiki": "The `get_unexpected_stops` method filters the list of all modules, returning those that are marked as `started` but are no longer `alive`.",
- "cellName": "Identify Unexpectedly Stopped Modules - manager.py:L252-253",
- "cellId": "5dd0e28d-e0e9-4433-8db9-e8de93de1abe",
- "visible": true,
- "startLine": 252,
- "endLine": 253,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "parentPath": "aw-qt/aw_qt/manager.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "6173a9e1-ecfa-4dd9-9f82-f80579406011"
- }
- ]
- },
- "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc": {
- "path": "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc",
- "cellName": "Display Failure Dialog - trayicon.py:L136-147",
- "cellId": "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc",
- "visible": true,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
- },
- "aw-qt/aw_qt/trayicon.py-simstep-a71f6cd0-490a-40b5-8a05-1c873f208882": {
- "path": "aw-qt/aw_qt/trayicon.py-simstep-a71f6cd0-490a-40b5-8a05-1c873f208882",
- "fileName": "trayicon.py",
- "wiki": "A `QMessageBox` is displayed to the user, informing them that a module has quit unexpectedly. The dialog includes the module's logs and provides a button to restart the module.",
- "cellName": "Display Failure Dialog - trayicon.py:L136-147",
- "cellId": "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc",
- "visible": true,
- "startLine": 136,
- "endLine": 147,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "a71f6cd0-490a-40b5-8a05-1c873f208882"
- }
- ]
- },
- "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7": {
- "path": "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
- "cellName": "Load Autostart\nConfig",
- "cellId": "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "generated-edge-simstep-6084ca69-514e-4bde-b2c0-1d33b26203e8-1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7": {
- "path": "generated-edge-simstep-6084ca69-514e-4bde-b2c0-1d33b26203e8-1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
- "fileName": "main.py",
- "cellName": "Load Autostart Config",
- "cellId": "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
- "visible": true,
- "startLine": 70,
- "endLine": 70,
- "parentCellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
- "parentPath": "aw-qt/aw_qt/main.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "6084ca69-514e-4bde-b2c0-1d33b26203e8"
- }
- ]
- },
- "030668a5-a377-4710-b39f-95efb5fa4768": {
- "path": "030668a5-a377-4710-b39f-95efb5fa4768",
- "cellName": "Pass Config\nto Manager",
- "cellId": "030668a5-a377-4710-b39f-95efb5fa4768",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "generated-edge-simstep-540119c2-b541-4342-aa59-233b4f0f8db5-030668a5-a377-4710-b39f-95efb5fa4768": {
- "path": "generated-edge-simstep-540119c2-b541-4342-aa59-233b4f0f8db5-030668a5-a377-4710-b39f-95efb5fa4768",
- "fileName": "main.py",
- "cellName": "Pass Config to Manager",
- "cellId": "030668a5-a377-4710-b39f-95efb5fa4768",
- "visible": true,
- "startLine": 77,
- "endLine": 78,
- "parentCellId": "9d82da70-d3bc-4199-9292-8dd7e71ab15d",
- "parentPath": "aw-qt/aw_qt/main.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "540119c2-b541-4342-aa59-233b4f0f8db5"
- }
- ]
- },
- "1fb5a75e-9c49-490d-b412-04ac1c7205fa": {
- "path": "1fb5a75e-9c49-490d-b412-04ac1c7205fa",
- "cellName": "Initiate Autostart\nSequence",
- "cellId": "1fb5a75e-9c49-490d-b412-04ac1c7205fa",
- "visible": true,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
- },
- "generated-edge-simstep-9aeaf443-6741-4557-9671-67d596f456b3-1fb5a75e-9c49-490d-b412-04ac1c7205fa": {
- "path": "generated-edge-simstep-9aeaf443-6741-4557-9671-67d596f456b3-1fb5a75e-9c49-490d-b412-04ac1c7205fa",
- "fileName": "manager.py",
- "cellName": "Initiate Autostart Sequence",
- "cellId": "1fb5a75e-9c49-490d-b412-04ac1c7205fa",
- "visible": true,
- "startLine": 276,
- "endLine": 286,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "parentPath": "aw-qt/aw_qt/manager.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "9aeaf443-6741-4557-9671-67d596f456b3"
- }
- ]
- },
- "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9": {
- "path": "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
- "cellName": "Module Process\nRunning",
- "cellId": "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "generated-edge-simstep-f968357d-53c4-41e8-b71f-c581c08b52e6-a5cd2cce-2771-436e-9fc7-aa013ee8bbc9": {
- "path": "generated-edge-simstep-f968357d-53c4-41e8-b71f-c581c08b52e6-a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
- "fileName": "manager.py",
- "cellName": "Module Process Running",
- "cellId": "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
- "visible": true,
- "startLine": 169,
- "endLine": 171,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "parentPath": "aw-qt/aw_qt/manager.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "f968357d-53c4-41e8-b71f-c581c08b52e6"
- }
- ]
- },
- "dfaa3fc8-eca8-4c67-b926-87798f511adb": {
- "path": "dfaa3fc8-eca8-4c67-b926-87798f511adb",
- "cellName": "Create Tray\nIcon Instance",
- "cellId": "dfaa3fc8-eca8-4c67-b926-87798f511adb",
- "visible": true,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497"
- },
- "generated-edge-simstep-03fd319d-4ffe-47cf-bf39-ac388da80fa7-dfaa3fc8-eca8-4c67-b926-87798f511adb": {
- "path": "generated-edge-simstep-03fd319d-4ffe-47cf-bf39-ac388da80fa7-dfaa3fc8-eca8-4c67-b926-87798f511adb",
- "fileName": "trayicon.py",
- "cellName": "Create Tray Icon Instance",
- "cellId": "dfaa3fc8-eca8-4c67-b926-87798f511adb",
- "visible": true,
- "startLine": 259,
- "endLine": 260,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "03fd319d-4ffe-47cf-bf39-ac388da80fa7"
- }
- ]
- },
- "d9e460b6-432d-49c8-8e76-0d8750aa2c10": {
- "path": "d9e460b6-432d-49c8-8e76-0d8750aa2c10",
- "cellName": "User Toggles\nModule",
- "cellId": "d9e460b6-432d-49c8-8e76-0d8750aa2c10",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "generated-edge-simstep-8e583414-7b87-42c9-bdb2-e56259be4cdf-d9e460b6-432d-49c8-8e76-0d8750aa2c10": {
- "path": "generated-edge-simstep-8e583414-7b87-42c9-bdb2-e56259be4cdf-d9e460b6-432d-49c8-8e76-0d8750aa2c10",
- "fileName": "trayicon.py",
- "cellName": "User Toggles Module",
- "cellId": "d9e460b6-432d-49c8-8e76-0d8750aa2c10",
- "visible": true,
- "startLine": 179,
- "endLine": 179,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "8e583414-7b87-42c9-bdb2-e56259be4cdf"
- }
- ]
- },
- "9d4dee50-64ef-459a-98fa-839761e16813": {
- "path": "9d4dee50-64ef-459a-98fa-839761e16813",
- "cellName": "Send Termination\nSignal",
- "cellId": "9d4dee50-64ef-459a-98fa-839761e16813",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "generated-edge-simstep-fdff8ecd-12b9-4bc0-ba7b-9402d26b1737-9d4dee50-64ef-459a-98fa-839761e16813": {
- "path": "generated-edge-simstep-fdff8ecd-12b9-4bc0-ba7b-9402d26b1737-9d4dee50-64ef-459a-98fa-839761e16813",
- "fileName": "manager.py",
- "cellName": "Send Termination Signal",
- "cellId": "9d4dee50-64ef-459a-98fa-839761e16813",
- "visible": true,
- "startLine": 191,
- "endLine": 191,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395",
- "parentPath": "aw-qt/aw_qt/manager.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "fdff8ecd-12b9-4bc0-ba7b-9402d26b1737"
- }
- ]
- },
- "f704019b-d227-47ad-8761-9a2ea01516cb": {
- "path": "f704019b-d227-47ad-8761-9a2ea01516cb",
- "cellName": "Query Module\nProcess State",
- "cellId": "f704019b-d227-47ad-8761-9a2ea01516cb",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "generated-edge-simstep-c0115129-b34b-4d27-9f73-cf2dc142ea81-f704019b-d227-47ad-8761-9a2ea01516cb": {
- "path": "generated-edge-simstep-c0115129-b34b-4d27-9f73-cf2dc142ea81-f704019b-d227-47ad-8761-9a2ea01516cb",
- "fileName": "trayicon.py",
- "cellName": "Query Module Process State",
- "cellId": "f704019b-d227-47ad-8761-9a2ea01516cb",
- "visible": true,
- "startLine": 153,
- "endLine": 153,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "c0115129-b34b-4d27-9f73-cf2dc142ea81"
- }
- ]
- },
- "ba9e605d-98a7-4b50-979a-05bf7213c681": {
- "path": "ba9e605d-98a7-4b50-979a-05bf7213c681",
- "cellName": "Check for\nUnexpected Stops",
- "cellId": "ba9e605d-98a7-4b50-979a-05bf7213c681",
- "visible": true,
- "parentCellId": "f2489cff-231c-4352-baac-95f17e0f6395"
- },
- "generated-edge-simstep-7775ac80-c954-464e-b230-b233216ee5e3-ba9e605d-98a7-4b50-979a-05bf7213c681": {
- "path": "generated-edge-simstep-7775ac80-c954-464e-b230-b233216ee5e3-ba9e605d-98a7-4b50-979a-05bf7213c681",
- "fileName": "trayicon.py",
- "cellName": "Check for Unexpected Stops",
- "cellId": "ba9e605d-98a7-4b50-979a-05bf7213c681",
- "visible": true,
- "startLine": 163,
- "endLine": 163,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "7775ac80-c954-464e-b230-b233216ee5e3"
- }
- ]
- },
- "2298c4b5-17de-487f-b592-2ac0f95eca84": {
- "path": "2298c4b5-17de-487f-b592-2ac0f95eca84",
- "cellName": "Trigger Failure\nNotification",
- "cellId": "2298c4b5-17de-487f-b592-2ac0f95eca84",
- "visible": true,
- "parentCellId": "52098e1d-ea54-42f8-9e69-f6bd54686e33"
- },
- "generated-edge-simstep-1ed5cd16-b593-41cf-84f2-233a8d64a227-2298c4b5-17de-487f-b592-2ac0f95eca84": {
- "path": "generated-edge-simstep-1ed5cd16-b593-41cf-84f2-233a8d64a227-2298c4b5-17de-487f-b592-2ac0f95eca84",
- "fileName": "trayicon.py",
- "cellName": "Trigger Failure Notification",
- "cellId": "2298c4b5-17de-487f-b592-2ac0f95eca84",
- "visible": true,
- "startLine": 166,
- "endLine": 166,
- "parentCellId": "38fbe4ec-4658-4084-864e-b163e0540497",
- "parentPath": "aw-qt/aw_qt/trayicon.py",
- "simSteps": [
- {
- "simulationKey": "How the module manager and tray icon works",
- "simStepId": "1ed5cd16-b593-41cf-84f2-233a8d64a227"
- }
- ]
- },
- "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1": {
- "path": "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1",
- "cellName": "Start Notification Service - main.py:L340-360",
- "cellId": "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "aw-notify/aw_notify/main.py-simstep-9b9a0f90-d7a7-40fb-8573-53b470ecf85d": {
- "path": "aw-notify/aw_notify/main.py-simstep-9b9a0f90-d7a7-40fb-8573-53b470ecf85d",
- "fileName": "main.py",
- "wiki": "The `aw-notify` service is started from the command line, which calls the `main` function. `main` in turn invokes the `start` function to begin the notification service.",
- "cellName": "Start Notification Service - main.py:L340-360",
- "cellId": "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1",
- "visible": true,
- "startLine": 340,
- "endLine": 360,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "9b9a0f90-d7a7-40fb-8573-53b470ecf85d"
- }
- ]
- },
- "553f1437-5c34-4d6d-8226-417014259fc5": {
- "path": "553f1437-5c34-4d6d-8226-417014259fc5",
- "cellName": "Initialize Threshold Alerts - main.py:L380-392",
- "cellId": "553f1437-5c34-4d6d-8226-417014259fc5",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "aw-notify/aw_notify/main.py-simstep-f636bdd6-a8e3-47ec-9f9d-986b21a81868": {
- "path": "aw-notify/aw_notify/main.py-simstep-f636bdd6-a8e3-47ec-9f9d-986b21a81868",
- "fileName": "main.py",
- "wiki": "The `threshold_alerts` function is called, which creates a list of `CategoryAlert` objects. Each object is configured with a specific category to monitor (e.g., 'Work', 'Twitter'), a list of time thresholds, and a display label.",
- "cellName": "Initialize Threshold Alerts - main.py:L380-392",
- "cellId": "553f1437-5c34-4d6d-8226-417014259fc5",
- "visible": true,
- "startLine": 380,
- "endLine": 392,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "f636bdd6-a8e3-47ec-9f9d-986b21a81868"
- }
- ]
- },
- "1de089eb-60a7-4d7f-bfb5-3f7f23315873": {
- "path": "1de089eb-60a7-4d7f-bfb5-3f7f23315873",
- "cellName": "Update Category Time - main.py:L262-276",
- "cellId": "1de089eb-60a7-4d7f-bfb5-3f7f23315873",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "aw-notify/aw_notify/main.py-simstep-945e3312-c7c9-4722-953b-94dc0feee249": {
- "path": "aw-notify/aw_notify/main.py-simstep-945e3312-c7c9-4722-953b-94dc0feee249",
- "fileName": "main.py",
- "wiki": "The `update` method of a `CategoryAlert` instance is called. It checks if enough time has passed to warrant a new query to the server. If so, it calls `get_time()` to fetch the latest activity duration for its category.",
- "cellName": "Update Category Time - main.py:L262-276",
- "cellId": "1de089eb-60a7-4d7f-bfb5-3f7f23315873",
- "visible": true,
- "startLine": 262,
- "endLine": 276,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "945e3312-c7c9-4722-953b-94dc0feee249"
- }
- ]
- },
- "e567d898-2785-43f6-98ef-f4b6d1232620": {
- "path": "e567d898-2785-43f6-98ef-f4b6d1232620",
- "cellName": "Server: Receive and Process Query - query.rs:L9-12",
- "cellId": "e567d898-2785-43f6-98ef-f4b6d1232620",
- "visible": true,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
- },
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-868edfd6-1f03-416e-88dc-7b09d05e4ba5": {
- "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-868edfd6-1f03-416e-88dc-7b09d05e4ba5",
- "fileName": "query.rs",
- "wiki": "The `aw-server-rust` instance receives the POST request at the `/api/0/query` endpoint. The request body, containing the query and time periods, is deserialized.",
- "cellName": "Server: Receive and Process Query - query.rs:L9-12",
- "cellId": "e567d898-2785-43f6-98ef-f4b6d1232620",
- "visible": true,
- "startLine": 9,
- "endLine": 12,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "868edfd6-1f03-416e-88dc-7b09d05e4ba5"
- }
- ]
- },
- "44016962-bb6d-4a70-b13c-4538926a02a4": {
- "path": "44016962-bb6d-4a70-b13c-4538926a02a4",
- "cellName": "Server: Fetch Events from Datastore - functions.rs:L150-162",
- "cellId": "44016962-bb6d-4a70-b13c-4538926a02a4",
- "visible": true,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e"
- },
- "aw-server-rust/aw-query/src/functions.rs-simstep-cc5cfecf-cee9-4582-aa6c-b74787a11da8": {
- "path": "aw-server-rust/aw-query/src/functions.rs-simstep-cc5cfecf-cee9-4582-aa6c-b74787a11da8",
- "fileName": "functions.rs",
- "wiki": "The query interpreter executes the `query_bucket` function from the query string. This function calls `ds.get_events` on the datastore to retrieve all relevant raw events within the specified time interval from the SQLite database.",
- "cellName": "Server: Fetch Events from Datastore - functions.rs:L150-162",
- "cellId": "44016962-bb6d-4a70-b13c-4538926a02a4",
- "visible": true,
- "startLine": 150,
- "endLine": 162,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "parentPath": "aw-server-rust/aw-query/src/functions.rs",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "cc5cfecf-cee9-4582-aa6c-b74787a11da8"
- }
- ]
- },
- "fd5d1362-e41b-43af-bfd8-7f7c344c9849": {
- "path": "fd5d1362-e41b-43af-bfd8-7f7c344c9849",
- "cellName": "Server: Send Query Result - query.rs:L28",
- "cellId": "fd5d1362-e41b-43af-bfd8-7f7c344c9849",
- "visible": true,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
- },
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-f52d6bfa-55fe-49ee-9f20-60bf296c76f4": {
- "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-f52d6bfa-55fe-49ee-9f20-60bf296c76f4",
- "fileName": "query.rs",
- "wiki": "After all transformations are complete, the query engine returns the final processed data. The server serializes this data into a JSON array and sends it back as the HTTP response.",
- "cellName": "Server: Send Query Result - query.rs:L28",
- "cellId": "fd5d1362-e41b-43af-bfd8-7f7c344c9849",
- "visible": true,
- "startLine": 28,
- "endLine": 28,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "f52d6bfa-55fe-49ee-9f20-60bf296c76f4"
- }
- ]
- },
- "a01b5cc8-f12f-447b-9879-6b55bda0ef87": {
- "path": "a01b5cc8-f12f-447b-9879-6b55bda0ef87",
- "cellName": "Process Query Result and Update State - main.py:L123-130",
- "cellId": "a01b5cc8-f12f-447b-9879-6b55bda0ef87",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "aw-notify/aw_notify/main.py-simstep-9c0b3f20-5c18-418a-82f7-78b04ebda9b5": {
- "path": "aw-notify/aw_notify/main.py-simstep-9c0b3f20-5c18-418a-82f7-78b04ebda9b5",
- "fileName": "main.py",
- "wiki": "The `get_time` function processes the server response, creating a dictionary mapping each category to its total duration. This dictionary is returned to the `update` method, which then updates the `time_spent` attribute of the `CategoryAlert` instance.",
- "cellName": "Process Query Result and Update State - main.py:L123-130",
- "cellId": "a01b5cc8-f12f-447b-9879-6b55bda0ef87",
- "visible": true,
- "startLine": 123,
- "endLine": 130,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "9c0b3f20-5c18-418a-82f7-78b04ebda9b5"
- }
- ]
- },
- "30303464-f5f8-4155-87e9-b81dda8175d9": {
- "path": "30303464-f5f8-4155-87e9-b81dda8175d9",
- "cellName": "Trigger Desktop Notification - main.py:L281-297",
- "cellId": "30303464-f5f8-4155-87e9-b81dda8175d9",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "aw-notify/aw_notify/main.py-simstep-a66f8ebc-93f8-4f9c-8f19-03bd951d1e98": {
- "path": "aw-notify/aw_notify/main.py-simstep-a66f8ebc-93f8-4f9c-8f19-03bd951d1e98",
- "fileName": "main.py",
- "wiki": "A threshold has been reached (e.g., time spent on 'Work' exceeds 1 hour). The `check` method calls the `notify` function, passing it a title and a formatted message to be displayed to the user.",
- "cellName": "Trigger Desktop Notification - main.py:L281-297",
- "cellId": "30303464-f5f8-4155-87e9-b81dda8175d9",
- "visible": true,
- "startLine": 281,
- "endLine": 297,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "a66f8ebc-93f8-4f9c-8f19-03bd951d1e98"
- }
- ]
- },
- "445477ac-c52d-4053-a45e-8c81da805c88": {
- "path": "445477ac-c52d-4053-a45e-8c81da805c88",
- "cellName": "User sees notification - main.py:L149-184",
- "cellId": "445477ac-c52d-4053-a45e-8c81da805c88",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "aw-notify/aw_notify/main.py-simstep-21533839-7ba4-4cfa-864a-2f67198cad68": {
- "path": "aw-notify/aw_notify/main.py-simstep-21533839-7ba4-4cfa-864a-2f67198cad68",
- "fileName": "main.py",
- "wiki": "The operating system displays a native notification on the user's desktop with the message '💼 Work: 1h'.",
- "cellName": "User sees notification - main.py:L149-184",
- "cellId": "445477ac-c52d-4053-a45e-8c81da805c88",
- "visible": true,
- "startLine": 149,
- "endLine": 184,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "21533839-7ba4-4cfa-864a-2f67198cad68"
- }
- ]
- },
- "f9ddc0fb-c342-4a4a-baec-53c6a2581b80": {
- "path": "f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
- "cellName": "Initialize Client\nand Get\nHostname",
- "cellId": "f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "generated-edge-simstep-3c977159-c34d-4907-9004-e5aaff3f3bdc-f9ddc0fb-c342-4a4a-baec-53c6a2581b80": {
- "path": "generated-edge-simstep-3c977159-c34d-4907-9004-e5aaff3f3bdc-f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
- "fileName": "main.py",
- "cellName": "Initialize Client and Get Hostname",
- "cellId": "f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
- "visible": true,
- "startLine": 368,
- "endLine": 370,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "3c977159-c34d-4907-9004-e5aaff3f3bdc"
- }
- ]
- },
- "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e": {
- "path": "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
- "cellName": "Enter Main\nLoop",
- "cellId": "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "generated-edge-simstep-7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b-22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e": {
- "path": "generated-edge-simstep-7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b-22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
- "fileName": "main.py",
- "cellName": "Enter Main Loop",
- "cellId": "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
- "visible": true,
- "startLine": 400,
- "endLine": 401,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b"
- }
- ]
- },
- "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd": {
- "path": "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
- "cellName": "API Call:\nQuery Server\nfor Activity\nData",
- "cellId": "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
- "visible": true
- },
- "generated-edge-simstep-f20bb756-15f3-4a7c-914b-aa61470cc435-5f61c8f5-897a-4dc2-81df-1eda2d84d5bd": {
- "path": "generated-edge-simstep-f20bb756-15f3-4a7c-914b-aa61470cc435-5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
- "fileName": "main.py",
- "cellName": "API Call: Query Server for Activity Data",
- "cellId": "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
- "visible": true,
- "startLine": 120,
- "endLine": 120,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "f20bb756-15f3-4a7c-914b-aa61470cc435"
- }
- ]
- },
- "8f02d20c-25fe-4a28-99de-3e8908d0a66f": {
- "path": "8f02d20c-25fe-4a28-99de-3e8908d0a66f",
- "cellName": "Server: Execute\nQuery",
- "cellId": "8f02d20c-25fe-4a28-99de-3e8908d0a66f",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-b835d5e0-434d-4469-94fe-d309114a9ef1-8f02d20c-25fe-4a28-99de-3e8908d0a66f": {
- "path": "generated-edge-simstep-b835d5e0-434d-4469-94fe-d309114a9ef1-8f02d20c-25fe-4a28-99de-3e8908d0a66f",
- "fileName": "query.rs",
- "cellName": "Server: Execute Query",
- "cellId": "8f02d20c-25fe-4a28-99de-3e8908d0a66f",
- "visible": true,
- "startLine": 16,
- "endLine": 16,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "b835d5e0-434d-4469-94fe-d309114a9ef1"
- }
- ]
- },
- "5595958a-cf9d-4894-9824-ecc89e5cf956": {
- "path": "5595958a-cf9d-4894-9824-ecc89e5cf956",
- "cellName": "Server: Transform\nRaw Events",
- "cellId": "5595958a-cf9d-4894-9824-ecc89e5cf956",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-027140c6-aa16-4070-89d3-3b553168e65e-5595958a-cf9d-4894-9824-ecc89e5cf956": {
- "path": "generated-edge-simstep-027140c6-aa16-4070-89d3-3b553168e65e-5595958a-cf9d-4894-9824-ecc89e5cf956",
- "fileName": "main.py",
- "cellName": "Server: Transform Raw Events",
- "cellId": "5595958a-cf9d-4894-9824-ecc89e5cf956",
- "visible": true,
- "startLine": 115,
- "endLine": 115,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "027140c6-aa16-4070-89d3-3b553168e65e"
- }
- ]
- },
- "1b9dc1d5-e6a7-4069-8473-2156853d662e": {
- "path": "1b9dc1d5-e6a7-4069-8473-2156853d662e",
- "cellName": "Data Flow:\nReceive and\nParse Server\nResponse",
- "cellId": "1b9dc1d5-e6a7-4069-8473-2156853d662e",
- "visible": true
- },
- "generated-edge-simstep-92487214-03b7-430e-aab5-b5a5fb85b2cb-1b9dc1d5-e6a7-4069-8473-2156853d662e": {
- "path": "generated-edge-simstep-92487214-03b7-430e-aab5-b5a5fb85b2cb-1b9dc1d5-e6a7-4069-8473-2156853d662e",
- "fileName": "main.py",
- "cellName": "Data Flow: Receive and Parse Server Response",
- "cellId": "1b9dc1d5-e6a7-4069-8473-2156853d662e",
- "visible": true,
- "startLine": 120,
- "endLine": 120,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "92487214-03b7-430e-aab5-b5a5fb85b2cb"
- }
- ]
- },
- "08e05622-d948-47eb-a56d-3d6782d638c0": {
- "path": "08e05622-d948-47eb-a56d-3d6782d638c0",
- "cellName": "Check for\nThreshold Breach",
- "cellId": "08e05622-d948-47eb-a56d-3d6782d638c0",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "generated-edge-simstep-c8b0fe19-76a8-458d-9923-c2f270e306b3-08e05622-d948-47eb-a56d-3d6782d638c0": {
- "path": "generated-edge-simstep-c8b0fe19-76a8-458d-9923-c2f270e306b3-08e05622-d948-47eb-a56d-3d6782d638c0",
- "fileName": "main.py",
- "cellName": "Check for Threshold Breach",
- "cellId": "08e05622-d948-47eb-a56d-3d6782d638c0",
- "visible": true,
- "startLine": 402,
- "endLine": 402,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "c8b0fe19-76a8-458d-9923-c2f270e306b3"
- }
- ]
- },
- "17c4cd6c-69f5-4df8-ac77-6955a0518939": {
- "path": "17c4cd6c-69f5-4df8-ac77-6955a0518939",
- "cellName": "Render Notification",
- "cellId": "17c4cd6c-69f5-4df8-ac77-6955a0518939",
- "visible": true,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358"
- },
- "generated-edge-simstep-e46653da-3493-419e-8f9c-397be83fe894-17c4cd6c-69f5-4df8-ac77-6955a0518939": {
- "path": "generated-edge-simstep-e46653da-3493-419e-8f9c-397be83fe894-17c4cd6c-69f5-4df8-ac77-6955a0518939",
- "fileName": "main.py",
- "cellName": "Render Notification",
- "cellId": "17c4cd6c-69f5-4df8-ac77-6955a0518939",
- "visible": true,
- "startLine": 161,
- "endLine": 177,
- "parentCellId": "954ebccb-39ec-4c50-aca4-0ac8c09e6358",
- "parentPath": "aw-notify/aw_notify/main.py",
- "simSteps": [
- {
- "simulationKey": "How time-based notifications work",
- "simStepId": "e46653da-3493-419e-8f9c-397be83fe894"
- }
- ]
- },
- "a1e562ae-ea06-4c6a-ab92-fa78417115f6": {
- "path": "a1e562ae-ea06-4c6a-ab92-fa78417115f6",
- "cellName": "Export Flow: Client Initiates Data Export - client.py:L291-292",
- "cellId": "a1e562ae-ea06-4c6a-ab92-fa78417115f6",
- "visible": true,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
- },
- "aw-client/aw_client/client.py-simstep-8739f5eb-aec2-47f1-b1e6-a05a2bb65acd": {
- "path": "aw-client/aw_client/client.py-simstep-8739f5eb-aec2-47f1-b1e6-a05a2bb65acd",
- "fileName": "client.py",
- "wiki": "A client application, using `aw-client`, calls the `export_all` method to begin the process of exporting all user data from the ActivityWatch server.",
- "cellName": "Export Flow: Client Initiates Data Export - client.py:L291-292",
- "cellId": "a1e562ae-ea06-4c6a-ab92-fa78417115f6",
- "visible": true,
- "startLine": 291,
- "endLine": 292,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "8739f5eb-aec2-47f1-b1e6-a05a2bb65acd"
- }
- ]
- },
- "07e4d089-e23f-4030-8c10-7dbdbd00e1c7": {
- "path": "07e4d089-e23f-4030-8c10-7dbdbd00e1c7",
- "cellName": "Export Flow: Server Handles Export Request - rest.py:L332-344",
- "cellId": "07e4d089-e23f-4030-8c10-7dbdbd00e1c7",
- "visible": true,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
- },
- "aw-server/aw_server/rest.py-simstep-7bdce779-492f-4dee-a68d-4e6d28dc079a": {
- "path": "aw-server/aw_server/rest.py-simstep-7bdce779-492f-4dee-a68d-4e6d28dc079a",
- "fileName": "rest.py",
- "wiki": "The `aw-server` (Flask application) receives the GET request and routes it to the `get` method of the `ExportAllResource` class, which is responsible for handling data exports.",
- "cellName": "Export Flow: Server Handles Export Request - rest.py:L332-344",
- "cellId": "07e4d089-e23f-4030-8c10-7dbdbd00e1c7",
- "visible": true,
- "startLine": 332,
- "endLine": 344,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "7bdce779-492f-4dee-a68d-4e6d28dc079a"
- }
- ]
- },
- "19faa606-15ad-4c47-a983-692a1f30a667": {
- "path": "19faa606-15ad-4c47-a983-692a1f30a667",
- "cellName": "Export Flow: Aggregate All Buckets and Events - api.py:L97-103",
- "cellId": "19faa606-15ad-4c47-a983-692a1f30a667",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6": {
- "path": "aw-server/aw_server/api.py-simstep-d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6",
- "fileName": "api.py",
- "wiki": "The `export_all` method in the `ServerAPI` class begins by fetching all existing buckets. It then iterates through each bucket to export its metadata and all associated events.",
- "cellName": "Export Flow: Aggregate All Buckets and Events - api.py:L97-103",
- "cellId": "19faa606-15ad-4c47-a983-692a1f30a667",
- "visible": true,
- "startLine": 97,
- "endLine": 103,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6"
- }
- ]
- },
- "e590d109-3712-4d3d-9241-ba9cd9a7eeaa": {
- "path": "e590d109-3712-4d3d-9241-ba9cd9a7eeaa",
- "cellName": "Export Flow: Datastore Retrieves Events - api.py:L214-228",
- "cellId": "e590d109-3712-4d3d-9241-ba9cd9a7eeaa",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-5fb7b7d5-1759-43dc-a711-b2b0b5df3893": {
- "path": "aw-server/aw_server/api.py-simstep-5fb7b7d5-1759-43dc-a711-b2b0b5df3893",
- "fileName": "api.py",
- "wiki": "The `get_events` function in the API layer queries the datastore, which fetches the corresponding events from the underlying database (e.g., SQLite).",
- "cellName": "Export Flow: Datastore Retrieves Events - api.py:L214-228",
- "cellId": "e590d109-3712-4d3d-9241-ba9cd9a7eeaa",
- "visible": true,
- "startLine": 214,
- "endLine": 228,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "5fb7b7d5-1759-43dc-a711-b2b0b5df3893"
- }
- ]
- },
- "6e7e85b1-9708-4f64-ac9e-efc54338c444": {
- "path": "6e7e85b1-9708-4f64-ac9e-efc54338c444",
- "cellName": "Export Flow: Server Sends JSON File Response - rest.py:L336-344",
- "cellId": "6e7e85b1-9708-4f64-ac9e-efc54338c444",
- "visible": true,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
- },
- "aw-server/aw_server/rest.py-simstep-cfd637bd-f6b2-44cf-8330-7b2c59c0658b": {
- "path": "aw-server/aw_server/rest.py-simstep-cfd637bd-f6b2-44cf-8330-7b2c59c0658b",
- "fileName": "rest.py",
- "wiki": "The `ExportAllResource` constructs a final JSON payload and creates an HTTP response with a `Content-Disposition` header, prompting the client to download the data as `aw-buckets-export.json`.",
- "cellName": "Export Flow: Server Sends JSON File Response - rest.py:L336-344",
- "cellId": "6e7e85b1-9708-4f64-ac9e-efc54338c444",
- "visible": true,
- "startLine": 336,
- "endLine": 344,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "cfd637bd-f6b2-44cf-8330-7b2c59c0658b"
- }
- ]
- },
- "e60e25ae-e9aa-4497-8555-7e3d99a4049f": {
- "path": "e60e25ae-e9aa-4497-8555-7e3d99a4049f",
- "cellName": "Import Flow: Client Initiates Data Import - client.py:L297-299",
- "cellId": "e60e25ae-e9aa-4497-8555-7e3d99a4049f",
- "visible": true,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
- },
- "aw-client/aw_client/client.py-simstep-ea6d2274-023a-4d5f-abf4-0414c6c7f68d": {
- "path": "aw-client/aw_client/client.py-simstep-ea6d2274-023a-4d5f-abf4-0414c6c7f68d",
- "fileName": "client.py",
- "wiki": "A client application, such as a script using `aw-client`, calls a method like `import_bucket` to start the data import process. This example shows a single bucket import, but the server supports importing multiple buckets at once.",
- "cellName": "Import Flow: Client Initiates Data Import - client.py:L297-299",
- "cellId": "e60e25ae-e9aa-4497-8555-7e3d99a4049f",
- "visible": true,
- "startLine": 297,
- "endLine": 299,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "ea6d2274-023a-4d5f-abf4-0414c6c7f68d"
- }
- ]
- },
- "12725c25-974e-4363-bb91-c61c8745ed75": {
- "path": "12725c25-974e-4363-bb91-c61c8745ed75",
- "cellName": "Import Flow: Server Handles Import Request - rest.py:L129-341",
- "cellId": "12725c25-974e-4363-bb91-c61c8745ed75",
- "visible": true,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
- },
- "aw-server/aw_server/rest.py-simstep-3e1decf0-1329-4da8-a7c7-870ffe960a54": {
- "path": "aw-server/aw_server/rest.py-simstep-3e1decf0-1329-4da8-a7c7-870ffe960a54",
- "fileName": "rest.py",
- "wiki": "The `aw-server` receives the POST request and routes it to the `post` method of the `ImportAllResource` class. This method extracts the `buckets` data from the request.",
- "cellName": "Import Flow: Server Handles Import Request - rest.py:L129-341",
- "cellId": "12725c25-974e-4363-bb91-c61c8745ed75",
- "visible": true,
- "startLine": 129,
- "endLine": 341,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "3e1decf0-1329-4da8-a7c7-870ffe960a54"
- }
- ]
- },
- "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570": {
- "path": "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570",
- "cellName": "Import Flow: Iterate and Import Each Bucket - api.py:L133-135",
- "cellId": "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-4050248c-1638-452c-8826-677a7a2fece8": {
- "path": "aw-server/aw_server/api.py-simstep-4050248c-1638-452c-8826-677a7a2fece8",
- "fileName": "api.py",
- "wiki": "The `import_all` method loops through each bucket from the input data and calls `import_bucket` to process them individually.",
- "cellName": "Import Flow: Iterate and Import Each Bucket - api.py:L133-135",
- "cellId": "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570",
- "visible": true,
- "startLine": 133,
- "endLine": 135,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "4050248c-1638-452c-8826-677a7a2fece8"
- }
- ]
- },
- "07630c61-6df6-484b-81c3-0984379bfd68": {
- "path": "07630c61-6df6-484b-81c3-0984379bfd68",
- "cellName": "Import Flow: Create and Insert Events - api.py:L128-131",
- "cellId": "07630c61-6df6-484b-81c3-0984379bfd68",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "aw-server/aw_server/api.py-simstep-164ed08b-0873-499b-b945-e062cf362429": {
- "path": "aw-server/aw_server/api.py-simstep-164ed08b-0873-499b-b945-e062cf362429",
- "fileName": "api.py",
- "wiki": "After creating the bucket, `import_bucket` calls `create_events`, which in turn calls the datastore's `insert` method to add all events from the imported data into the newly created bucket.",
- "cellName": "Import Flow: Create and Insert Events - api.py:L128-131",
- "cellId": "07630c61-6df6-484b-81c3-0984379bfd68",
- "visible": true,
- "startLine": 128,
- "endLine": 131,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "164ed08b-0873-499b-b945-e062cf362429"
- }
- ]
- },
- "ae563be0-ff29-4c20-8f6d-6771f04c8da3": {
- "path": "ae563be0-ff29-4c20-8f6d-6771f04c8da3",
- "cellName": "Import Flow: Server Sends Success Response - rest.py:L129-341",
- "cellId": "ae563be0-ff29-4c20-8f6d-6771f04c8da3",
- "visible": true,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0"
- },
- "aw-server/aw_server/rest.py-simstep-3fd4d48c-e70c-4217-92c1-7554445cf03b": {
- "path": "aw-server/aw_server/rest.py-simstep-3fd4d48c-e70c-4217-92c1-7554445cf03b",
- "fileName": "rest.py",
- "wiki": "After all buckets and events have been successfully imported, the `ImportAllResource` returns a 200 OK status to the client.",
- "cellName": "Import Flow: Server Sends Success Response - rest.py:L129-341",
- "cellId": "ae563be0-ff29-4c20-8f6d-6771f04c8da3",
- "visible": true,
- "startLine": 129,
- "endLine": 341,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "3fd4d48c-e70c-4217-92c1-7554445cf03b"
- }
- ]
- },
- "5fe912cd-a72c-4cc1-969b-b5eb6759ace9": {
- "path": "5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
- "cellName": "Export Flow:\nAPI Call\nto Export\nEndpoint",
- "cellId": "5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
- "visible": true
- },
- "generated-edge-simstep-8efaf2e1-7c6d-4820-90a5-2abb80bf65ed-5fe912cd-a72c-4cc1-969b-b5eb6759ace9": {
- "path": "generated-edge-simstep-8efaf2e1-7c6d-4820-90a5-2abb80bf65ed-5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
- "fileName": "client.py",
- "cellName": "Export Flow: API Call to Export Endpoint",
- "cellId": "5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
- "visible": true,
- "startLine": 292,
- "endLine": 292,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "8efaf2e1-7c6d-4820-90a5-2abb80bf65ed"
- }
- ]
- },
- "8515a29c-385b-4ec5-886c-ba3a3a48518e": {
- "path": "8515a29c-385b-4ec5-886c-ba3a3a48518e",
- "cellName": "Export Flow:\nCall to\nAPI Layer\nfor Export\nLogic",
- "cellId": "8515a29c-385b-4ec5-886c-ba3a3a48518e",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
- },
- "generated-edge-simstep-6449735d-8c85-4d49-bb8c-c2b1f9918ffc-8515a29c-385b-4ec5-886c-ba3a3a48518e": {
- "path": "generated-edge-simstep-6449735d-8c85-4d49-bb8c-c2b1f9918ffc-8515a29c-385b-4ec5-886c-ba3a3a48518e",
- "fileName": "rest.py",
- "cellName": "Export Flow: Call to API Layer for Export Logic",
- "cellId": "8515a29c-385b-4ec5-886c-ba3a3a48518e",
- "visible": true,
- "startLine": 337,
- "endLine": 337,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "6449735d-8c85-4d49-bb8c-c2b1f9918ffc"
- }
- ]
- },
- "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff": {
- "path": "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
- "cellName": "Export Flow:\nFetching Events\nfor a\nBucket",
- "cellId": "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "generated-edge-simstep-60764034-1b94-4c15-9015-09e8b775f736-ec71fb4b-213d-4fa0-bdfa-9882eb11dcff": {
- "path": "generated-edge-simstep-60764034-1b94-4c15-9015-09e8b775f736-ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
- "fileName": "api.py",
- "cellName": "Export Flow: Fetching Events for a Bucket",
- "cellId": "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
- "visible": true,
- "startLine": 91,
- "endLine": 91,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "60764034-1b94-4c15-9015-09e8b775f736"
- }
- ]
- },
- "272a1088-1b0c-43f9-8335-d7055539c813": {
- "path": "272a1088-1b0c-43f9-8335-d7055539c813",
- "cellName": "Export Flow:\nReturning Exported\nData to\nREST Layer",
- "cellId": "272a1088-1b0c-43f9-8335-d7055539c813",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
- },
- "generated-edge-simstep-7a5f8838-8ed9-47b3-907f-077efeedaa10-272a1088-1b0c-43f9-8335-d7055539c813": {
- "path": "generated-edge-simstep-7a5f8838-8ed9-47b3-907f-077efeedaa10-272a1088-1b0c-43f9-8335-d7055539c813",
- "fileName": "api.py",
- "cellName": "Export Flow: Returning Exported Data to REST Layer",
- "cellId": "272a1088-1b0c-43f9-8335-d7055539c813",
- "visible": true,
- "startLine": 103,
- "endLine": 103,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "7a5f8838-8ed9-47b3-907f-077efeedaa10"
- }
- ]
- },
- "ebfbcf3c-bc57-4fe1-866e-fde1b860e633": {
- "path": "ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
- "cellName": "Import Flow:\nAPI Call\nto Import\nEndpoint",
- "cellId": "ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
- "visible": true
- },
- "generated-edge-simstep-f5c06885-1138-4c13-ae70-10b9d409be5b-ebfbcf3c-bc57-4fe1-866e-fde1b860e633": {
- "path": "generated-edge-simstep-f5c06885-1138-4c13-ae70-10b9d409be5b-ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
- "fileName": "client.py",
- "cellName": "Import Flow: API Call to Import Endpoint",
- "cellId": "ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
- "visible": true,
- "startLine": 299,
- "endLine": 299,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "f5c06885-1138-4c13-ae70-10b9d409be5b"
- }
- ]
- },
- "0614b31f-64d9-4e85-a5f5-6304f0702bd7": {
- "path": "0614b31f-64d9-4e85-a5f5-6304f0702bd7",
- "cellName": "Import Flow:\nCall to\nAPI Layer\nfor Import\nLogic",
- "cellId": "0614b31f-64d9-4e85-a5f5-6304f0702bd7",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
- },
- "generated-edge-simstep-988adf58-e1be-4352-be66-4f02188fc28a-0614b31f-64d9-4e85-a5f5-6304f0702bd7": {
- "path": "generated-edge-simstep-988adf58-e1be-4352-be66-4f02188fc28a-0614b31f-64d9-4e85-a5f5-6304f0702bd7",
- "fileName": "rest.py",
- "cellName": "Import Flow: Call to API Layer for Import Logic",
- "cellId": "0614b31f-64d9-4e85-a5f5-6304f0702bd7",
- "visible": true,
- "startLine": 129,
- "endLine": 341,
- "parentCellId": "7f67f305-e40b-496e-87a4-97725d0636a0",
- "parentPath": "aw-server/aw_server/rest.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "988adf58-e1be-4352-be66-4f02188fc28a"
- }
- ]
- },
- "941b8c57-be7c-49cd-ba2a-d2237f8f129b": {
- "path": "941b8c57-be7c-49cd-ba2a-d2237f8f129b",
- "cellName": "Import Flow:\nCreate Bucket\nin Datastore",
- "cellId": "941b8c57-be7c-49cd-ba2a-d2237f8f129b",
- "visible": true,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc"
- },
- "generated-edge-simstep-7e01821d-906c-4518-a1e0-6b71be84291a-941b8c57-be7c-49cd-ba2a-d2237f8f129b": {
- "path": "generated-edge-simstep-7e01821d-906c-4518-a1e0-6b71be84291a-941b8c57-be7c-49cd-ba2a-d2237f8f129b",
- "fileName": "api.py",
- "cellName": "Import Flow: Create Bucket in Datastore",
- "cellId": "941b8c57-be7c-49cd-ba2a-d2237f8f129b",
- "visible": true,
- "startLine": 110,
- "endLine": 120,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "7e01821d-906c-4518-a1e0-6b71be84291a"
- }
- ]
- },
- "1f7db50a-bc15-48d1-9f06-27ed743afa75": {
- "path": "1f7db50a-bc15-48d1-9f06-27ed743afa75",
- "cellName": "Import Flow:\nPersist Events\nto Database",
- "cellId": "1f7db50a-bc15-48d1-9f06-27ed743afa75",
- "visible": true,
- "parentCellId": "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49"
- },
- "generated-edge-simstep-666a933a-7a74-4d90-be19-7610f7bd3d74-1f7db50a-bc15-48d1-9f06-27ed743afa75": {
- "path": "generated-edge-simstep-666a933a-7a74-4d90-be19-7610f7bd3d74-1f7db50a-bc15-48d1-9f06-27ed743afa75",
- "fileName": "api.py",
- "cellName": "Import Flow: Persist Events to Database",
- "cellId": "1f7db50a-bc15-48d1-9f06-27ed743afa75",
- "visible": true,
- "startLine": 235,
- "endLine": 235,
- "parentCellId": "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc",
- "parentPath": "aw-server/aw_server/api.py",
- "simSteps": [
- {
- "simulationKey": "How data export and import works",
- "simStepId": "666a933a-7a74-4d90-be19-7610f7bd3d74"
- }
- ]
- },
- "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c": {
- "path": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c",
- "cellName": "examples",
- "cellId": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c",
- "visible": true,
- "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793"
- },
- "9b8f28aa-5406-437c-8363-bcfe0f788580": {
- "path": "9b8f28aa-5406-437c-8363-bcfe0f788580",
- "cellName": "working_hours.py",
- "cellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
- "visible": true,
- "parentCellId": "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c"
- },
- "237e712f-0c66-4488-b6e9-1ef8c3b71b51": {
- "path": "237e712f-0c66-4488-b6e9-1ef8c3b71b51",
- "cellName": "Start Script Execution - working_hours.py:L91-115",
- "cellId": "237e712f-0c66-4488-b6e9-1ef8c3b71b51",
- "visible": true,
- "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580"
- },
- "aw-client/examples/working_hours.py-simstep-e90cee0c-3a20-498b-97b9-2086a61dc02b": {
- "path": "aw-client/examples/working_hours.py-simstep-e90cee0c-3a20-498b-97b9-2086a61dc02b",
- "fileName": "working_hours.py",
- "wiki": "The user executes the `working_hours.py` script to calculate work time. The script defines a regex for 'Work' activities and sets up time periods to query.",
- "cellName": "Start Script Execution - working_hours.py:L91-115",
- "cellId": "237e712f-0c66-4488-b6e9-1ef8c3b71b51",
- "visible": true,
- "startLine": 91,
- "endLine": 115,
- "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
- "parentPath": "aw-client/examples/working_hours.py",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "e90cee0c-3a20-498b-97b9-2086a61dc02b"
- }
- ]
- },
- "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c": {
- "path": "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c",
- "cellName": "Prepare API Request - client.py:L305-339",
- "cellId": "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c",
- "visible": true,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
- },
- "aw-client/aw_client/client.py-simstep-0d34430a-af81-407b-8817-672288674005": {
- "path": "aw-client/aw_client/client.py-simstep-0d34430a-af81-407b-8817-672288674005",
- "fileName": "client.py",
- "wiki": "The `ActivityWatchClient.query` method formats the time periods into ISO 8601 interval strings and packages the query and time periods into a JSON payload for the HTTP POST request.",
- "cellName": "Prepare API Request - client.py:L305-339",
- "cellId": "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c",
- "visible": true,
- "startLine": 305,
- "endLine": 339,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "0d34430a-af81-407b-8817-672288674005"
- }
- ]
- },
- "73994797-596f-4b60-a36e-5f45cba1fcd3": {
- "path": "73994797-596f-4b60-a36e-5f45cba1fcd3",
- "cellName": "Receive Query Request (aw-server-rust) - query.rs:L10-23",
- "cellId": "73994797-596f-4b60-a36e-5f45cba1fcd3",
- "visible": true,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
- },
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-c988a25d-05ad-4c19-87ac-362c79af1d00": {
- "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-c988a25d-05ad-4c19-87ac-362c79af1d00",
- "fileName": "query.rs",
- "wiki": "The Rust-based `aw-server` receives the POST request at the `/api/0/query` endpoint. It parses the JSON body into a `Query` struct and prepares to execute the query against the datastore.",
- "cellName": "Receive Query Request (aw-server-rust) - query.rs:L10-23",
- "cellId": "73994797-596f-4b60-a36e-5f45cba1fcd3",
- "visible": true,
- "startLine": 10,
- "endLine": 23,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "c988a25d-05ad-4c19-87ac-362c79af1d00"
- }
- ]
- },
- "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b": {
- "path": "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b",
- "cellName": "Parse and Interpret Query - lib.rs:L53-64",
- "cellId": "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b",
- "visible": true,
- "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237"
- },
- "aw-server-rust/aw-query/src/lib.rs-simstep-b482a39f-e520-4d4d-8b2f-d1298922763f": {
- "path": "aw-server-rust/aw-query/src/lib.rs-simstep-b482a39f-e520-4d4d-8b2f-d1298922763f",
- "fileName": "lib.rs",
- "wiki": "The `aw_query` library's main function takes the query string, tokenizes it with a lexer, parses it into an Abstract Syntax Tree (AST), and then interprets the AST to execute the query logic.",
- "cellName": "Parse and Interpret Query - lib.rs:L53-64",
- "cellId": "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b",
- "visible": true,
- "startLine": 53,
- "endLine": 64,
- "parentCellId": "d020e6ae-765b-4374-947a-57f7ad4a9237",
- "parentPath": "aw-server-rust/aw-query/src/lib.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "b482a39f-e520-4d4d-8b2f-d1298922763f"
- }
- ]
- },
- "0b3e80ff-b4c9-42db-b067-1a9ba48e9218": {
- "path": "0b3e80ff-b4c9-42db-b067-1a9ba48e9218",
- "cellName": "Database Query - datastore.rs:L700-797",
- "cellId": "0b3e80ff-b4c9-42db-b067-1a9ba48e9218",
- "visible": true,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
- },
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-04bbbe33-e9de-4c5f-b925-27196d20ef1d": {
- "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-04bbbe33-e9de-4c5f-b925-27196d20ef1d",
- "fileName": "datastore.rs",
- "wiki": "The datastore worker receives the request and executes a SQL `SELECT` statement against the SQLite database to retrieve the raw event data for the specified bucket and time range.",
- "cellName": "Database Query - datastore.rs:L700-797",
- "cellId": "0b3e80ff-b4c9-42db-b067-1a9ba48e9218",
- "visible": true,
- "startLine": 700,
- "endLine": 797,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "04bbbe33-e9de-4c5f-b925-27196d20ef1d"
- }
- ]
- },
- "60a529b9-b262-4c7f-9baf-5beb50025a86": {
- "path": "60a529b9-b262-4c7f-9baf-5beb50025a86",
- "cellName": "Deserialize Events - datastore.rs:L755-780",
- "cellId": "60a529b9-b262-4c7f-9baf-5beb50025a86",
- "visible": true,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
- },
- "aw-server-rust/aw-datastore/src/datastore.rs-simstep-1b3cdf02-5dad-411c-a35e-9250c8aafc9d": {
- "path": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-1b3cdf02-5dad-411c-a35e-9250c8aafc9d",
- "fileName": "datastore.rs",
- "wiki": "The datastore layer deserializes the raw database rows into structured `Event` objects.",
- "cellName": "Deserialize Events - datastore.rs:L755-780",
- "cellId": "60a529b9-b262-4c7f-9baf-5beb50025a86",
- "visible": true,
- "startLine": 755,
- "endLine": 780,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "1b3cdf02-5dad-411c-a35e-9250c8aafc9d"
- }
- ]
- },
- "06ecdf3e-50eb-4bf3-9c56-183f98a3186b": {
- "path": "06ecdf3e-50eb-4bf3-9c56-183f98a3186b",
- "cellName": "Perform Query Transformations - interpret.rs:L213-226",
- "cellId": "06ecdf3e-50eb-4bf3-9c56-183f98a3186b",
- "visible": true,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c"
- },
- "aw-server-rust/aw-query/src/interpret.rs-simstep-f7c58723-a402-45d1-8070-59c196e20fb2": {
- "path": "aw-server-rust/aw-query/src/interpret.rs-simstep-f7c58723-a402-45d1-8070-59c196e20fb2",
- "fileName": "interpret.rs",
- "wiki": "The query interpreter continues executing the AST. It applies a series of transformations to the fetched events, such as `flood`, `filter_period_intersect`, `categorize`, `merge_events_by_keys`, and `sum_durations`, as defined in the query string.",
- "cellName": "Perform Query Transformations - interpret.rs:L213-226",
- "cellId": "06ecdf3e-50eb-4bf3-9c56-183f98a3186b",
- "visible": true,
- "startLine": 213,
- "endLine": 226,
- "parentCellId": "9b5e1d70-af70-4de3-9b35-73b774a50c3c",
- "parentPath": "aw-server-rust/aw-query/src/interpret.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "f7c58723-a402-45d1-8070-59c196e20fb2"
- }
- ]
- },
- "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500": {
- "path": "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500",
- "cellName": "Serialize and Send Response - query.rs:L28",
- "cellId": "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500",
- "visible": true,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006"
- },
- "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-72197f38-6e3b-432c-be11-ce5fbb94efb9": {
- "path": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-72197f38-6e3b-432c-be11-ce5fbb94efb9",
- "fileName": "query.rs",
- "wiki": "The Rocket endpoint handler serializes the query result into a JSON string and sends it as the HTTP response.",
- "cellName": "Serialize and Send Response - query.rs:L28",
- "cellId": "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500",
- "visible": true,
- "startLine": 28,
- "endLine": 28,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "72197f38-6e3b-432c-be11-ce5fbb94efb9"
- }
- ]
- },
- "7057dbee-ccfe-43f8-9014-90812018a849": {
- "path": "7057dbee-ccfe-43f8-9014-90812018a849",
- "cellName": "Process Response in Client - client.py:L338",
- "cellId": "7057dbee-ccfe-43f8-9014-90812018a849",
- "visible": true,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2"
- },
- "aw-client/aw_client/client.py-simstep-642425c3-abd7-45fe-b5a9-a76bf90a9477": {
- "path": "aw-client/aw_client/client.py-simstep-642425c3-abd7-45fe-b5a9-a76bf90a9477",
- "fileName": "client.py",
- "wiki": "The `ActivityWatchClient` receives the HTTP response, checks for errors, and parses the JSON body into a Python list of dictionaries.",
- "cellName": "Process Response in Client - client.py:L338",
- "cellId": "7057dbee-ccfe-43f8-9014-90812018a849",
- "visible": true,
- "startLine": 338,
- "endLine": 338,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "642425c3-abd7-45fe-b5a9-a76bf90a9477"
- }
- ]
- },
- "e985450d-2666-412f-acf5-988a5c0c7de5": {
- "path": "e985450d-2666-412f-acf5-988a5c0c7de5",
- "cellName": "Process and Display Results - working_hours.py:L113-120",
- "cellId": "e985450d-2666-412f-acf5-988a5c0c7de5",
- "visible": true,
- "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580"
- },
- "aw-client/examples/working_hours.py-simstep-e38db73e-b347-4786-8efd-1e7cab44f73f": {
- "path": "aw-client/examples/working_hours.py-simstep-e38db73e-b347-4786-8efd-1e7cab44f73f",
- "fileName": "working_hours.py",
- "wiki": "The `working_hours.py` script receives the processed data, calculates total durations using `generous_approx` (which applies flooding), formats the output, and prints a tabulated summary to the console. It also saves the raw event data to a JSON file.",
- "cellName": "Process and Display Results - working_hours.py:L113-120",
- "cellId": "e985450d-2666-412f-acf5-988a5c0c7de5",
- "visible": true,
- "startLine": 113,
- "endLine": 120,
- "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
- "parentPath": "aw-client/examples/working_hours.py",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "e38db73e-b347-4786-8efd-1e7cab44f73f"
- }
- ]
- },
- "aecc1e90-5e71-43f4-a5b8-757de329fe3a": {
- "path": "aecc1e90-5e71-43f4-a5b8-757de329fe3a",
- "cellName": "Invoke AW\nClient Query",
- "cellId": "aecc1e90-5e71-43f4-a5b8-757de329fe3a",
- "visible": true,
- "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793"
- },
- "generated-edge-simstep-5aa97ae5-7e30-4d15-8f12-05942f2e75c9-aecc1e90-5e71-43f4-a5b8-757de329fe3a": {
- "path": "generated-edge-simstep-5aa97ae5-7e30-4d15-8f12-05942f2e75c9-aecc1e90-5e71-43f4-a5b8-757de329fe3a",
- "fileName": "working_hours.py",
- "cellName": "Invoke AW Client Query",
- "cellId": "aecc1e90-5e71-43f4-a5b8-757de329fe3a",
- "visible": true,
- "startLine": 86,
- "endLine": 86,
- "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
- "parentPath": "aw-client/examples/working_hours.py",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "5aa97ae5-7e30-4d15-8f12-05942f2e75c9"
- }
- ]
- },
- "62388ee6-67f4-4adc-b08e-90deeb10efd4": {
- "path": "62388ee6-67f4-4adc-b08e-90deeb10efd4",
- "cellName": "API Call:\nPOST /api/0/query/",
- "cellId": "62388ee6-67f4-4adc-b08e-90deeb10efd4",
- "visible": true
- },
- "generated-edge-simstep-834b7dbc-5efe-41ac-b75b-e43ad32141df-62388ee6-67f4-4adc-b08e-90deeb10efd4": {
- "path": "generated-edge-simstep-834b7dbc-5efe-41ac-b75b-e43ad32141df-62388ee6-67f4-4adc-b08e-90deeb10efd4",
- "fileName": "client.py",
- "cellName": "API Call: POST /api/0/query/",
- "cellId": "62388ee6-67f4-4adc-b08e-90deeb10efd4",
- "visible": true,
- "startLine": 122,
- "endLine": 127,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "834b7dbc-5efe-41ac-b75b-e43ad32141df"
- }
- ]
- },
- "31b60323-3a65-4184-a42f-f577f3a958ff": {
- "path": "31b60323-3a65-4184-a42f-f577f3a958ff",
- "cellName": "Execute Query",
- "cellId": "31b60323-3a65-4184-a42f-f577f3a958ff",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-98777081-df05-4b5c-89f6-5076fab00e92-31b60323-3a65-4184-a42f-f577f3a958ff": {
- "path": "generated-edge-simstep-98777081-df05-4b5c-89f6-5076fab00e92-31b60323-3a65-4184-a42f-f577f3a958ff",
- "fileName": "query.rs",
- "cellName": "Execute Query",
- "cellId": "31b60323-3a65-4184-a42f-f577f3a958ff",
- "visible": true,
- "startLine": 16,
- "endLine": 16,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "98777081-df05-4b5c-89f6-5076fab00e92"
- }
- ]
- },
- "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f": {
- "path": "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
- "cellName": "Data Fetch:\n`query_bucket`",
- "cellId": "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-914107de-b38a-4307-ab2c-e257ed3d2fb5-9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f": {
- "path": "generated-edge-simstep-914107de-b38a-4307-ab2c-e257ed3d2fb5-9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
- "fileName": "functions.rs",
- "cellName": "Data Fetch: `query_bucket`",
- "cellId": "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
- "visible": true,
- "startLine": 139,
- "endLine": 168,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "parentPath": "aw-server-rust/aw-query/src/functions.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "914107de-b38a-4307-ab2c-e257ed3d2fb5"
- }
- ]
- },
- "561eebea-ee66-4251-a29c-64c2e3aae490": {
- "path": "561eebea-ee66-4251-a29c-64c2e3aae490",
- "cellName": "Return Raw\nEvent Data",
- "cellId": "561eebea-ee66-4251-a29c-64c2e3aae490",
- "visible": true,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f"
- },
- "generated-edge-simstep-5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619-561eebea-ee66-4251-a29c-64c2e3aae490": {
- "path": "generated-edge-simstep-5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619-561eebea-ee66-4251-a29c-64c2e3aae490",
- "fileName": "datastore.rs",
- "cellName": "Return Raw Event Data",
- "cellId": "561eebea-ee66-4251-a29c-64c2e3aae490",
- "visible": true,
- "startLine": 748,
- "endLine": 788,
- "parentCellId": "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f",
- "parentPath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619"
- }
- ]
- },
- "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe": {
- "path": "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
- "cellName": "Return Deserialized\nEvents",
- "cellId": "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-d78663e6-a6d4-4ba7-a922-436bd075e457-2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe": {
- "path": "generated-edge-simstep-d78663e6-a6d4-4ba7-a922-436bd075e457-2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
- "fileName": "functions.rs",
- "cellName": "Return Deserialized Events",
- "cellId": "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
- "visible": true,
- "startLine": 167,
- "endLine": 167,
- "parentCellId": "bf649fa4-66cc-4975-8549-aa2f1db4a11e",
- "parentPath": "aw-server-rust/aw-query/src/functions.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "d78663e6-a6d4-4ba7-a922-436bd075e457"
- }
- ]
- },
- "3f00132f-3930-4b99-82cf-1ca7f818661b": {
- "path": "3f00132f-3930-4b99-82cf-1ca7f818661b",
- "cellName": "Return Final\nQuery Result",
- "cellId": "3f00132f-3930-4b99-82cf-1ca7f818661b",
- "visible": true,
- "parentCellId": "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0"
- },
- "generated-edge-simstep-633d97c2-762a-45cb-8900-308ab124d526-3f00132f-3930-4b99-82cf-1ca7f818661b": {
- "path": "generated-edge-simstep-633d97c2-762a-45cb-8900-308ab124d526-3f00132f-3930-4b99-82cf-1ca7f818661b",
- "fileName": "query.rs",
- "cellName": "Return Final Query Result",
- "cellId": "3f00132f-3930-4b99-82cf-1ca7f818661b",
- "visible": true,
- "startLine": 16,
- "endLine": 25,
- "parentCellId": "873444c7-80ea-4a0b-8620-92fc96cce006",
- "parentPath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "633d97c2-762a-45cb-8900-308ab124d526"
- }
- ]
- },
- "ec5d6b90-2f5f-4a07-b0e8-da3610035a92": {
- "path": "ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
- "cellName": "HTTP Response",
- "cellId": "ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
- "visible": true
- },
- "generated-edge-simstep-33e5b4e9-bd66-45f5-ab0f-543737810b99-ec5d6b90-2f5f-4a07-b0e8-da3610035a92": {
- "path": "generated-edge-simstep-33e5b4e9-bd66-45f5-ab0f-543737810b99-ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
- "fileName": "client.py",
- "cellName": "HTTP Response",
- "cellId": "ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
- "visible": true,
- "startLine": 337,
- "endLine": 338,
- "parentCellId": "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2",
- "parentPath": "aw-client/aw_client/client.py",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "33e5b4e9-bd66-45f5-ab0f-543737810b99"
- }
- ]
- },
- "c8cbde86-13c0-4232-898e-104d815a805c": {
- "path": "c8cbde86-13c0-4232-898e-104d815a805c",
- "cellName": "Return Result\nto Script",
- "cellId": "c8cbde86-13c0-4232-898e-104d815a805c",
- "visible": true,
- "parentCellId": "900d6121-1844-48ba-9a18-db1ec6ea9793"
- },
- "generated-edge-simstep-65443293-5e86-4e71-9e8d-19d61bd162d9-c8cbde86-13c0-4232-898e-104d815a805c": {
- "path": "generated-edge-simstep-65443293-5e86-4e71-9e8d-19d61bd162d9-c8cbde86-13c0-4232-898e-104d815a805c",
- "fileName": "working_hours.py",
- "cellName": "Return Result to Script",
- "cellId": "c8cbde86-13c0-4232-898e-104d815a805c",
- "visible": true,
- "startLine": 86,
- "endLine": 86,
- "parentCellId": "9b8f28aa-5406-437c-8363-bcfe0f788580",
- "parentPath": "aw-client/examples/working_hours.py",
- "simSteps": [
- {
- "simulationKey": "How custom scripting with the client library works",
- "simStepId": "65443293-5e86-4e71-9e8d-19d61bd162d9"
- }
- ]
- }
- },
- "simulations": {
- "How automated application and window time tracking works": {
- "name": "How automated application and window time tracking works",
- "simSteps": [
- {
- "simStepId": "caf92190-4958-42b9-b962-d21c9ff6c62d",
- "diagramNodeId": "638a5f20-935f-4345-8eaf-dfcd2aa6efb4",
- "simStepLabel": "Watcher Initialization",
- "simStepDescription": "The `aw-watcher-window` process starts. It parses arguments, sets up logging, and initializes the `ActivityWatchClient`. It also ensures a bucket for storing window activity exists on the server.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/main.py",
- "startLine": "62",
- "endLine": "69",
- "relevantVariables": [
- "ActivityWatchClient",
- "client",
- "bucket_id",
- "event_type"
- ]
- },
- "inputDataExample": "null",
- "outputDataExample": "{\n \"client_name\": \"aw-watcher-window\",\n \"hostname\": \"my-desktop\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event_type\": \"currentwindow\",\n \"queued\": true,\n \"poll_time\": 1.0\n}"
- },
- {
- "simStepId": "39835fd9-a301-482d-8b6d-9d16abbbaa29",
- "diagramNodeId": "6d9c0750-fa20-47af-9135-6cc6444cb6b0",
- "simStepLabel": "Start Heartbeat Loop",
- "simStepDescription": "The main function enters the `heartbeat_loop`, which will periodically poll for the active window information.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/main.py",
- "startLine": "98",
- "endLine": "109",
- "relevantVariables": [
- "heartbeat_loop"
- ]
- },
- "inputDataExample": "{\n \"client\": \"\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"poll_time\": 1.0\n}",
- "outputDataExample": "{\n \"client\": \"\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"poll_time\": 1.0\n}"
- },
- {
- "simStepId": "3e57e810-18fe-461f-a33c-f3eb0773ecf5",
- "diagramNodeId": "89c12f0e-0649-4963-8e57-d7fd7da30bc4",
- "simStepLabel": "Get Current Window Information",
- "simStepDescription": "Inside the loop, the `get_current_window` function is called. This function acts as a dispatcher, calling the appropriate OS-specific implementation to get the currently focused application and window title.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/lib.py",
- "startLine": "58",
- "endLine": "73",
- "relevantVariables": [
- "get_current_window",
- "get_current_window_linux",
- "get_current_window_macos",
- "get_current_window_windows"
- ]
- },
- "inputDataExample": "{\n \"strategy\": \"xlib\"\n}",
- "outputDataExample": "{\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n}"
- },
- {
- "simStepId": "81f5cf5a-47ed-4fce-9c97-27559b1c7976",
- "diagramNodeId": "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
- "simStepLabel": "Create Window Event",
- "simStepDescription": "The application name and title are used to create an `Event` object, which represents the user's current activity at this point in time.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/main.py",
- "startLine": "154",
- "endLine": "155",
- "relevantVariables": [
- "Event",
- "current_window_event"
- ]
- },
- "inputDataExample": "{\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n}",
- "outputDataExample": "{\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": 0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}"
- },
- {
- "simStepId": "706e836d-c3e2-4048-9eae-95e761ca9ffa",
- "diagramNodeId": "30328419-4cc4-4ea2-a7fb-1728782b23aa",
- "simStepLabel": "Send Heartbeat via Client",
- "simStepDescription": "The created event is sent as a heartbeat to the `aw-server` using the `ActivityWatchClient`. The `queued=True` parameter enables local event merging and a persistent queue for offline robustness.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/main.py",
- "startLine": "160",
- "endLine": "162",
- "relevantVariables": [
- "client.heartbeat"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": 0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"pulsetime\": 2.0,\n \"queued\": true\n}",
- "outputDataExample": "null"
- },
- {
- "simStepId": "11bc8b75-0103-4652-9fec-e55af41400a0",
- "diagramNodeId": "78766ca9-9103-486a-8755-f57a09e7f5a7",
- "simStepLabel": "Local Heartbeat Pre-Merging",
- "simStepDescription": "The `aw-client` library attempts to merge the new heartbeat with the previous one if the data is identical and it's within the `pulsetime` window. If merging occurs and the total duration is less than the `commit_interval`, the event is held locally. Otherwise, it's added to a request queue for sending to the server.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "244",
- "endLine": "259",
- "relevantVariables": [
- "heartbeat_merge",
- "last_heartbeat",
- "self.request_queue"
- ]
- },
- "inputDataExample": "{\n \"last_heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"0s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"new_heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": \"0s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"pulsetime\": 2.0\n}",
- "outputDataExample": "{\n \"last_heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"0s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"new_heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": \"0s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"pulsetime\": 2.0\n}"
- },
- {
- "simStepId": "432d1978-befd-4dfd-979b-fe28821d4e00",
- "diagramNodeId": "82482fcc-b698-4f91-a27c-a4110d012d99",
- "simStepLabel": "Queue and Dispatch Request",
- "simStepDescription": "The `RequestQueue` thread picks up the heartbeat request. It formats an HTTP POST request to the server's heartbeat API endpoint: `/api/0/buckets/{bucket_id}/heartbeat`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "531",
- "endLine": "533",
- "relevantVariables": [
- "RequestQueue._dispatch_request",
- "self.client._post"
- ]
- },
- "inputDataExample": "{\n \"endpoint\": \"/api/0/buckets/aw-watcher-window_my-desktop/heartbeat?pulsetime=2.0\",\n \"data\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
- "outputDataExample": "{\n \"method\": \"POST\",\n \"url\": \"http://localhost:5600/api/0/buckets/aw-watcher-window_my-desktop/heartbeat?pulsetime=2.0\",\n \"headers\": {\n \"Content-Type\": \"application/json\"\n },\n \"body\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
- },
- {
- "simStepId": "97f58e0a-cbeb-4895-b613-d8e9fd129a42",
- "diagramNodeId": "5a7fba44-6d4d-4836-bc13-ed69518c9d45",
- "simStepLabel": "API Call: Heartbeat Received",
- "simStepDescription": "The `aw-server` receives the HTTP POST request at the heartbeat endpoint. The Flask-RESTX framework routes this to the `HeartbeatResource`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "272",
- "endLine": "276",
- "relevantVariables": [
- "HeartbeatResource"
- ]
- },
- "inputDataExample": "{\n \"url\": \"/api/0/buckets/aw-watcher-window_my-desktop/heartbeat?pulsetime=2.0\",\n \"body\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
- "outputDataExample": "{\n \"url\": \"/api/0/buckets/aw-watcher-window_my-desktop/heartbeat?pulsetime=2.0\",\n \"body\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
- },
- {
- "simStepId": "addb33f5-b815-49f0-9b54-a8ee3fb3b87b",
- "diagramNodeId": "2217c8ca-4cbb-4721-acb9-1057b3b16d69",
- "simStepLabel": "Server-Side Heartbeat Logic",
- "simStepDescription": "The `HeartbeatResource`'s `post` method calls the `api.heartbeat` function, which contains the main server-side logic. It fetches the last event from the bucket and determines if the new heartbeat should be merged with it (by extending its duration) or if a new event should be created.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "254",
- "endLine": "337",
- "relevantVariables": [
- "ServerAPI.heartbeat",
- "heartbeat_merge",
- "self.db"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"heartbeat\": {\n \"timestamp\": \"2023-10-27T10:00:01.000Z\",\n \"duration\": 0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n },\n \"pulsetime\": 2.0\n}",
- "outputDataExample": "{\n \"merged_event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"1s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
- },
- {
- "simStepId": "cd6c54a5-c0bd-4b99-9446-ea921ee876a6",
- "diagramNodeId": "6a5be6b6-e11d-460d-8193-427f3a9e42ac",
- "simStepLabel": "Data to Datastore",
- "simStepDescription": "The API layer sends the merged or new event to the datastore abstraction layer to be persisted.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "314",
- "endLine": "335",
- "relevantVariables": [
- "self.db[bucket_id].replace_last",
- "self.db[bucket_id].insert"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"1s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
- "outputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"1s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
- },
- {
- "simStepId": "5573707d-aa48-4a66-a3dc-25c841986d39",
- "diagramNodeId": "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a",
- "simStepLabel": "Persist Event to Database",
- "simStepDescription": "The `datastore`'s `Bucket` object calls the appropriate method on the configured storage strategy (e.g., `PeeweeStorage`). If merging, `replace_last` is used to update the last event. If it's a new event, `insert` is used.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_datastore/datastore.py",
- "startLine": "127",
- "endLine": "188",
- "relevantVariables": [
- "Bucket.insert",
- "Bucket.replace_last"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event_to_replace_with\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": \"1s\",\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
- "outputDataExample": "{\n \"success\": true\n}"
- },
- {
- "simStepId": "960cb01a-addf-4a23-a3d6-c1f868b3524d",
- "diagramNodeId": "",
- "simStepLabel": "SQL Execution",
- "simStepDescription": "The Peewee storage backend translates the high-level `insert` or `replace_last` call into specific SQL statements (INSERT OR REPLACE, or UPDATE) that are executed against the SQLite database file.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_datastore/storages/peewee.py",
- "startLine": "293",
- "endLine": "300",
- "relevantVariables": [
- "PeeweeStorage.replace_last",
- "self._get_last",
- "e.save"
- ]
- },
- "inputDataExample": "{\n \"operation\": \"replace_last\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}",
- "outputDataExample": "{\n \"operation\": \"replace_last\",\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"event\": {\n \"timestamp\": \"2023-10-27T10:00:00.000Z\",\n \"duration\": 1.0,\n \"data\": {\n \"app\": \"chrome\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n }\n}"
- }
- ],
- "description": "- A dedicated watcher module (
aw-watcher-window) runs in the background to monitor user activity - It periodically polls the operating system to get the currently focused application name (e
- g
- , 'chrome
- exe') and the title of the active window
- This information is packaged into an
Event object and sent as a heartbeat to the aw-server via the client library - The server stores these events in a specific
bucket for the watcher, creating a continuous timeline of application usage - This process is designed to be cross-platform, with specific implementations for Windows, macOS, and Linux
",
- "simulationNodesAndEdges": {
- "638a5f20-935f-4345-8eaf-dfcd2aa6efb4": {
- "simStepIds": [
- "caf92190-4958-42b9-b962-d21c9ff6c62d"
- ]
- },
- "89c12f0e-0649-4963-8e57-d7fd7da30bc4": {
- "simStepIds": [
- "3e57e810-18fe-461f-a33c-f3eb0773ecf5"
- ]
- },
- "30328419-4cc4-4ea2-a7fb-1728782b23aa": {
- "simStepIds": [
- "706e836d-c3e2-4048-9eae-95e761ca9ffa"
- ]
- },
- "82482fcc-b698-4f91-a27c-a4110d012d99": {
- "simStepIds": [
- "432d1978-befd-4dfd-979b-fe28821d4e00"
- ]
- },
- "2217c8ca-4cbb-4721-acb9-1057b3b16d69": {
- "simStepIds": [
- "addb33f5-b815-49f0-9b54-a8ee3fb3b87b"
- ]
- },
- "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a": {
- "simStepIds": [
- "5573707d-aa48-4a66-a3dc-25c841986d39"
- ]
- },
- "6d9c0750-fa20-47af-9135-6cc6444cb6b0": {
- "simStepIds": [
- "39835fd9-a301-482d-8b6d-9d16abbbaa29"
- ]
- },
- "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26": {
- "simStepIds": [
- "81f5cf5a-47ed-4fce-9c97-27559b1c7976"
- ]
- },
- "78766ca9-9103-486a-8755-f57a09e7f5a7": {
- "simStepIds": [
- "11bc8b75-0103-4652-9fec-e55af41400a0"
- ]
- },
- "5a7fba44-6d4d-4836-bc13-ed69518c9d45": {
- "simStepIds": [
- "97f58e0a-cbeb-4895-b613-d8e9fd129a42"
- ]
- },
- "6a5be6b6-e11d-460d-8193-427f3a9e42ac": {
- "simStepIds": [
- "cd6c54a5-c0bd-4b99-9446-ea921ee876a6"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "aw-watcher-window, get_current_window, heartbeat, ActivityWatchClient, Event",
- "generationPrompt": "How automated application and window time tracking works",
- "generationKeywords": "aw-watcher-window, get_current_window, heartbeat, ActivityWatchClient, Event",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 19,
- "promptTokenCount": 14219,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 124,
- "promptTokenCount": 90775,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 67,
- "promptTokenCount": 47327,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": [
- {
- "path": "aw-server-rust/aw-server/src/endpoints/import.rs",
- "container": "server",
- "triggerType": "http",
- "identifier": "application/json"
- }
- ]
- },
- "crossLayerTriggers": [
- {
- "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "identifier": "application/json",
- "type": "http",
- "matchedTargets": [
- ".github/workflows/test.yml",
- "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "aw-server-rust/aw-server/src/endpoints/import.rs"
- ]
- }
- ]
- }
- },
- "How activity data visualization works": {
- "name": "How activity data visualization works",
- "simSteps": [
- {
- "simStepId": "81f31a9b-3434-4458-a7d3-bdcf610af75e",
- "diagramNodeId": "12f9554d-dd4e-4f66-bd20-8845b718ef19",
- "simStepLabel": "Client-side: Construct Activity Query",
- "simStepDescription": "The user accesses the ActivityWatch web UI. The frontend constructs a query using the ActivityWatch Query Language to fetch and process data for the main dashboard visualization. This query is designed to get window and AFK (Away From Keyboard) events, filter out AFK periods, categorize activities based on rules, and aggregate the results.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/queries.py",
- "startLine": "243",
- "endLine": "301",
- "relevantVariables": [
- "fullDesktopQuery",
- "canonicalEvents"
- ]
- },
- "inputDataExample": "{\n \"hostname\": \"my-desktop\",\n \"timeRange\": {\n \"start\": \"2023-10-26T00:00:00Z\",\n \"end\": \"2023-10-27T00:00:00Z\"\n }\n}",
- "outputDataExample": "{\n \"query\": \"\\n events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\\n not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\\n not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\\n events = filter_period_intersect(events, not_afk);\\n events = categorize(events, [[\\\"Work\\\", {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"GitHub|Stack Overflow\\\"}]]);\\n title_events = sort_by_duration(merge_events_by_keys(events, [\\\"app\\\", \\\"title\\\"]));\\n app_events = sort_by_duration(merge_events_by_keys(title_events, [\\\"app\\\"]));\\n cat_events = sort_by_duration(merge_events_by_keys(events, [\\\"$category\\\"]));\\n duration = sum_durations(events);\\n RETURN = {\\\"events\\\": events, \\\"window\\\": {\\\"app_events\\\": app_events, \\\"title_events\\\": title_events, \\\"cat_events\\\": cat_events, \\\"duration\\\": duration}};\\n \"\n}"
- },
- {
- "simStepId": "c1a26d9b-d661-4a99-8275-39a414824ed6",
- "diagramNodeId": "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
- "simStepLabel": "API Call: POST /api/0/query/",
- "simStepDescription": "The client sends the generated query string and the desired time periods to the `aw-server` via an HTTP POST request to the `/api/0/query/` endpoint.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "305",
- "endLine": "339",
- "relevantVariables": [
- "query"
- ]
- },
- "inputDataExample": "{\n \"timeperiods\": [\n \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n ],\n \"query\": [\n \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\",\n \"not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\",\n \"not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\",\n \"events = filter_period_intersect(events, not_afk);\",\n \"events = categorize(events, [[\\\"Work\\\", {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"GitHub|Stack Overflow\\\"}]]);\",\n \"RETURN = events;\"\n ]\n}",
- "outputDataExample": "{\n \"timeperiods\": [\n \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n ],\n \"query\": [\n \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\",\n \"not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\",\n \"not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\",\n \"events = filter_period_intersect(events, not_afk);\",\n \"events = categorize(events, [[\\\"Work\\\", {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"GitHub|Stack Overflow\\\"}]]);\",\n \"RETURN = events;\"\n ]\n}"
- },
- {
- "simStepId": "e91513ab-13ec-4eea-9942-9620dbe3b92b",
- "diagramNodeId": "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1",
- "simStepLabel": "Backend: Receive Query Request",
- "simStepDescription": "The `aw-server-rust` (or the Python equivalent `aw-server`) receives the POST request. The `/api/0/query` endpoint deserializes the JSON body into a `Query` struct containing the query statements and time intervals.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "9",
- "endLine": "23",
- "relevantVariables": [
- "query"
- ]
- },
- "inputDataExample": "{\n \"timeperiods\": [\n \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n ],\n \"query\": [\n \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\",\n \"not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\",\n \"not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\",\n \"events = filter_period_intersect(events, not_afk);\",\n \"RETURN = events;\"\n ]\n}",
- "outputDataExample": "{\n \"query_code\": \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-desktop\\\")));\\nnot_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-desktop\\\")));\\n...\",\n \"intervals\": [\n \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n ]\n}"
- },
- {
- "simStepId": "a7b6aefb-1401-4756-bfa1-1eb9a76cde07",
- "diagramNodeId": "c8403507-4895-4695-84b5-9305afdc3c9f",
- "simStepLabel": "API Endpoint -> Query Engine",
- "simStepDescription": "The API endpoint joins the query lines into a single string and passes it, along with the time interval and a datastore reference, to the `aw_query::query` function for execution.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "16",
- "endLine": "16",
- "relevantVariables": [
- "aw_query::query"
- ]
- },
- "inputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_my-desktop\\\"); RETURN = events;\",\n \"interval\": \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n}",
- "outputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_my-desktop\\\"); RETURN = events;\",\n \"interval\": \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n}"
- },
- {
- "simStepId": "3291e01a-482d-401b-98b5-759573be65ca",
- "diagramNodeId": "a9279dbc-8fda-434c-bc5a-4eefaca0df56",
- "simStepLabel": "Query Engine: Parse and Interpret",
- "simStepDescription": "The `aw_query::query` function orchestrates the execution. It first uses a lexer to tokenize the query string, then a parser to build an Abstract Syntax Tree (AST). Finally, it invokes the interpreter to execute the AST.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/lib.rs",
- "startLine": "53",
- "endLine": "64",
- "relevantVariables": [
- "query",
- "lexer::Lexer",
- "parser::parse",
- "interpret::interpret_prog"
- ]
- },
- "inputDataExample": "{\n \"code\": \"events = query_bucket(\\\"aw-watcher-window_my-desktop\\\"); RETURN = events;\",\n \"ti\": \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n}",
- "outputDataExample": "{\n \"program\": {\n \"stmts\": [\n {\n \"node\": \"Assign(\\\"events\\\", Function(\\\"query_bucket\\\", List([String(\\\"aw-watcher-window_my-desktop\\\")])))\"\n },\n {\n \"node\": \"Return(Var(\\\"events\\\"))\"\n }\n ]\n }\n}"
- },
- {
- "simStepId": "00784ae1-bb99-494c-bf46-fe5947de5066",
- "diagramNodeId": "8f8d2c55-63c0-48ec-b931-f848e245688f",
- "simStepLabel": "Interpreter -> `query_bucket`",
- "simStepDescription": "While traversing the AST, the interpreter encounters the `query_bucket` function call. It resolves this function from its environment of built-in functions and prepares to execute it.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/interpret.rs",
- "startLine": "213",
- "endLine": "226",
- "relevantVariables": [
- "Function(fname, e)",
- "fun(args, env, ds)"
- ]
- },
- "inputDataExample": "{\n \"functionName\": \"query_bucket\",\n \"args\": [\n \"aw-watcher-window_my-desktop\"\n ]\n}",
- "outputDataExample": "{\n \"functionName\": \"query_bucket\",\n \"args\": [\n \"aw-watcher-window_my-desktop\"\n ]\n}"
- },
- {
- "simStepId": "475886bc-26d3-4528-84ae-2f9c8e1dfcf9",
- "diagramNodeId": "be2c99a2-8b27-487f-9c8f-e1d1836613cc",
- "simStepLabel": "Execute `query_bucket`",
- "simStepDescription": "The `query_bucket` function is executed. It reads the time interval from its environment and makes a call to the datastore's `get_events` method to fetch raw event data from the specified bucket.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/functions.rs",
- "startLine": "139",
- "endLine": "168",
- "relevantVariables": [
- "qfunctions::query_bucket",
- "ds.get_events"
- ]
- },
- "inputDataExample": "{\n \"args\": [\n \"aw-watcher-window_my-desktop\"\n ],\n \"env\": {\n \"TIMEINTERVAL\": \"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"\n }\n}",
- "outputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"startTime\": \"2023-10-26T00:00:00Z\",\n \"endTime\": \"2023-10-27T00:00:00Z\"\n}"
- },
- {
- "simStepId": "e1bf9f3c-e763-4e75-8c62-1a8d739d53cc",
- "diagramNodeId": "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
- "simStepLabel": "`query_bucket` -> Datastore",
- "simStepDescription": "The call to `get_events` is sent to the datastore worker thread, which will translate it into a database query.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
- "startLine": "414",
- "endLine": "430",
- "relevantVariables": [
- "get_events"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"starttime_opt\": \"2023-10-26T00:00:00Z\",\n \"endtime_opt\": \"2023-10-27T00:00:00Z\",\n \"limit_opt\": -1\n}",
- "outputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-desktop\",\n \"starttime_opt\": \"2023-10-26T00:00:00Z\",\n \"endtime_opt\": \"2023-10-27T00:00:00Z\",\n \"limit_opt\": -1\n}"
- },
- {
- "simStepId": "ff017206-8323-4caa-9eca-4fc760c2470f",
- "diagramNodeId": "48d1c5e2-32b3-4eaf-9005-dd0a65a77448",
- "simStepLabel": "Datastore: Retrieve Events from SQLite",
- "simStepDescription": "The `aw-datastore` component executes a `SELECT` query against its SQLite database. It retrieves all events from the `aw-watcher-window_my-desktop` bucket that fall within the specified time range.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "startLine": "700",
- "endLine": "797",
- "relevantVariables": [
- "get_events",
- "stmt.query_map"
- ]
- },
- "inputDataExample": "{\n \"sql\": \"SELECT id, starttime, endtime, datastr FROM events WHERE bucketrow = (SELECT rowid FROM buckets WHERE id = ?) AND endtime >= ? AND starttime <= ? ORDER BY starttime DESC LIMIT ?\",\n \"params\": [\n 1,\n 1698278400000000000,\n 1698364800000000000,\n -1\n ]\n}",
- "outputDataExample": "{\n \"rows\": [\n {\n \"id\": 101,\n \"timestamp\": \"2023-10-26T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\"app\": \"Code\", \"title\": \"README.md\"}\n },\n {\n \"id\": 102,\n \"timestamp\": \"2023-10-26T10:05:00Z\",\n \"duration\": 600,\n \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch Documentation\"}\n }\n ]\n}"
- },
- {
- "simStepId": "f7dfb334-099f-4750-a893-cd96b1c46278",
- "diagramNodeId": "7a14a4d3-a453-4e33-9b10-fb192e40e34e",
- "simStepLabel": "Datastore -> Query Engine",
- "simStepDescription": "The raw event data is returned from the datastore, through the `query_bucket` function, and back to the interpreter as a list of `DataType::Event`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/functions.rs",
- "startLine": "163",
- "endLine": "167",
- "relevantVariables": [
- "ret"
- ]
- },
- "inputDataExample": "[\n {\n \"id\": 101,\n \"timestamp\": \"2023-10-26T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\"app\": \"Code\", \"title\": \"README.md\"}\n },\n {\n \"id\": 102,\n \"timestamp\": \"2023-10-26T10:05:00Z\",\n \"duration\": 600,\n \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch Documentation\"}\n }\n]",
- "outputDataExample": "[\n {\n \"id\": 101,\n \"timestamp\": \"2023-10-26T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\"app\": \"Code\", \"title\": \"README.md\"}\n },\n {\n \"id\": 102,\n \"timestamp\": \"2023-10-26T10:05:00Z\",\n \"duration\": 600,\n \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch Documentation\"}\n }\n]"
- },
- {
- "simStepId": "50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10",
- "diagramNodeId": "48a7e119-b25c-4b9f-9a95-bd649493ff48",
- "simStepLabel": "Transform: Filter AFK Periods",
- "simStepDescription": "The interpreter continues executing the query, calling transformation functions like `filter_period_intersect`. This function takes the window activity events and intersects them with the 'not-afk' events, effectively removing any time the user was away from the keyboard.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-transform/src/filter_period.rs",
- "startLine": "20",
- "endLine": "69",
- "relevantVariables": [
- "filter_period_intersect"
- ]
- },
- "inputDataExample": "{\n \"events\": [\n {\"timestamp\": \"2023-10-26T10:00:00Z\", \"duration\": 1200, \"data\": {\"app\": \"Code\"}}\n ],\n \"filter_events\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 600, \"data\": {\"status\": \"not-afk\"}}\n ]\n}",
- "outputDataExample": "{\n \"filtered_events\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 600, \"data\": {\"app\": \"Code\"}}\n ]\n}"
- },
- {
- "simStepId": "78aaa465-8377-43f1-9ba6-36ddcf9300cf",
- "diagramNodeId": "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
- "simStepLabel": "Return Transformed Data",
- "simStepDescription": "The list of filtered, non-AFK events is returned to the interpreter. This data is then passed to subsequent transformation functions specified in the query, such as `categorize` or `merge_events_by_keys`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/interpret.rs",
- "startLine": "36",
- "endLine": "228",
- "relevantVariables": [
- "interpret_expr"
- ]
- },
- "inputDataExample": "{\n \"filtered_events\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 600, \"data\": {\"app\": \"Code\"}}\n ]\n}",
- "outputDataExample": "{\n \"filtered_events\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 600, \"data\": {\"app\": \"Code\"}}\n ]\n}"
- },
- {
- "simStepId": "18492fe4-5b57-4749-a2e8-d18f3c546e89",
- "diagramNodeId": "63ebaed0-610a-46cd-8a5b-392c2874aecb",
- "simStepLabel": "Final Aggregation and Return",
- "simStepDescription": "The interpreter completes the query by performing final aggregations like `merge_events_by_keys` and `sort_by_duration`. It assembles the results into a final dictionary structure as defined by the `RETURN` statement in the query script.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/interpret.rs",
- "startLine": "30",
- "endLine": "33",
- "relevantVariables": [
- "env.remove(\"RETURN\")"
- ]
- },
- "inputDataExample": "{\n \"events_to_aggregate\": [\n {\"timestamp\": \"2023-10-26T10:05:00Z\", \"duration\": 300, \"data\": {\"app\": \"Code\", \"title\": \"File A\"}},\n {\"timestamp\": \"2023-10-26T10:10:00Z\", \"duration\": 300, \"data\": {\"app\": \"Code\", \"title\": \"File B\"}}\n ]\n}",
- "outputDataExample": "{\n \"window\": {\n \"app_events\": [\n {\"data\": {\"app\": \"Code\"}, \"duration\": 600}\n ],\n \"duration\": 600\n }\n}"
- },
- {
- "simStepId": "785d1355-bf16-42a7-846e-a2bf3ecbb35b",
- "diagramNodeId": "889f0869-2c33-499b-a558-ede80ee18a54",
- "simStepLabel": "API Response: Send Processed Data",
- "simStepDescription": "The query engine returns the final aggregated data to the API endpoint. The endpoint serializes this data into a JSON format and sends it back to the web client as the HTTP response.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "28",
- "endLine": "28",
- "relevantVariables": [
- "json!(results)"
- ]
- },
- "inputDataExample": "{\n \"window\": {\n \"app_events\": [\n {\"data\": {\"app\": \"Code\", \"title\": \"...\"}, \"duration\": 1800}\n ],\n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\", \"Programming\"]}, \"duration\": 1800}\n ]\n }\n}",
- "outputDataExample": "{\n \"window\": {\n \"app_events\": [\n {\"data\": {\"app\": \"Code\", \"title\": \"...\"}, \"duration\": 1800}\n ],\n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\", \"Programming\"]}, \"duration\": 1800}\n ]\n }\n}"
- },
- {
- "simStepId": "9396ef3a-ed06-4635-bb1d-3b136660bcc4",
- "diagramNodeId": "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd",
- "simStepLabel": "Frontend: Render Dashboard",
- "simStepDescription": "The `aw-webui` frontend receives the JSON data. Its JavaScript code then processes this data to render the various visualizations on the activity dashboard, such as the top applications and categories pie charts, and the activity timeline.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "README.md",
- "startLine": "243",
- "endLine": "250",
- "relevantVariables": [
- "The frontend (`aw-webui`) includes",
- "Data visualization"
- ]
- },
- "inputDataExample": "{\n \"window\": {\n \"app_events\": [\n {\"data\": {\"app\": \"Code\"}, \"duration\": 1800},\n {\"data\": {\"app\": \"Firefox\"}, \"duration\": 1200}\n ],\n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\", \"Programming\"]}, \"duration\": 1800},\n {\"data\": {\"$category\": [\"Media\", \"Video\"]}, \"duration\": 900}\n ]\n }\n}",
- "outputDataExample": "{\n \"dashboardState\": {\n \"topApps\": [{\"label\": \"Code\", \"value\": 1800}, {\"label\": \"Firefox\", \"value\": 1200}],\n \"topCategories\": [{\"label\": \"Work > Programming\", \"value\": 1800}, {\"label\": \"Media > Video\", \"value\": 900}]\n }\n}"
- }
- ],
- "description": "- The
aw-server is responsible for serving a web-based user interface, aw-webui - Users can access this interface, typically at
localhost:5600, to view their tracked data - The web UI sends API requests to the server, using the ActivityWatch Query Language to fetch and process data for display
- Key visualization features include a main activity dashboard showing top applications and categories, a detailed zoomable timeline of events, and a raw data browser
",
- "simulationNodesAndEdges": {
- "12f9554d-dd4e-4f66-bd20-8845b718ef19": {
- "simStepIds": [
- "81f31a9b-3434-4458-a7d3-bdcf610af75e"
- ]
- },
- "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1": {
- "simStepIds": [
- "e91513ab-13ec-4eea-9942-9620dbe3b92b"
- ]
- },
- "a9279dbc-8fda-434c-bc5a-4eefaca0df56": {
- "simStepIds": [
- "3291e01a-482d-401b-98b5-759573be65ca"
- ]
- },
- "be2c99a2-8b27-487f-9c8f-e1d1836613cc": {
- "simStepIds": [
- "475886bc-26d3-4528-84ae-2f9c8e1dfcf9"
- ]
- },
- "48d1c5e2-32b3-4eaf-9005-dd0a65a77448": {
- "simStepIds": [
- "ff017206-8323-4caa-9eca-4fc760c2470f"
- ]
- },
- "48a7e119-b25c-4b9f-9a95-bd649493ff48": {
- "simStepIds": [
- "50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10"
- ]
- },
- "63ebaed0-610a-46cd-8a5b-392c2874aecb": {
- "simStepIds": [
- "18492fe4-5b57-4749-a2e8-d18f3c546e89"
- ]
- },
- "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd": {
- "simStepIds": [
- "9396ef3a-ed06-4635-bb1d-3b136660bcc4"
- ]
- },
- "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f": {
- "simStepIds": [
- "c1a26d9b-d661-4a99-8275-39a414824ed6"
- ]
- },
- "c8403507-4895-4695-84b5-9305afdc3c9f": {
- "simStepIds": [
- "a7b6aefb-1401-4756-bfa1-1eb9a76cde07"
- ]
- },
- "8f8d2c55-63c0-48ec-b931-f848e245688f": {
- "simStepIds": [
- "00784ae1-bb99-494c-bf46-fe5947de5066"
- ]
- },
- "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013": {
- "simStepIds": [
- "e1bf9f3c-e763-4e75-8c62-1a8d739d53cc"
- ]
- },
- "7a14a4d3-a453-4e33-9b10-fb192e40e34e": {
- "simStepIds": [
- "f7dfb334-099f-4750-a893-cd96b1c46278"
- ]
- },
- "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa": {
- "simStepIds": [
- "78aaa465-8377-43f1-9ba6-36ddcf9300cf"
- ]
- },
- "889f0869-2c33-499b-a558-ede80ee18a54": {
- "simStepIds": [
- "785d1355-bf16-42a7-846e-a2bf3ecbb35b"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "aw-webui, aw-server, query, timeline, dashboard",
- "generationPrompt": "How activity data visualization works",
- "generationKeywords": "aw-webui, aw-server, query, timeline, dashboard",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 12,
- "promptTokenCount": 8319,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 123,
- "promptTokenCount": 96744,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 72,
- "promptTokenCount": 53807,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": [
- {
- "path": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "container": "server",
- "triggerType": "http",
- "identifier": "application/json"
- }
- ]
- },
- "crossLayerTriggers": [
- {
- "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "identifier": "application/json",
- "type": "http",
- "matchedTargets": [
- ".github/workflows/test.yml",
- "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "aw-server-rust/aw-server/src/endpoints/import.rs"
- ]
- }
- ]
- }
- },
- "How activity categorization works": {
- "name": "How activity categorization works",
- "simSteps": [
- {
- "simStepId": "1b40cfa3-9cf5-4dc3-830f-74cb1d476d50",
- "diagramNodeId": "49029598-25ad-4498-b744-e2180f404fe5",
- "simStepLabel": "Query Construction",
- "simStepDescription": "A client application or script constructs a query to fetch and categorize events. The `canonicalEvents` function is often used, which includes a `categorize` step. The categorization rules (classes) can be provided directly or fetched from the server's settings.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/queries.py",
- "startLine": "84",
- "endLine": "151",
- "relevantVariables": [
- "canonicalEvents",
- "params",
- "classes_str",
- "categorize"
- ]
- },
- "inputDataExample": "{\n \"params\": {\n \"bid_window\": \"aw-watcher-window_my-pc\",\n \"bid_afk\": \"aw-watcher-afk_my-pc\",\n \"classes\": [\n [\n [\"Work\", \"Programming\"],\n {\"type\": \"regex\", \"regex\": \"Visual Studio Code|Sublime Text\", \"ignore_case\": true}\n ],\n [\n [\"Work\", \"Programming\", \"Rust\"],\n {\"type\": \"regex\", \"regex\": \"\\\\.rs|cargo\", \"ignore_case\": true}\n ]\n ]\n }\n}",
- "outputDataExample": "{\n \"query\": \"events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-pc\\\")));\\nnot_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-pc\\\")));\\nnot_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\\nevents = filter_period_intersect(events, not_afk);\\nevents = categorize(events, [[\\\"Work\\\",\\\"Programming\\\"],{\\\"type\\\":\\\"regex\\\",\\\"regex\\\":\\\"Visual Studio Code|Sublime Text\\\",\\\"ignore_case\\\":true}],[\\\"Work\\\",\\\"Programming\\\",\\\"Rust\\\"],{\\\"type\\\":\\\"regex\\\",\\\"regex\\\":\\\"\\\\\\\\.rs|cargo\\\",\\\"ignore_case\\\":true}]]);\"\n}"
- },
- {
- "simStepId": "9eeb592f-5c44-4ce1-a7a0-261bc6d6b679",
- "diagramNodeId": "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
- "simStepLabel": "API Call: Execute Query",
- "simStepDescription": "The client sends the constructed query string to the ActivityWatch server's API endpoint for execution.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "119",
- "endLine": "131",
- "relevantVariables": [
- "self.post"
- ]
- },
- "inputDataExample": "{\n \"query\": \"... events = categorize(events, [[\\\"Work\\\",\\\"Programming\\\"],{\\\"type\\\":\\\"regex\\\",\\\"regex\\\":\\\"Visual Studio Code|Sublime Text\\\",\\\"ignore_case\\\":true}]]); ...\",\n \"timeperiods\": [\"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"]\n}",
- "outputDataExample": "{\n \"query\": \"... events = categorize(events, [[\\\"Work\\\",\\\"Programming\\\"],{\\\"type\\\":\\\"regex\\\",\\\"regex\\\":\\\"Visual Studio Code|Sublime Text\\\",\\\"ignore_case\\\":true}]]); ...\",\n \"timeperiods\": [\"2023-10-26T00:00:00Z/2023-10-27T00:00:00Z\"]\n}"
- },
- {
- "simStepId": "af6c51b2-ee18-406c-acc6-6e5d9588d012",
- "diagramNodeId": "ff986e21-7050-4c3d-ae40-3a678f46221d",
- "simStepLabel": "Query Engine: Function Invocation",
- "simStepDescription": "The `aw-server-rust` query engine parses the query, recognizes the `categorize` function call, and invokes its registered implementation, passing the fetched events and rules as arguments.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/functions.rs",
- "startLine": "278",
- "endLine": "295",
- "relevantVariables": [
- "categorize",
- "aw_transform::classify::categorize"
- ]
- },
- "inputDataExample": "{\n \"args\": [\n {\n \"DataType::List\": [\"Event(...)\", \"Event(...)\"]\n },\n {\n \"DataType::List\": [\n [\n [\"Work\", \"Programming\"],\n {\"type\": \"regex\", \"regex\": \"Visual Studio Code\"}\n ]\n ]\n }\n ]\n}",
- "outputDataExample": "{\n \"DataType::List\": [\"Event(categorized)\", \"Event(categorized)\"]\n}"
- },
- {
- "simStepId": "e598a658-8e0e-4a76-9310-af0d60ec5828",
- "diagramNodeId": "79c14e32-8192-488e-ab72-b9c4c6edb346",
- "simStepLabel": "Data Transformation: Convert Rules",
- "simStepDescription": "Before executing the core logic, the query engine converts the rule definitions from the generic `DataType::Dict` format into the strongly-typed `Rule` struct that the transform function expects.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/datatype.rs",
- "startLine": "272",
- "endLine": "346",
- "relevantVariables": [
- "TryFrom<&DataType> for Rule",
- "RegexRule::new"
- ]
- },
- "inputDataExample": "{\n \"DataType::Dict\": {\n \"type\": \"regex\",\n \"regex\": \"Visual Studio Code\",\n \"ignore_case\": true\n }\n}",
- "outputDataExample": "{\n \"Rule::Regex\": {\n \"regex\": \"(?i)Visual Studio Code\"\n }\n}"
- },
- {
- "simStepId": "55815d72-39f6-4201-ad99-6ebd57d0eece",
- "diagramNodeId": "e99fcabc-934a-46cd-8823-d3e04ceea63c",
- "simStepLabel": "Categorization Core Logic",
- "simStepDescription": "The main `categorize` function iterates through each event and applies the list of rules to it by calling `categorize_one`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-transform/src/classify.rs",
- "startLine": "70",
- "endLine": "76",
- "relevantVariables": [
- "categorize",
- "categorize_one"
- ]
- },
- "inputDataExample": "{\n \"events\": [\n {\n \"timestamp\": \"2023-10-27T10:00:00Z\",\n \"duration\": 60,\n \"data\": {\"app\": \"Code\", \"title\": \"classify.rs - aw-server-rust\"}\n }\n ],\n \"rules\": [\n [\n [\"Work\", \"Programming\", \"Rust\"],\n {\"regex\": \"(?i)\\\\.rs|cargo\"}\n ]\n ]\n}",
- "outputDataExample": "{\n \"classified_events\": [\n {\n \"timestamp\": \"2023-10-27T10:00:00Z\",\n \"duration\": 60,\n \"data\": {\n \"app\": \"Code\",\n \"title\": \"classify.rs - aw-server-rust\",\n \"$category\": [\"Work\", \"Programming\", \"Rust\"]\n }\n }\n ]\n}"
- },
- {
- "simStepId": "9f7f50e4-03c6-4d7c-95c8-3317d37115eb",
- "diagramNodeId": "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
- "simStepLabel": "Event-Rule Matching",
- "simStepDescription": "For each event, the system iterates through all provided rules and invokes the `matches` method to check if the rule's regex pattern can be found within any of the event's data fields.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-transform/src/classify.rs",
- "startLine": "49",
- "endLine": "57",
- "relevantVariables": [
- "RuleTrait for RegexRule",
- "matches",
- "self.regex.is_match"
- ]
- },
- "inputDataExample": "{\n \"event\": {\n \"data\": {\"app\": \"Code\", \"title\": \"classify.rs - aw-server-rust\"}\n },\n \"rule\": {\n \"regex\": \"(?i)\\\\.rs|cargo\"\n }\n}",
- "outputDataExample": "{\n \"event\": {\n \"data\": {\"app\": \"Code\", \"title\": \"classify.rs - aw-server-rust\"}\n },\n \"rule\": {\n \"regex\": \"(?i)\\\\.rs|cargo\"\n }\n}"
- },
- {
- "simStepId": "e863b0b1-c3ce-4b13-ad7d-a7438f650035",
- "diagramNodeId": "294c7beb-b479-47e2-bd3c-6d616497ecd2",
- "simStepLabel": "Select Highest-Ranking Category",
- "simStepDescription": "If an event matches multiple categories, this function selects the most specific one. Specificity is determined by the depth of the category hierarchy (e.g., `['Work', 'Programming', 'Rust']` is deeper than `['Work', 'Programming']`). If no rules match, a default category of `['Uncategorized']` is assigned.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-transform/src/classify.rs",
- "startLine": "116",
- "endLine": "122",
- "relevantVariables": [
- "_pick_highest_ranking_category"
- ]
- },
- "inputDataExample": "{\n \"current_best_category\": [\"Work\", \"Programming\"],\n \"new_matching_category\": [\"Work\", \"Programming\", \"Rust\"]\n}",
- "outputDataExample": "{\n \"chosen_category\": [\"Work\", \"Programming\", \"Rust\"]\n}"
- },
- {
- "simStepId": "ebd328dc-4cdf-452d-b4aa-10b65e9c354d",
- "diagramNodeId": "b4391f38-d9ee-4377-8568-efca87206124",
- "simStepLabel": "Return Categorized Events",
- "simStepDescription": "After processing all events, the modified list, now with a `$category` field in each event's data, is returned to the query engine. The server then serializes this as JSON and sends it back to the client.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-transform/src/classify.rs",
- "startLine": "85",
- "endLine": "88",
- "relevantVariables": [
- "event.data.insert"
- ]
- },
- "inputDataExample": "{\n \"classified_events\": [\n {\n \"timestamp\": \"2023-10-27T10:00:00Z\",\n \"duration\": 60,\n \"data\": {\n \"app\": \"Code\",\n \"title\": \"classify.rs - aw-server-rust\",\n \"$category\": [\"Work\", \"Programming\", \"Rust\"]\n }\n }\n ]\n}",
- "outputDataExample": "{\n \"classified_events\": [\n {\n \"timestamp\": \"2023-10-27T10:00:00Z\",\n \"duration\": 60,\n \"data\": {\n \"app\": \"Code\",\n \"title\": \"classify.rs - aw-server-rust\",\n \"$category\": [\"Work\", \"Programming\", \"Rust\"]\n }\n }\n ]\n}"
- },
- {
- "simStepId": "2108914e-2569-47bf-aa87-af337de03f8c",
- "diagramNodeId": "9847b0a7-39f2-44f8-ae14-73eab42d8894",
- "simStepLabel": "Client Consumes Categorized Data",
- "simStepDescription": "The client application receives the categorized events. It can then use the `$category` field to perform aggregations and generate reports, such as calculating the total time spent in each top-level category for the day.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "123",
- "endLine": "130",
- "relevantVariables": [
- "cat_time",
- "e[\"data\"][\"$category\"][0]"
- ]
- },
- "inputDataExample": "{\n \"cat_events\": [\n {\n \"data\": {\"$category\": [\"Work\", \"Programming\", \"Rust\"]},\n \"duration\": 3600\n },\n {\n \"data\": {\"$category\": [\"Work\", \"Meetings\"]},\n \"duration\": 1800\n },\n {\n \"data\": {\"$category\": [\"Media\", \"Video\"]},\n \"duration\": 1200\n }\n ]\n}",
- "outputDataExample": "{\n \"aggregated_time\": {\n \"Work\": \"1h 30m\",\n \"Media\": \"20m\"\n }\n}"
- }
- ],
- "description": "- ActivityWatch allows users to transform raw data into meaningful insights through categorization
- This is achieved by defining rules, typically using regular expressions (
regex), that match against event data like window titles or application names - The
categorize function, used within the query language, applies these rules to events and assigns them to a category (e - g
- ,
Work, Programming) - These categories are then used in the web UI to generate aggregated reports, helping users understand how they spend their time across different life areas
",
- "simulationNodesAndEdges": {
- "49029598-25ad-4498-b744-e2180f404fe5": {
- "simStepIds": [
- "1b40cfa3-9cf5-4dc3-830f-74cb1d476d50"
- ]
- },
- "ff986e21-7050-4c3d-ae40-3a678f46221d": {
- "simStepIds": [
- "af6c51b2-ee18-406c-acc6-6e5d9588d012"
- ]
- },
- "e99fcabc-934a-46cd-8823-d3e04ceea63c": {
- "simStepIds": [
- "55815d72-39f6-4201-ad99-6ebd57d0eece"
- ]
- },
- "294c7beb-b479-47e2-bd3c-6d616497ecd2": {
- "simStepIds": [
- "e863b0b1-c3ce-4b13-ad7d-a7438f650035"
- ]
- },
- "9847b0a7-39f2-44f8-ae14-73eab42d8894": {
- "simStepIds": [
- "2108914e-2569-47bf-aa87-af337de03f8c"
- ]
- },
- "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661": {
- "simStepIds": [
- "9eeb592f-5c44-4ce1-a7a0-261bc6d6b679"
- ]
- },
- "79c14e32-8192-488e-ab72-b9c4c6edb346": {
- "simStepIds": [
- "e598a658-8e0e-4a76-9310-af0d60ec5828"
- ]
- },
- "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8": {
- "simStepIds": [
- "9f7f50e4-03c6-4d7c-95c8-3317d37115eb"
- ]
- },
- "b4391f38-d9ee-4377-8568-efca87206124": {
- "simStepIds": [
- "ebd328dc-4cdf-452d-b4aa-10b65e9c354d"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "categorize, Rule, regex, category, aw_transform/classify.py",
- "generationPrompt": "How activity categorization works",
- "generationKeywords": "categorize, Rule, regex, category, aw_transform/classify.py",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 11,
- "promptTokenCount": 6843,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 13,
- "promptTokenCount": 13255,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 16,
- "promptTokenCount": 10044,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": []
- }
- }
- },
- "How the data query language works": {
- "name": "How the data query language works",
- "simSteps": [
- {
- "simStepId": "06f7c9e7-1c78-4114-867b-3dbb20dcc427",
- "diagramNodeId": "5540d168-0892-4d44-a835-530768fbad09",
- "simStepLabel": "Python Flow: Client Initiates API Query",
- "simStepDescription": "A client application, using the `aw-client` library, constructs a query to fetch data from the ActivityWatch server. It specifies the query string and the time periods to analyze.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "305",
- "endLine": "338",
- "relevantVariables": [
- "query",
- "timeperiods",
- "endpoint",
- "data"
- ]
- },
- "inputDataExample": "{\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');\\nRETURN = events;\",\n \"timeperiods\": [\n {\n \"start\": \"2023-01-01T00:00:00Z\",\n \"end\": \"2023-01-02T00:00:00Z\"\n }\n ]\n}",
- "outputDataExample": "{\n \"endpoint\": \"query/\",\n \"data\": {\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ]\n }\n}"
- },
- {
- "simStepId": "5dc6bd77-15d2-44c3-b665-8de88288c314",
- "diagramNodeId": "71408ae2-19e6-4327-bab9-8918af09c855",
- "simStepLabel": "API Call: Transmit Query to Python Server",
- "simStepDescription": "The client sends an HTTP POST request to the `/api/0/query/` endpoint of the `aw-server` (Python implementation), with the query and time periods in the request body.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "115",
- "endLine": "127",
- "relevantVariables": [
- "_post"
- ]
- },
- "inputDataExample": "{\n \"endpoint\": \"query/\",\n \"data\": {\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ]\n }\n}",
- "outputDataExample": "{\n \"endpoint\": \"query/\",\n \"data\": {\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ]\n }\n}"
- },
- {
- "simStepId": "671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7",
- "diagramNodeId": "abf45adb-988a-4613-ab4a-acb8cef0c90a",
- "simStepLabel": "Python Flow: API Endpoint Receives Request",
- "simStepDescription": "The Flask-based `aw-server` receives the incoming POST request. The `/api/0/query/` route is handled by the `QueryResource`, which extracts the query payload from the request.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "310",
- "endLine": "326",
- "relevantVariables": [
- "QueryResource",
- "post",
- "request",
- "current_app.api.query2"
- ]
- },
- "inputDataExample": "{\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ]\n}",
- "outputDataExample": "{\n \"name\": \"\",\n \"query\": {\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ]\n },\n \"cache\": false\n}"
- },
- {
- "simStepId": "5a0d9b17-b09a-4aa5-9234-c01cb2aadef4",
- "diagramNodeId": "891bfe3a-f22a-4998-acea-aa6d0c362821",
- "simStepLabel": "Data Flow: Pass Query to API Logic",
- "simStepDescription": "The parsed query data is passed from the REST endpoint layer to the `ServerAPI` business logic layer for processing.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "320",
- "endLine": "323",
- "relevantVariables": [
- "current_app.api.query2"
- ]
- },
- "inputDataExample": "{\n \"name\": \"\",\n \"query\": {\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ]\n },\n \"cache\": false\n}",
- "outputDataExample": "{\n \"name\": \"\",\n \"query\": {\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ]\n },\n \"cache\": false\n}"
- },
- {
- "simStepId": "a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31",
- "diagramNodeId": "96c3be58-d96a-4b11-b4f3-e778387f76b8",
- "simStepLabel": "Python Flow: ServerAPI Orchestrates Query",
- "simStepDescription": "The `ServerAPI.query2` method iterates through each specified time period and invokes the core query engine (`query2.query`) from `aw-core` for each one.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "339",
- "endLine": "349",
- "relevantVariables": [
- "query2",
- "timeperiods",
- "starttime",
- "endtime",
- "query2.query"
- ]
- },
- "inputDataExample": "{\n \"name\": \"\",\n \"query\": [\n \"events = query_bucket('aw-watcher-window_test-host');\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00+00:00/2023-01-02T00:00:00+00:00\"\n ],\n \"cache\": false\n}",
- "outputDataExample": "{\n \"name\": \"\",\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');RETURN = events;\",\n \"starttime\": \"2023-01-01T00:00:00+00:00\",\n \"endtime\": \"2023-01-02T00:00:00+00:00\",\n \"datastore\": \"\"\n}"
- },
- {
- "simStepId": "833f0f0f-ec00-4960-b1f9-46d8a8530a01",
- "diagramNodeId": "b79b67f9-1be1-48f1-920a-9ebdd4417272",
- "simStepLabel": "Data Flow: Pass Query to Interpreter",
- "simStepDescription": "The raw query string, along with the time range and a datastore instance, is passed to the `query` function in `aw-core/aw_query/query2.py`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "348",
- "endLine": "348",
- "relevantVariables": [
- "query2.query"
- ]
- },
- "inputDataExample": "{\n \"name\": \"\",\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');RETURN = events;\",\n \"starttime\": \"2023-01-01T00:00:00+00:00\",\n \"endtime\": \"2023-01-02T00:00:00+00:00\",\n \"datastore\": \"\"\n}",
- "outputDataExample": "{\n \"name\": \"\",\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');RETURN = events;\",\n \"starttime\": \"2023-01-01T00:00:00+00:00\",\n \"endtime\": \"2023-01-02T00:00:00+00:00\",\n \"datastore\": \"\"\n}"
- },
- {
- "simStepId": "5f7b6985-edf0-42eb-8822-847d0d7b8e9b",
- "diagramNodeId": "c0a28353-be8d-4bc8-a1be-2879961fc4df",
- "simStepLabel": "Python Flow: Parse and Interpret Query",
- "simStepDescription": "The `query` function in `aw-core/aw_query/query2.py` acts as the interpreter. It splits the query into individual statements, parses each one into tokens (like variables and function calls), and then interprets them chronologically. Function calls are resolved by looking them up in the `functions` dictionary, which is populated by functions in `aw-core/aw_query/functions.py`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_query/query2.py",
- "startLine": "404",
- "endLine": "418",
- "relevantVariables": [
- "query",
- "parse",
- "interpret"
- ]
- },
- "inputDataExample": "{\n \"query\": \"events = query_bucket('aw-watcher-window_test-host');\\nRETURN = events;\"\n}",
- "outputDataExample": "{\n \"statement\": \"events = query_bucket('aw-watcher-window_test-host')\",\n \"var\": \"\",\n \"val\": \"\"\n}"
- },
- {
- "simStepId": "7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6",
- "diagramNodeId": "4059fcbe-a1ee-41d0-b576-55a1d278bca0",
- "simStepLabel": "Data Flow: Execute Query Function",
- "simStepDescription": "During interpretation, a `QFunction` token for `query_bucket` is executed. The `interpret` method looks up `q2_query_bucket` in `aw-core/aw_query/functions.py` and calls it.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_query/query2.py",
- "startLine": "133",
- "endLine": "148",
- "relevantVariables": [
- "QFunction.interpret",
- "functions"
- ]
- },
- "inputDataExample": "{\n \"function_name\": \"query_bucket\",\n \"args\": [\n \"\",\n \"{'STARTTIME': '...', 'ENDTIME': '...'}\",\n \"aw-watcher-window_test-host\"\n ]\n}",
- "outputDataExample": "{\n \"function_name\": \"query_bucket\",\n \"args\": [\n \"\",\n \"{'STARTTIME': '...', 'ENDTIME': '...'}\",\n \"aw-watcher-window_test-host\"\n ]\n}"
- },
- {
- "simStepId": "6ea3ab36-027f-40b9-a0ba-9ede77ae1117",
- "diagramNodeId": "fb0bcd2a-5999-47fc-bb41-11233e3544fa",
- "simStepLabel": "Python Flow: Fetch Events from Datastore",
- "simStepDescription": "The `q2_query_bucket` function interacts with the datastore to fetch events for the specified bucket and time range.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_query/functions.py",
- "startLine": "151",
- "endLine": "164",
- "relevantVariables": [
- "q2_query_bucket",
- "datastore.get"
- ]
- },
- "inputDataExample": "{\n \"bucketname\": \"aw-watcher-window_test-host\",\n \"starttime\": \"2023-01-01T00:00:00+00:00\",\n \"endtime\": \"2023-01-02T00:00:00+00:00\"\n}",
- "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
- },
- {
- "simStepId": "ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c",
- "diagramNodeId": "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
- "simStepLabel": "Data Flow: Return Events to Interpreter",
- "simStepDescription": "The list of fetched events is returned from the datastore, through the `q2_query_bucket` function, and back to the `interpret` function.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_datastore/datastore.py",
- "startLine": "88",
- "endLine": "114",
- "relevantVariables": [
- "Bucket.get",
- "self.ds.storage_strategy.get_events"
- ]
- },
- "inputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
- "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
- },
- {
- "simStepId": "ab3fe2d5-9396-4241-b64e-2a187e97de75",
- "diagramNodeId": "5eb14d26-499c-4ea4-8282-3f923646dbdb",
- "simStepLabel": "Python Flow: Finalize and Return Result",
- "simStepDescription": "The interpreter completes all statements. The `get_return` function is called to extract the final value assigned to the `RETURN` variable from the execution namespace.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_query/query2.py",
- "startLine": "396",
- "endLine": "401",
- "relevantVariables": [
- "get_return",
- "namespace['RETURN']"
- ]
- },
- "inputDataExample": "{\n \"namespace\": {\n \"STARTTIME\": \"...\",\n \"ENDTIME\": \"...\",\n \"events\": [{\"id\": 101, ...}],\n \"RETURN\": [{\"id\": 101, ...}]\n }\n}",
- "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
- },
- {
- "simStepId": "fe43857f-ef7d-455d-a9c4-37d54d12207a",
- "diagramNodeId": "c4b6d403-d2a9-4cff-8a72-31189a53c0db",
- "simStepLabel": "API Call: Send JSON Response",
- "simStepDescription": "The final result is returned up the call stack to the `rest.py` endpoint, serialized into JSON, and sent back to the client as an HTTP response.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "323",
- "endLine": "323",
- "relevantVariables": [
- "jsonify"
- ]
- },
- "inputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
- "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
- },
- {
- "simStepId": "3118dc4c-d7ad-4996-aa81-a205ccdf6e72",
- "diagramNodeId": "7ace16a3-9438-4e78-bcf9-79131079c89d",
- "simStepLabel": "Rust Flow: Client Initiates API Query",
- "simStepDescription": "A client application sends a query to the ActivityWatch server. This example uses the Rust client for consistency, but any HTTP client can be used.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-client-rust/src/blocking.rs",
- "startLine": "64",
- "endLine": "69",
- "relevantVariables": [
- "query"
- ]
- },
- "inputDataExample": "{\n \"query\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\",\n \"timeperiods\": [\n {\n \"start\": \"2023-01-01T00:00:00Z\",\n \"end\": \"2023-01-02T00:00:00Z\"\n }\n ]\n}",
- "outputDataExample": "{\n \"url\": \"http://127.0.0.1:5600/api/0/query\",\n \"body\": {\n \"query\": [\n \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00Z/2023-01-02T00:00:00Z\"\n ]\n }\n}"
- },
- {
- "simStepId": "97542310-17cf-4c99-9ce9-a328dffa5f4c",
- "diagramNodeId": "ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
- "simStepLabel": "API Call: Transmit Query to Rust Server",
- "simStepDescription": "The client sends an HTTP POST request to the `/api/0/query` endpoint of the `aw-server-rust` implementation, with the query and time periods in the request body.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-client-rust/src/lib.rs",
- "startLine": "112",
- "endLine": "137",
- "relevantVariables": [
- "query"
- ]
- },
- "inputDataExample": "{\n \"url\": \"http://127.0.0.1:5600/api/0/query\",\n \"body\": {\n \"query\": [\n \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00Z/2023-01-02T00:00:00Z\"\n ]\n }\n}",
- "outputDataExample": "{\n \"url\": \"http://127.0.0.1:5600/api/0/query\",\n \"body\": {\n \"query\": [\n \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00Z/2023-01-02T00:00:00Z\"\n ]\n }\n}"
- },
- {
- "simStepId": "1c25a330-b713-4866-9440-8737c787ce33",
- "diagramNodeId": "b93b83dd-fff3-44dc-ac22-3ea63117c222",
- "simStepLabel": "Rust Flow: API Endpoint Receives Request",
- "simStepDescription": "The Rocket-based `aw-server-rust` receives the request. The `query` endpoint in `endpoints/query.rs` deserializes the JSON payload into a `Query` struct and joins the query lines.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "9",
- "endLine": "29",
- "relevantVariables": [
- "query",
- "query_req",
- "query_code",
- "intervals"
- ]
- },
- "inputDataExample": "{\n \"query\": [\n \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\",\n \"RETURN = events;\"\n ],\n \"timeperiods\": [\n \"2023-01-01T00:00:00Z/2023-01-02T00:00:00Z\"\n ]\n}",
- "outputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\",\n \"interval\": \"\"\n}"
- },
- {
- "simStepId": "6eb126a9-5234-4495-9727-ec2741ce9660",
- "diagramNodeId": "d3cb01a0-d8cd-4382-b122-d1234b0562bc",
- "simStepLabel": "Data Flow: Pass Query to Core Engine",
- "simStepDescription": "The query string and time interval are passed from the endpoint to the `aw_query::query` function, the entry point of the Rust query engine.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "16",
- "endLine": "24",
- "relevantVariables": [
- "aw_query::query"
- ]
- },
- "inputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\",\n \"interval\": \"\"\n}",
- "outputDataExample": "{\n \"query_code\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\",\n \"interval\": \"\"\n}"
- },
- {
- "simStepId": "024a46d7-abc2-4c35-92d1-900d198f748c",
- "diagramNodeId": "d8afb2b7-af24-431a-b206-828a8b7cef2a",
- "simStepLabel": "Rust Flow: Lexing and Parsing",
- "simStepDescription": "The `aw_query::query` function first uses a lexer (`lexer.rs`) to convert the query string into a stream of tokens. Then, a parser (`parser.rs`) consumes the tokens to build an Abstract Syntax Tree (AST) representing the query's structure.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/lib.rs",
- "startLine": "53",
- "endLine": "62",
- "relevantVariables": [
- "query",
- "lexer::Lexer",
- "parser::parse"
- ]
- },
- "inputDataExample": "{\n \"code\": \"events = query_bucket(\\\"aw-watcher-window_test-host\\\");\\nRETURN = events;\"\n}",
- "outputDataExample": "{\n \"program\": \"\"\n}"
- },
- {
- "simStepId": "acc1ad56-50cb-41ab-9217-f8d15af6686c",
- "diagramNodeId": "e72e1881-49ce-41ad-966a-90a26ca47453",
- "simStepLabel": "Data Flow: Pass AST to Interpreter",
- "simStepDescription": "The generated Abstract Syntax Tree (AST) is passed to the `interpret_prog` function for execution.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/lib.rs",
- "startLine": "63",
- "endLine": "63",
- "relevantVariables": [
- "interpret::interpret_prog"
- ]
- },
- "inputDataExample": "{\n \"program\": \"\"\n}",
- "outputDataExample": "{\n \"program\": \"\"\n}"
- },
- {
- "simStepId": "e3204124-26ff-4799-8462-100305c27ae1",
- "diagramNodeId": "630bda35-fbd5-40ec-b47d-37ad66379d94",
- "simStepLabel": "Rust Flow: Interpret AST",
- "simStepDescription": "The `interpret_prog` function in `interpret.rs` initializes an environment and recursively evaluates each expression (`Expr`) in the AST using `interpret_expr`. Function calls are resolved by looking up their names in the environment, which is pre-populated with built-in functions from `functions.rs`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/interpret.rs",
- "startLine": "21",
- "endLine": "34",
- "relevantVariables": [
- "interpret_prog",
- "interpret_expr"
- ]
- },
- "inputDataExample": "{\n \"expression\": \"Assign('events', Function('query_bucket', ...))\"\n}",
- "outputDataExample": "{\n \"env\": {\n \"events\": \"\",\n \"query_bucket\": \"\"\n }\n}"
- },
- {
- "simStepId": "f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5",
- "diagramNodeId": "15dfaeb9-fb37-4296-972f-0188abd0b353",
- "simStepLabel": "Data Flow: Execute Query Function",
- "simStepDescription": "When interpreting a `Function` node, the corresponding function from the `qfunctions` module in `functions.rs` is executed. In this case, `query_bucket` is called.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/interpret.rs",
- "startLine": "213",
- "endLine": "226",
- "relevantVariables": [
- "Expr_::Function",
- "fun"
- ]
- },
- "inputDataExample": "{\n \"function_name\": \"query_bucket\",\n \"args\": [\n \"aw-watcher-window_test-host\"\n ]\n}",
- "outputDataExample": "{\n \"function_name\": \"query_bucket\",\n \"args\": [\n \"aw-watcher-window_test-host\"\n ]\n}"
- },
- {
- "simStepId": "06d75f72-3fc8-47d8-85ab-f7fa317f4de5",
- "diagramNodeId": "eecd0f91-7c53-4352-8d85-05c3dd46bee1",
- "simStepLabel": "Rust Flow: Fetch Events from Datastore",
- "simStepDescription": "The `query_bucket` function calls the datastore's `get_events` method to retrieve events from the specified bucket within the given time interval.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/functions.rs",
- "startLine": "139",
- "endLine": "167",
- "relevantVariables": [
- "qfunctions::query_bucket",
- "ds.get_events"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_test-host\",\n \"interval\": \"\"\n}",
- "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
- },
- {
- "simStepId": "f69e7df0-6666-4b48-a0a6-1000c8ccede0",
- "diagramNodeId": "9792d1f0-08be-4f90-8e68-3caee0eb2498",
- "simStepLabel": "Data Flow: Return Events to Interpreter",
- "simStepDescription": "The datastore returns a `Vec`, which is then wrapped in a `DataType::List` and returned by the `query_bucket` function back to the interpreter.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "startLine": "700",
- "endLine": "797",
- "relevantVariables": [
- "get_events"
- ]
- },
- "inputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
- "outputDataExample": "[{\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\",\n \"duration\": 300,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
- },
- {
- "simStepId": "9382ac29-7930-4f83-afdd-deb2bfc221e3",
- "diagramNodeId": "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4",
- "simStepLabel": "Rust Flow: Finalize and Return Result",
- "simStepDescription": "After executing all statements (including handling the `Return` expression which sets the special `RETURN` variable in the environment), the `interpret_prog` function retrieves the final value from the environment.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/interpret.rs",
- "startLine": "30",
- "endLine": "33",
- "relevantVariables": [
- "env.remove(\"RETURN\")"
- ]
- },
- "inputDataExample": "{\n \"env\": {\n \"TIMEINTERVAL\": \"...\",\n \"events\": \"\",\n \"RETURN\": \"\"\n }\n}",
- "outputDataExample": "[\n {\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n },\n \"duration\": 300.0,\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\"\n }\n]"
- },
- {
- "simStepId": "2f510957-0fdb-4253-a4fb-4122a252fc1e",
- "diagramNodeId": "",
- "simStepLabel": "API Call: Send JSON Response",
- "simStepDescription": "The final result is returned up the call stack to the `endpoints/query.rs` endpoint, serialized into a JSON `Value`, and sent back to the client as an HTTP response.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "28",
- "endLine": "28",
- "relevantVariables": [
- "json!"
- ]
- },
- "inputDataExample": "[\n {\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n },\n \"duration\": 300.0,\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\"\n }\n]",
- "outputDataExample": "[\n {\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n },\n \"duration\": 300.0,\n \"id\": 101,\n \"timestamp\": \"2023-01-01T10:00:00Z\"\n }\n]"
- }
- ],
- "description": "- ActivityWatch features a powerful custom query language for advanced data analysis and transformation
- Queries are scripts composed of function calls and variable assignments that process event data fetched from the datastore
- It includes a rich library of transformation functions like
filter_keyvals, merge_events_by_keys, sum_durations, and categorize - The
aw-server parses and executes these queries, returning the final value assigned to the RETURN variable - Users can run custom queries through the Web UI's Query Explorer or programmatically via the API
",
- "simulationNodesAndEdges": {
- "5540d168-0892-4d44-a835-530768fbad09": {
- "simStepIds": [
- "06f7c9e7-1c78-4114-867b-3dbb20dcc427"
- ]
- },
- "abf45adb-988a-4613-ab4a-acb8cef0c90a": {
- "simStepIds": [
- "671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7"
- ]
- },
- "96c3be58-d96a-4b11-b4f3-e778387f76b8": {
- "simStepIds": [
- "a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31"
- ]
- },
- "c0a28353-be8d-4bc8-a1be-2879961fc4df": {
- "simStepIds": [
- "5f7b6985-edf0-42eb-8822-847d0d7b8e9b"
- ]
- },
- "fb0bcd2a-5999-47fc-bb41-11233e3544fa": {
- "simStepIds": [
- "6ea3ab36-027f-40b9-a0ba-9ede77ae1117"
- ]
- },
- "5eb14d26-499c-4ea4-8282-3f923646dbdb": {
- "simStepIds": [
- "ab3fe2d5-9396-4241-b64e-2a187e97de75"
- ]
- },
- "7ace16a3-9438-4e78-bcf9-79131079c89d": {
- "simStepIds": [
- "3118dc4c-d7ad-4996-aa81-a205ccdf6e72"
- ]
- },
- "b93b83dd-fff3-44dc-ac22-3ea63117c222": {
- "simStepIds": [
- "1c25a330-b713-4866-9440-8737c787ce33"
- ]
- },
- "d8afb2b7-af24-431a-b206-828a8b7cef2a": {
- "simStepIds": [
- "024a46d7-abc2-4c35-92d1-900d198f748c"
- ]
- },
- "630bda35-fbd5-40ec-b47d-37ad66379d94": {
- "simStepIds": [
- "e3204124-26ff-4799-8462-100305c27ae1"
- ]
- },
- "eecd0f91-7c53-4352-8d85-05c3dd46bee1": {
- "simStepIds": [
- "06d75f72-3fc8-47d8-85ab-f7fa317f4de5"
- ]
- },
- "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4": {
- "simStepIds": [
- "9382ac29-7930-4f83-afdd-deb2bfc221e3"
- ]
- },
- "71408ae2-19e6-4327-bab9-8918af09c855": {
- "simStepIds": [
- "5dc6bd77-15d2-44c3-b665-8de88288c314"
- ]
- },
- "891bfe3a-f22a-4998-acea-aa6d0c362821": {
- "simStepIds": [
- "5a0d9b17-b09a-4aa5-9234-c01cb2aadef4"
- ]
- },
- "b79b67f9-1be1-48f1-920a-9ebdd4417272": {
- "simStepIds": [
- "833f0f0f-ec00-4960-b1f9-46d8a8530a01"
- ]
- },
- "4059fcbe-a1ee-41d0-b576-55a1d278bca0": {
- "simStepIds": [
- "7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6"
- ]
- },
- "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4": {
- "simStepIds": [
- "ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c"
- ]
- },
- "c4b6d403-d2a9-4cff-8a72-31189a53c0db": {
- "simStepIds": [
- "fe43857f-ef7d-455d-a9c4-37d54d12207a"
- ]
- },
- "ed18dcc0-5e4a-44fb-b661-f746f1e893f1": {
- "simStepIds": [
- "97542310-17cf-4c99-9ce9-a328dffa5f4c"
- ]
- },
- "d3cb01a0-d8cd-4382-b122-d1234b0562bc": {
- "simStepIds": [
- "6eb126a9-5234-4495-9727-ec2741ce9660"
- ]
- },
- "e72e1881-49ce-41ad-966a-90a26ca47453": {
- "simStepIds": [
- "acc1ad56-50cb-41ab-9217-f8d15af6686c"
- ]
- },
- "15dfaeb9-fb37-4296-972f-0188abd0b353": {
- "simStepIds": [
- "f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5"
- ]
- },
- "9792d1f0-08be-4f90-8e68-3caee0eb2498": {
- "simStepIds": [
- "f69e7df0-6666-4b48-a0a6-1000c8ccede0"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "query2, aw_query, QFunction, interpret, RETURN",
- "generationPrompt": "How the data query language works",
- "generationKeywords": "query2, aw_query, QFunction, interpret, RETURN",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 14,
- "promptTokenCount": 9352,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 123,
- "promptTokenCount": 88309,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 54,
- "promptTokenCount": 34979,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": [
- {
- "path": ".github/workflows/test.yml",
- "container": "shared",
- "triggerType": "http",
- "identifier": "application/json"
- }
- ]
- },
- "crossLayerTriggers": [
- {
- "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "identifier": "application/json",
- "type": "http",
- "matchedTargets": [
- ".github/workflows/test.yml",
- "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "aw-server-rust/aw-server/src/endpoints/import.rs"
- ]
- }
- ]
- }
- },
- "How AFK (Away From Keyboard) detection works": {
- "name": "How AFK (Away From Keyboard) detection works",
- "simSteps": [
- {
- "simStepId": "8ffbcadf-f26a-483a-9902-95e5a761de64",
- "diagramNodeId": "ba27c535-e0e5-44ae-b9f0-2827227ebfe2",
- "simStepLabel": "AFK Watcher Entrypoint",
- "simStepDescription": "The `aw-watcher-afk` process is started. The `main` function is called, which parses command-line arguments, sets up logging, and initializes the `AFKWatcher`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/__main__.py",
- "startLine": "7",
- "endLine": "21",
- "relevantVariables": [
- "main",
- "parse_args",
- "setup_logging",
- "AFKWatcher",
- "watcher.run"
- ]
- },
- "inputDataExample": "null",
- "outputDataExample": "{\"testing\": false, \"verbose\": false, \"host\": null, \"port\": null, \"timeout\": 180.0, \"poll_time\": 5.0}"
- },
- {
- "simStepId": "60e1002f-9782-4c8d-b104-f4bb172e2c91",
- "diagramNodeId": "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
- "simStepLabel": "Initialize Watcher",
- "simStepDescription": "The parsed arguments and testing flag are passed to the `AFKWatcher` constructor.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/__main__.py",
- "startLine": "20",
- "endLine": "20",
- "relevantVariables": [
- "AFKWatcher"
- ]
- },
- "inputDataExample": "{\"testing\": false, \"verbose\": false, \"host\": null, \"port\": null, \"timeout\": 180.0, \"poll_time\": 5.0}",
- "outputDataExample": "{\"testing\": false, \"verbose\": false, \"host\": null, \"port\": null, \"timeout\": 180.0, \"poll_time\": 5.0}"
- },
- {
- "simStepId": "daeeac12-287a-4144-9028-6ea841b196c4",
- "diagramNodeId": "79468b99-a4de-48b7-bb67-506dc0dcb41c",
- "simStepLabel": "Load Configuration",
- "simStepDescription": "The `AFKWatcher` constructor loads its configuration, setting the `timeout` (time of inactivity to be considered AFK) and `poll_time` (how often to check for activity). It also initializes the `ActivityWatchClient` to communicate with the server.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "42",
- "endLine": "53",
- "relevantVariables": [
- "AFKWatcher.__init__",
- "Settings",
- "load_config",
- "ActivityWatchClient"
- ]
- },
- "inputDataExample": "{\"args\": {\"timeout\": 180.0, \"poll_time\": 5.0, \"host\": null, \"port\": null}, \"testing\": false}",
- "outputDataExample": "{\"settings\": {\"timeout\": 180, \"poll_time\": 5}, \"client\": \"\", \"bucketname\": \"aw-watcher-afk_my-laptop\"}"
- },
- {
- "simStepId": "1422a5f8-ad2e-4b32-8955-ee6bb3053286",
- "diagramNodeId": "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
- "simStepLabel": "Start Main Loop",
- "simStepDescription": "After initialization, the `run` method is called, which creates the necessary data bucket on the server and then starts the main `heartbeat_loop`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "71",
- "endLine": "72",
- "relevantVariables": [
- "self.client",
- "self.heartbeat_loop"
- ]
- },
- "inputDataExample": "null",
- "outputDataExample": "null"
- },
- {
- "simStepId": "6579f587-817d-4d23-a9df-86abc54273ae",
- "diagramNodeId": "6b45de30-296e-4896-915c-371f09843599",
- "simStepLabel": "Check User Activity",
- "simStepDescription": "Inside the `heartbeat_loop`, the watcher calls `seconds_since_last_input()` to get the time elapsed since the last keyboard or mouse activity from the operating system.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "86",
- "endLine": "86",
- "relevantVariables": [
- "seconds_since_last_input"
- ]
- },
- "inputDataExample": "null",
- "outputDataExample": "{\"seconds_since_input\": 185.3}"
- },
- {
- "simStepId": "2588211c-b086-4768-8a87-a86764c7e5cd",
- "diagramNodeId": "e514d9e2-e803-4041-b693-65878401b214",
- "simStepLabel": "Platform-Specific Call",
- "simStepDescription": "The `seconds_since_last_input` call is dispatched to the appropriate platform-specific implementation (Windows, macOS, or Unix).",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "14",
- "endLine": "24",
- "relevantVariables": [
- "system",
- "seconds_since_last_input"
- ]
- },
- "inputDataExample": "null",
- "outputDataExample": "null"
- },
- {
- "simStepId": "4d2c85c7-0754-429a-8a55-c64d4da0d37c",
- "diagramNodeId": "b7321a6c-302b-4701-9ea5-5c05c6d3e71b",
- "simStepLabel": "Get Idle Time (Unix Example)",
- "simStepDescription": "On Unix-like systems, listeners for mouse and keyboard events are checked. If a new event has occurred since the last check, the `last_activity` timestamp is updated. The function then returns the total seconds between now and the last recorded activity.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/unix.py",
- "startLine": "21",
- "endLine": "31",
- "relevantVariables": [
- "LastInputUnix.seconds_since_last_input",
- "self.mouseListener.has_new_event",
- "self.keyboardListener.has_new_event"
- ]
- },
- "inputDataExample": "null",
- "outputDataExample": "185.3"
- },
- {
- "simStepId": "9195e582-b3fa-4848-b151-0236a8a5d176",
- "diagramNodeId": "eeb9224a-fff6-4652-b733-ea430b820a2c",
- "simStepLabel": "Return Idle Time",
- "simStepDescription": "The idle time in seconds is returned to the `heartbeat_loop`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "86",
- "endLine": "86",
- "relevantVariables": [
- "seconds_since_input"
- ]
- },
- "inputDataExample": "185.3",
- "outputDataExample": "185.3"
- },
- {
- "simStepId": "3e0e033c-c32f-4d0d-aa65-a278d77e80c7",
- "diagramNodeId": "faab8465-be29-479d-890a-7936dc5cfbdd",
- "simStepLabel": "Detect State Change: User Becomes AFK",
- "simStepDescription": "The watcher compares the idle time with the configured timeout. Since the user was previously not AFK (`afk=False`) and the idle time (`185.3s`) is greater than the timeout (`180s`), the user's state changes to AFK.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "98",
- "endLine": "105",
- "relevantVariables": [
- "afk",
- "seconds_since_input",
- "self.settings.timeout",
- "self.ping"
- ]
- },
- "inputDataExample": "{\"afk\": false, \"seconds_since_input\": 185.3, \"timeout\": 180}",
- "outputDataExample": "{\"afk\": true}"
- },
- {
- "simStepId": "78d78341-ced8-4fc6-bc93-ce4a62c8adf6",
- "diagramNodeId": "196358b9-6ae9-4f52-ad78-ff88b4a49403",
- "simStepLabel": "Send Final 'not-afk' Heartbeat",
- "simStepDescription": "Before officially changing the state, a final `not-afk` heartbeat is sent to accurately mark the end of the active period.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "100",
- "endLine": "100",
- "relevantVariables": [
- "self.ping"
- ]
- },
- "inputDataExample": "{\"afk\": false, \"timestamp\": \"2023-10-27T10:27:15.123456+00:00\"}",
- "outputDataExample": "{\"afk\": false, \"timestamp\": \"2023-10-27T10:27:15.123456+00:00\"}"
- },
- {
- "simStepId": "dc58bc3e-b09e-4df2-870b-76419e78dd3d",
- "diagramNodeId": "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5",
- "simStepLabel": "Prepare Event for Server",
- "simStepDescription": "The `ping` method constructs an `Event` object containing the user's status. It then calls the client's `heartbeat` method to send this event to the `aw-server`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "55",
- "endLine": "59",
- "relevantVariables": [
- "ping",
- "Event",
- "self.client.heartbeat"
- ]
- },
- "inputDataExample": "{\"afk\": false, \"timestamp\": \"2023-10-27T10:27:15.123456+00:00\", \"duration\": 0}",
- "outputDataExample": "{\"timestamp\": \"2023-10-27T10:27:15.123Z\", \"duration\": 0.0, \"data\": {\"status\": \"not-afk\"}}"
- },
- {
- "simStepId": "c9a127c1-afd0-4def-a0fe-c490c9b64039",
- "diagramNodeId": "b520b088-6f6f-4b32-afba-5ef244691c44",
- "simStepLabel": "Send First 'afk' Heartbeat",
- "simStepDescription": "After the state change, the first `afk` heartbeat is sent to mark the beginning of the idle period.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "103",
- "endLine": "105",
- "relevantVariables": [
- "self.ping"
- ]
- },
- "inputDataExample": "{\"afk\": true, \"timestamp\": \"2023-10-27T10:27:15.124456+00:00\", \"duration\": 185.3}",
- "outputDataExample": "{\"afk\": true, \"timestamp\": \"2023-10-27T10:27:15.124456+00:00\", \"duration\": 185.3}"
- },
- {
- "simStepId": "7357e239-3712-4b55-a94c-2165ea1f3255",
- "diagramNodeId": "c27977fb-af8a-4779-8f78-a99b40221157",
- "simStepLabel": "Server Receives and Processes Heartbeat",
- "simStepDescription": "The `aw-server` receives the heartbeat event. The `heartbeat` method in the API layer checks if the new event's data is the same as the last event. Since the status changed from 'not-afk' to 'afk', it will not merge them and will instead insert a new event.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "268",
- "endLine": "276",
- "relevantVariables": [
- "heartbeat",
- "last_event",
- "heartbeat_merge",
- "self.db[bucket_id].insert"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-afk_my-laptop\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:27:15.124Z\", \"duration\": 185.3, \"data\": {\"status\": \"afk\"}}, \"pulsetime\": 185.0}",
- "outputDataExample": "{\"id\": 102, \"timestamp\": \"2023-10-27T10:27:15.124Z\", \"duration\": 185.3, \"data\": {\"status\": \"afk\"}}"
- },
- {
- "simStepId": "9fde1b44-5dbf-4530-88e2-ca54c220b462",
- "diagramNodeId": "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
- "simStepLabel": "Pause for Poll Time",
- "simStepDescription": "After processing the current state and sending heartbeats, the loop pauses for the configured `poll_time` before the next check.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "119",
- "endLine": "119",
- "relevantVariables": [
- "sleep",
- "self.settings.poll_time"
- ]
- },
- "inputDataExample": "{\"poll_time\": 5}",
- "outputDataExample": "{\"poll_time\": 5}"
- },
- {
- "simStepId": "1e5ad77f-aeff-49b6-9634-65e52f011a83",
- "diagramNodeId": "802c1941-09e1-4038-a0bf-bd4e553ff6f6",
- "simStepLabel": "Loop Repeats",
- "simStepDescription": "The process repeats. The watcher continues to send `afk` heartbeats on each poll interval as long as the user remains idle. When activity resumes, the condition `afk and seconds_since_input < self.settings.timeout` will trigger, sending a `not-afk` event and resetting the state.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "startLine": "76",
- "endLine": "76",
- "relevantVariables": [
- "while True"
- ]
- },
- "inputDataExample": "null",
- "outputDataExample": "null"
- }
- ],
- "description": "- The
aw-watcher-afk module monitors user presence by tracking keyboard and mouse activity - It periodically queries the operating system for the time elapsed since the last input event
- If this time exceeds a configurable timeout, the watcher sends an
afk status event - When activity resumes, it sends a
not-afk event - This AFK data is crucial for accurately measuring active screen time, as it allows queries to filter out periods when the user was idle
",
- "simulationNodesAndEdges": {
- "ba27c535-e0e5-44ae-b9f0-2827227ebfe2": {
- "simStepIds": [
- "8ffbcadf-f26a-483a-9902-95e5a761de64"
- ]
- },
- "79468b99-a4de-48b7-bb67-506dc0dcb41c": {
- "simStepIds": [
- "daeeac12-287a-4144-9028-6ea841b196c4"
- ]
- },
- "6b45de30-296e-4896-915c-371f09843599": {
- "simStepIds": [
- "6579f587-817d-4d23-a9df-86abc54273ae"
- ]
- },
- "b7321a6c-302b-4701-9ea5-5c05c6d3e71b": {
- "simStepIds": [
- "4d2c85c7-0754-429a-8a55-c64d4da0d37c"
- ]
- },
- "faab8465-be29-479d-890a-7936dc5cfbdd": {
- "simStepIds": [
- "3e0e033c-c32f-4d0d-aa65-a278d77e80c7"
- ]
- },
- "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5": {
- "simStepIds": [
- "dc58bc3e-b09e-4df2-870b-76419e78dd3d"
- ]
- },
- "c27977fb-af8a-4779-8f78-a99b40221157": {
- "simStepIds": [
- "7357e239-3712-4b55-a94c-2165ea1f3255"
- ]
- },
- "802c1941-09e1-4038-a0bf-bd4e553ff6f6": {
- "simStepIds": [
- "1e5ad77f-aeff-49b6-9634-65e52f011a83"
- ]
- },
- "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250": {
- "simStepIds": [
- "60e1002f-9782-4c8d-b104-f4bb172e2c91"
- ]
- },
- "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838": {
- "simStepIds": [
- "1422a5f8-ad2e-4b32-8955-ee6bb3053286"
- ]
- },
- "e514d9e2-e803-4041-b693-65878401b214": {
- "simStepIds": [
- "2588211c-b086-4768-8a87-a86764c7e5cd"
- ]
- },
- "eeb9224a-fff6-4652-b733-ea430b820a2c": {
- "simStepIds": [
- "9195e582-b3fa-4848-b151-0236a8a5d176"
- ]
- },
- "196358b9-6ae9-4f52-ad78-ff88b4a49403": {
- "simStepIds": [
- "78d78341-ced8-4fc6-bc93-ce4a62c8adf6"
- ]
- },
- "b520b088-6f6f-4b32-afba-5ef244691c44": {
- "simStepIds": [
- "c9a127c1-afd0-4def-a0fe-c490c9b64039"
- ]
- },
- "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0": {
- "simStepIds": [
- "9fde1b44-5dbf-4530-88e2-ca54c220b462"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "aw-watcher-afk, seconds_since_last_input, afk, not-afk, heartbeat_loop",
- "generationPrompt": "How AFK (Away From Keyboard) detection works",
- "generationKeywords": "aw-watcher-afk, seconds_since_last_input, afk, not-afk, heartbeat_loop",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 8,
- "promptTokenCount": 4269,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 9,
- "promptTokenCount": 7504,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 77,
- "promptTokenCount": 69327,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": []
- }
- }
- },
- "How the heartbeat API enables efficient tracking works": {
- "name": "How the heartbeat API enables efficient tracking works",
- "simSteps": [
- {
- "simStepId": "46ccc29e-b251-435a-8768-4304d477261a",
- "diagramNodeId": "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c",
- "simStepLabel": "[Python Flow - Watcher] Detect Active Window Change",
- "simStepDescription": "The `aw-watcher-window` process on macOS, implemented in Swift, detects a change in the active window or its title. An observer callback function like `windowTitleChanged` is triggered, which captures the application name (`app`) and the window title (`title`).",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "startLine": "306",
- "endLine": "375",
- "relevantVariables": [
- "windowTitleChanged",
- "frontmost",
- "data",
- "heartbeat"
- ]
- },
- "inputDataExample": "{\"axObserver\": \"\", \"axElement\": \"\", \"notification\": \"kAXTitleChangedNotification\"}",
- "outputDataExample": "{\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}"
- },
- {
- "simStepId": "b6456941-3a8f-452d-a4eb-67915b00d5b3",
- "diagramNodeId": "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
- "simStepLabel": "Data Transmission: Pass Event Data for Heartbeat",
- "simStepDescription": "The captured window data is packaged into a `Heartbeat` object and passed to the `sendHeartbeat` function to be sent to the server.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "startLine": "373",
- "endLine": "374",
- "relevantVariables": [
- "heartbeat",
- "sendHeartbeat"
- ]
- },
- "inputDataExample": "{\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}",
- "outputDataExample": "{\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}"
- },
- {
- "simStepId": "e873b3e2-2ebd-43ee-8f97-e02f869578f7",
- "diagramNodeId": "67a89dcc-93fc-413d-aa21-eca0b7227bc2",
- "simStepLabel": "[Python Flow - Watcher] Send Heartbeat API Request",
- "simStepDescription": "The `sendHeartbeatSingle` function constructs an HTTP POST request. It sets the URL to the heartbeat endpoint, including the bucket name and a calculated `pulsetime` as a query parameter. The heartbeat data is JSON-encoded and sent as the request body.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "startLine": "253",
- "endLine": "268",
- "relevantVariables": [
- "sendHeartbeatSingle",
- "urlRequest",
- "URLSession.shared.upload"
- ]
- },
- "inputDataExample": "{\"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"url\": \"http://localhost:5600/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"method\": \"POST\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}"
- },
- {
- "simStepId": "02717bea-6ee3-48ef-8c41-0c9f3e9d9a58",
- "diagramNodeId": "a676f81f-8c68-4fc8-94b7-583bada02d70",
- "simStepLabel": "API Call: Watcher -> Python Server",
- "simStepDescription": "The watcher sends the HTTP POST request containing the heartbeat event to the `aw-server` (Python) instance.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "272",
- "endLine": "272",
- "relevantVariables": [
- "HeartbeatResource"
- ]
- },
- "inputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}",
- "outputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}"
- },
- {
- "simStepId": "e98f7509-f28f-4534-8f2a-f525edc73f69",
- "diagramNodeId": "9de5f1e4-764e-4be7-90a1-65fa23ca0dea",
- "simStepLabel": "[Python Server] Handle Heartbeat Endpoint",
- "simStepDescription": "The `aw-server` (Flask) routes the incoming request to the `post` method of the `HeartbeatResource`. This method parses the JSON body into an `Event` object and extracts the `pulsetime` from the URL parameters.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "283",
- "endLine": "304",
- "relevantVariables": [
- "HeartbeatResource",
- "post",
- "heartbeat",
- "pulsetime",
- "current_app.api.heartbeat"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"request_json\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
- },
- {
- "simStepId": "d57d2bf7-916c-44cd-844d-b1900c276925",
- "diagramNodeId": "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
- "simStepLabel": "Data Transmission: REST -> API Logic",
- "simStepDescription": "The REST controller passes the parsed heartbeat event, bucket ID, and pulsetime to the core API logic for processing.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "300",
- "endLine": "300",
- "relevantVariables": [
- "current_app.api.heartbeat"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
- },
- {
- "simStepId": "bb678fe2-e6e3-472b-8ae4-95e362d4bdaf",
- "diagramNodeId": "7c02469d-20a7-415d-940e-fbd82d0fc997",
- "simStepLabel": "[Python Server] Process Heartbeat Event",
- "simStepDescription": "The `ServerAPI.heartbeat` method retrieves the last event from the specified bucket, either from an in-memory cache (`self.last_event`) or the database. It then compares the data of the new heartbeat with the last event. If the data is the same, it calls `heartbeat_merge` to attempt a merge.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "254",
- "endLine": "337",
- "relevantVariables": [
- "heartbeat",
- "last_event",
- "heartbeat_merge"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"merged_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}"
- },
- {
- "simStepId": "40b16e25-734b-44d2-86cd-7c301723ff5f",
- "diagramNodeId": "9aec4875-5718-4c38-a57c-1d3053c38ba5",
- "simStepLabel": "Data Transmission: Pass Events to Merge Function",
- "simStepDescription": "The last recorded event, the new heartbeat event, and the pulsetime are passed to the `heartbeat_merge` utility function to determine if they can be combined.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "305",
- "endLine": "305",
- "relevantVariables": [
- "heartbeat_merge"
- ]
- },
- "inputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
- },
- {
- "simStepId": "d2eac5dc-58f7-408c-beba-c1711beec25a",
- "diagramNodeId": "dc7a3836-03e1-4a54-9817-b62f36466ec0",
- "simStepLabel": "[Python Server] Core Merge Logic",
- "simStepDescription": "The `heartbeat_merge` function checks if the event data is identical and if the new heartbeat's timestamp is within the `pulsetime` window of the last event's end time. If both conditions are met, it creates a new merged event by extending the duration of the last event to cover the time up to the new heartbeat. Otherwise, it returns `None`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_transform/heartbeats.py",
- "startLine": "26",
- "endLine": "56",
- "relevantVariables": [
- "heartbeat_merge",
- "last_event",
- "heartbeat",
- "pulsetime",
- "within_pulsetime_window",
- "new_duration"
- ]
- },
- "inputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": \"0:00:00\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}"
- },
- {
- "simStepId": "9f918447-9e45-4c3b-b34f-658f58d35495",
- "diagramNodeId": "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
- "simStepLabel": "Data Transmission: Return Merged Event",
- "simStepDescription": "The `heartbeat_merge` function returns the newly created merged event (or `None`) back to the `ServerAPI.heartbeat` method.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-core/aw_transform/heartbeats.py",
- "startLine": "54",
- "endLine": "56",
- "relevantVariables": [
- "last_event",
- "None"
- ]
- },
- "inputDataExample": "{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}",
- "outputDataExample": "{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}"
- },
- {
- "simStepId": "976cfbd0-8946-4157-81b0-0ae6dffa43e1",
- "diagramNodeId": "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f",
- "simStepLabel": "[Python Server] Update Database",
- "simStepDescription": "If a merged event was returned, the `ServerAPI.heartbeat` method updates its local cache (`self.last_event`) and calls `self.db[bucket_id].replace_last(merged)` to persist the change in the database. This replaces the previous event with the new, longer-duration event. If no merged event was returned, it inserts a new event instead.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "313",
- "endLine": "315",
- "relevantVariables": [
- "self.last_event",
- "self.db[bucket_id].replace_last"
- ]
- },
- "inputDataExample": "{\"merged_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": \"0:00:10.123000\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}",
- "outputDataExample": "{\"success\": true}"
- },
- {
- "simStepId": "8420fd6c-dba4-41c0-b11d-7280a428ab36",
- "diagramNodeId": "b3da175e-36b5-4025-ba15-6c54e1d850dd",
- "simStepLabel": "[Rust Flow - Watcher] Detect and Send Heartbeat",
- "simStepDescription": "This step marks the beginning of the alternative `aw-server-rust` implementation flow. The process is initiated in the same way as the Python flow: a watcher detects an activity change and prepares a heartbeat event. The Swift-based watcher is implementation-agnostic and sends the same HTTP request regardless of the server.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "startLine": "203",
- "endLine": "268",
- "relevantVariables": [
- "sendHeartbeat",
- "sendHeartbeatSingle"
- ]
- },
- "inputDataExample": "{\"axObserver\": \"\", \"axElement\": \"\", \"notification\": \"kAXTitleChangedNotification\"}",
- "outputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}"
- },
- {
- "simStepId": "7e361c3d-a5a9-45f3-a83d-98e39ff45675",
- "diagramNodeId": "2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
- "simStepLabel": "API Call: Watcher -> Rust Server",
- "simStepDescription": "The watcher sends the HTTP POST request containing the heartbeat event to the `aw-server-rust` instance.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "startLine": "145",
- "endLine": "149",
- "relevantVariables": [
- "bucket_events_heartbeat"
- ]
- },
- "inputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}",
- "outputDataExample": "{\"request\": {\"method\": \"POST\", \"url\": \"/api/0/buckets/aw-watcher-window_my-mac/heartbeat?pulsetime=61.0\", \"body\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}}"
- },
- {
- "simStepId": "41b8b1d6-f9fe-47ad-851e-574e804f7171",
- "diagramNodeId": "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926",
- "simStepLabel": "[Rust Server] Handle Heartbeat Endpoint",
- "simStepDescription": "The `aw-server-rust` (Rocket) routes the incoming request to the `bucket_events_heartbeat` function. This function parses the JSON body and pulsetime, then calls the `datastore.heartbeat` method to process the event.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "startLine": "150",
- "endLine": "162",
- "relevantVariables": [
- "bucket_events_heartbeat",
- "heartbeat_json",
- "pulsetime",
- "state.datastore"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat_json\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
- },
- {
- "simStepId": "bfcc2f87-9167-4784-a3b3-f71d6e7a6e71",
- "diagramNodeId": "4a4afbdf-0303-4d84-bbf8-5121c74965a0",
- "simStepLabel": "Data Transmission: Endpoint -> Datastore",
- "simStepDescription": "The endpoint function passes the heartbeat data to the datastore worker layer for processing.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "startLine": "158",
- "endLine": "158",
- "relevantVariables": [
- "datastore.heartbeat"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
- },
- {
- "simStepId": "b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3",
- "diagramNodeId": "b6b4c8cb-741a-4e38-b800-61273375cd64",
- "simStepLabel": "[Rust Server] Queue Heartbeat Command",
- "simStepDescription": "The `Datastore::heartbeat` method in `worker.rs` creates a `Command::Heartbeat` enum variant and sends it to the datastore worker thread through a multi-producer, single-consumer (mpsc) channel. This decouples API handling from database operations.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
- "startLine": "385",
- "endLine": "399",
- "relevantVariables": [
- "heartbeat",
- "Command::Heartbeat",
- "self.requester.request"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"Command::Heartbeat\": {\"bucket_id\": \"aw-watcher-window_my-mac\", \"event\": {...}, \"pulsetime\": 61.0}}"
- },
- {
- "simStepId": "eefd671a-3b08-4336-bd26-cb6eb04070ec",
- "diagramNodeId": "21d1c973-0f67-4aca-9d1b-eade3b5d347b",
- "simStepLabel": "Data Transmission: Command Channel",
- "simStepDescription": "The heartbeat command is sent over the mpsc channel to the dedicated datastore worker thread.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
- "startLine": "167",
- "endLine": "175",
- "relevantVariables": [
- "self.responder.poll"
- ]
- },
- "inputDataExample": "{\"Command::Heartbeat\": {\"bucket_id\": \"aw-watcher-window_my-mac\", \"event\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}}",
- "outputDataExample": "{\"Command::Heartbeat\": {\"bucket_id\": \"aw-watcher-window_my-mac\", \"event\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}}"
- },
- {
- "simStepId": "a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb",
- "diagramNodeId": "f0e92638-21d1-4b7e-9f2e-17b67a33ef78",
- "simStepLabel": "[Rust Server] Process Heartbeat in Worker",
- "simStepDescription": "The `DatastoreWorker::handle_request` method receives the command, matches it to `Command::Heartbeat`, and calls the `heartbeat` method on the `DatastoreInstance`, which directly interacts with the SQLite database connection.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
- "startLine": "240",
- "endLine": "248",
- "relevantVariables": [
- "handle_request",
- "ds.heartbeat",
- "self.last_heartbeat"
- ]
- },
- "inputDataExample": "{\"Command::Heartbeat\": {\"bucket_id\": \"aw-watcher-window_my-mac\", \"event\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}}",
- "outputDataExample": "{\"Response::Event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.123, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}"
- },
- {
- "simStepId": "9750ac2c-c0fb-4fe5-815f-398886fc827b",
- "diagramNodeId": "959b342e-eb44-4255-8176-1600a5fa17ac",
- "simStepLabel": "Data Transmission: Worker -> Datastore Instance",
- "simStepDescription": "The worker thread calls the `heartbeat` method on the datastore instance, passing the event data.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/worker.rs",
- "startLine": "241",
- "endLine": "241",
- "relevantVariables": [
- "ds.heartbeat"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-mac\", \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
- },
- {
- "simStepId": "c59f4b10-f6c9-4fd8-ba70-ea60667a01e8",
- "diagramNodeId": "b0093d22-e8cc-4e9e-8711-7e698b537efc",
- "simStepLabel": "[Rust Server] Core Merge Logic",
- "simStepDescription": "The `DatastoreInstance::heartbeat` method retrieves the last event and calls `aw_transform::heartbeat`. This function checks for data equality and pulsetime. If successful, it returns a `Some(merged_event)`. If not, `None`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "startLine": "600",
- "endLine": "642",
- "relevantVariables": [
- "heartbeat",
- "last_event",
- "aw_transform::heartbeat"
- ]
- },
- "inputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"Some(merged_heartbeat)\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.123, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}"
- },
- {
- "simStepId": "7b396541-e74f-4baf-9b1b-c1f7a914ba7a",
- "diagramNodeId": "0fe644bb-a583-40d8-9377-3641c90c4f62",
- "simStepLabel": "Data Transmission: Pass Events to Merge Function",
- "simStepDescription": "The last event, new heartbeat, and pulsetime are passed to the `aw_transform::heartbeat` function for the merge calculation.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "startLine": "628",
- "endLine": "628",
- "relevantVariables": [
- "aw_transform::heartbeat"
- ]
- },
- "inputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}",
- "outputDataExample": "{\"last_event\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"heartbeat\": {\"timestamp\": \"2023-10-27T10:00:10.123Z\", \"duration\": 0, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}, \"pulsetime\": 61.0}"
- },
- {
- "simStepId": "da146aa5-e96f-4db6-a36f-b405b1a11255",
- "diagramNodeId": "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8",
- "simStepLabel": "[Rust Server] Update Database",
- "simStepDescription": "Based on the result from `aw_transform::heartbeat`, the `DatastoreInstance::heartbeat` method either calls `self.replace_last_event` to update the last event in the database with the merged one, or `self.insert_events` to create a new event. The merged or new event is then cached and returned.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "startLine": "628",
- "endLine": "639",
- "relevantVariables": [
- "replace_last_event",
- "insert_events"
- ]
- },
- "inputDataExample": "{\"merged_heartbeat\": {\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 10.123, \"data\": {\"app\": \"Visual Studio Code\", \"title\": \"aw-server/api.py - activitywatch\"}}}",
- "outputDataExample": "{\"success\": true}"
- }
- ],
- "description": "- Watchers use a
heartbeat mechanism to efficiently report continuous states, such as the currently active window - Instead of sending events with long durations, watchers send frequent, zero-duration
heartbeat events - The
aw-server receives these heartbeats and, if the new event's data is identical to the previous one and arrives within a pulsetime window, it merges them by extending the duration of the last event - This approach significantly reduces the amount of data that needs to be stored and transmitted, making the tracking process highly efficient
- If the data changes (e
- g
- , the user switches windows), a new event is created, starting a new continuous period
",
- "simulationNodesAndEdges": {
- "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c": {
- "simStepIds": [
- "46ccc29e-b251-435a-8768-4304d477261a"
- ]
- },
- "67a89dcc-93fc-413d-aa21-eca0b7227bc2": {
- "simStepIds": [
- "e873b3e2-2ebd-43ee-8f97-e02f869578f7"
- ]
- },
- "9de5f1e4-764e-4be7-90a1-65fa23ca0dea": {
- "simStepIds": [
- "e98f7509-f28f-4534-8f2a-f525edc73f69"
- ]
- },
- "7c02469d-20a7-415d-940e-fbd82d0fc997": {
- "simStepIds": [
- "bb678fe2-e6e3-472b-8ae4-95e362d4bdaf"
- ]
- },
- "dc7a3836-03e1-4a54-9817-b62f36466ec0": {
- "simStepIds": [
- "d2eac5dc-58f7-408c-beba-c1711beec25a"
- ]
- },
- "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f": {
- "simStepIds": [
- "976cfbd0-8946-4157-81b0-0ae6dffa43e1"
- ]
- },
- "b3da175e-36b5-4025-ba15-6c54e1d850dd": {
- "simStepIds": [
- "8420fd6c-dba4-41c0-b11d-7280a428ab36"
- ]
- },
- "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926": {
- "simStepIds": [
- "41b8b1d6-f9fe-47ad-851e-574e804f7171"
- ]
- },
- "b6b4c8cb-741a-4e38-b800-61273375cd64": {
- "simStepIds": [
- "b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3"
- ]
- },
- "f0e92638-21d1-4b7e-9f2e-17b67a33ef78": {
- "simStepIds": [
- "a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb"
- ]
- },
- "b0093d22-e8cc-4e9e-8711-7e698b537efc": {
- "simStepIds": [
- "c59f4b10-f6c9-4fd8-ba70-ea60667a01e8"
- ]
- },
- "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8": {
- "simStepIds": [
- "da146aa5-e96f-4db6-a36f-b405b1a11255"
- ]
- },
- "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f": {
- "simStepIds": [
- "b6456941-3a8f-452d-a4eb-67915b00d5b3"
- ]
- },
- "a676f81f-8c68-4fc8-94b7-583bada02d70": {
- "simStepIds": [
- "02717bea-6ee3-48ef-8c41-0c9f3e9d9a58"
- ]
- },
- "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75": {
- "simStepIds": [
- "d57d2bf7-916c-44cd-844d-b1900c276925"
- ]
- },
- "9aec4875-5718-4c38-a57c-1d3053c38ba5": {
- "simStepIds": [
- "40b16e25-734b-44d2-86cd-7c301723ff5f"
- ]
- },
- "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0": {
- "simStepIds": [
- "9f918447-9e45-4c3b-b34f-658f58d35495"
- ]
- },
- "2df6b81e-6b59-4aec-92c7-e9d9f2332be6": {
- "simStepIds": [
- "7e361c3d-a5a9-45f3-a83d-98e39ff45675"
- ]
- },
- "4a4afbdf-0303-4d84-bbf8-5121c74965a0": {
- "simStepIds": [
- "bfcc2f87-9167-4784-a3b3-f71d6e7a6e71"
- ]
- },
- "21d1c973-0f67-4aca-9d1b-eade3b5d347b": {
- "simStepIds": [
- "eefd671a-3b08-4336-bd26-cb6eb04070ec"
- ]
- },
- "959b342e-eb44-4255-8176-1600a5fa17ac": {
- "simStepIds": [
- "9750ac2c-c0fb-4fe5-815f-398886fc827b"
- ]
- },
- "0fe644bb-a583-40d8-9377-3641c90c4f62": {
- "simStepIds": [
- "7b396541-e74f-4baf-9b1b-c1f7a914ba7a"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "heartbeat, heartbeat_merge, pulsetime, aw-server/api.py, aw_transform/heartbeats.py",
- "generationPrompt": "How the heartbeat API enables efficient tracking works",
- "generationKeywords": "heartbeat, heartbeat_merge, pulsetime, aw-server/api.py, aw_transform/heartbeats.py",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 5,
- "promptTokenCount": 2654,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 123,
- "promptTokenCount": 103244,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 62,
- "promptTokenCount": 64640,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": [
- {
- "path": "aw-server-rust/aw-server/src/endpoints/import.rs",
- "container": "server",
- "triggerType": "http",
- "identifier": "application/json"
- }
- ]
- },
- "crossLayerTriggers": [
- {
- "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "identifier": "application/json",
- "type": "http",
- "matchedTargets": [
- ".github/workflows/test.yml",
- "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "aw-server-rust/aw-server/src/endpoints/import.rs"
- ]
- }
- ]
- }
- },
- "How the module manager and tray icon works": {
- "name": "How the module manager and tray icon works",
- "simSteps": [
- {
- "simStepId": "61d1a03e-ed06-496d-8495-36419b9c8607",
- "diagramNodeId": "d1bb4e12-29b6-4f70-9931-321214e3ea2a",
- "simStepLabel": "Application Entrypoint",
- "simStepDescription": "The `aw-qt` application is launched. It parses command-line arguments, sets up logging, loads configuration, and initializes the `Manager`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/main.py",
- "startLine": "41",
- "endLine": "53",
- "relevantVariables": [
- "main",
- "testing",
- "verbose",
- "autostart_modules"
- ]
- },
- "inputDataExample": "{\n \"command\": \"aw-qt --testing\"\n}",
- "outputDataExample": "{\n \"testing\": true,\n \"verbose\": false,\n \"autostart_modules\": null,\n \"no_gui\": false,\n \"interactive_cli\": false\n}"
- },
- {
- "simStepId": "6084ca69-514e-4bde-b2c0-1d33b26203e8",
- "diagramNodeId": "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
- "simStepLabel": "Load Autostart Config",
- "simStepDescription": "The application triggers the loading of autostart module settings based on the `testing` flag.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/main.py",
- "startLine": "70",
- "endLine": "70",
- "relevantVariables": [
- "AwQtSettings"
- ]
- },
- "inputDataExample": "{\n \"testing\": true\n}",
- "outputDataExample": "{\n \"testing\": true\n}"
- },
- {
- "simStepId": "c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a",
- "diagramNodeId": "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc",
- "simStepLabel": "Read Configuration File",
- "simStepDescription": "The `AwQtSettings` class reads the `aw-qt.toml` configuration file to determine which modules to autostart.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/config.py",
- "startLine": "16",
- "endLine": "24",
- "relevantVariables": [
- "AwQtSettings",
- "load_config_toml",
- "autostart_modules"
- ]
- },
- "inputDataExample": "{\n \"testing\": true\n}",
- "outputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}"
- },
- {
- "simStepId": "540119c2-b541-4342-aa59-233b4f0f8db5",
- "diagramNodeId": "030668a5-a377-4710-b39f-95efb5fa4768",
- "simStepLabel": "Pass Config to Manager",
- "simStepDescription": "The list of modules to autostart is passed from the main function to the `Manager` instance during its initialization and autostart sequence.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/main.py",
- "startLine": "77",
- "endLine": "78",
- "relevantVariables": [
- "manager",
- "Manager",
- "autostart"
- ]
- },
- "inputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}",
- "outputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}"
- },
- {
- "simStepId": "e716abbb-c96e-4613-bca2-0c094e8df129",
- "diagramNodeId": "cae37571-f0ba-4abe-aefd-53e49f26137f",
- "simStepLabel": "Discover Modules",
- "simStepDescription": "The `Manager` class is instantiated and discovers all available `aw-*` executables. It searches for bundled modules within its own directory structure and for system-wide modules in the user's PATH.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/manager.py",
- "startLine": "241",
- "endLine": "250",
- "relevantVariables": [
- "discover_modules",
- "_discover_modules_bundled",
- "_discover_modules_system",
- "filter_modules"
- ]
- },
- "inputDataExample": "{\n \"testing\": true\n}",
- "outputDataExample": "{\n \"modules\": [\n {\n \"name\": \"aw-server\",\n \"path\": \"/path/to/aw-server\",\n \"type\": \"bundled\"\n },\n {\n \"name\": \"aw-watcher-afk\",\n \"path\": \"/path/to/aw-watcher-afk\",\n \"type\": \"bundled\"\n },\n {\n \"name\": \"aw-watcher-window\",\n \"path\": \"/path/to/aw-watcher-window\",\n \"type\": \"system\"\n }\n ]\n}"
- },
- {
- "simStepId": "9aeaf443-6741-4557-9671-67d596f456b3",
- "diagramNodeId": "1fb5a75e-9c49-490d-b412-04ac1c7205fa",
- "simStepLabel": "Initiate Autostart Sequence",
- "simStepDescription": "With the list of discovered modules and the autostart configuration, the `Manager` begins the startup sequence for each required module.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/manager.py",
- "startLine": "276",
- "endLine": "286",
- "relevantVariables": [
- "autostart",
- "start"
- ]
- },
- "inputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}",
- "outputDataExample": "{\n \"autostart_modules\": [\n \"aw-server\",\n \"aw-watcher-afk\",\n \"aw-watcher-window\"\n ]\n}"
- },
- {
- "simStepId": "8be10173-751a-4da9-99a9-321c23e71aaa",
- "diagramNodeId": "8f981b6f-7bed-4d9a-8486-79f85b06d904",
- "simStepLabel": "Spawn Module Process",
- "simStepDescription": "For each module designated for autostart, the `Module.start` method is called. This method constructs the execution command and uses `subprocess.Popen` to launch the module as a new, independent process. `aw-server` is started first.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/manager.py",
- "startLine": "147",
- "endLine": "172",
- "relevantVariables": [
- "Module.start",
- "subprocess.Popen",
- "exec_cmd",
- "_process",
- "started"
- ]
- },
- "inputDataExample": "{\n \"module_name\": \"aw-server\",\n \"testing\": true\n}",
- "outputDataExample": "{\n \"process_id\": 12345\n}"
- },
- {
- "simStepId": "f968357d-53c4-41e8-b71f-c581c08b52e6",
- "diagramNodeId": "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
- "simStepLabel": "Module Process Running",
- "simStepDescription": "The `aw-server` module process is now running independently. Control returns to the `aw-qt` main process, which proceeds to start other modules and initialize the GUI.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/manager.py",
- "startLine": "169",
- "endLine": "171",
- "relevantVariables": [
- "_process"
- ]
- },
- "inputDataExample": "{\n \"module\": \"aw-server\",\n \"status\": \"started\"\n}",
- "outputDataExample": "{\n \"module\": \"aw-server\",\n \"status\": \"started\"\n}"
- },
- {
- "simStepId": "6ae15f2e-5331-4153-b9d2-2a297b65c55f",
- "diagramNodeId": "4d657da7-6757-4d72-9324-765a991f73d7",
- "simStepLabel": "Initialize Tray Icon",
- "simStepDescription": "After attempting to start all autostart modules, the `trayicon.run` function is called. This initializes the PyQt application and creates the system tray icon, making ActivityWatch accessible to the user.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "207",
- "endLine": "211",
- "relevantVariables": [
- "run",
- "app",
- "QApplication"
- ]
- },
- "inputDataExample": "{\n \"manager\": \"\",\n \"testing\": true\n}",
- "outputDataExample": "{\n \"app_exit_code\": 0\n}"
- },
- {
- "simStepId": "03fd319d-4ffe-47cf-bf39-ac388da80fa7",
- "diagramNodeId": "dfaa3fc8-eca8-4c67-b926-87798f511adb",
- "simStepLabel": "Create Tray Icon Instance",
- "simStepDescription": "The `run` function creates an instance of the `TrayIcon` class, passing the `manager` object which holds the state of all modules.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "259",
- "endLine": "260",
- "relevantVariables": [
- "TrayIcon",
- "manager"
- ]
- },
- "inputDataExample": "{\n \"manager\": \"\"\n}",
- "outputDataExample": "{\n \"manager\": \"\"\n}"
- },
- {
- "simStepId": "08d88f03-4133-41d6-9cbb-0df16703b864",
- "diagramNodeId": "05bd0955-8e55-4657-80ee-f6389995db6d",
- "simStepLabel": "Build Tray Menu",
- "simStepDescription": "The `TrayIcon` constructor builds the context menu. It creates a 'Modules' submenu by iterating through the modules discovered by the manager. Each module is represented as a checkable menu item, with its initial state reflecting whether it's currently running.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "174",
- "endLine": "193",
- "relevantVariables": [
- "_build_modulemenu",
- "add_module_menuitem",
- "module.is_alive"
- ]
- },
- "inputDataExample": "{\n \"modules_bundled\": [\n \"aw-server\"\n ],\n \"modules_system\": [\n \"aw-watcher-window\"\n ]\n}",
- "outputDataExample": "{\n \"menu_actions\": {\n \"aw-server\": {\n \"checked\": true\n },\n \"aw-watcher-window\": {\n \"checked\": true\n }\n }\n}"
- },
- {
- "simStepId": "8e583414-7b87-42c9-bdb2-e56259be4cdf",
- "diagramNodeId": "d9e460b6-432d-49c8-8e76-0d8750aa2c10",
- "simStepLabel": "User Toggles Module",
- "simStepDescription": "The user clicks on a module in the tray menu, triggering the associated lambda function which calls `module.toggle()`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "179",
- "endLine": "179",
- "relevantVariables": [
- "module.toggle"
- ]
- },
- "inputDataExample": "{\n \"user_action\": \"click\",\n \"menu_item\": \"aw-server\"\n}",
- "outputDataExample": "{\n \"user_action\": \"click\",\n \"menu_item\": \"aw-server\"\n}"
- },
- {
- "simStepId": "520ab3f2-ef6c-4334-89fc-280f6d86d14b",
- "diagramNodeId": "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b",
- "simStepLabel": "Toggle Module State",
- "simStepDescription": "The `toggle` method in the `Module` class checks if the module is currently started. If it is, it calls `stop()`; otherwise, it calls `start()`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/manager.py",
- "startLine": "202",
- "endLine": "206",
- "relevantVariables": [
- "toggle",
- "self.started",
- "self.stop",
- "self.start"
- ]
- },
- "inputDataExample": "{\n \"module_name\": \"aw-server\",\n \"current_state\": \"started\"\n}",
- "outputDataExample": "{\n \"action_taken\": \"stop\"\n}"
- },
- {
- "simStepId": "fdff8ecd-12b9-4bc0-ba7b-9402d26b1737",
- "diagramNodeId": "9d4dee50-64ef-459a-98fa-839761e16813",
- "simStepLabel": "Send Termination Signal",
- "simStepDescription": "The `stop()` method sends a SIGTERM signal to the module's subprocess to gracefully shut it down.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/manager.py",
- "startLine": "191",
- "endLine": "191",
- "relevantVariables": [
- "_process.terminate"
- ]
- },
- "inputDataExample": "{\n \"process_id\": 12345\n}",
- "outputDataExample": "{\n \"process_id\": 12345\n}"
- },
- {
- "simStepId": "01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9",
- "diagramNodeId": "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5",
- "simStepLabel": "Periodic Status Check",
- "simStepDescription": "A recurring timer in `TrayIcon` triggers `rebuild_modules_menu` every 2 seconds. This function updates the checkmarks in the 'Modules' menu to reflect the current running status of each module.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "149",
- "endLine": "158",
- "relevantVariables": [
- "rebuild_modules_menu",
- "QtCore.QTimer.singleShot"
- ]
- },
- "inputDataExample": "{}",
- "outputDataExample": "{\n \"menu_updates\": [\n {\n \"module\": \"aw-server\",\n \"is_alive\": false\n }\n ]\n}"
- },
- {
- "simStepId": "c0115129-b34b-4d27-9f73-cf2dc142ea81",
- "diagramNodeId": "f704019b-d227-47ad-8761-9a2ea01516cb",
- "simStepLabel": "Query Module Process State",
- "simStepDescription": "To update the menu, `rebuild_modules_menu` calls `module.is_alive()` for each module's menu action.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "153",
- "endLine": "153",
- "relevantVariables": [
- "module.is_alive"
- ]
- },
- "inputDataExample": "{\n \"module_name\": \"aw-server\"\n}",
- "outputDataExample": "{\n \"module_name\": \"aw-server\"\n}"
- },
- {
- "simStepId": "899b57ba-4a68-4620-977a-80981d089e85",
- "diagramNodeId": "421b1687-98a6-4773-a7dc-cdc564be5f8e",
- "simStepLabel": "Check if Module Process is Alive",
- "simStepDescription": "The `is_alive` method polls the subprocess to check its status. It returns `True` if the process is running and `False` otherwise.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/manager.py",
- "startLine": "208",
- "endLine": "214",
- "relevantVariables": [
- "is_alive",
- "_process.poll",
- "_process.returncode"
- ]
- },
- "inputDataExample": "{\n \"_process\": \"\"\n}",
- "outputDataExample": "{\n \"is_alive\": false\n}"
- },
- {
- "simStepId": "7775ac80-c954-464e-b230-b233216ee5e3",
- "diagramNodeId": "ba9e605d-98a7-4b50-979a-05bf7213c681",
- "simStepLabel": "Check for Unexpected Stops",
- "simStepDescription": "A separate periodic timer calls `check_module_status`, which in turn calls `manager.get_unexpected_stops()` to detect if any managed modules have crashed.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "163",
- "endLine": "163",
- "relevantVariables": [
- "self.manager.get_unexpected_stops"
- ]
- },
- "inputDataExample": "{}",
- "outputDataExample": "{}"
- },
- {
- "simStepId": "6173a9e1-ecfa-4dd9-9f82-f80579406011",
- "diagramNodeId": "5dd0e28d-e0e9-4433-8db9-e8de93de1abe",
- "simStepLabel": "Identify Unexpectedly Stopped Modules",
- "simStepDescription": "The `get_unexpected_stops` method filters the list of all modules, returning those that are marked as `started` but are no longer `alive`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/manager.py",
- "startLine": "252",
- "endLine": "253",
- "relevantVariables": [
- "get_unexpected_stops",
- "x.started",
- "x.is_alive"
- ]
- },
- "inputDataExample": "{\n \"modules\": [\n {\n \"name\": \"aw-watcher-afk\",\n \"started\": true,\n \"is_alive\": false\n }\n ]\n}",
- "outputDataExample": "{\n \"unexpected_stops\": [\n {\n \"name\": \"aw-watcher-afk\",\n \"started\": true,\n \"is_alive\": false\n }\n ]\n}"
- },
- {
- "simStepId": "1ed5cd16-b593-41cf-84f2-233a8d64a227",
- "diagramNodeId": "2298c4b5-17de-487f-b592-2ac0f95eca84",
- "simStepLabel": "Trigger Failure Notification",
- "simStepDescription": "If any modules are identified as having stopped unexpectedly, the `show_module_failed_dialog` function is called for each one.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "166",
- "endLine": "166",
- "relevantVariables": [
- "show_module_failed_dialog"
- ]
- },
- "inputDataExample": "{\n \"failed_module\": \"\"\n}",
- "outputDataExample": "{\n \"failed_module\": \"\"\n}"
- },
- {
- "simStepId": "a71f6cd0-490a-40b5-8a05-1c873f208882",
- "diagramNodeId": "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc",
- "simStepLabel": "Display Failure Dialog",
- "simStepDescription": "A `QMessageBox` is displayed to the user, informing them that a module has quit unexpectedly. The dialog includes the module's logs and provides a button to restart the module.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-qt/aw_qt/trayicon.py",
- "startLine": "136",
- "endLine": "147",
- "relevantVariables": [
- "show_module_failed_dialog",
- "QMessageBox",
- "module.read_log",
- "module.start"
- ]
- },
- "inputDataExample": "{\n \"module_name\": \"aw-watcher-afk\",\n \"log_content\": \"ERROR: Something went wrong...\"\n}",
- "outputDataExample": "{\n \"user_choice\": \"Restart\"\n}"
- }
- ],
- "description": "- The
aw-qt application provides a system tray icon that acts as a central control panel for ActivityWatch - It discovers and manages all the runnable modules, such as the server and various watchers
- From the tray menu, users can start and stop individual modules, check their status, and access the web UI
- The manager handles the autostarting of configured modules on system login, ensuring that time tracking is always active without manual intervention
",
- "simulationNodesAndEdges": {
- "d1bb4e12-29b6-4f70-9931-321214e3ea2a": {
- "simStepIds": [
- "61d1a03e-ed06-496d-8495-36419b9c8607"
- ]
- },
- "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc": {
- "simStepIds": [
- "c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a"
- ]
- },
- "cae37571-f0ba-4abe-aefd-53e49f26137f": {
- "simStepIds": [
- "e716abbb-c96e-4613-bca2-0c094e8df129"
- ]
- },
- "8f981b6f-7bed-4d9a-8486-79f85b06d904": {
- "simStepIds": [
- "8be10173-751a-4da9-99a9-321c23e71aaa"
- ]
- },
- "4d657da7-6757-4d72-9324-765a991f73d7": {
- "simStepIds": [
- "6ae15f2e-5331-4153-b9d2-2a297b65c55f"
- ]
- },
- "05bd0955-8e55-4657-80ee-f6389995db6d": {
- "simStepIds": [
- "08d88f03-4133-41d6-9cbb-0df16703b864"
- ]
- },
- "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b": {
- "simStepIds": [
- "520ab3f2-ef6c-4334-89fc-280f6d86d14b"
- ]
- },
- "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5": {
- "simStepIds": [
- "01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9"
- ]
- },
- "421b1687-98a6-4773-a7dc-cdc564be5f8e": {
- "simStepIds": [
- "899b57ba-4a68-4620-977a-80981d089e85"
- ]
- },
- "5dd0e28d-e0e9-4433-8db9-e8de93de1abe": {
- "simStepIds": [
- "6173a9e1-ecfa-4dd9-9f82-f80579406011"
- ]
- },
- "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc": {
- "simStepIds": [
- "a71f6cd0-490a-40b5-8a05-1c873f208882"
- ]
- },
- "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7": {
- "simStepIds": [
- "6084ca69-514e-4bde-b2c0-1d33b26203e8"
- ]
- },
- "030668a5-a377-4710-b39f-95efb5fa4768": {
- "simStepIds": [
- "540119c2-b541-4342-aa59-233b4f0f8db5"
- ]
- },
- "1fb5a75e-9c49-490d-b412-04ac1c7205fa": {
- "simStepIds": [
- "9aeaf443-6741-4557-9671-67d596f456b3"
- ]
- },
- "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9": {
- "simStepIds": [
- "f968357d-53c4-41e8-b71f-c581c08b52e6"
- ]
- },
- "dfaa3fc8-eca8-4c67-b926-87798f511adb": {
- "simStepIds": [
- "03fd319d-4ffe-47cf-bf39-ac388da80fa7"
- ]
- },
- "d9e460b6-432d-49c8-8e76-0d8750aa2c10": {
- "simStepIds": [
- "8e583414-7b87-42c9-bdb2-e56259be4cdf"
- ]
- },
- "9d4dee50-64ef-459a-98fa-839761e16813": {
- "simStepIds": [
- "fdff8ecd-12b9-4bc0-ba7b-9402d26b1737"
- ]
- },
- "f704019b-d227-47ad-8761-9a2ea01516cb": {
- "simStepIds": [
- "c0115129-b34b-4d27-9f73-cf2dc142ea81"
- ]
- },
- "ba9e605d-98a7-4b50-979a-05bf7213c681": {
- "simStepIds": [
- "7775ac80-c954-464e-b230-b233216ee5e3"
- ]
- },
- "2298c4b5-17de-487f-b592-2ac0f95eca84": {
- "simStepIds": [
- "1ed5cd16-b593-41cf-84f2-233a8d64a227"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "aw-qt, Manager, Module, autostart, start",
- "generationPrompt": "How the module manager and tray icon works",
- "generationKeywords": "aw-qt, Manager, Module, autostart, start",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 11,
- "promptTokenCount": 10004,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 124,
- "promptTokenCount": 89898,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 47,
- "promptTokenCount": 40704,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": [
- {
- "path": "aw-server-rust/aw-server/src/endpoints/import.rs",
- "container": "server",
- "triggerType": "http",
- "identifier": "application/json"
- }
- ]
- },
- "crossLayerTriggers": [
- {
- "sourcePath": "aw-watcher-window/aw_watcher_window/macos.swift",
- "identifier": "application/json",
- "type": "http",
- "matchedTargets": [
- ".github/workflows/test.yml",
- "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "aw-server-rust/aw-server/src/endpoints/import.rs"
- ]
- }
- ]
- }
- },
- "How time-based notifications work": {
- "name": "How time-based notifications work",
- "simSteps": [
- {
- "simStepId": "9b9a0f90-d7a7-40fb-8573-53b470ecf85d",
- "diagramNodeId": "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1",
- "simStepLabel": "Start Notification Service",
- "simStepDescription": "The `aw-notify` service is started from the command line, which calls the `main` function. `main` in turn invokes the `start` function to begin the notification service.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "340",
- "endLine": "360",
- "relevantVariables": [
- "main",
- "start"
- ]
- },
- "inputDataExample": "{\n \"command\": \"aw-notify start\"\n}",
- "outputDataExample": "{\n \"status\": \"Service starting...\"\n}"
- },
- {
- "simStepId": "3c977159-c34d-4907-9004-e5aaff3f3bdc",
- "diagramNodeId": "f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
- "simStepLabel": "Initialize Client and Get Hostname",
- "simStepDescription": "The `start` function initializes the `ActivityWatchClient` to communicate with the `aw-server` and retrieves the local hostname.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "368",
- "endLine": "370",
- "relevantVariables": [
- "aw_client.ActivityWatchClient",
- "aw.get_info"
- ]
- },
- "inputDataExample": "{\n \"testing\": false,\n \"port\": null\n}",
- "outputDataExample": "{\n \"testing\": false,\n \"port\": null\n}"
- },
- {
- "simStepId": "f636bdd6-a8e3-47ec-9f9d-986b21a81868",
- "diagramNodeId": "553f1437-5c34-4d6d-8226-417014259fc5",
- "simStepLabel": "Initialize Threshold Alerts",
- "simStepDescription": "The `threshold_alerts` function is called, which creates a list of `CategoryAlert` objects. Each object is configured with a specific category to monitor (e.g., 'Work', 'Twitter'), a list of time thresholds, and a display label.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "380",
- "endLine": "392",
- "relevantVariables": [
- "threshold_alerts",
- "CategoryAlert",
- "alerts"
- ]
- },
- "inputDataExample": "{}",
- "outputDataExample": "{\n \"alerts\": [\n {\n \"category\": \"Work\",\n \"label\": \"💼 Work\",\n \"thresholds\": [900, 1800, 3600, 7200, 14400]\n },\n {\n \"category\": \"Twitter\",\n \"label\": \"🐦 Twitter\",\n \"thresholds\": [900, 1800, 3600]\n }\n ]\n}"
- },
- {
- "simStepId": "7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b",
- "diagramNodeId": "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
- "simStepLabel": "Enter Main Loop",
- "simStepDescription": "The service enters an infinite `while True` loop to periodically check activity against the defined thresholds. The loop starts by calling `alert.update()` for each configured alert.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "400",
- "endLine": "401",
- "relevantVariables": [
- "alerts",
- "alert.update"
- ]
- },
- "inputDataExample": "{\n \"alert_object\": {\n \"category\": \"Work\",\n \"label\": \"💼 Work\",\n \"thresholds\": [900, 1800, 3600, 7200, 14400],\n \"time_spent\": 0\n }\n}",
- "outputDataExample": "{\n \"alert_object\": {\n \"category\": \"Work\",\n \"label\": \"💼 Work\",\n \"thresholds\": [900, 1800, 3600, 7200, 14400],\n \"time_spent\": 0\n }\n}"
- },
- {
- "simStepId": "945e3312-c7c9-4722-953b-94dc0feee249",
- "diagramNodeId": "1de089eb-60a7-4d7f-bfb5-3f7f23315873",
- "simStepLabel": "Update Category Time",
- "simStepDescription": "The `update` method of a `CategoryAlert` instance is called. It checks if enough time has passed to warrant a new query to the server. If so, it calls `get_time()` to fetch the latest activity duration for its category.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "262",
- "endLine": "276",
- "relevantVariables": [
- "update",
- "time_to_next_threshold",
- "get_time"
- ]
- },
- "inputDataExample": "{\n \"self.category\": \"Work\",\n \"self.time_to_next_threshold\": \"900s\",\n \"self.last_check\": \"1970-01-01T00:00:00Z\"\n}",
- "outputDataExample": "{\n \"status\": \"Time to update, calling get_time()\"\n}"
- },
- {
- "simStepId": "f20bb756-15f3-4a7c-914b-aa61470cc435",
- "diagramNodeId": "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
- "simStepLabel": "API Call: Query Server for Activity Data",
- "simStepDescription": "The `get_time` function constructs a query to summarize activity data and sends it to the `aw-server` via an HTTP POST request to the `/api/0/query` endpoint.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "120",
- "endLine": "120",
- "relevantVariables": [
- "aw.query",
- "query",
- "timeperiods"
- ]
- },
- "inputDataExample": "{\n \"query\": \"...canonicalEvents... cat_events = sort_by_duration(merge_events_by_keys(events, [\\\"$category\\\"])); ...\",\n \"timeperiods\": [\"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"]\n}",
- "outputDataExample": "{\n \"query\": \"...canonicalEvents... cat_events = sort_by_duration(merge_events_by_keys(events, [\\\"$category\\\"])); ...\",\n \"timeperiods\": [\"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"]\n}"
- },
- {
- "simStepId": "868edfd6-1f03-416e-88dc-7b09d05e4ba5",
- "diagramNodeId": "e567d898-2785-43f6-98ef-f4b6d1232620",
- "simStepLabel": "Server: Receive and Process Query",
- "simStepDescription": "The `aw-server-rust` instance receives the POST request at the `/api/0/query` endpoint. The request body, containing the query and time periods, is deserialized.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "9",
- "endLine": "12",
- "relevantVariables": [
- "query",
- "query_req"
- ]
- },
- "inputDataExample": "{\n \"query\": [\"...query string...\"],\n \"timeperiods\": [\"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"]\n}",
- "outputDataExample": "{\n \"query_code\": \"...query string...\",\n \"intervals\": [\"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"]\n}"
- },
- {
- "simStepId": "b835d5e0-434d-4469-94fe-d309114a9ef1",
- "diagramNodeId": "8f02d20c-25fe-4a28-99de-3e8908d0a66f",
- "simStepLabel": "Server: Execute Query",
- "simStepDescription": "The server's query endpoint passes the parsed query string and time interval to the `aw_query` library for execution against the datastore.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "16",
- "endLine": "16",
- "relevantVariables": [
- "aw_query::query"
- ]
- },
- "inputDataExample": "{\n \"query_code\": \"...query string...\",\n \"interval\": \"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"\n}",
- "outputDataExample": "{\n \"query_code\": \"...query string...\",\n \"interval\": \"2023-10-27T04:00:00Z/2023-10-28T04:00:00Z\"\n}"
- },
- {
- "simStepId": "cc5cfecf-cee9-4582-aa6c-b74787a11da8",
- "diagramNodeId": "44016962-bb6d-4a70-b13c-4538926a02a4",
- "simStepLabel": "Server: Fetch Events from Datastore",
- "simStepDescription": "The query interpreter executes the `query_bucket` function from the query string. This function calls `ds.get_events` on the datastore to retrieve all relevant raw events within the specified time interval from the SQLite database.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/functions.rs",
- "startLine": "150",
- "endLine": "162",
- "relevantVariables": [
- "query_bucket",
- "ds.get_events"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-hostname\",\n \"interval\": {\n \"start\": \"2023-10-27T04:00:00Z\",\n \"end\": \"2023-10-28T04:00:00Z\"\n }\n}",
- "outputDataExample": "{\n \"events\": [\n {\"id\": 1, \"timestamp\": \"2023-10-27T10:00:00Z\", \"duration\": 300, \"data\": {\"app\": \"Code\", \"title\": \"main.py\"}},\n {\"id\": 2, \"timestamp\": \"2023-10-27T10:05:00Z\", \"duration\": 600, \"data\": {\"app\": \"Firefox\", \"title\": \"Stack Overflow\"}}\n ]\n}"
- },
- {
- "simStepId": "027140c6-aa16-4070-89d3-3b553168e65e",
- "diagramNodeId": "5595958a-cf9d-4894-9824-ecc89e5cf956",
- "simStepLabel": "Server: Transform Raw Events",
- "simStepDescription": "The raw events are passed through a series of transform functions as defined in the query, such as `merge_events_by_keys` to group events by category and `sort_by_duration` to order them.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "115",
- "endLine": "115",
- "relevantVariables": [
- "merge_events_by_keys",
- "sort_by_duration"
- ]
- },
- "inputDataExample": "{\n \"transform_function\": \"merge_events_by_keys\",\n \"events\": [{\"id\": 1, \"data\": {\"$category\": [\"Work\"]}}, ...]\n}",
- "outputDataExample": "{\n \"transform_function\": \"merge_events_by_keys\",\n \"events\": [{\"id\": 1, \"data\": {\"$category\": [\"Work\"]}}, ...]\n}"
- },
- {
- "simStepId": "f52d6bfa-55fe-49ee-9f20-60bf296c76f4",
- "diagramNodeId": "fd5d1362-e41b-43af-bfd8-7f7c344c9849",
- "simStepLabel": "Server: Send Query Result",
- "simStepDescription": "After all transformations are complete, the query engine returns the final processed data. The server serializes this data into a JSON array and sends it back as the HTTP response.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "28",
- "endLine": "28",
- "relevantVariables": [
- "json!",
- "results"
- ]
- },
- "inputDataExample": "{\n \"results_to_serialize\": [\n {\n \"events\": [], \n \"duration\": 5400, \n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\"]}, \"duration\": 3600},\n {\"data\": {\"$category\": [\"Social Media\"]}, \"duration\": 1800}\n ]\n }\n ]\n}",
- "outputDataExample": "{\n \"status\": 200,\n \"body\": \"[{\\\"events\\\":[],\\\"duration\\\":5400,\\\"cat_events\\\":[{\\\"data\\\":{\\\"$category\\\":[\\\"Work\\\"]},\\\"duration\\\":3600},{\\\"data\\\":{\\\"$category\\\":[\\\"Social Media\\\"]},\\\"duration\\\":1800}]}]\"\n}"
- },
- {
- "simStepId": "92487214-03b7-430e-aab5-b5a5fb85b2cb",
- "diagramNodeId": "1b9dc1d5-e6a7-4069-8473-2156853d662e",
- "simStepLabel": "Data Flow: Receive and Parse Server Response",
- "simStepDescription": "The `aw-notify` client receives the HTTP response. The `get_time` function parses the JSON body to extract the categorized event durations.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "120",
- "endLine": "120",
- "relevantVariables": [
- "aw.query"
- ]
- },
- "inputDataExample": "{\n \"response_body\": \"[{\\\"cat_events\\\":[{\\\"data\\\":{\\\"$category\\\":[\\\"Work\\\"]},\\\"duration\\\":3600}, {\\\"data\\\":{\\\"$category\\\":[\\\"All\\\"]},\\\"duration\\\":5400}]}]\"\n}",
- "outputDataExample": "{\n \"response_body\": \"[{\\\"cat_events\\\":[{\\\"data\\\":{\\\"$category\\\":[\\\"Work\\\"]},\\\"duration\\\":3600}, {\\\"data\\\":{\\\"$category\\\":[\\\"All\\\"]},\\\"duration\\\":5400}]}]\"\n}"
- },
- {
- "simStepId": "9c0b3f20-5c18-418a-82f7-78b04ebda9b5",
- "diagramNodeId": "a01b5cc8-f12f-447b-9879-6b55bda0ef87",
- "simStepLabel": "Process Query Result and Update State",
- "simStepDescription": "The `get_time` function processes the server response, creating a dictionary mapping each category to its total duration. This dictionary is returned to the `update` method, which then updates the `time_spent` attribute of the `CategoryAlert` instance.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "123",
- "endLine": "130",
- "relevantVariables": [
- "cat_time",
- "res"
- ]
- },
- "inputDataExample": "{\n \"cat_events\": [\n {\"data\": {\"$category\": [\"Work\"]}, \"duration\": 3660},\n {\"data\": {\"$category\": [\"All\"]}, \"duration\": 5430}\n ]\n}",
- "outputDataExample": "{\n \"self.time_spent\": \"3660s\"\n}"
- },
- {
- "simStepId": "c8b0fe19-76a8-458d-9923-c2f270e306b3",
- "diagramNodeId": "08e05622-d948-47eb-a56d-3d6782d638c0",
- "simStepLabel": "Check for Threshold Breach",
- "simStepDescription": "After updating the time spent, the main loop calls the `check` method on the `CategoryAlert` instance. This method iterates through its configured thresholds to see if any have been met or exceeded by the new `time_spent` value.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "402",
- "endLine": "402",
- "relevantVariables": [
- "alert.check"
- ]
- },
- "inputDataExample": "{\n \"self.time_spent\": \"3660s\",\n \"self.thresholds_untriggered\": [3600, 7200, 14400]\n}",
- "outputDataExample": "{\n \"self.time_spent\": \"3660s\",\n \"self.thresholds_untriggered\": [3600, 7200, 14400]\n}"
- },
- {
- "simStepId": "a66f8ebc-93f8-4f9c-8f19-03bd951d1e98",
- "diagramNodeId": "30303464-f5f8-4155-87e9-b81dda8175d9",
- "simStepLabel": "Trigger Desktop Notification",
- "simStepDescription": "A threshold has been reached (e.g., time spent on 'Work' exceeds 1 hour). The `check` method calls the `notify` function, passing it a title and a formatted message to be displayed to the user.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "281",
- "endLine": "297",
- "relevantVariables": [
- "check",
- "thres",
- "self.time_spent",
- "notify"
- ]
- },
- "inputDataExample": "{\n \"thres\": 3600,\n \"self.time_spent\": 3660,\n \"self.label\": \"💼 Work\"\n}",
- "outputDataExample": "{\n \"title\": \"Goal reached!\",\n \"msg\": \"💼 Work: 1h (1h 1m)\"\n}"
- },
- {
- "simStepId": "e46653da-3493-419e-8f9c-397be83fe894",
- "diagramNodeId": "17c4cd6c-69f5-4df8-ac77-6955a0518939",
- "simStepLabel": "Render Notification",
- "simStepDescription": "The `notify` function uses the `desktop-notifier` library to send the notification to the operating system's notification center.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "161",
- "endLine": "177",
- "relevantVariables": [
- "notifier.send"
- ]
- },
- "inputDataExample": "{\n \"title\": \"Goal reached!\",\n \"msg\": \"💼 Work: 1h (1h 1m)\"\n}",
- "outputDataExample": "{\n \"title\": \"Goal reached!\",\n \"msg\": \"💼 Work: 1h (1h 1m)\"\n}"
- },
- {
- "simStepId": "21533839-7ba4-4cfa-864a-2f67198cad68",
- "diagramNodeId": "445477ac-c52d-4053-a45e-8c81da805c88",
- "simStepLabel": "User sees notification",
- "simStepDescription": "The operating system displays a native notification on the user's desktop with the message '💼 Work: 1h'.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "149",
- "endLine": "184",
- "relevantVariables": [
- "notify"
- ]
- },
- "inputDataExample": "{\n \"notification_payload\": {\n \"title\": \"Goal reached!\",\n \"message\": \"💼 Work: 1h (1h 1m)\"\n }\n}",
- "outputDataExample": "null"
- },
- {
- "simStepId": "8702751d-5f93-4a07-9f11-b22c5e109d8a",
- "diagramNodeId": "",
- "simStepLabel": "Wait for Next Cycle",
- "simStepDescription": "After checking all alerts, the main loop pauses for 10 seconds before starting the next iteration.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-notify/aw_notify/main.py",
- "startLine": "409",
- "endLine": "409",
- "relevantVariables": [
- "sleep"
- ]
- },
- "inputDataExample": "{}",
- "outputDataExample": "{}"
- }
- ],
- "description": "- The
aw-notify module provides proactive alerts based on a user's activity - It runs as a background service, periodically querying the
aw-server to get summaries of time spent in different categories - Users can configure thresholds for specific categories (e
- g
- , 'notify after 30 minutes on Social Media')
- When a threshold is reached,
aw-notify sends a native desktop notification to the user - It can also provide daily summary notifications and alerts about the server's status
",
- "simulationNodesAndEdges": {
- "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1": {
- "simStepIds": [
- "9b9a0f90-d7a7-40fb-8573-53b470ecf85d"
- ]
- },
- "553f1437-5c34-4d6d-8226-417014259fc5": {
- "simStepIds": [
- "f636bdd6-a8e3-47ec-9f9d-986b21a81868"
- ]
- },
- "1de089eb-60a7-4d7f-bfb5-3f7f23315873": {
- "simStepIds": [
- "945e3312-c7c9-4722-953b-94dc0feee249"
- ]
- },
- "e567d898-2785-43f6-98ef-f4b6d1232620": {
- "simStepIds": [
- "868edfd6-1f03-416e-88dc-7b09d05e4ba5"
- ]
- },
- "44016962-bb6d-4a70-b13c-4538926a02a4": {
- "simStepIds": [
- "cc5cfecf-cee9-4582-aa6c-b74787a11da8"
- ]
- },
- "fd5d1362-e41b-43af-bfd8-7f7c344c9849": {
- "simStepIds": [
- "f52d6bfa-55fe-49ee-9f20-60bf296c76f4"
- ]
- },
- "a01b5cc8-f12f-447b-9879-6b55bda0ef87": {
- "simStepIds": [
- "9c0b3f20-5c18-418a-82f7-78b04ebda9b5"
- ]
- },
- "30303464-f5f8-4155-87e9-b81dda8175d9": {
- "simStepIds": [
- "a66f8ebc-93f8-4f9c-8f19-03bd951d1e98"
- ]
- },
- "445477ac-c52d-4053-a45e-8c81da805c88": {
- "simStepIds": [
- "21533839-7ba4-4cfa-864a-2f67198cad68"
- ]
- },
- "f9ddc0fb-c342-4a4a-baec-53c6a2581b80": {
- "simStepIds": [
- "3c977159-c34d-4907-9004-e5aaff3f3bdc"
- ]
- },
- "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e": {
- "simStepIds": [
- "7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b"
- ]
- },
- "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd": {
- "simStepIds": [
- "f20bb756-15f3-4a7c-914b-aa61470cc435"
- ]
- },
- "8f02d20c-25fe-4a28-99de-3e8908d0a66f": {
- "simStepIds": [
- "b835d5e0-434d-4469-94fe-d309114a9ef1"
- ]
- },
- "5595958a-cf9d-4894-9824-ecc89e5cf956": {
- "simStepIds": [
- "027140c6-aa16-4070-89d3-3b553168e65e"
- ]
- },
- "1b9dc1d5-e6a7-4069-8473-2156853d662e": {
- "simStepIds": [
- "92487214-03b7-430e-aab5-b5a5fb85b2cb"
- ]
- },
- "08e05622-d948-47eb-a56d-3d6782d638c0": {
- "simStepIds": [
- "c8b0fe19-76a8-458d-9923-c2f270e306b3"
- ]
- },
- "17c4cd6c-69f5-4df8-ac77-6955a0518939": {
- "simStepIds": [
- "e46653da-3493-419e-8f9c-397be83fe894"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "aw-notify, CategoryAlert, DesktopNotifier, thresholds, get_time",
- "generationPrompt": "How time-based notifications work",
- "generationKeywords": "aw-notify, CategoryAlert, DesktopNotifier, thresholds, get_time",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 123,
- "promptTokenCount": 142893,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 62,
- "promptTokenCount": 64061,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": []
- }
- }
- },
- "How data export and import works": {
- "name": "How data export and import works",
- "simSteps": [
- {
- "simStepId": "8739f5eb-aec2-47f1-b1e6-a05a2bb65acd",
- "diagramNodeId": "a1e562ae-ea06-4c6a-ab92-fa78417115f6",
- "simStepLabel": "Export Flow: Client Initiates Data Export",
- "simStepDescription": "A client application, using `aw-client`, calls the `export_all` method to begin the process of exporting all user data from the ActivityWatch server.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "291",
- "endLine": "292",
- "relevantVariables": [
- "export_all"
- ]
- },
- "inputDataExample": "{}",
- "outputDataExample": "{}"
- },
- {
- "simStepId": "8efaf2e1-7c6d-4820-90a5-2abb80bf65ed",
- "diagramNodeId": "5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
- "simStepLabel": "Export Flow: API Call to Export Endpoint",
- "simStepDescription": "The `aw-client` sends an HTTP GET request to the `/api/0/export` endpoint on the `aw-server` to fetch all bucket and event data.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "292",
- "endLine": "292",
- "relevantVariables": [
- "_get"
- ]
- },
- "inputDataExample": "{\"method\": \"GET\", \"endpoint\": \"/api/0/export\"}",
- "outputDataExample": "{\"method\": \"GET\", \"endpoint\": \"/api/0/export\"}"
- },
- {
- "simStepId": "7bdce779-492f-4dee-a68d-4e6d28dc079a",
- "diagramNodeId": "07e4d089-e23f-4030-8c10-7dbdbd00e1c7",
- "simStepLabel": "Export Flow: Server Handles Export Request",
- "simStepDescription": "The `aw-server` (Flask application) receives the GET request and routes it to the `get` method of the `ExportAllResource` class, which is responsible for handling data exports.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "332",
- "endLine": "344",
- "relevantVariables": [
- "ExportAllResource",
- "get"
- ]
- },
- "inputDataExample": "{\"request\": \"GET /api/0/export\"}",
- "outputDataExample": "{}"
- },
- {
- "simStepId": "6449735d-8c85-4d49-bb8c-c2b1f9918ffc",
- "diagramNodeId": "8515a29c-385b-4ec5-886c-ba3a3a48518e",
- "simStepLabel": "Export Flow: Call to API Layer for Export Logic",
- "simStepDescription": "The REST endpoint handler calls the `export_all` method within the `ServerAPI` class to orchestrate the data aggregation process.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "337",
- "endLine": "337",
- "relevantVariables": [
- "current_app.api.export_all"
- ]
- },
- "inputDataExample": "{}",
- "outputDataExample": "{}"
- },
- {
- "simStepId": "d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6",
- "diagramNodeId": "19faa606-15ad-4c47-a983-692a1f30a667",
- "simStepLabel": "Export Flow: Aggregate All Buckets and Events",
- "simStepDescription": "The `export_all` method in the `ServerAPI` class begins by fetching all existing buckets. It then iterates through each bucket to export its metadata and all associated events.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "97",
- "endLine": "103",
- "relevantVariables": [
- "export_all",
- "get_buckets",
- "export_bucket"
- ]
- },
- "inputDataExample": "{}",
- "outputDataExample": "{\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\"}}"
- },
- {
- "simStepId": "60764034-1b94-4c15-9015-09e8b775f736",
- "diagramNodeId": "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
- "simStepLabel": "Export Flow: Fetching Events for a Bucket",
- "simStepDescription": "For each bucket, the `export_bucket` function calls `get_events` to retrieve all events associated with that bucket from the datastore.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "91",
- "endLine": "91",
- "relevantVariables": [
- "get_events"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"limit\": -1}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"limit\": -1}"
- },
- {
- "simStepId": "5fb7b7d5-1759-43dc-a711-b2b0b5df3893",
- "diagramNodeId": "e590d109-3712-4d3d-9241-ba9cd9a7eeaa",
- "simStepLabel": "Export Flow: Datastore Retrieves Events",
- "simStepDescription": "The `get_events` function in the API layer queries the datastore, which fetches the corresponding events from the underlying database (e.g., SQLite).",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "214",
- "endLine": "228",
- "relevantVariables": [
- "get_events",
- "self.db[bucket_id].get"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"limit\": -1, \"start\": null, \"end\": null}",
- "outputDataExample": "[{\"id\": 1, \"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180.0, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"id\": 2, \"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120.0, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]"
- },
- {
- "simStepId": "7a5f8838-8ed9-47b3-907f-077efeedaa10",
- "diagramNodeId": "272a1088-1b0c-43f9-8335-d7055539c813",
- "simStepLabel": "Export Flow: Returning Exported Data to REST Layer",
- "simStepDescription": "After collecting and formatting all buckets and their events (and scrubbing event IDs), the `export_all` method returns the complete data structure to the REST resource.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "103",
- "endLine": "103",
- "relevantVariables": [
- "exported_buckets"
- ]
- },
- "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\", \"last_updated\": \"2023-10-27T10:05:00.000Z\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]}}}",
- "outputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\", \"last_updated\": \"2023-10-27T10:05:00.000Z\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]}}}"
- },
- {
- "simStepId": "cfd637bd-f6b2-44cf-8330-7b2c59c0658b",
- "diagramNodeId": "6e7e85b1-9708-4f64-ac9e-efc54338c444",
- "simStepLabel": "Export Flow: Server Sends JSON File Response",
- "simStepDescription": "The `ExportAllResource` constructs a final JSON payload and creates an HTTP response with a `Content-Disposition` header, prompting the client to download the data as `aw-buckets-export.json`.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "336",
- "endLine": "344",
- "relevantVariables": [
- "buckets_export",
- "payload",
- "response"
- ]
- },
- "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\", \"last_updated\": \"2023-10-27T10:05:00.000Z\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]}}}",
- "outputDataExample": "HTTP Response with JSON file and headers: {\"Content-Disposition\": \"attachment; filename=aw-buckets-export.json\"}"
- },
- {
- "simStepId": "ea6d2274-023a-4d5f-abf4-0414c6c7f68d",
- "diagramNodeId": "e60e25ae-e9aa-4497-8555-7e3d99a4049f",
- "simStepLabel": "Import Flow: Client Initiates Data Import",
- "simStepDescription": "A client application, such as a script using `aw-client`, calls a method like `import_bucket` to start the data import process. This example shows a single bucket import, but the server supports importing multiple buckets at once.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "297",
- "endLine": "299",
- "relevantVariables": [
- "import_bucket"
- ]
- },
- "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00Z\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\", \"title\": \"ActivityWatch - GitHub\"}}, {\"timestamp\": \"2023-10-27T10:03:00.000Z\", \"duration\": 120, \"data\": {\"app\": \"Code\", \"title\": \"api.py - MyProject\"}}]}}}",
- "outputDataExample": "{}"
- },
- {
- "simStepId": "f5c06885-1138-4c13-ae70-10b9d409be5b",
- "diagramNodeId": "ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
- "simStepLabel": "Import Flow: API Call to Import Endpoint",
- "simStepDescription": "The client sends an HTTP POST request to the `/api/0/import` endpoint, with the JSON data containing buckets and events in the request body.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "299",
- "endLine": "299",
- "relevantVariables": [
- "_post"
- ]
- },
- "inputDataExample": "{\"method\": \"POST\", \"endpoint\": \"/api/0/import\", \"payload\": {\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}}",
- "outputDataExample": "{\"method\": \"POST\", \"endpoint\": \"/api/0/import\", \"payload\": {\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}}"
- },
- {
- "simStepId": "3e1decf0-1329-4da8-a7c7-870ffe960a54",
- "diagramNodeId": "12725c25-974e-4363-bb91-c61c8745ed75",
- "simStepLabel": "Import Flow: Server Handles Import Request",
- "simStepDescription": "The `aw-server` receives the POST request and routes it to the `post` method of the `ImportAllResource` class. This method extracts the `buckets` data from the request.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "129",
- "endLine": "341",
- "relevantVariables": [
- "ImportAllResource",
- "post",
- "buckets"
- ]
- },
- "inputDataExample": "{\"request\": \"POST /api/0/import\", \"payload\": {\"buckets\": {}}}",
- "outputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}"
- },
- {
- "simStepId": "988adf58-e1be-4352-be66-4f02188fc28a",
- "diagramNodeId": "0614b31f-64d9-4e85-a5f5-6304f0702bd7",
- "simStepLabel": "Import Flow: Call to API Layer for Import Logic",
- "simStepDescription": "The REST endpoint handler calls the `import_all` method in the `ServerAPI` to process the imported data.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "129",
- "endLine": "341",
- "relevantVariables": [
- "current_app.api.import_all"
- ]
- },
- "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}",
- "outputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}"
- },
- {
- "simStepId": "4050248c-1638-452c-8826-677a7a2fece8",
- "diagramNodeId": "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570",
- "simStepLabel": "Import Flow: Iterate and Import Each Bucket",
- "simStepDescription": "The `import_all` method loops through each bucket from the input data and calls `import_bucket` to process them individually.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "133",
- "endLine": "135",
- "relevantVariables": [
- "import_all",
- "import_bucket"
- ]
- },
- "inputDataExample": "{\"buckets\": {\"aw-watcher-window_my-pc\": {\"id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"hostname\": \"my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\"}]}}}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\"}"
- },
- {
- "simStepId": "7e01821d-906c-4518-a1e0-6b71be84291a",
- "diagramNodeId": "941b8c57-be7c-49cd-ba2a-d2237f8f129b",
- "simStepLabel": "Import Flow: Create Bucket in Datastore",
- "simStepDescription": "The `import_bucket` method calls `db.create_bucket` to create the new bucket with its metadata in the datastore.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "110",
- "endLine": "120",
- "relevantVariables": [
- "self.db.create_bucket"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00.000Z\"}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"type\": \"currentwindow\", \"client\": \"aw-watcher-window\", \"hostname\": \"my-pc\", \"created\": \"2023-10-27T10:00:00.000Z\"}"
- },
- {
- "simStepId": "164ed08b-0873-499b-b945-e062cf362429",
- "diagramNodeId": "07630c61-6df6-484b-81c3-0984379bfd68",
- "simStepLabel": "Import Flow: Create and Insert Events",
- "simStepDescription": "After creating the bucket, `import_bucket` calls `create_events`, which in turn calls the datastore's `insert` method to add all events from the imported data into the newly created bucket.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "128",
- "endLine": "131",
- "relevantVariables": [
- "create_events"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\"}}]}",
- "outputDataExample": "null"
- },
- {
- "simStepId": "666a933a-7a74-4d90-be19-7610f7bd3d74",
- "diagramNodeId": "1f7db50a-bc15-48d1-9f06-27ed743afa75",
- "simStepLabel": "Import Flow: Persist Events to Database",
- "simStepDescription": "The `create_events` method calls the datastore to persist the events to the database.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/api.py",
- "startLine": "235",
- "endLine": "235",
- "relevantVariables": [
- "self.db[bucket_id].insert"
- ]
- },
- "inputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\"}}]}",
- "outputDataExample": "{\"bucket_id\": \"aw-watcher-window_my-pc\", \"events\": [{\"timestamp\": \"2023-10-27T10:00:00.000Z\", \"duration\": 180, \"data\": {\"app\": \"Firefox\"}}]}"
- },
- {
- "simStepId": "3fd4d48c-e70c-4217-92c1-7554445cf03b",
- "diagramNodeId": "ae563be0-ff29-4c20-8f6d-6771f04c8da3",
- "simStepLabel": "Import Flow: Server Sends Success Response",
- "simStepDescription": "After all buckets and events have been successfully imported, the `ImportAllResource` returns a 200 OK status to the client.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server/aw_server/rest.py",
- "startLine": "129",
- "endLine": "341",
- "relevantVariables": []
- },
- "inputDataExample": "{}",
- "outputDataExample": "{\"status_code\": 200, \"message\": \"OK\"}"
- }
- ],
- "description": "- To ensure users have full control over their data,
aw-server provides API endpoints for data migration - The export feature allows a user to download all their tracked data, including bucket metadata and all associated events, into a single JSON file
- This file can be used for backups, analysis with external tools, or migration to another machine
- The import feature can read this JSON file to recreate the buckets and insert all the events, effectively restoring a user's complete history
",
- "simulationNodesAndEdges": {
- "a1e562ae-ea06-4c6a-ab92-fa78417115f6": {
- "simStepIds": [
- "8739f5eb-aec2-47f1-b1e6-a05a2bb65acd"
- ]
- },
- "07e4d089-e23f-4030-8c10-7dbdbd00e1c7": {
- "simStepIds": [
- "7bdce779-492f-4dee-a68d-4e6d28dc079a"
- ]
- },
- "19faa606-15ad-4c47-a983-692a1f30a667": {
- "simStepIds": [
- "d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6"
- ]
- },
- "e590d109-3712-4d3d-9241-ba9cd9a7eeaa": {
- "simStepIds": [
- "5fb7b7d5-1759-43dc-a711-b2b0b5df3893"
- ]
- },
- "6e7e85b1-9708-4f64-ac9e-efc54338c444": {
- "simStepIds": [
- "cfd637bd-f6b2-44cf-8330-7b2c59c0658b"
- ]
- },
- "e60e25ae-e9aa-4497-8555-7e3d99a4049f": {
- "simStepIds": [
- "ea6d2274-023a-4d5f-abf4-0414c6c7f68d"
- ]
- },
- "12725c25-974e-4363-bb91-c61c8745ed75": {
- "simStepIds": [
- "3e1decf0-1329-4da8-a7c7-870ffe960a54"
- ]
- },
- "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570": {
- "simStepIds": [
- "4050248c-1638-452c-8826-677a7a2fece8"
- ]
- },
- "07630c61-6df6-484b-81c3-0984379bfd68": {
- "simStepIds": [
- "164ed08b-0873-499b-b945-e062cf362429"
- ]
- },
- "ae563be0-ff29-4c20-8f6d-6771f04c8da3": {
- "simStepIds": [
- "3fd4d48c-e70c-4217-92c1-7554445cf03b"
- ]
- },
- "5fe912cd-a72c-4cc1-969b-b5eb6759ace9": {
- "simStepIds": [
- "8efaf2e1-7c6d-4820-90a5-2abb80bf65ed"
- ]
- },
- "8515a29c-385b-4ec5-886c-ba3a3a48518e": {
- "simStepIds": [
- "6449735d-8c85-4d49-bb8c-c2b1f9918ffc"
- ]
- },
- "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff": {
- "simStepIds": [
- "60764034-1b94-4c15-9015-09e8b775f736"
- ]
- },
- "272a1088-1b0c-43f9-8335-d7055539c813": {
- "simStepIds": [
- "7a5f8838-8ed9-47b3-907f-077efeedaa10"
- ]
- },
- "ebfbcf3c-bc57-4fe1-866e-fde1b860e633": {
- "simStepIds": [
- "f5c06885-1138-4c13-ae70-10b9d409be5b"
- ]
- },
- "0614b31f-64d9-4e85-a5f5-6304f0702bd7": {
- "simStepIds": [
- "988adf58-e1be-4352-be66-4f02188fc28a"
- ]
- },
- "941b8c57-be7c-49cd-ba2a-d2237f8f129b": {
- "simStepIds": [
- "7e01821d-906c-4518-a1e0-6b71be84291a"
- ]
- },
- "1f7db50a-bc15-48d1-9f06-27ed743afa75": {
- "simStepIds": [
- "666a933a-7a74-4d90-be19-7610f7bd3d74"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "export_all, import_bucket, get_buckets, create_events, aw-server/api.py",
- "generationPrompt": "How data export and import works",
- "generationKeywords": "export_all, import_bucket, get_buckets, create_events, aw-server/api.py",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 6,
- "promptTokenCount": 4701,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 123,
- "promptTokenCount": 104218,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 58,
- "promptTokenCount": 57795,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": []
- }
- }
- },
- "How custom scripting with the client library works": {
- "name": "How custom scripting with the client library works",
- "simSteps": [
- {
- "simStepId": "e90cee0c-3a20-498b-97b9-2086a61dc02b",
- "diagramNodeId": "237e712f-0c66-4488-b6e9-1ef8c3b71b51",
- "simStepLabel": "Start Script Execution",
- "simStepDescription": "The user executes the `working_hours.py` script to calculate work time. The script defines a regex for 'Work' activities and sets up time periods to query.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/examples/working_hours.py",
- "startLine": "91",
- "endLine": "115",
- "relevantVariables": [
- "main",
- "query"
- ]
- },
- "inputDataExample": "null",
- "outputDataExample": "{\n \"regex\": \"Google Docs|libreoffice|ReText|GitHub|Stack Overflow|BitBucket|Gitlab|vim|Spyder|kate|Ghidra|Scite|ActivityWatch|aw-\",\n \"hostname\": \"my-laptop\",\n \"timeperiods\": [\n [\"2023-10-26T04:00:00+00:00\", \"2023-10-27T04:00:00+00:00\"],\n [\"2023-10-27T04:00:00+00:00\", \"2023-10-28T04:00:00+00:00\"]\n ]\n}"
- },
- {
- "simStepId": "5aa97ae5-7e30-4d15-8f12-05942f2e75c9",
- "diagramNodeId": "aecc1e90-5e71-43f4-a5b8-757de329fe3a",
- "simStepLabel": "Invoke AW Client Query",
- "simStepDescription": "The script constructs a query string using helper functions from `aw_client.queries` and then calls the `aw.query()` method to execute it against the ActivityWatch server.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/examples/working_hours.py",
- "startLine": "86",
- "endLine": "86",
- "relevantVariables": [
- "aw.query"
- ]
- },
- "inputDataExample": "{\n \"query\": \"\\n events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-laptop\\\")));\\n not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-laptop\\\")));\\n not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\\n events = filter_period_intersect(events, not_afk);\\n events = categorize(events, [[\\\"Work\\\"], {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"Google Docs|libreoffice|ReText|GitHub|Stack Overflow|BitBucket|Gitlab|vim|Spyder|kate|Ghidra|Scite|ActivityWatch|aw-\\\", \\\"ignore_case\\\": true}]);\\n events = filter_keyvals(events, \\\"$category\\\", [[\\\"Work\\\"]]);\\n duration = sum_durations(events);\\n RETURN = {\\\"events\\\": events, \\\"duration\\\": duration};\\n \",\n \"timeperiods\": [\n [\"2023-10-26T04:00:00+00:00\", \"2023-10-27T04:00:00+00:00\"],\n [\"2023-10-27T04:00:00+00:00\", \"2023-10-28T04:00:00+00:00\"]\n ]\n}",
- "outputDataExample": "{\n \"query\": \"\\n events = flood(query_bucket(find_bucket(\\\"aw-watcher-window_my-laptop\\\")));\\n not_afk = flood(query_bucket(find_bucket(\\\"aw-watcher-afk_my-laptop\\\")));\\n not_afk = filter_keyvals(not_afk, \\\"status\\\", [\\\"not-afk\\\"]);\\n events = filter_period_intersect(events, not_afk);\\n events = categorize(events, [[\\\"Work\\\"], {\\\"type\\\": \\\"regex\\\", \\\"regex\\\": \\\"Google Docs|libreoffice|ReText|GitHub|Stack Overflow|BitBucket|Gitlab|vim|Spyder|kate|Ghidra|Scite|ActivityWatch|aw-\\\", \\\"ignore_case\\\": true}]);\\n events = filter_keyvals(events, \\\"$category\\\", [[\\\"Work\\\"]]);\\n duration = sum_durations(events);\\n RETURN = {\\\"events\\\": events, \\\"duration\\\": duration};\\n \",\n \"timeperiods\": [\n [\"2023-10-26T04:00:00+00:00\", \"2023-10-27T04:00:00+00:00\"],\n [\"2023-10-27T04:00:00+00:00\", \"2023-10-28T04:00:00+00:00\"]\n ]\n}"
- },
- {
- "simStepId": "0d34430a-af81-407b-8817-672288674005",
- "diagramNodeId": "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c",
- "simStepLabel": "Prepare API Request",
- "simStepDescription": "The `ActivityWatchClient.query` method formats the time periods into ISO 8601 interval strings and packages the query and time periods into a JSON payload for the HTTP POST request.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "305",
- "endLine": "339",
- "relevantVariables": [
- "query",
- "_post"
- ]
- },
- "inputDataExample": "{\n \"query\": \"...query string...\",\n \"timeperiods\": [[\"2023-10-26T04:00:00+00:00\", \"2023-10-27T04:00:00+00:00\"]]\n}",
- "outputDataExample": "{\n \"endpoint\": \"query/\",\n \"data\": {\n \"timeperiods\": [\"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"],\n \"query\": [\"...statement1...\", \"...statement2...\"]\n }\n}"
- },
- {
- "simStepId": "834b7dbc-5efe-41ac-b75b-e43ad32141df",
- "diagramNodeId": "62388ee6-67f4-4adc-b08e-90deeb10efd4",
- "simStepLabel": "API Call: POST /api/0/query/",
- "simStepDescription": "The client sends the formatted JSON payload as an HTTP POST request to the `/api/0/query/` endpoint on the `aw-server`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "122",
- "endLine": "127",
- "relevantVariables": [
- "req.post"
- ]
- },
- "inputDataExample": "{\n \"timeperiods\": [\"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"],\n \"query\": [\"events = query_bucket(...)\", \"RETURN = events;\"]\n}",
- "outputDataExample": "{\n \"timeperiods\": [\"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"],\n \"query\": [\"events = query_bucket(...)\", \"RETURN = events;\"]\n}"
- },
- {
- "simStepId": "c988a25d-05ad-4c19-87ac-362c79af1d00",
- "diagramNodeId": "73994797-596f-4b60-a36e-5f45cba1fcd3",
- "simStepLabel": "Receive Query Request (aw-server-rust)",
- "simStepDescription": "The Rust-based `aw-server` receives the POST request at the `/api/0/query` endpoint. It parses the JSON body into a `Query` struct and prepares to execute the query against the datastore.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "10",
- "endLine": "23",
- "relevantVariables": [
- "query",
- "query_req",
- "aw_query::query"
- ]
- },
- "inputDataExample": "{\n \"timeperiods\": [\"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"],\n \"query\": [\"events = query_bucket(...)\", \"RETURN = events;\"]\n}",
- "outputDataExample": "{\n \"query_code\": \"events = query_bucket(...)\\nRETURN = events;\",\n \"interval\": \"2023-10-26T04:00:00+00:00/2023-10-27T04:00:00+00:00\"\n}"
- },
- {
- "simStepId": "98777081-df05-4b5c-89f6-5076fab00e92",
- "diagramNodeId": "31b60323-3a65-4184-a42f-f577f3a958ff",
- "simStepLabel": "Execute Query",
- "simStepDescription": "The endpoint handler passes the raw query string, time interval, and a datastore reference to the `aw_query::query` function, which is the entry point for the query engine.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "16",
- "endLine": "16",
- "relevantVariables": [
- "aw_query::query"
- ]
- },
- "inputDataExample": "{\n \"code\": \"events = query_bucket(\\\"aw-watcher-window_my-laptop\\\"); RETURN = events;\",\n \"ti\": \"2023-10-26T04:00:00Z/2023-10-27T04:00:00Z\",\n \"ds\": \"Datastore object\"\n}",
- "outputDataExample": "{\n \"code\": \"events = query_bucket(\\\"aw-watcher-window_my-laptop\\\"); RETURN = events;\",\n \"ti\": \"2023-10-26T04:00:00Z/2023-10-27T04:00:00Z\",\n \"ds\": \"Datastore object\"\n}"
- },
- {
- "simStepId": "b482a39f-e520-4d4d-8b2f-d1298922763f",
- "diagramNodeId": "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b",
- "simStepLabel": "Parse and Interpret Query",
- "simStepDescription": "The `aw_query` library's main function takes the query string, tokenizes it with a lexer, parses it into an Abstract Syntax Tree (AST), and then interprets the AST to execute the query logic.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/lib.rs",
- "startLine": "53",
- "endLine": "64",
- "relevantVariables": [
- "query",
- "lexer::Lexer",
- "parser::parse",
- "interpret::interpret_prog"
- ]
- },
- "inputDataExample": "{\n \"code\": \"events = query_bucket(...); RETURN = events;\"\n}",
- "outputDataExample": "{\n \"program\": \"AST representation of the query\"\n}"
- },
- {
- "simStepId": "914107de-b38a-4307-ab2c-e257ed3d2fb5",
- "diagramNodeId": "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
- "simStepLabel": "Data Fetch: `query_bucket`",
- "simStepDescription": "During interpretation, the `query_bucket` function is called. This function requests all events for a given bucket ID within the specified time interval from the datastore.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/functions.rs",
- "startLine": "139",
- "endLine": "168",
- "relevantVariables": [
- "query_bucket",
- "ds.get_events"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-laptop\",\n \"interval\": \"2023-10-26T04:00:00Z/2023-10-27T04:00:00Z\"\n}",
- "outputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-laptop\",\n \"interval\": \"2023-10-26T04:00:00Z/2023-10-27T04:00:00Z\"\n}"
- },
- {
- "simStepId": "04bbbe33-e9de-4c5f-b925-27196d20ef1d",
- "diagramNodeId": "0b3e80ff-b4c9-42db-b067-1a9ba48e9218",
- "simStepLabel": "Database Query",
- "simStepDescription": "The datastore worker receives the request and executes a SQL `SELECT` statement against the SQLite database to retrieve the raw event data for the specified bucket and time range.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "startLine": "700",
- "endLine": "797",
- "relevantVariables": [
- "get_events",
- "conn.prepare"
- ]
- },
- "inputDataExample": "{\n \"bucket_id\": \"aw-watcher-window_my-laptop\",\n \"starttime_opt\": \"2023-10-26T04:00:00Z\",\n \"endtime_opt\": \"2023-10-27T04:00:00Z\",\n \"limit_opt\": null\n}",
- "outputDataExample": "{\n \"rows\": [\n [1, 1698307200000000000, 1698307260000000000, \"{\\\"app\\\":\\\"Firefox\\\",\\\"title\\\":\\\"ActivityWatch - GitHub\\\"}\"]\n ]\n}"
- },
- {
- "simStepId": "5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619",
- "diagramNodeId": "561eebea-ee66-4251-a29c-64c2e3aae490",
- "simStepLabel": "Return Raw Event Data",
- "simStepDescription": "The raw rows from the SQLite query are returned to the datastore layer for processing.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "startLine": "748",
- "endLine": "788",
- "relevantVariables": [
- "rows"
- ]
- },
- "inputDataExample": "{\n \"rows\": [\n [1, 1698307200000000000, 1698307260000000000, \"{\\\"app\\\":\\\"Firefox\\\",\\\"title\\\":\\\"ActivityWatch - GitHub\\\"}\"]\n ]\n}",
- "outputDataExample": "{\n \"rows\": [\n [1, 1698307200000000000, 1698307260000000000, \"{\\\"app\\\":\\\"Firefox\\\",\\\"title\\\":\\\"ActivityWatch - GitHub\\\"}\"]\n ]\n}"
- },
- {
- "simStepId": "1b3cdf02-5dad-411c-a35e-9250c8aafc9d",
- "diagramNodeId": "60a529b9-b262-4c7f-9baf-5beb50025a86",
- "simStepLabel": "Deserialize Events",
- "simStepDescription": "The datastore layer deserializes the raw database rows into structured `Event` objects.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-datastore/src/datastore.rs",
- "startLine": "755",
- "endLine": "780",
- "relevantVariables": [
- "Event"
- ]
- },
- "inputDataExample": "{\n \"row\": [1, 1698307200000000000, 1698307260000000000, \"{\\\"app\\\":\\\"Firefox\\\",\\\"title\\\":\\\"ActivityWatch - GitHub\\\"}\"]\n}",
- "outputDataExample": "{\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 60.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}"
- },
- {
- "simStepId": "d78663e6-a6d4-4ba7-a922-436bd075e457",
- "diagramNodeId": "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
- "simStepLabel": "Return Deserialized Events",
- "simStepDescription": "A vector of `Event` objects is returned from the datastore up to the query engine.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/functions.rs",
- "startLine": "167",
- "endLine": "167",
- "relevantVariables": [
- "ret"
- ]
- },
- "inputDataExample": "[{\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 60.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
- "outputDataExample": "[{\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 60.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]"
- },
- {
- "simStepId": "f7c58723-a402-45d1-8070-59c196e20fb2",
- "diagramNodeId": "06ecdf3e-50eb-4bf3-9c56-183f98a3186b",
- "simStepLabel": "Perform Query Transformations",
- "simStepDescription": "The query interpreter continues executing the AST. It applies a series of transformations to the fetched events, such as `flood`, `filter_period_intersect`, `categorize`, `merge_events_by_keys`, and `sum_durations`, as defined in the query string.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-query/src/interpret.rs",
- "startLine": "213",
- "endLine": "226",
- "relevantVariables": [
- "interpret_expr",
- "fun"
- ]
- },
- "inputDataExample": "[{\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 60.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\"\n }\n}]",
- "outputDataExample": "{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}"
- },
- {
- "simStepId": "633d97c2-762a-45cb-8900-308ab124d526",
- "diagramNodeId": "3f00132f-3930-4b99-82cf-1ca7f818661b",
- "simStepLabel": "Return Final Query Result",
- "simStepDescription": "The final computed result, as specified by the `RETURN` statement in the query, is passed from the query engine back to the API endpoint handler.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "16",
- "endLine": "25",
- "relevantVariables": [
- "result"
- ]
- },
- "inputDataExample": "{\n \"events\": [{\"id\":1, ...}],\n \"duration\": 55.0\n}",
- "outputDataExample": "{\n \"events\": [{\"id\":1, ...}],\n \"duration\": 55.0\n}"
- },
- {
- "simStepId": "72197f38-6e3b-432c-be11-ce5fbb94efb9",
- "diagramNodeId": "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500",
- "simStepLabel": "Serialize and Send Response",
- "simStepDescription": "The Rocket endpoint handler serializes the query result into a JSON string and sends it as the HTTP response.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "startLine": "28",
- "endLine": "28",
- "relevantVariables": [
- "json!"
- ]
- },
- "inputDataExample": "{\n \"events\": [{\"id\":1, ...}],\n \"duration\": 55.0\n}",
- "outputDataExample": "[{\n \"events\": [{\"id\":1, ...}],\n \"duration\": 55.0\n}]"
- },
- {
- "simStepId": "33e5b4e9-bd66-45f5-ab0f-543737810b99",
- "diagramNodeId": "ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
- "simStepLabel": "HTTP Response",
- "simStepDescription": "The `aw-server` sends the JSON response back to the `aw-client`.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "337",
- "endLine": "338",
- "relevantVariables": [
- "response"
- ]
- },
- "inputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]",
- "outputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]"
- },
- {
- "simStepId": "642425c3-abd7-45fe-b5a9-a76bf90a9477",
- "diagramNodeId": "7057dbee-ccfe-43f8-9014-90812018a849",
- "simStepLabel": "Process Response in Client",
- "simStepDescription": "The `ActivityWatchClient` receives the HTTP response, checks for errors, and parses the JSON body into a Python list of dictionaries.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/aw_client/client.py",
- "startLine": "338",
- "endLine": "338",
- "relevantVariables": [
- "response.json()"
- ]
- },
- "inputDataExample": "HTTP Response with JSON body: `[{\"events\": [...], \"duration\": 55.0}]`",
- "outputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]"
- },
- {
- "simStepId": "65443293-5e86-4e71-9e8d-19d61bd162d9",
- "diagramNodeId": "c8cbde86-13c0-4232-898e-104d815a805c",
- "simStepLabel": "Return Result to Script",
- "simStepDescription": "The parsed data is returned from the `aw.query()` method call back to the `working_hours.py` script.",
- "isEdge": 1,
- "sourceCodeMapping": {
- "filePath": "aw-client/examples/working_hours.py",
- "startLine": "86",
- "endLine": "86",
- "relevantVariables": [
- "res"
- ]
- },
- "inputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]",
- "outputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]"
- },
- {
- "simStepId": "e38db73e-b347-4786-8efd-1e7cab44f73f",
- "diagramNodeId": "e985450d-2666-412f-acf5-988a5c0c7de5",
- "simStepLabel": "Process and Display Results",
- "simStepDescription": "The `working_hours.py` script receives the processed data, calculates total durations using `generous_approx` (which applies flooding), formats the output, and prints a tabulated summary to the console. It also saves the raw event data to a JSON file.",
- "isEdge": 0,
- "sourceCodeMapping": {
- "filePath": "aw-client/examples/working_hours.py",
- "startLine": "113",
- "endLine": "120",
- "relevantVariables": [
- "_print",
- "generous_approx",
- "json.dump"
- ]
- },
- "inputDataExample": "[{\n \"events\": [\n {\n \"id\": 1,\n \"timestamp\": \"2023-10-26T08:00:00Z\",\n \"duration\": 55.0,\n \"data\": {\n \"app\": \"Firefox\",\n \"title\": \"ActivityWatch - GitHub\",\n \"$category\": [\"Work\", \"Programming\"]\n }\n }\n ],\n \"duration\": 55.0\n}]",
- "outputDataExample": "Console Output:\n| Date | Duration | Events |\n|------------|------------|--------|\n| 2023-10-26 | 0:00:55 | 1 |\n\nTotal: 0:00:55"
- }
- ],
- "description": "- The
aw-client library provides a high-level Python interface for interacting with the aw-server REST API - It empowers developers and power users to build custom scripts, new watchers, or data analysis tools
- The library handles API authentication, request queuing for offline support, and data serialization
- The
examples directory showcases common use cases, such as calculating daily active time, generating custom reports, and exporting data to a pandas DataFrame for further analysis
",
- "simulationNodesAndEdges": {
- "237e712f-0c66-4488-b6e9-1ef8c3b71b51": {
- "simStepIds": [
- "e90cee0c-3a20-498b-97b9-2086a61dc02b"
- ]
- },
- "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c": {
- "simStepIds": [
- "0d34430a-af81-407b-8817-672288674005"
- ]
- },
- "73994797-596f-4b60-a36e-5f45cba1fcd3": {
- "simStepIds": [
- "c988a25d-05ad-4c19-87ac-362c79af1d00"
- ]
- },
- "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b": {
- "simStepIds": [
- "b482a39f-e520-4d4d-8b2f-d1298922763f"
- ]
- },
- "0b3e80ff-b4c9-42db-b067-1a9ba48e9218": {
- "simStepIds": [
- "04bbbe33-e9de-4c5f-b925-27196d20ef1d"
- ]
- },
- "60a529b9-b262-4c7f-9baf-5beb50025a86": {
- "simStepIds": [
- "1b3cdf02-5dad-411c-a35e-9250c8aafc9d"
- ]
- },
- "06ecdf3e-50eb-4bf3-9c56-183f98a3186b": {
- "simStepIds": [
- "f7c58723-a402-45d1-8070-59c196e20fb2"
- ]
- },
- "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500": {
- "simStepIds": [
- "72197f38-6e3b-432c-be11-ce5fbb94efb9"
- ]
- },
- "7057dbee-ccfe-43f8-9014-90812018a849": {
- "simStepIds": [
- "642425c3-abd7-45fe-b5a9-a76bf90a9477"
- ]
- },
- "e985450d-2666-412f-acf5-988a5c0c7de5": {
- "simStepIds": [
- "e38db73e-b347-4786-8efd-1e7cab44f73f"
- ]
- },
- "aecc1e90-5e71-43f4-a5b8-757de329fe3a": {
- "simStepIds": [
- "5aa97ae5-7e30-4d15-8f12-05942f2e75c9"
- ]
- },
- "62388ee6-67f4-4adc-b08e-90deeb10efd4": {
- "simStepIds": [
- "834b7dbc-5efe-41ac-b75b-e43ad32141df"
- ]
- },
- "31b60323-3a65-4184-a42f-f577f3a958ff": {
- "simStepIds": [
- "98777081-df05-4b5c-89f6-5076fab00e92"
- ]
- },
- "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f": {
- "simStepIds": [
- "914107de-b38a-4307-ab2c-e257ed3d2fb5"
- ]
- },
- "561eebea-ee66-4251-a29c-64c2e3aae490": {
- "simStepIds": [
- "5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619"
- ]
- },
- "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe": {
- "simStepIds": [
- "d78663e6-a6d4-4ba7-a922-436bd075e457"
- ]
- },
- "3f00132f-3930-4b99-82cf-1ca7f818661b": {
- "simStepIds": [
- "633d97c2-762a-45cb-8900-308ab124d526"
- ]
- },
- "ec5d6b90-2f5f-4a07-b0e8-da3610035a92": {
- "simStepIds": [
- "33e5b4e9-bd66-45f5-ab0f-543737810b99"
- ]
- },
- "c8cbde86-13c0-4232-898e-104d815a805c": {
- "simStepIds": [
- "65443293-5e86-4e71-9e8d-19d61bd162d9"
- ]
- }
- },
- "isAIGenerated": true,
- "keywords": "aw_client, ActivityWatchClient, insert_events, query, aw-client/examples",
- "generationPrompt": "How custom scripting with the client library works",
- "generationKeywords": "aw_client, ActivityWatchClient, insert_events, query, aw-client/examples",
- "meta": {
- "containerCoverage": {
- "perContainerTotals": {
- "frontend": {
- "promptFileCount": 18,
- "promptTokenCount": 9716,
- "suggestedFileCount": 5
- },
- "server": {
- "promptFileCount": 123,
- "promptTokenCount": 94957,
- "suggestedFileCount": 7
- },
- "drawio": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- },
- "shared": {
- "promptFileCount": 67,
- "promptTokenCount": 54942,
- "suggestedFileCount": 17
- },
- "unknown": {
- "promptFileCount": 0,
- "promptTokenCount": 0,
- "suggestedFileCount": 0
- }
- },
- "missingContainers": [],
- "addedFiles": []
- }
- }
- }
- },
- "cellToPath": {
- "02d954ad-e1f5-4853-9860-a553ea21245b": "aw-watcher-window",
- "900d6121-1844-48ba-9a18-db1ec6ea9793": "aw-client",
- "efb8048c-455c-4e7a-aa18-9e8b04779b71": "aw-server",
- "1eed769a-5d0a-443c-9cc3-4e8f59c84abb": "aw-core",
- "306c9af9-c4b4-4bea-85d2-fc4830dedc4c": "aw-watcher-window/aw_watcher_window",
- "48103d9a-f009-4555-bb82-435f417b0644": "aw-client/aw_client",
- "b6e912cd-6fa0-4d47-afd0-0b49c97f7f49": "aw-server/aw_server",
- "5093a30d-28ac-4c2b-811d-65c61efc0882": "aw-core/aw_datastore",
- "1bbc4c76-4066-4521-a1d8-0248c1418060": "aw-watcher-window/aw_watcher_window/main.py",
- "f55ac327-589c-4d8a-ac08-6db49ae00e75": "aw-watcher-window/aw_watcher_window/lib.py",
- "4c4b52ec-ced7-45a9-b08c-c66c0c1a80e2": "aw-client/aw_client/client.py",
- "7f67f305-e40b-496e-87a4-97725d0636a0": "aw-server/aw_server/rest.py",
- "ecd3eb0c-cbf1-4d55-862c-9f191d373fcc": "aw-server/aw_server/api.py",
- "aba7852e-7836-4343-ae26-5ecb9a02d42d": "aw-core/aw_datastore/datastore.py",
- "b2eb5c59-4162-4dea-ac74-511f22996f00": "aw-core/aw_datastore/storages",
- "a63cc090-4355-47fb-8b22-62cd1b842ddb": "aw-core/aw_datastore/storages/peewee.py",
- "638a5f20-935f-4345-8eaf-dfcd2aa6efb4": "aw-watcher-window/aw_watcher_window/main.py-simstep-caf92190-4958-42b9-b962-d21c9ff6c62d",
- "89c12f0e-0649-4963-8e57-d7fd7da30bc4": "aw-watcher-window/aw_watcher_window/lib.py-simstep-3e57e810-18fe-461f-a33c-f3eb0773ecf5",
- "30328419-4cc4-4ea2-a7fb-1728782b23aa": "aw-watcher-window/aw_watcher_window/main.py-simstep-706e836d-c3e2-4048-9eae-95e761ca9ffa",
- "82482fcc-b698-4f91-a27c-a4110d012d99": "aw-client/aw_client/client.py-simstep-432d1978-befd-4dfd-979b-fe28821d4e00",
- "2217c8ca-4cbb-4721-acb9-1057b3b16d69": "aw-server/aw_server/api.py-simstep-addb33f5-b815-49f0-9b54-a8ee3fb3b87b",
- "d7c1e2e0-cc37-4c2f-a45d-6b705e72093a": "aw-core/aw_datastore/datastore.py-simstep-5573707d-aa48-4a66-a3dc-25c841986d39",
- "6d9c0750-fa20-47af-9135-6cc6444cb6b0": "generated-edge-simstep-39835fd9-a301-482d-8b6d-9d16abbbaa29-6d9c0750-fa20-47af-9135-6cc6444cb6b0",
- "3fe51be8-fc72-4a07-8a11-bef3ffb6dd26": "generated-edge-simstep-81f5cf5a-47ed-4fce-9c97-27559b1c7976-3fe51be8-fc72-4a07-8a11-bef3ffb6dd26",
- "78766ca9-9103-486a-8755-f57a09e7f5a7": "generated-edge-simstep-11bc8b75-0103-4652-9fec-e55af41400a0-78766ca9-9103-486a-8755-f57a09e7f5a7",
- "5a7fba44-6d4d-4836-bc13-ed69518c9d45": "generated-edge-simstep-97f58e0a-cbeb-4895-b613-d8e9fd129a42-5a7fba44-6d4d-4836-bc13-ed69518c9d45",
- "6a5be6b6-e11d-460d-8193-427f3a9e42ac": "generated-edge-simstep-cd6c54a5-c0bd-4b99-9446-ea921ee876a6-6a5be6b6-e11d-460d-8193-427f3a9e42ac",
- "4ec0ae2c-a0ea-42aa-ae4b-3a457060e1d0": "aw-server-rust",
- "d4939ae3-d0c2-44b2-90c5-9a7791e083b5": "README.md",
- "e4fd3d3d-801a-4bc3-8891-9fdd6222369c": "aw-server-rust/aw-server",
- "d70684b2-06ba-4f18-9c40-80de0778c035": "aw-server-rust/aw-query",
- "a542ca3c-9d99-490f-89de-186bb284b0fe": "aw-server-rust/aw-datastore",
- "6d2ab9ea-9e77-402f-a726-95d44e0f23c8": "aw-server-rust/aw-transform",
- "941d7da8-a28d-4d5e-806f-3b546909f74e": "aw-client/aw_client/queries.py",
- "1d20fc8f-ecf1-46d5-a092-2a3ae1be247e": "aw-server-rust/aw-server/src",
- "e6b26caf-0857-4e8d-8f29-124af90c1966": "aw-server-rust/aw-query/src",
- "234cf403-9edd-4f7e-96eb-81e90587bbdc": "aw-server-rust/aw-datastore/src",
- "7e71e7fe-f8aa-4693-a92e-4c3b664c1528": "aw-server-rust/aw-transform/src",
- "11799249-188d-43b3-b410-54dcff47aeba": "aw-server-rust/aw-server/src/endpoints",
- "d020e6ae-765b-4374-947a-57f7ad4a9237": "aw-server-rust/aw-query/src/lib.rs",
- "9b5e1d70-af70-4de3-9b35-73b774a50c3c": "aw-server-rust/aw-query/src/interpret.rs",
- "bf649fa4-66cc-4975-8549-aa2f1db4a11e": "aw-server-rust/aw-query/src/functions.rs",
- "c3bb8632-e3d6-4b2f-86ea-2472e155f19e": "aw-server-rust/aw-datastore/src/worker.rs",
- "65cffe0e-3235-4eb6-8a30-a61c0ead9d0f": "aw-server-rust/aw-datastore/src/datastore.rs",
- "b30f23b1-e47a-4ce6-bf59-4d93d4bcf6ca": "aw-server-rust/aw-transform/src/filter_period.rs",
- "873444c7-80ea-4a0b-8620-92fc96cce006": "aw-server-rust/aw-server/src/endpoints/query.rs",
- "12f9554d-dd4e-4f66-bd20-8845b718ef19": "aw-client/aw_client/queries.py-simstep-81f31a9b-3434-4458-a7d3-bdcf610af75e",
- "22eb0e3c-2438-488f-8ee2-a5bb806ad0d1": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-e91513ab-13ec-4eea-9942-9620dbe3b92b",
- "a9279dbc-8fda-434c-bc5a-4eefaca0df56": "aw-server-rust/aw-query/src/lib.rs-simstep-3291e01a-482d-401b-98b5-759573be65ca",
- "be2c99a2-8b27-487f-9c8f-e1d1836613cc": "aw-server-rust/aw-query/src/functions.rs-simstep-475886bc-26d3-4528-84ae-2f9c8e1dfcf9",
- "48d1c5e2-32b3-4eaf-9005-dd0a65a77448": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-ff017206-8323-4caa-9eca-4fc760c2470f",
- "48a7e119-b25c-4b9f-9a95-bd649493ff48": "aw-server-rust/aw-transform/src/filter_period.rs-simstep-50fdc5f4-02bb-4f28-8c70-aa0dbdbd7c10",
- "63ebaed0-610a-46cd-8a5b-392c2874aecb": "aw-server-rust/aw-query/src/interpret.rs-simstep-18492fe4-5b57-4749-a2e8-d18f3c546e89",
- "e1a5ea0f-392f-40e2-abe5-e7b6f16cf9bd": "README.md-simstep-9396ef3a-ed06-4635-bb1d-3b136660bcc4",
- "6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f": "generated-edge-simstep-c1a26d9b-d661-4a99-8275-39a414824ed6-6d8a3571-eb75-4ebd-a02f-dd85b2e5ed9f",
- "c8403507-4895-4695-84b5-9305afdc3c9f": "generated-edge-simstep-a7b6aefb-1401-4756-bfa1-1eb9a76cde07-c8403507-4895-4695-84b5-9305afdc3c9f",
- "8f8d2c55-63c0-48ec-b931-f848e245688f": "generated-edge-simstep-00784ae1-bb99-494c-bf46-fe5947de5066-8f8d2c55-63c0-48ec-b931-f848e245688f",
- "5f0c5a39-ef1b-43eb-8332-3fc7e3b98013": "generated-edge-simstep-e1bf9f3c-e763-4e75-8c62-1a8d739d53cc-5f0c5a39-ef1b-43eb-8332-3fc7e3b98013",
- "7a14a4d3-a453-4e33-9b10-fb192e40e34e": "generated-edge-simstep-f7dfb334-099f-4750-a893-cd96b1c46278-7a14a4d3-a453-4e33-9b10-fb192e40e34e",
- "8dd706f0-fb9b-496a-8ba8-26f289f0e2fa": "generated-edge-simstep-78aaa465-8377-43f1-9ba6-36ddcf9300cf-8dd706f0-fb9b-496a-8ba8-26f289f0e2fa",
- "889f0869-2c33-499b-a558-ede80ee18a54": "generated-edge-simstep-785d1355-bf16-42a7-846e-a2bf3ecbb35b-889f0869-2c33-499b-a558-ede80ee18a54",
- "0b23a1ca-091a-4f70-b49e-95910c8179bf": "aw-notify",
- "4d835cac-01b7-4b3d-a7f5-189f89fda1c7": "aw-notify/aw_notify",
- "954ebccb-39ec-4c50-aca4-0ac8c09e6358": "aw-notify/aw_notify/main.py",
- "60cb37da-078e-4380-88f0-e6746007277d": "aw-server-rust/aw-query/src/datatype.rs",
- "22d8d360-9b15-49db-bc15-de087f960e23": "aw-server-rust/aw-transform/src/classify.rs",
- "49029598-25ad-4498-b744-e2180f404fe5": "aw-client/aw_client/queries.py-simstep-1b40cfa3-9cf5-4dc3-830f-74cb1d476d50",
- "ff986e21-7050-4c3d-ae40-3a678f46221d": "aw-server-rust/aw-query/src/functions.rs-simstep-af6c51b2-ee18-406c-acc6-6e5d9588d012",
- "e99fcabc-934a-46cd-8823-d3e04ceea63c": "aw-server-rust/aw-transform/src/classify.rs-simstep-55815d72-39f6-4201-ad99-6ebd57d0eece",
- "294c7beb-b479-47e2-bd3c-6d616497ecd2": "aw-server-rust/aw-transform/src/classify.rs-simstep-e863b0b1-c3ce-4b13-ad7d-a7438f650035",
- "9847b0a7-39f2-44f8-ae14-73eab42d8894": "aw-notify/aw_notify/main.py-simstep-2108914e-2569-47bf-aa87-af337de03f8c",
- "e0c2455d-d2a0-4b88-bd3a-6f7b2472a661": "generated-edge-simstep-9eeb592f-5c44-4ce1-a7a0-261bc6d6b679-e0c2455d-d2a0-4b88-bd3a-6f7b2472a661",
- "79c14e32-8192-488e-ab72-b9c4c6edb346": "generated-edge-simstep-e598a658-8e0e-4a76-9310-af0d60ec5828-79c14e32-8192-488e-ab72-b9c4c6edb346",
- "341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8": "generated-edge-simstep-9f7f50e4-03c6-4d7c-95c8-3317d37115eb-341fbb1e-cb5d-4d1e-ab62-36211ddbe3c8",
- "b4391f38-d9ee-4377-8568-efca87206124": "generated-edge-simstep-ebd328dc-4cdf-452d-b4aa-10b65e9c354d-b4391f38-d9ee-4377-8568-efca87206124",
- "701d49bd-2670-4a9f-8ffd-52f62726ddc0": "aw-core/aw_query",
- "22692aea-cd7a-4c08-8c76-c16bb5499546": "aw-server-rust/aw-client-rust",
- "0fb8ce44-e9ea-4e8a-a049-33211b003d20": "aw-core/aw_query/query2.py",
- "e1b937af-2584-42ee-8281-e1bffda373ae": "aw-core/aw_query/functions.py",
- "08296022-1e80-4653-821d-b48d9cf30c68": "aw-server-rust/aw-client-rust/src",
- "8dafeb60-1305-46f7-baac-4153d6d18539": "aw-server-rust/aw-client-rust/src/blocking.rs",
- "6b6d3131-f59f-46b0-8c5a-f074e58c1bdf": "aw-server-rust/aw-client-rust/src/lib.rs",
- "5540d168-0892-4d44-a835-530768fbad09": "aw-client/aw_client/client.py-simstep-06f7c9e7-1c78-4114-867b-3dbb20dcc427",
- "abf45adb-988a-4613-ab4a-acb8cef0c90a": "aw-server/aw_server/rest.py-simstep-671ac45b-885a-4c8d-93ec-2bf7f4b9e0e7",
- "96c3be58-d96a-4b11-b4f3-e778387f76b8": "aw-server/aw_server/api.py-simstep-a9275a8e-9b0a-4089-a9ae-94dd2a6a1a31",
- "c0a28353-be8d-4bc8-a1be-2879961fc4df": "aw-core/aw_query/query2.py-simstep-5f7b6985-edf0-42eb-8822-847d0d7b8e9b",
- "fb0bcd2a-5999-47fc-bb41-11233e3544fa": "aw-core/aw_query/functions.py-simstep-6ea3ab36-027f-40b9-a0ba-9ede77ae1117",
- "5eb14d26-499c-4ea4-8282-3f923646dbdb": "aw-core/aw_query/query2.py-simstep-ab3fe2d5-9396-4241-b64e-2a187e97de75",
- "7ace16a3-9438-4e78-bcf9-79131079c89d": "aw-server-rust/aw-client-rust/src/blocking.rs-simstep-3118dc4c-d7ad-4996-aa81-a205ccdf6e72",
- "b93b83dd-fff3-44dc-ac22-3ea63117c222": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-1c25a330-b713-4866-9440-8737c787ce33",
- "d8afb2b7-af24-431a-b206-828a8b7cef2a": "aw-server-rust/aw-query/src/lib.rs-simstep-024a46d7-abc2-4c35-92d1-900d198f748c",
- "630bda35-fbd5-40ec-b47d-37ad66379d94": "aw-server-rust/aw-query/src/interpret.rs-simstep-e3204124-26ff-4799-8462-100305c27ae1",
- "eecd0f91-7c53-4352-8d85-05c3dd46bee1": "aw-server-rust/aw-query/src/functions.rs-simstep-06d75f72-3fc8-47d8-85ab-f7fa317f4de5",
- "8b2c7b05-2fba-4660-ae4f-ca14ffb773f4": "aw-server-rust/aw-query/src/interpret.rs-simstep-9382ac29-7930-4f83-afdd-deb2bfc221e3",
- "71408ae2-19e6-4327-bab9-8918af09c855": "generated-edge-simstep-5dc6bd77-15d2-44c3-b665-8de88288c314-71408ae2-19e6-4327-bab9-8918af09c855",
- "891bfe3a-f22a-4998-acea-aa6d0c362821": "generated-edge-simstep-5a0d9b17-b09a-4aa5-9234-c01cb2aadef4-891bfe3a-f22a-4998-acea-aa6d0c362821",
- "b79b67f9-1be1-48f1-920a-9ebdd4417272": "generated-edge-simstep-833f0f0f-ec00-4960-b1f9-46d8a8530a01-b79b67f9-1be1-48f1-920a-9ebdd4417272",
- "4059fcbe-a1ee-41d0-b576-55a1d278bca0": "generated-edge-simstep-7f2c62ec-a42b-4575-9a7b-7ba92fb2e8f6-4059fcbe-a1ee-41d0-b576-55a1d278bca0",
- "e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4": "generated-edge-simstep-ba09fbe0-059a-42c4-bfec-7adf7d1d9a2c-e7c6aaa2-b8a3-41aa-9493-82c37cc8f9a4",
- "c4b6d403-d2a9-4cff-8a72-31189a53c0db": "generated-edge-simstep-fe43857f-ef7d-455d-a9c4-37d54d12207a-c4b6d403-d2a9-4cff-8a72-31189a53c0db",
- "ed18dcc0-5e4a-44fb-b661-f746f1e893f1": "generated-edge-simstep-97542310-17cf-4c99-9ce9-a328dffa5f4c-ed18dcc0-5e4a-44fb-b661-f746f1e893f1",
- "d3cb01a0-d8cd-4382-b122-d1234b0562bc": "generated-edge-simstep-6eb126a9-5234-4495-9727-ec2741ce9660-d3cb01a0-d8cd-4382-b122-d1234b0562bc",
- "e72e1881-49ce-41ad-966a-90a26ca47453": "generated-edge-simstep-acc1ad56-50cb-41ab-9217-f8d15af6686c-e72e1881-49ce-41ad-966a-90a26ca47453",
- "15dfaeb9-fb37-4296-972f-0188abd0b353": "generated-edge-simstep-f53fc8fc-fdf3-4a44-b9c2-6c470e1493b5-15dfaeb9-fb37-4296-972f-0188abd0b353",
- "9792d1f0-08be-4f90-8e68-3caee0eb2498": "generated-edge-simstep-f69e7df0-6666-4b48-a0a6-1000c8ccede0-9792d1f0-08be-4f90-8e68-3caee0eb2498",
- "7ee7b20f-9df9-4269-8f41-bc7e191503bd": "aw-watcher-afk",
- "8f0b906e-fb77-4a52-aee5-1f494bec596c": "aw-watcher-afk/aw_watcher_afk",
- "d242d1ad-7cdf-414b-812a-f3e5af153562": "aw-watcher-afk/aw_watcher_afk/__main__.py",
- "c443335f-7f08-4436-8862-5aab2adcf7e0": "aw-watcher-afk/aw_watcher_afk/afk.py",
- "72e53989-6741-4b0d-b49c-f58d0333cdd1": "aw-watcher-afk/aw_watcher_afk/unix.py",
- "ba27c535-e0e5-44ae-b9f0-2827227ebfe2": "aw-watcher-afk/aw_watcher_afk/__main__.py-simstep-8ffbcadf-f26a-483a-9902-95e5a761de64",
- "79468b99-a4de-48b7-bb67-506dc0dcb41c": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-daeeac12-287a-4144-9028-6ea841b196c4",
- "6b45de30-296e-4896-915c-371f09843599": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-6579f587-817d-4d23-a9df-86abc54273ae",
- "b7321a6c-302b-4701-9ea5-5c05c6d3e71b": "aw-watcher-afk/aw_watcher_afk/unix.py-simstep-4d2c85c7-0754-429a-8a55-c64d4da0d37c",
- "faab8465-be29-479d-890a-7936dc5cfbdd": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-3e0e033c-c32f-4d0d-aa65-a278d77e80c7",
- "52c92f9c-9d8e-4fac-9644-6b24e87d7bc5": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-dc58bc3e-b09e-4df2-870b-76419e78dd3d",
- "c27977fb-af8a-4779-8f78-a99b40221157": "aw-server/aw_server/api.py-simstep-7357e239-3712-4b55-a94c-2165ea1f3255",
- "802c1941-09e1-4038-a0bf-bd4e553ff6f6": "aw-watcher-afk/aw_watcher_afk/afk.py-simstep-1e5ad77f-aeff-49b6-9634-65e52f011a83",
- "7c2f1d5b-706c-4dd2-9d8c-62b3e6886250": "generated-edge-simstep-60e1002f-9782-4c8d-b104-f4bb172e2c91-7c2f1d5b-706c-4dd2-9d8c-62b3e6886250",
- "1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838": "generated-edge-simstep-1422a5f8-ad2e-4b32-8955-ee6bb3053286-1fd7f9ff-5311-4e14-bce7-8f3c5fd5b838",
- "e514d9e2-e803-4041-b693-65878401b214": "generated-edge-simstep-2588211c-b086-4768-8a87-a86764c7e5cd-e514d9e2-e803-4041-b693-65878401b214",
- "eeb9224a-fff6-4652-b733-ea430b820a2c": "generated-edge-simstep-9195e582-b3fa-4848-b151-0236a8a5d176-eeb9224a-fff6-4652-b733-ea430b820a2c",
- "196358b9-6ae9-4f52-ad78-ff88b4a49403": "generated-edge-simstep-78d78341-ced8-4fc6-bc93-ce4a62c8adf6-196358b9-6ae9-4f52-ad78-ff88b4a49403",
- "b520b088-6f6f-4b32-afba-5ef244691c44": "generated-edge-simstep-c9a127c1-afd0-4def-a0fe-c490c9b64039-b520b088-6f6f-4b32-afba-5ef244691c44",
- "f0e34997-66ab-4bc2-9a5e-1f00b40d47b0": "generated-edge-simstep-9fde1b44-5dbf-4530-88e2-ca54c220b462-f0e34997-66ab-4bc2-9a5e-1f00b40d47b0",
- "34f5debb-c898-419f-9c17-186d2a5f6e85": "aw-core/aw_transform",
- "40ad45bd-b0eb-4f2c-a091-f933962a90b8": "aw-watcher-window/aw_watcher_window/macos.swift",
- "6860aa38-bc11-4d81-9260-87eba1c02581": "aw-core/aw_transform/heartbeats.py",
- "0f86982d-c1d5-4ceb-8574-3e19c2db7159": "aw-server-rust/aw-server/src/endpoints/bucket.rs",
- "e3f5c5d5-8149-4399-bd8f-efaaa8128a1c": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-46ccc29e-b251-435a-8768-4304d477261a",
- "67a89dcc-93fc-413d-aa21-eca0b7227bc2": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-e873b3e2-2ebd-43ee-8f97-e02f869578f7",
- "9de5f1e4-764e-4be7-90a1-65fa23ca0dea": "aw-server/aw_server/rest.py-simstep-e98f7509-f28f-4534-8f2a-f525edc73f69",
- "7c02469d-20a7-415d-940e-fbd82d0fc997": "aw-server/aw_server/api.py-simstep-bb678fe2-e6e3-472b-8ae4-95e362d4bdaf",
- "dc7a3836-03e1-4a54-9817-b62f36466ec0": "aw-core/aw_transform/heartbeats.py-simstep-d2eac5dc-58f7-408c-beba-c1711beec25a",
- "b512c6a9-f50f-4ff8-9c3a-ea0aa5b4ac5f": "aw-server/aw_server/api.py-simstep-976cfbd0-8946-4157-81b0-0ae6dffa43e1",
- "b3da175e-36b5-4025-ba15-6c54e1d850dd": "aw-watcher-window/aw_watcher_window/macos.swift-simstep-8420fd6c-dba4-41c0-b11d-7280a428ab36",
- "5d7a2fad-5c5d-4e92-b5a8-0ebda1ae6926": "aw-server-rust/aw-server/src/endpoints/bucket.rs-simstep-41b8b1d6-f9fe-47ad-851e-574e804f7171",
- "b6b4c8cb-741a-4e38-b800-61273375cd64": "aw-server-rust/aw-datastore/src/worker.rs-simstep-b8c32ff7-4bb6-4bfa-a5f0-18fe042ed3d3",
- "f0e92638-21d1-4b7e-9f2e-17b67a33ef78": "aw-server-rust/aw-datastore/src/worker.rs-simstep-a17a8d9a-7a3c-46b5-ae0d-e10615e2ecbb",
- "b0093d22-e8cc-4e9e-8711-7e698b537efc": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-c59f4b10-f6c9-4fd8-ba70-ea60667a01e8",
- "9ab3400b-0b7a-4e4d-a93e-4667c63c92c8": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-da146aa5-e96f-4db6-a36f-b405b1a11255",
- "4d96dbc5-cd5e-4ef9-8733-721776e8fb8f": "generated-edge-simstep-b6456941-3a8f-452d-a4eb-67915b00d5b3-4d96dbc5-cd5e-4ef9-8733-721776e8fb8f",
- "a676f81f-8c68-4fc8-94b7-583bada02d70": "generated-edge-simstep-02717bea-6ee3-48ef-8c41-0c9f3e9d9a58-a676f81f-8c68-4fc8-94b7-583bada02d70",
- "a1b18b07-52a9-4bfe-ad37-bdae87d5bd75": "generated-edge-simstep-d57d2bf7-916c-44cd-844d-b1900c276925-a1b18b07-52a9-4bfe-ad37-bdae87d5bd75",
- "9aec4875-5718-4c38-a57c-1d3053c38ba5": "generated-edge-simstep-40b16e25-734b-44d2-86cd-7c301723ff5f-9aec4875-5718-4c38-a57c-1d3053c38ba5",
- "31cd2b01-8df9-4d95-9a91-d4c3aa153eb0": "generated-edge-simstep-9f918447-9e45-4c3b-b34f-658f58d35495-31cd2b01-8df9-4d95-9a91-d4c3aa153eb0",
- "2df6b81e-6b59-4aec-92c7-e9d9f2332be6": "generated-edge-simstep-7e361c3d-a5a9-45f3-a83d-98e39ff45675-2df6b81e-6b59-4aec-92c7-e9d9f2332be6",
- "4a4afbdf-0303-4d84-bbf8-5121c74965a0": "generated-edge-simstep-bfcc2f87-9167-4784-a3b3-f71d6e7a6e71-4a4afbdf-0303-4d84-bbf8-5121c74965a0",
- "21d1c973-0f67-4aca-9d1b-eade3b5d347b": "generated-edge-simstep-eefd671a-3b08-4336-bd26-cb6eb04070ec-21d1c973-0f67-4aca-9d1b-eade3b5d347b",
- "959b342e-eb44-4255-8176-1600a5fa17ac": "generated-edge-simstep-9750ac2c-c0fb-4fe5-815f-398886fc827b-959b342e-eb44-4255-8176-1600a5fa17ac",
- "0fe644bb-a583-40d8-9377-3641c90c4f62": "generated-edge-simstep-7b396541-e74f-4baf-9b1b-c1f7a914ba7a-0fe644bb-a583-40d8-9377-3641c90c4f62",
- "315afad3-54aa-4009-bbe4-8e17ade01ec1": "aw-qt",
- "52098e1d-ea54-42f8-9e69-f6bd54686e33": "aw-qt/aw_qt",
- "9d82da70-d3bc-4199-9292-8dd7e71ab15d": "aw-qt/aw_qt/main.py",
- "f47c0efe-5fd2-488b-b325-b2965448260a": "aw-qt/aw_qt/config.py",
- "f2489cff-231c-4352-baac-95f17e0f6395": "aw-qt/aw_qt/manager.py",
- "38fbe4ec-4658-4084-864e-b163e0540497": "aw-qt/aw_qt/trayicon.py",
- "d1bb4e12-29b6-4f70-9931-321214e3ea2a": "aw-qt/aw_qt/main.py-simstep-61d1a03e-ed06-496d-8495-36419b9c8607",
- "635c1aaf-2ad6-496c-bc18-bf02f0c6b5dc": "aw-qt/aw_qt/config.py-simstep-c1b0fd97-d918-4ed5-bcc5-1fd0c4a61a4a",
- "cae37571-f0ba-4abe-aefd-53e49f26137f": "aw-qt/aw_qt/manager.py-simstep-e716abbb-c96e-4613-bca2-0c094e8df129",
- "8f981b6f-7bed-4d9a-8486-79f85b06d904": "aw-qt/aw_qt/manager.py-simstep-8be10173-751a-4da9-99a9-321c23e71aaa",
- "4d657da7-6757-4d72-9324-765a991f73d7": "aw-qt/aw_qt/trayicon.py-simstep-6ae15f2e-5331-4153-b9d2-2a297b65c55f",
- "05bd0955-8e55-4657-80ee-f6389995db6d": "aw-qt/aw_qt/trayicon.py-simstep-08d88f03-4133-41d6-9cbb-0df16703b864",
- "bcd83c0f-43dd-444b-b4ef-c3d95ef9ca9b": "aw-qt/aw_qt/manager.py-simstep-520ab3f2-ef6c-4334-89fc-280f6d86d14b",
- "1a51dc8f-a97e-4f38-a424-b85d43c0f3e5": "aw-qt/aw_qt/trayicon.py-simstep-01fb7b9a-f0bd-4892-b5e5-2d5e7374a6d9",
- "421b1687-98a6-4773-a7dc-cdc564be5f8e": "aw-qt/aw_qt/manager.py-simstep-899b57ba-4a68-4620-977a-80981d089e85",
- "5dd0e28d-e0e9-4433-8db9-e8de93de1abe": "aw-qt/aw_qt/manager.py-simstep-6173a9e1-ecfa-4dd9-9f82-f80579406011",
- "bcf67bab-b4dc-4225-b7d1-876dbc2bdcbc": "aw-qt/aw_qt/trayicon.py-simstep-a71f6cd0-490a-40b5-8a05-1c873f208882",
- "1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7": "generated-edge-simstep-6084ca69-514e-4bde-b2c0-1d33b26203e8-1e4f996b-b8ba-4a83-a5b6-52f5b55fa8c7",
- "030668a5-a377-4710-b39f-95efb5fa4768": "generated-edge-simstep-540119c2-b541-4342-aa59-233b4f0f8db5-030668a5-a377-4710-b39f-95efb5fa4768",
- "1fb5a75e-9c49-490d-b412-04ac1c7205fa": "generated-edge-simstep-9aeaf443-6741-4557-9671-67d596f456b3-1fb5a75e-9c49-490d-b412-04ac1c7205fa",
- "a5cd2cce-2771-436e-9fc7-aa013ee8bbc9": "generated-edge-simstep-f968357d-53c4-41e8-b71f-c581c08b52e6-a5cd2cce-2771-436e-9fc7-aa013ee8bbc9",
- "dfaa3fc8-eca8-4c67-b926-87798f511adb": "generated-edge-simstep-03fd319d-4ffe-47cf-bf39-ac388da80fa7-dfaa3fc8-eca8-4c67-b926-87798f511adb",
- "d9e460b6-432d-49c8-8e76-0d8750aa2c10": "generated-edge-simstep-8e583414-7b87-42c9-bdb2-e56259be4cdf-d9e460b6-432d-49c8-8e76-0d8750aa2c10",
- "9d4dee50-64ef-459a-98fa-839761e16813": "generated-edge-simstep-fdff8ecd-12b9-4bc0-ba7b-9402d26b1737-9d4dee50-64ef-459a-98fa-839761e16813",
- "f704019b-d227-47ad-8761-9a2ea01516cb": "generated-edge-simstep-c0115129-b34b-4d27-9f73-cf2dc142ea81-f704019b-d227-47ad-8761-9a2ea01516cb",
- "ba9e605d-98a7-4b50-979a-05bf7213c681": "generated-edge-simstep-7775ac80-c954-464e-b230-b233216ee5e3-ba9e605d-98a7-4b50-979a-05bf7213c681",
- "2298c4b5-17de-487f-b592-2ac0f95eca84": "generated-edge-simstep-1ed5cd16-b593-41cf-84f2-233a8d64a227-2298c4b5-17de-487f-b592-2ac0f95eca84",
- "df20050b-5b10-43ad-ba4c-d7f2e2ce36e1": "aw-notify/aw_notify/main.py-simstep-9b9a0f90-d7a7-40fb-8573-53b470ecf85d",
- "553f1437-5c34-4d6d-8226-417014259fc5": "aw-notify/aw_notify/main.py-simstep-f636bdd6-a8e3-47ec-9f9d-986b21a81868",
- "1de089eb-60a7-4d7f-bfb5-3f7f23315873": "aw-notify/aw_notify/main.py-simstep-945e3312-c7c9-4722-953b-94dc0feee249",
- "e567d898-2785-43f6-98ef-f4b6d1232620": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-868edfd6-1f03-416e-88dc-7b09d05e4ba5",
- "44016962-bb6d-4a70-b13c-4538926a02a4": "aw-server-rust/aw-query/src/functions.rs-simstep-cc5cfecf-cee9-4582-aa6c-b74787a11da8",
- "fd5d1362-e41b-43af-bfd8-7f7c344c9849": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-f52d6bfa-55fe-49ee-9f20-60bf296c76f4",
- "a01b5cc8-f12f-447b-9879-6b55bda0ef87": "aw-notify/aw_notify/main.py-simstep-9c0b3f20-5c18-418a-82f7-78b04ebda9b5",
- "30303464-f5f8-4155-87e9-b81dda8175d9": "aw-notify/aw_notify/main.py-simstep-a66f8ebc-93f8-4f9c-8f19-03bd951d1e98",
- "445477ac-c52d-4053-a45e-8c81da805c88": "aw-notify/aw_notify/main.py-simstep-21533839-7ba4-4cfa-864a-2f67198cad68",
- "f9ddc0fb-c342-4a4a-baec-53c6a2581b80": "generated-edge-simstep-3c977159-c34d-4907-9004-e5aaff3f3bdc-f9ddc0fb-c342-4a4a-baec-53c6a2581b80",
- "22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e": "generated-edge-simstep-7ee6134a-a8a4-4340-ade7-2e1c6f5d9d9b-22f4c1cb-e44d-4b7e-a56e-d1e350f7ec2e",
- "5f61c8f5-897a-4dc2-81df-1eda2d84d5bd": "generated-edge-simstep-f20bb756-15f3-4a7c-914b-aa61470cc435-5f61c8f5-897a-4dc2-81df-1eda2d84d5bd",
- "8f02d20c-25fe-4a28-99de-3e8908d0a66f": "generated-edge-simstep-b835d5e0-434d-4469-94fe-d309114a9ef1-8f02d20c-25fe-4a28-99de-3e8908d0a66f",
- "5595958a-cf9d-4894-9824-ecc89e5cf956": "generated-edge-simstep-027140c6-aa16-4070-89d3-3b553168e65e-5595958a-cf9d-4894-9824-ecc89e5cf956",
- "1b9dc1d5-e6a7-4069-8473-2156853d662e": "generated-edge-simstep-92487214-03b7-430e-aab5-b5a5fb85b2cb-1b9dc1d5-e6a7-4069-8473-2156853d662e",
- "08e05622-d948-47eb-a56d-3d6782d638c0": "generated-edge-simstep-c8b0fe19-76a8-458d-9923-c2f270e306b3-08e05622-d948-47eb-a56d-3d6782d638c0",
- "17c4cd6c-69f5-4df8-ac77-6955a0518939": "generated-edge-simstep-e46653da-3493-419e-8f9c-397be83fe894-17c4cd6c-69f5-4df8-ac77-6955a0518939",
- "a1e562ae-ea06-4c6a-ab92-fa78417115f6": "aw-client/aw_client/client.py-simstep-8739f5eb-aec2-47f1-b1e6-a05a2bb65acd",
- "07e4d089-e23f-4030-8c10-7dbdbd00e1c7": "aw-server/aw_server/rest.py-simstep-7bdce779-492f-4dee-a68d-4e6d28dc079a",
- "19faa606-15ad-4c47-a983-692a1f30a667": "aw-server/aw_server/api.py-simstep-d50e0e2b-f958-4171-a4ab-7f55a7c4a1b6",
- "e590d109-3712-4d3d-9241-ba9cd9a7eeaa": "aw-server/aw_server/api.py-simstep-5fb7b7d5-1759-43dc-a711-b2b0b5df3893",
- "6e7e85b1-9708-4f64-ac9e-efc54338c444": "aw-server/aw_server/rest.py-simstep-cfd637bd-f6b2-44cf-8330-7b2c59c0658b",
- "e60e25ae-e9aa-4497-8555-7e3d99a4049f": "aw-client/aw_client/client.py-simstep-ea6d2274-023a-4d5f-abf4-0414c6c7f68d",
- "12725c25-974e-4363-bb91-c61c8745ed75": "aw-server/aw_server/rest.py-simstep-3e1decf0-1329-4da8-a7c7-870ffe960a54",
- "35d0bf22-ee6a-4fa8-a4fe-a0017e6f8570": "aw-server/aw_server/api.py-simstep-4050248c-1638-452c-8826-677a7a2fece8",
- "07630c61-6df6-484b-81c3-0984379bfd68": "aw-server/aw_server/api.py-simstep-164ed08b-0873-499b-b945-e062cf362429",
- "ae563be0-ff29-4c20-8f6d-6771f04c8da3": "aw-server/aw_server/rest.py-simstep-3fd4d48c-e70c-4217-92c1-7554445cf03b",
- "5fe912cd-a72c-4cc1-969b-b5eb6759ace9": "generated-edge-simstep-8efaf2e1-7c6d-4820-90a5-2abb80bf65ed-5fe912cd-a72c-4cc1-969b-b5eb6759ace9",
- "8515a29c-385b-4ec5-886c-ba3a3a48518e": "generated-edge-simstep-6449735d-8c85-4d49-bb8c-c2b1f9918ffc-8515a29c-385b-4ec5-886c-ba3a3a48518e",
- "ec71fb4b-213d-4fa0-bdfa-9882eb11dcff": "generated-edge-simstep-60764034-1b94-4c15-9015-09e8b775f736-ec71fb4b-213d-4fa0-bdfa-9882eb11dcff",
- "272a1088-1b0c-43f9-8335-d7055539c813": "generated-edge-simstep-7a5f8838-8ed9-47b3-907f-077efeedaa10-272a1088-1b0c-43f9-8335-d7055539c813",
- "ebfbcf3c-bc57-4fe1-866e-fde1b860e633": "generated-edge-simstep-f5c06885-1138-4c13-ae70-10b9d409be5b-ebfbcf3c-bc57-4fe1-866e-fde1b860e633",
- "0614b31f-64d9-4e85-a5f5-6304f0702bd7": "generated-edge-simstep-988adf58-e1be-4352-be66-4f02188fc28a-0614b31f-64d9-4e85-a5f5-6304f0702bd7",
- "941b8c57-be7c-49cd-ba2a-d2237f8f129b": "generated-edge-simstep-7e01821d-906c-4518-a1e0-6b71be84291a-941b8c57-be7c-49cd-ba2a-d2237f8f129b",
- "1f7db50a-bc15-48d1-9f06-27ed743afa75": "generated-edge-simstep-666a933a-7a74-4d90-be19-7610f7bd3d74-1f7db50a-bc15-48d1-9f06-27ed743afa75",
- "0c9dfed4-36e1-4fa4-b183-d5c914ccde3c": "aw-client/examples",
- "9b8f28aa-5406-437c-8363-bcfe0f788580": "aw-client/examples/working_hours.py",
- "237e712f-0c66-4488-b6e9-1ef8c3b71b51": "aw-client/examples/working_hours.py-simstep-e90cee0c-3a20-498b-97b9-2086a61dc02b",
- "8cc72c99-4114-4f4f-a4e4-0c40e8fe844c": "aw-client/aw_client/client.py-simstep-0d34430a-af81-407b-8817-672288674005",
- "73994797-596f-4b60-a36e-5f45cba1fcd3": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-c988a25d-05ad-4c19-87ac-362c79af1d00",
- "6a4cfe75-78bf-4ed7-9de5-b3809f12b57b": "aw-server-rust/aw-query/src/lib.rs-simstep-b482a39f-e520-4d4d-8b2f-d1298922763f",
- "0b3e80ff-b4c9-42db-b067-1a9ba48e9218": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-04bbbe33-e9de-4c5f-b925-27196d20ef1d",
- "60a529b9-b262-4c7f-9baf-5beb50025a86": "aw-server-rust/aw-datastore/src/datastore.rs-simstep-1b3cdf02-5dad-411c-a35e-9250c8aafc9d",
- "06ecdf3e-50eb-4bf3-9c56-183f98a3186b": "aw-server-rust/aw-query/src/interpret.rs-simstep-f7c58723-a402-45d1-8070-59c196e20fb2",
- "4fb2a7f5-a50b-418c-a096-fd4e6d0a3500": "aw-server-rust/aw-server/src/endpoints/query.rs-simstep-72197f38-6e3b-432c-be11-ce5fbb94efb9",
- "7057dbee-ccfe-43f8-9014-90812018a849": "aw-client/aw_client/client.py-simstep-642425c3-abd7-45fe-b5a9-a76bf90a9477",
- "e985450d-2666-412f-acf5-988a5c0c7de5": "aw-client/examples/working_hours.py-simstep-e38db73e-b347-4786-8efd-1e7cab44f73f",
- "aecc1e90-5e71-43f4-a5b8-757de329fe3a": "generated-edge-simstep-5aa97ae5-7e30-4d15-8f12-05942f2e75c9-aecc1e90-5e71-43f4-a5b8-757de329fe3a",
- "62388ee6-67f4-4adc-b08e-90deeb10efd4": "generated-edge-simstep-834b7dbc-5efe-41ac-b75b-e43ad32141df-62388ee6-67f4-4adc-b08e-90deeb10efd4",
- "31b60323-3a65-4184-a42f-f577f3a958ff": "generated-edge-simstep-98777081-df05-4b5c-89f6-5076fab00e92-31b60323-3a65-4184-a42f-f577f3a958ff",
- "9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f": "generated-edge-simstep-914107de-b38a-4307-ab2c-e257ed3d2fb5-9a1c5091-4301-4a8f-8fdb-33f2ae2bfb8f",
- "561eebea-ee66-4251-a29c-64c2e3aae490": "generated-edge-simstep-5eb2bbe9-10c4-4fcb-8a5a-ab87a2e91619-561eebea-ee66-4251-a29c-64c2e3aae490",
- "2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe": "generated-edge-simstep-d78663e6-a6d4-4ba7-a922-436bd075e457-2cbf35b6-37cc-435f-8afb-9ecbfc0a0cbe",
- "3f00132f-3930-4b99-82cf-1ca7f818661b": "generated-edge-simstep-633d97c2-762a-45cb-8900-308ab124d526-3f00132f-3930-4b99-82cf-1ca7f818661b",
- "ec5d6b90-2f5f-4a07-b0e8-da3610035a92": "generated-edge-simstep-33e5b4e9-bd66-45f5-ab0f-543737810b99-ec5d6b90-2f5f-4a07-b0e8-da3610035a92",
- "c8cbde86-13c0-4232-898e-104d815a805c": "generated-edge-simstep-65443293-5e86-4e71-9e8d-19d61bd162d9-c8cbde86-13c0-4232-898e-104d815a805c"
- }
-}
\ No newline at end of file