forge-openclaw-plugin 0.2.26 → 0.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +59 -3
  2. package/dist/assets/{board-ta0rUHOf.js → board-C6jCchjI.js} +2 -2
  3. package/dist/assets/{board-ta0rUHOf.js.map → board-C6jCchjI.js.map} +1 -1
  4. package/dist/assets/index-DVvS8iiU.css +1 -0
  5. package/dist/assets/index-zYB-9Dfo.js +85 -0
  6. package/dist/assets/index-zYB-9Dfo.js.map +1 -0
  7. package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js +2 -0
  8. package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js.map +1 -0
  9. package/dist/assets/{motion-fBKPB6yw.js → motion-DFHrH2rd.js} +2 -2
  10. package/dist/assets/{motion-fBKPB6yw.js.map → motion-DFHrH2rd.js.map} +1 -1
  11. package/dist/assets/{table-C-IGTQni.js → table-ZL7Di_u3.js} +2 -2
  12. package/dist/assets/{table-C-IGTQni.js.map → table-ZL7Di_u3.js.map} +1 -1
  13. package/dist/assets/{ui-DInOpaYF.js → ui-CKNPpz7q.js} +2 -2
  14. package/dist/assets/{ui-DInOpaYF.js.map → ui-CKNPpz7q.js.map} +1 -1
  15. package/dist/assets/vendor-DoNZuFhn.js +1247 -0
  16. package/dist/assets/vendor-DoNZuFhn.js.map +1 -0
  17. package/dist/index.html +7 -7
  18. package/dist/openclaw/local-runtime.js +16 -0
  19. package/dist/openclaw/routes.d.ts +27 -0
  20. package/dist/openclaw/routes.js +16 -12
  21. package/dist/server/server/migrations/037_workbench_public_inputs_and_run_inputs.sql +5 -0
  22. package/dist/server/server/migrations/038_data_management_settings.sql +11 -0
  23. package/dist/server/server/migrations/039_life_force_and_action_points.sql +114 -0
  24. package/dist/server/server/migrations/040_screen_time_domain.sql +89 -0
  25. package/dist/server/server/migrations/041_companion_source_states.sql +21 -0
  26. package/dist/server/server/migrations/042_movement_boxes.sql +47 -0
  27. package/dist/server/server/migrations/043_movement_box_overlap_overrides.sql +26 -0
  28. package/dist/server/server/src/app.js +1684 -117
  29. package/dist/server/server/src/connectors/box-registry.js +44 -9
  30. package/dist/server/server/src/data-management-types.js +107 -0
  31. package/dist/server/server/src/db.js +68 -4
  32. package/dist/server/server/src/demo-data.js +2 -2
  33. package/dist/server/server/src/health.js +702 -18
  34. package/dist/server/server/src/managers/platform/llm-manager.js +7 -4
  35. package/dist/server/server/src/managers/platform/mock-workbench-provider.js +149 -0
  36. package/dist/server/server/src/managers/platform/secrets-manager.js +18 -1
  37. package/dist/server/server/src/managers/runtime.js +9 -0
  38. package/dist/server/server/src/movement.js +1971 -112
  39. package/dist/server/server/src/openapi.js +489 -1
  40. package/dist/server/server/src/psyche-types.js +9 -1
  41. package/dist/server/server/src/repositories/activity-events.js +8 -0
  42. package/dist/server/server/src/repositories/ai-connectors.js +522 -74
  43. package/dist/server/server/src/repositories/habits.js +37 -1
  44. package/dist/server/server/src/repositories/model-settings.js +13 -3
  45. package/dist/server/server/src/repositories/notes.js +3 -0
  46. package/dist/server/server/src/repositories/settings.js +380 -18
  47. package/dist/server/server/src/repositories/tasks.js +170 -10
  48. package/dist/server/server/src/runtime-data-root.js +82 -0
  49. package/dist/server/server/src/screen-time.js +802 -0
  50. package/dist/server/server/src/services/data-management.js +788 -0
  51. package/dist/server/server/src/services/entity-crud.js +205 -2
  52. package/dist/server/server/src/services/knowledge-graph.js +1455 -0
  53. package/dist/server/server/src/services/life-force-model.js +197 -0
  54. package/dist/server/server/src/services/life-force.js +1270 -0
  55. package/dist/server/server/src/services/psyche-observation-calendar.js +383 -16
  56. package/dist/server/server/src/types.js +286 -13
  57. package/dist/server/server/src/web.js +228 -13
  58. package/dist/server/src/components/customization/utility-widgets.js +136 -27
  59. package/dist/server/src/components/ui/info-tooltip.js +25 -0
  60. package/dist/server/src/components/workbench-boxes/calendar/calendar-boxes.js +78 -0
  61. package/dist/server/src/components/workbench-boxes/goals/goals-boxes.js +62 -0
  62. package/dist/server/src/components/workbench-boxes/habits/habits-boxes.js +62 -0
  63. package/dist/server/src/components/workbench-boxes/health/health-boxes.js +63 -8
  64. package/dist/server/src/components/workbench-boxes/insights/insights-boxes.js +50 -0
  65. package/dist/server/src/components/workbench-boxes/kanban/kanban-boxes.js +62 -54
  66. package/dist/server/src/components/workbench-boxes/movement/movement-boxes.js +18 -8
  67. package/dist/server/src/components/workbench-boxes/notes/notes-boxes.js +56 -38
  68. package/dist/server/src/components/workbench-boxes/overview/overview-boxes.js +65 -0
  69. package/dist/server/src/components/workbench-boxes/preferences/preferences-boxes.js +78 -0
  70. package/dist/server/src/components/workbench-boxes/projects/projects-boxes.js +35 -30
  71. package/dist/server/src/components/workbench-boxes/psyche/psyche-boxes.js +88 -0
  72. package/dist/server/src/components/workbench-boxes/questionnaires/questionnaires-boxes.js +61 -0
  73. package/dist/server/src/components/workbench-boxes/review/review-boxes.js +53 -0
  74. package/dist/server/src/components/workbench-boxes/shared/define-workbench-box.js +3 -1
  75. package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +39 -3
  76. package/dist/server/src/components/workbench-boxes/strategies/strategies-boxes.js +62 -0
  77. package/dist/server/src/components/workbench-boxes/tasks/tasks-boxes.js +76 -0
  78. package/dist/server/src/components/workbench-boxes/today/today-boxes.js +47 -32
  79. package/dist/server/src/components/workbench-boxes/wiki/wiki-boxes.js +60 -0
  80. package/dist/server/src/lib/api.js +280 -21
  81. package/dist/server/src/lib/data-management-types.js +1 -0
  82. package/dist/server/src/lib/entity-visuals.js +279 -0
  83. package/dist/server/src/lib/knowledge-graph-types.js +276 -0
  84. package/dist/server/src/lib/knowledge-graph.js +470 -0
  85. package/dist/server/src/lib/schemas.js +4 -0
  86. package/dist/server/src/lib/snapshot-normalizer.js +43 -1
  87. package/dist/server/src/lib/workbench/contracts.js +229 -0
  88. package/dist/server/src/lib/workbench/nodes.js +200 -0
  89. package/dist/server/src/lib/workbench/registry.js +52 -5
  90. package/dist/server/src/lib/workbench/runtime.js +254 -38
  91. package/dist/server/src/lib/workbench/tool-catalog.js +68 -0
  92. package/openclaw.plugin.json +1 -1
  93. package/package.json +1 -1
  94. package/server/migrations/037_workbench_public_inputs_and_run_inputs.sql +5 -0
  95. package/server/migrations/038_data_management_settings.sql +11 -0
  96. package/server/migrations/039_life_force_and_action_points.sql +114 -0
  97. package/server/migrations/040_screen_time_domain.sql +89 -0
  98. package/server/migrations/041_companion_source_states.sql +21 -0
  99. package/server/migrations/042_movement_boxes.sql +47 -0
  100. package/server/migrations/043_movement_box_overlap_overrides.sql +26 -0
  101. package/skills/forge-openclaw/SKILL.md +24 -11
  102. package/skills/forge-openclaw/entity_conversation_playbooks.md +210 -34
  103. package/skills/forge-openclaw/psyche_entity_playbooks.md +113 -17
  104. package/dist/assets/index-Ro0ZF_az.css +0 -1
  105. package/dist/assets/index-ytlpSj23.js +0 -79
  106. package/dist/assets/index-ytlpSj23.js.map +0 -1
  107. package/dist/assets/vendor-lE3tZJcC.js +0 -876
  108. package/dist/assets/vendor-lE3tZJcC.js.map +0 -1
package/dist/index.html CHANGED
@@ -13,14 +13,14 @@
13
13
  />
14
14
  <link rel="icon" type="image/png" href="/forge/assets/favicon-BCHm9dUV.ico" />
15
15
  <link rel="alternate icon" href="/forge/assets/favicon-BCHm9dUV.ico" />
16
- <script type="module" crossorigin src="/forge/assets/index-ytlpSj23.js"></script>
17
- <link rel="modulepreload" crossorigin href="/forge/assets/vendor-lE3tZJcC.js">
18
- <link rel="modulepreload" crossorigin href="/forge/assets/board-ta0rUHOf.js">
19
- <link rel="modulepreload" crossorigin href="/forge/assets/ui-DInOpaYF.js">
20
- <link rel="modulepreload" crossorigin href="/forge/assets/motion-fBKPB6yw.js">
21
- <link rel="modulepreload" crossorigin href="/forge/assets/table-C-IGTQni.js">
16
+ <script type="module" crossorigin src="/forge/assets/index-zYB-9Dfo.js"></script>
17
+ <link rel="modulepreload" crossorigin href="/forge/assets/vendor-DoNZuFhn.js">
18
+ <link rel="modulepreload" crossorigin href="/forge/assets/board-C6jCchjI.js">
19
+ <link rel="modulepreload" crossorigin href="/forge/assets/ui-CKNPpz7q.js">
20
+ <link rel="modulepreload" crossorigin href="/forge/assets/motion-DFHrH2rd.js">
21
+ <link rel="modulepreload" crossorigin href="/forge/assets/table-ZL7Di_u3.js">
22
22
  <link rel="stylesheet" crossorigin href="/forge/assets/vendor-DT3pnAKJ.css">
23
- <link rel="stylesheet" crossorigin href="/forge/assets/index-Ro0ZF_az.css">
23
+ <link rel="stylesheet" crossorigin href="/forge/assets/index-DVvS8iiU.css">
24
24
  </head>
25
25
  <body class="bg-canvas text-ink antialiased">
26
26
  <div id="root"></div>
@@ -165,6 +165,16 @@ function isLocalOrigin(origin) {
165
165
  return false;
166
166
  }
167
167
  }
168
+ function isTruthyEnvFlag(value) {
169
+ if (!value) {
170
+ return false;
171
+ }
172
+ const normalized = value.trim().toLowerCase();
173
+ return normalized === "1" || normalized === "true" || normalized === "yes";
174
+ }
175
+ function shouldEnableManagedDevWeb(plan, env = process.env) {
176
+ return plan.mode === "source" || isTruthyEnvFlag(env.FORGE_OPENCLAW_DEV);
177
+ }
168
178
  function getCurrentModuleRoot() {
169
179
  return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
170
180
  }
@@ -368,6 +378,7 @@ async function spawnManagedRuntime(config, plan) {
368
378
  : [plan.entryFile, plan.sourceEntryFile ?? path.join(plan.packageRoot, "server", "src", "index.ts")];
369
379
  const logPath = getRuntimeLogPath(config);
370
380
  const logFd = openRuntimeLogFile(logPath);
381
+ const enableManagedDevWeb = shouldEnableManagedDevWeb(plan);
371
382
  const child = spawn(process.execPath, args, {
372
383
  cwd: plan.packageRoot,
373
384
  env: {
@@ -375,6 +386,11 @@ async function spawnManagedRuntime(config, plan) {
375
386
  HOST: "127.0.0.1",
376
387
  PORT: String(config.port),
377
388
  FORGE_BASE_PATH: "/forge/",
389
+ ...(enableManagedDevWeb
390
+ ? {
391
+ FORGE_DEV_WEB_ORIGIN: process.env.FORGE_DEV_WEB_ORIGIN ?? "http://127.0.0.1:3027/forge/"
392
+ }
393
+ : {}),
378
394
  ...(config.dataRoot ? { FORGE_DATA_ROOT: config.dataRoot } : {})
379
395
  },
380
396
  stdio: ["ignore", logFd, logFd],
@@ -32,5 +32,32 @@ export declare function buildRouteParityReport(pathMap: Record<string, Record<st
32
32
  unexpectedMirrors: `${Uppercase<string>} ${string}`[];
33
33
  };
34
34
  export declare function registerForgePluginRoutes(api: ForgePluginRouteApi, config: ForgePluginConfig): void;
35
+ export declare function runRouteCheck(config: ForgePluginConfig): Promise<{
36
+ supported: `${Uppercase<string>} ${string}`[];
37
+ mirrored: `${Uppercase<string>} ${string}`[];
38
+ missingFromPlugin: `${Uppercase<string>} ${string}`[];
39
+ missingFromOpenApi: `${Uppercase<string>} ${string}`[];
40
+ unexpectedMirrors: `${Uppercase<string>} ${string}`[];
41
+ }>;
42
+ export declare function runDoctor(config: ForgePluginConfig): Promise<{
43
+ ok: boolean;
44
+ origin: string;
45
+ port: number;
46
+ baseUrl: string;
47
+ webAppUrl: string;
48
+ actorLabel: string;
49
+ apiTokenConfigured: boolean;
50
+ operatorSessionBootstrapAvailable: boolean;
51
+ warnings: string[];
52
+ overview: unknown;
53
+ onboarding: unknown;
54
+ routeParity: {
55
+ supported: `${Uppercase<string>} ${string}`[];
56
+ mirrored: `${Uppercase<string>} ${string}`[];
57
+ missingFromPlugin: `${Uppercase<string>} ${string}`[];
58
+ missingFromOpenApi: `${Uppercase<string>} ${string}`[];
59
+ unexpectedMirrors: `${Uppercase<string>} ${string}`[];
60
+ };
61
+ }>;
35
62
  export declare function registerForgePluginCli(api: ForgePluginCliApi, config: ForgePluginConfig): void;
36
63
  export {};
@@ -681,7 +681,7 @@ async function runReadOnly(config, path) {
681
681
  path
682
682
  }));
683
683
  }
684
- async function runRouteCheck(config) {
684
+ export async function runRouteCheck(config) {
685
685
  const openapi = await runReadOnly(config, "/api/v1/openapi.json");
686
686
  const pathMap = typeof openapi === "object" &&
687
687
  openapi !== null &&
@@ -692,14 +692,21 @@ async function runRouteCheck(config) {
692
692
  : {};
693
693
  return buildRouteParityReport(pathMap);
694
694
  }
695
- async function runDoctor(config) {
696
- const [health, overview, onboarding, routeParity, uiUrl] = await Promise.all([
697
- runReadOnly(config, "/api/v1/health"),
695
+ export async function runDoctor(config) {
696
+ const [doctorResponse, overview, onboarding, routeParity, uiUrl] = await Promise.all([
697
+ runReadOnly(config, "/api/v1/doctor"),
698
698
  runReadOnly(config, "/api/v1/operator/overview"),
699
699
  runReadOnly(config, "/api/v1/agents/onboarding"),
700
700
  runRouteCheck(config),
701
701
  resolveForgeUiUrl(config)
702
702
  ]);
703
+ const doctorBody = typeof doctorResponse === "object" &&
704
+ doctorResponse !== null &&
705
+ "doctor" in doctorResponse &&
706
+ typeof doctorResponse.doctor === "object" &&
707
+ doctorResponse.doctor !== null
708
+ ? doctorResponse.doctor
709
+ : null;
703
710
  const overviewBody = typeof overview === "object" &&
704
711
  overview !== null &&
705
712
  "overview" in overview &&
@@ -712,10 +719,9 @@ async function runDoctor(config) {
712
719
  overviewBody.capabilities !== null
713
720
  ? overviewBody.capabilities
714
721
  : null;
715
- const overviewWarnings = Array.isArray(overviewBody?.warnings)
716
- ? overviewBody.warnings.filter((entry) => typeof entry === "string")
722
+ const warnings = Array.isArray(doctorBody?.warnings)
723
+ ? doctorBody.warnings.filter((entry) => typeof entry === "string")
717
724
  : [];
718
- const warnings = [];
719
725
  const canBootstrap = canBootstrapOperatorSession(config.baseUrl);
720
726
  if (config.apiToken.trim().length === 0 && canBootstrap) {
721
727
  warnings.push("Forge apiToken is blank, but this target can bootstrap a local or Tailscale operator session for protected reads and writes.");
@@ -723,9 +729,6 @@ async function runDoctor(config) {
723
729
  else if (config.apiToken.trim().length === 0) {
724
730
  warnings.push("Forge apiToken is missing, and this target cannot use local or Tailscale operator-session bootstrap. Protected writes will fail.");
725
731
  }
726
- if (overviewWarnings.length > 0) {
727
- warnings.push(...overviewWarnings);
728
- }
729
732
  if (capabilities && capabilities.canReadPsyche === false) {
730
733
  warnings.push("The configured token cannot read Psyche state. Sensitive reflection summaries will stay partial.");
731
734
  }
@@ -739,7 +742,9 @@ async function runDoctor(config) {
739
742
  warnings.push(`Plugin still mirrors ${routeParity.unexpectedMirrors.length} unexpected route${routeParity.unexpectedMirrors.length === 1 ? "" : "s"} outside the curated contract.`);
740
743
  }
741
744
  return {
742
- ok: (config.apiToken.trim().length > 0 || canBootstrap) &&
745
+ ...(doctorBody ?? {}),
746
+ ok: doctorBody?.ok === true &&
747
+ (config.apiToken.trim().length > 0 || canBootstrap) &&
743
748
  routeParity.missingFromPlugin.length === 0 &&
744
749
  routeParity.missingFromOpenApi.length === 0 &&
745
750
  routeParity.unexpectedMirrors.length === 0,
@@ -751,7 +756,6 @@ async function runDoctor(config) {
751
756
  apiTokenConfigured: config.apiToken.trim().length > 0,
752
757
  operatorSessionBootstrapAvailable: canBootstrap,
753
758
  warnings,
754
- health,
755
759
  overview,
756
760
  onboarding,
757
761
  routeParity
@@ -0,0 +1,5 @@
1
+ ALTER TABLE ai_connectors
2
+ ADD COLUMN public_inputs_json TEXT NOT NULL DEFAULT '[]';
3
+
4
+ ALTER TABLE ai_connector_runs
5
+ ADD COLUMN inputs_json TEXT NOT NULL DEFAULT '{}';
@@ -0,0 +1,11 @@
1
+ CREATE TABLE IF NOT EXISTS data_management_settings (
2
+ id INTEGER PRIMARY KEY CHECK (id = 1),
3
+ preferred_data_root TEXT NOT NULL DEFAULT '',
4
+ backup_directory TEXT NOT NULL DEFAULT '',
5
+ backup_frequency_hours INTEGER,
6
+ auto_repair_enabled INTEGER NOT NULL DEFAULT 1,
7
+ last_auto_backup_at TEXT,
8
+ last_manual_backup_at TEXT,
9
+ created_at TEXT NOT NULL,
10
+ updated_at TEXT NOT NULL
11
+ );
@@ -0,0 +1,114 @@
1
+ ALTER TABLE tasks
2
+ ADD COLUMN resolution_kind TEXT;
3
+
4
+ ALTER TABLE tasks
5
+ ADD COLUMN split_parent_task_id TEXT;
6
+
7
+ CREATE TABLE IF NOT EXISTS life_force_profiles (
8
+ user_id TEXT PRIMARY KEY,
9
+ base_daily_ap INTEGER NOT NULL DEFAULT 200,
10
+ readiness_multiplier REAL NOT NULL DEFAULT 1.0,
11
+ life_force_level INTEGER NOT NULL DEFAULT 1,
12
+ activation_level INTEGER NOT NULL DEFAULT 1,
13
+ focus_level INTEGER NOT NULL DEFAULT 1,
14
+ vigor_level INTEGER NOT NULL DEFAULT 1,
15
+ composure_level INTEGER NOT NULL DEFAULT 1,
16
+ flow_level INTEGER NOT NULL DEFAULT 1,
17
+ created_at TEXT NOT NULL,
18
+ updated_at TEXT NOT NULL
19
+ );
20
+
21
+ CREATE TABLE IF NOT EXISTS life_force_weekday_templates (
22
+ id TEXT PRIMARY KEY,
23
+ user_id TEXT NOT NULL,
24
+ weekday INTEGER NOT NULL,
25
+ baseline_daily_ap INTEGER NOT NULL DEFAULT 200,
26
+ points_json TEXT NOT NULL,
27
+ created_at TEXT NOT NULL,
28
+ updated_at TEXT NOT NULL,
29
+ UNIQUE(user_id, weekday)
30
+ );
31
+
32
+ CREATE TABLE IF NOT EXISTS life_force_day_snapshots (
33
+ id TEXT PRIMARY KEY,
34
+ user_id TEXT NOT NULL,
35
+ date_key TEXT NOT NULL,
36
+ daily_budget_ap REAL NOT NULL,
37
+ sleep_recovery_multiplier REAL NOT NULL DEFAULT 1.0,
38
+ readiness_multiplier REAL NOT NULL DEFAULT 1.0,
39
+ fatigue_debt_carry REAL NOT NULL DEFAULT 0,
40
+ points_json TEXT NOT NULL,
41
+ created_at TEXT NOT NULL,
42
+ updated_at TEXT NOT NULL,
43
+ UNIQUE(user_id, date_key)
44
+ );
45
+
46
+ CREATE TABLE IF NOT EXISTS action_profile_templates (
47
+ id TEXT PRIMARY KEY,
48
+ profile_key TEXT NOT NULL UNIQUE,
49
+ entity_type TEXT,
50
+ title TEXT NOT NULL,
51
+ profile_json TEXT NOT NULL,
52
+ created_at TEXT NOT NULL,
53
+ updated_at TEXT NOT NULL
54
+ );
55
+
56
+ CREATE TABLE IF NOT EXISTS entity_action_profiles (
57
+ id TEXT PRIMARY KEY,
58
+ entity_type TEXT NOT NULL,
59
+ entity_id TEXT NOT NULL,
60
+ profile_json TEXT NOT NULL,
61
+ created_at TEXT NOT NULL,
62
+ updated_at TEXT NOT NULL,
63
+ UNIQUE(entity_type, entity_id)
64
+ );
65
+
66
+ CREATE TABLE IF NOT EXISTS ap_ledger_events (
67
+ id TEXT PRIMARY KEY,
68
+ user_id TEXT NOT NULL,
69
+ date_key TEXT NOT NULL,
70
+ entity_type TEXT NOT NULL,
71
+ entity_id TEXT NOT NULL,
72
+ event_kind TEXT NOT NULL,
73
+ source_kind TEXT NOT NULL,
74
+ starts_at TEXT,
75
+ ends_at TEXT,
76
+ total_ap REAL NOT NULL,
77
+ rate_ap_per_hour REAL,
78
+ metadata_json TEXT NOT NULL DEFAULT '{}',
79
+ created_at TEXT NOT NULL
80
+ );
81
+
82
+ CREATE INDEX IF NOT EXISTS idx_ap_ledger_user_date
83
+ ON ap_ledger_events(user_id, date_key, created_at DESC);
84
+
85
+ CREATE INDEX IF NOT EXISTS idx_ap_ledger_entity
86
+ ON ap_ledger_events(entity_type, entity_id, created_at DESC);
87
+
88
+ CREATE TABLE IF NOT EXISTS stat_xp_events (
89
+ id TEXT PRIMARY KEY,
90
+ user_id TEXT NOT NULL,
91
+ stat_key TEXT NOT NULL,
92
+ delta_xp REAL NOT NULL,
93
+ entity_type TEXT,
94
+ entity_id TEXT,
95
+ metadata_json TEXT NOT NULL DEFAULT '{}',
96
+ created_at TEXT NOT NULL
97
+ );
98
+
99
+ CREATE INDEX IF NOT EXISTS idx_stat_xp_user_stat
100
+ ON stat_xp_events(user_id, stat_key, created_at DESC);
101
+
102
+ CREATE TABLE IF NOT EXISTS fatigue_signals (
103
+ id TEXT PRIMARY KEY,
104
+ user_id TEXT NOT NULL,
105
+ date_key TEXT NOT NULL,
106
+ signal_type TEXT NOT NULL,
107
+ observed_at TEXT NOT NULL,
108
+ note TEXT NOT NULL DEFAULT '',
109
+ delta REAL NOT NULL DEFAULT 0,
110
+ created_at TEXT NOT NULL
111
+ );
112
+
113
+ CREATE INDEX IF NOT EXISTS idx_fatigue_signals_user_date
114
+ ON fatigue_signals(user_id, date_key, observed_at DESC);
@@ -0,0 +1,89 @@
1
+ CREATE TABLE IF NOT EXISTS screen_time_settings (
2
+ user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
3
+ tracking_enabled INTEGER NOT NULL DEFAULT 0,
4
+ sync_enabled INTEGER NOT NULL DEFAULT 1,
5
+ authorization_status TEXT NOT NULL DEFAULT 'not_determined',
6
+ capture_state TEXT NOT NULL DEFAULT 'disabled',
7
+ last_captured_day_key TEXT,
8
+ last_capture_started_at TEXT,
9
+ last_capture_ended_at TEXT,
10
+ metadata_json TEXT NOT NULL DEFAULT '{}',
11
+ created_at TEXT NOT NULL,
12
+ updated_at TEXT NOT NULL
13
+ );
14
+
15
+ CREATE TABLE IF NOT EXISTS screen_time_day_summaries (
16
+ id TEXT PRIMARY KEY,
17
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
18
+ pairing_session_id TEXT REFERENCES companion_pairing_sessions(id) ON DELETE SET NULL,
19
+ source_device TEXT NOT NULL DEFAULT 'iPhone',
20
+ date_key TEXT NOT NULL,
21
+ total_activity_seconds INTEGER NOT NULL DEFAULT 0,
22
+ pickup_count INTEGER NOT NULL DEFAULT 0,
23
+ notification_count INTEGER NOT NULL DEFAULT 0,
24
+ first_pickup_at TEXT,
25
+ longest_activity_seconds INTEGER NOT NULL DEFAULT 0,
26
+ top_app_bundle_ids_json TEXT NOT NULL DEFAULT '[]',
27
+ top_category_labels_json TEXT NOT NULL DEFAULT '[]',
28
+ metadata_json TEXT NOT NULL DEFAULT '{}',
29
+ created_at TEXT NOT NULL,
30
+ updated_at TEXT NOT NULL,
31
+ UNIQUE (user_id, source_device, date_key)
32
+ );
33
+
34
+ CREATE INDEX IF NOT EXISTS idx_screen_time_day_summaries_user
35
+ ON screen_time_day_summaries(user_id, date_key DESC);
36
+
37
+ CREATE TABLE IF NOT EXISTS screen_time_hourly_segments (
38
+ id TEXT PRIMARY KEY,
39
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
40
+ pairing_session_id TEXT REFERENCES companion_pairing_sessions(id) ON DELETE SET NULL,
41
+ source_device TEXT NOT NULL DEFAULT 'iPhone',
42
+ date_key TEXT NOT NULL,
43
+ hour_index INTEGER NOT NULL,
44
+ started_at TEXT NOT NULL,
45
+ ended_at TEXT NOT NULL,
46
+ total_activity_seconds INTEGER NOT NULL DEFAULT 0,
47
+ pickup_count INTEGER NOT NULL DEFAULT 0,
48
+ notification_count INTEGER NOT NULL DEFAULT 0,
49
+ first_pickup_at TEXT,
50
+ longest_activity_started_at TEXT,
51
+ longest_activity_ended_at TEXT,
52
+ metadata_json TEXT NOT NULL DEFAULT '{}',
53
+ created_at TEXT NOT NULL,
54
+ updated_at TEXT NOT NULL,
55
+ UNIQUE (user_id, source_device, date_key, hour_index)
56
+ );
57
+
58
+ CREATE INDEX IF NOT EXISTS idx_screen_time_hourly_segments_user
59
+ ON screen_time_hourly_segments(user_id, started_at DESC);
60
+
61
+ CREATE TABLE IF NOT EXISTS screen_time_app_usage (
62
+ id TEXT PRIMARY KEY,
63
+ segment_id TEXT NOT NULL REFERENCES screen_time_hourly_segments(id) ON DELETE CASCADE,
64
+ bundle_identifier TEXT NOT NULL,
65
+ display_name TEXT NOT NULL DEFAULT '',
66
+ category_label TEXT,
67
+ total_activity_seconds INTEGER NOT NULL DEFAULT 0,
68
+ pickup_count INTEGER NOT NULL DEFAULT 0,
69
+ notification_count INTEGER NOT NULL DEFAULT 0,
70
+ created_at TEXT NOT NULL,
71
+ updated_at TEXT NOT NULL,
72
+ UNIQUE (segment_id, bundle_identifier)
73
+ );
74
+
75
+ CREATE INDEX IF NOT EXISTS idx_screen_time_app_usage_segment
76
+ ON screen_time_app_usage(segment_id, total_activity_seconds DESC);
77
+
78
+ CREATE TABLE IF NOT EXISTS screen_time_category_usage (
79
+ id TEXT PRIMARY KEY,
80
+ segment_id TEXT NOT NULL REFERENCES screen_time_hourly_segments(id) ON DELETE CASCADE,
81
+ category_label TEXT NOT NULL,
82
+ total_activity_seconds INTEGER NOT NULL DEFAULT 0,
83
+ created_at TEXT NOT NULL,
84
+ updated_at TEXT NOT NULL,
85
+ UNIQUE (segment_id, category_label)
86
+ );
87
+
88
+ CREATE INDEX IF NOT EXISTS idx_screen_time_category_usage_segment
89
+ ON screen_time_category_usage(segment_id, total_activity_seconds DESC);
@@ -0,0 +1,21 @@
1
+ CREATE TABLE IF NOT EXISTS companion_pairing_source_states (
2
+ id TEXT PRIMARY KEY,
3
+ pairing_session_id TEXT NOT NULL REFERENCES companion_pairing_sessions(id) ON DELETE CASCADE,
4
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
5
+ source_key TEXT NOT NULL,
6
+ desired_enabled INTEGER NOT NULL DEFAULT 1,
7
+ applied_enabled INTEGER NOT NULL DEFAULT 0,
8
+ authorization_status TEXT NOT NULL DEFAULT 'not_determined',
9
+ sync_eligible INTEGER NOT NULL DEFAULT 0,
10
+ last_observed_at TEXT,
11
+ metadata_json TEXT NOT NULL DEFAULT '{}',
12
+ created_at TEXT NOT NULL,
13
+ updated_at TEXT NOT NULL,
14
+ UNIQUE (pairing_session_id, source_key)
15
+ );
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_companion_pairing_source_states_pairing
18
+ ON companion_pairing_source_states(pairing_session_id, source_key);
19
+
20
+ CREATE INDEX IF NOT EXISTS idx_companion_pairing_source_states_user
21
+ ON companion_pairing_source_states(user_id, updated_at DESC);
@@ -0,0 +1,47 @@
1
+ CREATE TABLE IF NOT EXISTS movement_boxes (
2
+ id TEXT PRIMARY KEY,
3
+ user_id TEXT NOT NULL,
4
+ kind TEXT NOT NULL CHECK (kind IN ('stay', 'trip', 'missing')),
5
+ source_kind TEXT NOT NULL CHECK (source_kind IN ('automatic', 'user_defined')),
6
+ origin TEXT NOT NULL CHECK (
7
+ origin IN (
8
+ 'recorded',
9
+ 'continued_stay',
10
+ 'repaired_gap',
11
+ 'missing',
12
+ 'user_defined',
13
+ 'user_invalidated'
14
+ )
15
+ ),
16
+ started_at TEXT NOT NULL,
17
+ ended_at TEXT NOT NULL,
18
+ title TEXT NOT NULL DEFAULT '',
19
+ subtitle TEXT NOT NULL DEFAULT '',
20
+ place_label TEXT,
21
+ anchor_external_uid TEXT,
22
+ tags_json TEXT NOT NULL DEFAULT '[]',
23
+ distance_meters REAL,
24
+ average_speed_mps REAL,
25
+ editable INTEGER NOT NULL DEFAULT 0,
26
+ override_count INTEGER NOT NULL DEFAULT 0,
27
+ overridden_automatic_box_ids_json TEXT NOT NULL DEFAULT '[]',
28
+ raw_stay_ids_json TEXT NOT NULL DEFAULT '[]',
29
+ raw_trip_ids_json TEXT NOT NULL DEFAULT '[]',
30
+ raw_point_count INTEGER NOT NULL DEFAULT 0,
31
+ has_legacy_corrections INTEGER NOT NULL DEFAULT 0,
32
+ legacy_origin_key TEXT,
33
+ metadata_json TEXT NOT NULL DEFAULT '{}',
34
+ deleted_at TEXT,
35
+ created_at TEXT NOT NULL,
36
+ updated_at TEXT NOT NULL
37
+ );
38
+
39
+ CREATE INDEX IF NOT EXISTS idx_movement_boxes_user_time
40
+ ON movement_boxes(user_id, started_at, ended_at);
41
+
42
+ CREATE INDEX IF NOT EXISTS idx_movement_boxes_user_source
43
+ ON movement_boxes(user_id, source_kind, deleted_at, started_at);
44
+
45
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_movement_boxes_legacy_origin
46
+ ON movement_boxes(user_id, legacy_origin_key)
47
+ WHERE legacy_origin_key IS NOT NULL;
@@ -0,0 +1,26 @@
1
+ ALTER TABLE movement_boxes
2
+ ADD COLUMN true_started_at TEXT;
3
+
4
+ ALTER TABLE movement_boxes
5
+ ADD COLUMN true_ended_at TEXT;
6
+
7
+ ALTER TABLE movement_boxes
8
+ ADD COLUMN overridden_started_at TEXT;
9
+
10
+ ALTER TABLE movement_boxes
11
+ ADD COLUMN overridden_ended_at TEXT;
12
+
13
+ ALTER TABLE movement_boxes
14
+ ADD COLUMN overridden_by_box_id TEXT;
15
+
16
+ ALTER TABLE movement_boxes
17
+ ADD COLUMN overridden_user_box_ids_json TEXT NOT NULL DEFAULT '[]';
18
+
19
+ ALTER TABLE movement_boxes
20
+ ADD COLUMN override_ranges_json TEXT NOT NULL DEFAULT '[]';
21
+
22
+ ALTER TABLE movement_boxes
23
+ ADD COLUMN is_overridden INTEGER NOT NULL DEFAULT 0;
24
+
25
+ ALTER TABLE movement_boxes
26
+ ADD COLUMN is_fully_hidden INTEGER NOT NULL DEFAULT 0;