@kaeawc/auto-mobile 0.0.8 → 0.0.11

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 (27) hide show
  1. package/dist/schemas/tool-definitions.json +123 -31
  2. package/dist/src/db/migrations/2025_12_28_000_initial_schema.ts +2 -0
  3. package/dist/src/db/migrations/2025_12_30_000_performance_thresholds.ts +6 -0
  4. package/dist/src/db/migrations/2025_12_30_001_navigation_graph.ts +16 -0
  5. package/dist/src/db/migrations/2025_12_31_000_accessibility_baselines.ts +3 -0
  6. package/dist/src/db/migrations/2025_12_31_001_memory_audit.ts +8 -0
  7. package/dist/src/db/migrations/2026_01_01_000_recomposition_metrics.ts +3 -0
  8. package/dist/src/db/migrations/2026_01_02_000_prediction_history.ts +7 -0
  9. package/dist/src/db/migrations/2026_01_03_000_feature_flags.ts +1 -0
  10. package/dist/src/db/migrations/2026_01_03_000_test_executions.ts +3 -0
  11. package/dist/src/db/migrations/2026_01_05_000_tool_calls.ts +3 -0
  12. package/dist/src/db/migrations/2026_01_08_000_test_coverage.ts +9 -0
  13. package/dist/src/db/migrations/2026_01_09_000_video_recordings.ts +6 -0
  14. package/dist/src/db/migrations/2026_01_10_000_device_snapshots.ts +5 -0
  15. package/dist/src/db/migrations/2026_01_11_000_installed_apps.ts +3 -0
  16. package/dist/src/db/migrations/2026_01_11_000_video_recording_highlights.ts +19 -4
  17. package/dist/src/db/migrations/2026_01_13_000_installed_apps_session_tracking.ts +1 -0
  18. package/dist/src/db/migrations/2026_01_14_000_appearance_config.ts +1 -0
  19. package/dist/src/db/migrations/2026_01_25_001_test_run_details.ts +4 -0
  20. package/dist/src/db/migrations/2026_01_27_000_crash_anr_monitoring.ts +13 -0
  21. package/dist/src/db/migrations/2026_01_27_000_failures.ts +16 -0
  22. package/dist/src/db/migrations/2026_01_29_000_named_nodes.ts +92 -0
  23. package/dist/src/db/migrations/2026_01_30_000_performance_live_metrics.ts +105 -0
  24. package/dist/src/index.js +316 -315
  25. package/dist/src/index.js.map +1 -1
  26. package/package.json +9 -9
  27. package/schemas/tool-definitions.json +1528 -140
@@ -807,6 +807,60 @@
807
807
  "additionalProperties": {}
808
808
  }
809
809
  },
810
+ {
811
+ "name": "exportPlan",
812
+ "description": "Stop the active test recording and export recorded interactions as a YAML plan. Returns the plan content.",
813
+ "inputSchema": {
814
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
815
+ "type": "object",
816
+ "properties": {
817
+ "recordingId": {
818
+ "description": "Recording ID to export (uses active recording if not specified)",
819
+ "type": "string"
820
+ },
821
+ "planName": {
822
+ "description": "Name for the exported plan (auto-generated if not specified)",
823
+ "type": "string"
824
+ }
825
+ },
826
+ "additionalProperties": false
827
+ },
828
+ "outputSchema": {
829
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
830
+ "type": "object",
831
+ "properties": {
832
+ "success": {
833
+ "type": "boolean"
834
+ },
835
+ "recordingId": {
836
+ "type": "string"
837
+ },
838
+ "planName": {
839
+ "type": "string"
840
+ },
841
+ "planContent": {
842
+ "type": "string"
843
+ },
844
+ "stepCount": {
845
+ "type": "integer",
846
+ "minimum": -9007199254740991,
847
+ "maximum": 9007199254740991
848
+ },
849
+ "durationMs": {
850
+ "type": "integer",
851
+ "minimum": -9007199254740991,
852
+ "maximum": 9007199254740991
853
+ },
854
+ "error": {
855
+ "type": "string"
856
+ }
857
+ },
858
+ "required": [
859
+ "success"
860
+ ],
861
+ "additionalProperties": false
862
+ }
863
+ },
810
864
  {
811
865
  "name": "getDeepLinks",
812
866
  "description": "Query deep links for app",
@@ -3600,34 +3654,34 @@
3600
3654
  "in",
3601
3655
  "out"
3602
3656
  ],
3603
- "description": "Pinch direction (in=zoom out, out=zoom in)"
3657
+ "description": "Pinch direction"
3604
3658
  },
3605
3659
  "distanceStart": {
3606
- "description": "Start distance px",
3660
+ "description": "Initial finger distance (px, default: 400)",
3607
3661
  "type": "number"
3608
3662
  },
3609
3663
  "distanceEnd": {
3610
- "description": "End distance px",
3664
+ "description": "Final finger distance (px, default: 100)",
3611
3665
  "type": "number"
3612
3666
  },
3613
3667
  "scale": {
3614
- "description": "Scale multiplier",
3668
+ "description": "Scale factor (overrides distances)",
3615
3669
  "type": "number"
3616
3670
  },
3617
3671
  "duration": {
3618
- "description": "Duration ms (default: 300)",
3672
+ "description": "Gesture duration (ms)",
3619
3673
  "type": "number"
3620
3674
  },
3621
3675
  "rotationDegrees": {
3622
- "description": "Rotation degrees (+ = clockwise)",
3676
+ "description": "Rotation during pinch (degrees)",
3623
3677
  "type": "number"
3624
3678
  },
3625
3679
  "includeSystemInsets": {
3626
- "description": "Include system bars (default false)",
3680
+ "description": "Use full screen including status/nav bars",
3627
3681
  "type": "boolean"
3628
3682
  },
3629
3683
  "container": {
3630
- "description": "Container to pinch within",
3684
+ "description": "Container selector object to scope search. Provide { \"elementId\": \"<id>\" } or { \"text\": \"<text>\" }.",
3631
3685
  "anyOf": [
3632
3686
  {
3633
3687
  "type": "object",
@@ -3658,7 +3712,7 @@
3658
3712
  ]
3659
3713
  },
3660
3714
  "autoTarget": {
3661
- "description": "Auto-target surface (default true)",
3715
+ "description": "Auto-target pinchable containers",
3662
3716
  "type": "boolean"
3663
3717
  },
3664
3718
  "platform": {
@@ -4112,6 +4166,44 @@
4112
4166
  "additionalProperties": false
4113
4167
  }
4114
4168
  },
4169
+ {
4170
+ "name": "startTestRecording",
4171
+ "description": "Start test recording mode on the active device. Records user interactions for later export as a test plan. Returns the session ID which can be used with exportPlan.",
4172
+ "inputSchema": {
4173
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4174
+ "type": "object",
4175
+ "properties": {},
4176
+ "additionalProperties": false
4177
+ },
4178
+ "outputSchema": {
4179
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4180
+ "type": "object",
4181
+ "properties": {
4182
+ "success": {
4183
+ "type": "boolean"
4184
+ },
4185
+ "recordingId": {
4186
+ "type": "string"
4187
+ },
4188
+ "startedAt": {
4189
+ "type": "string"
4190
+ },
4191
+ "deviceId": {
4192
+ "type": "string"
4193
+ },
4194
+ "platform": {
4195
+ "type": "string"
4196
+ },
4197
+ "error": {
4198
+ "type": "string"
4199
+ }
4200
+ },
4201
+ "required": [
4202
+ "success"
4203
+ ],
4204
+ "additionalProperties": false
4205
+ }
4206
+ },
4115
4207
  {
4116
4208
  "name": "swipeOn",
4117
4209
  "description": "Swipe/scroll on screen or elements",
@@ -4120,11 +4212,11 @@
4120
4212
  "type": "object",
4121
4213
  "properties": {
4122
4214
  "includeSystemInsets": {
4123
- "description": "Include system bars (default false)",
4215
+ "description": "Use full screen including status/nav bars",
4124
4216
  "type": "boolean"
4125
4217
  },
4126
4218
  "container": {
4127
- "description": "Container to swipe within (elementId or text). REQUIRED for lists. Omit for full-screen swipes.",
4219
+ "description": "Container selector object to scope search. Provide { \"elementId\": \"<id>\" } or { \"text\": \"<text>\" }.",
4128
4220
  "anyOf": [
4129
4221
  {
4130
4222
  "type": "object",
@@ -4155,7 +4247,7 @@
4155
4247
  ]
4156
4248
  },
4157
4249
  "autoTarget": {
4158
- "description": "Auto-target scrollable container (default true)",
4250
+ "description": "Auto-target scrollable containers (default: true)",
4159
4251
  "type": "boolean"
4160
4252
  },
4161
4253
  "direction": {
@@ -4166,10 +4258,10 @@
4166
4258
  "left",
4167
4259
  "right"
4168
4260
  ],
4169
- "description": "Finger movement direction. up=finger up/reveals above, down=finger down/reveals below, left/right=finger left/right"
4261
+ "description": "Swipe/scroll direction"
4170
4262
  },
4171
4263
  "gestureType": {
4172
- "description": "swipeFingerTowardsDirection=finger moves in direction (default), scrollTowardsDirection=content scrolls in direction",
4264
+ "description": "swipeFingerTowardsDirection: finger moves in direction (e.g., 'up' = finger up = content scrolls down). scrollTowardsDirection: content moves in direction (e.g., 'up' = content up = see content below). Default: scrollTowardsDirection.",
4173
4265
  "type": "string",
4174
4266
  "enum": [
4175
4267
  "swipeFingerTowardsDirection",
@@ -4177,7 +4269,7 @@
4177
4269
  ]
4178
4270
  },
4179
4271
  "lookFor": {
4180
- "description": "Swipe until we find a match",
4272
+ "description": "Element to look for during swipe",
4181
4273
  "anyOf": [
4182
4274
  {
4183
4275
  "type": "object",
@@ -4208,21 +4300,23 @@
4208
4300
  ]
4209
4301
  },
4210
4302
  "boomerang": {
4211
- "description": "Return to the starting point after swiping (default false)",
4303
+ "description": "Return to start position after swipe apex",
4212
4304
  "type": "boolean"
4213
4305
  },
4214
4306
  "apexPause": {
4215
- "description": "Pause at the furthest point in ms (default 100)",
4307
+ "description": "Pause duration at swipe apex in ms (0-3000)",
4216
4308
  "type": "number",
4217
- "minimum": 0
4309
+ "minimum": 0,
4310
+ "maximum": 3000
4218
4311
  },
4219
4312
  "returnSpeed": {
4220
- "description": "Return speed multiplier (default 1.0)",
4313
+ "description": "Speed multiplier for return swipe (0.1-3.0)",
4221
4314
  "type": "number",
4222
- "exclusiveMinimum": 0
4315
+ "minimum": 0.1,
4316
+ "maximum": 3
4223
4317
  },
4224
4318
  "speed": {
4225
- "description": "Scroll speed",
4319
+ "description": "Swipe speed preset",
4226
4320
  "type": "string",
4227
4321
  "enum": [
4228
4322
  "slow",
@@ -5119,36 +5213,34 @@
5119
5213
  "dismiss",
5120
5214
  "clearAll"
5121
5215
  ],
5122
- "description": "System tray action"
5216
+ "description": "Action: open=expand tray, find=search for notification, tap=tap notification, dismiss=swipe away, clearAll=dismiss all for app"
5123
5217
  },
5124
5218
  "notification": {
5125
- "description": "Notification match criteria",
5219
+ "description": "Notification criteria to match",
5126
5220
  "type": "object",
5127
5221
  "properties": {
5128
5222
  "title": {
5129
- "description": "Notification title (case-insensitive, partial match)",
5223
+ "description": "Notification title to match",
5130
5224
  "type": "string"
5131
5225
  },
5132
5226
  "body": {
5133
- "description": "Notification body (case-insensitive, partial match)",
5227
+ "description": "Notification body to match",
5134
5228
  "type": "string"
5135
5229
  },
5136
5230
  "appId": {
5137
- "description": "Notification app package ID (Android only)",
5231
+ "description": "App package ID to match",
5138
5232
  "type": "string"
5139
5233
  },
5140
5234
  "tapActionLabel": {
5141
- "description": "Notification action button label to tap (tap only)",
5235
+ "description": "Action button label to tap (for 'tap' action)",
5142
5236
  "type": "string"
5143
5237
  }
5144
5238
  },
5145
5239
  "additionalProperties": false
5146
5240
  },
5147
5241
  "awaitTimeout": {
5148
- "description": "Wait timeout ms (default: 5000)",
5149
- "type": "integer",
5150
- "minimum": 0,
5151
- "maximum": 9007199254740991
5242
+ "description": "Timeout in ms to wait for notification (default: 5000)",
5243
+ "type": "number"
5152
5244
  },
5153
5245
  "platform": {
5154
5246
  "type": "string",
@@ -4,6 +4,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
4
4
  // Create device_configs table
5
5
  await db.schema
6
6
  .createTable("device_configs")
7
+ .ifNotExists()
7
8
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
8
9
  .addColumn("device_id", "text", col => col.notNull().unique())
9
10
  .addColumn("platform", "text", col => col.notNull())
@@ -18,6 +19,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
18
19
  // Create index on device_id for fast lookups
19
20
  await db.schema
20
21
  .createIndex("idx_device_configs_device_id")
22
+ .ifNotExists()
21
23
  .on("device_configs")
22
24
  .column("device_id")
23
25
  .execute();
@@ -4,6 +4,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
4
4
  // Create performance_thresholds table
5
5
  await db.schema
6
6
  .createTable("performance_thresholds")
7
+ .ifNotExists()
7
8
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
8
9
  .addColumn("device_id", "text", col => col.notNull())
9
10
  .addColumn("session_id", "text", col => col.notNull())
@@ -26,6 +27,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
26
27
  // Create index on device_id for fast lookups
27
28
  await db.schema
28
29
  .createIndex("idx_performance_thresholds_device_id")
30
+ .ifNotExists()
29
31
  .on("performance_thresholds")
30
32
  .column("device_id")
31
33
  .execute();
@@ -33,6 +35,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
33
35
  // Create index on session_id for session-specific queries
34
36
  await db.schema
35
37
  .createIndex("idx_performance_thresholds_session_id")
38
+ .ifNotExists()
36
39
  .on("performance_thresholds")
37
40
  .column("session_id")
38
41
  .execute();
@@ -40,6 +43,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
40
43
  // Create composite index for device + created_at for TTL queries
41
44
  await db.schema
42
45
  .createIndex("idx_performance_thresholds_device_created")
46
+ .ifNotExists()
43
47
  .on("performance_thresholds")
44
48
  .columns(["device_id", "created_at"])
45
49
  .execute();
@@ -47,6 +51,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
47
51
  // Create performance_audit_results table to store audit outcomes
48
52
  await db.schema
49
53
  .createTable("performance_audit_results")
54
+ .ifNotExists()
50
55
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
51
56
  .addColumn("device_id", "text", col => col.notNull())
52
57
  .addColumn("session_id", "text", col => col.notNull())
@@ -72,6 +77,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
72
77
  // Create index on device_id + timestamp for historical queries
73
78
  await db.schema
74
79
  .createIndex("idx_performance_audit_results_device_timestamp")
80
+ .ifNotExists()
75
81
  .on("performance_audit_results")
76
82
  .columns(["device_id", "timestamp"])
77
83
  .execute();
@@ -4,6 +4,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
4
4
  // Create navigation_apps table
5
5
  await db.schema
6
6
  .createTable("navigation_apps")
7
+ .ifNotExists()
7
8
  .addColumn("app_id", "text", col => col.primaryKey())
8
9
  .addColumn("created_at", "text", col =>
9
10
  col.notNull().defaultTo("datetime('now')")
@@ -14,6 +15,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
14
15
  // Create navigation_nodes table
15
16
  await db.schema
16
17
  .createTable("navigation_nodes")
18
+ .ifNotExists()
17
19
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
18
20
  .addColumn("app_id", "text", col =>
19
21
  col.notNull().references("navigation_apps.app_id").onDelete("cascade")
@@ -32,6 +34,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
32
34
  // Create unique constraint on (app_id, screen_name)
33
35
  await db.schema
34
36
  .createIndex("idx_navigation_nodes_app_screen")
37
+ .ifNotExists()
35
38
  .on("navigation_nodes")
36
39
  .columns(["app_id", "screen_name"])
37
40
  .unique()
@@ -40,6 +43,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
40
43
  // Create navigation_edges table
41
44
  await db.schema
42
45
  .createTable("navigation_edges")
46
+ .ifNotExists()
43
47
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
44
48
  .addColumn("app_id", "text", col =>
45
49
  col.notNull().references("navigation_apps.app_id").onDelete("cascade")
@@ -57,18 +61,21 @@ export async function up(db: Kysely<unknown>): Promise<void> {
57
61
  // Create indices for navigation_edges
58
62
  await db.schema
59
63
  .createIndex("idx_navigation_edges_app")
64
+ .ifNotExists()
60
65
  .on("navigation_edges")
61
66
  .column("app_id")
62
67
  .execute();
63
68
 
64
69
  await db.schema
65
70
  .createIndex("idx_navigation_edges_from")
71
+ .ifNotExists()
66
72
  .on("navigation_edges")
67
73
  .column("from_screen")
68
74
  .execute();
69
75
 
70
76
  await db.schema
71
77
  .createIndex("idx_navigation_edges_to")
78
+ .ifNotExists()
72
79
  .on("navigation_edges")
73
80
  .column("to_screen")
74
81
  .execute();
@@ -76,6 +83,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
76
83
  // Create ui_elements table
77
84
  await db.schema
78
85
  .createTable("ui_elements")
86
+ .ifNotExists()
79
87
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
80
88
  .addColumn("app_id", "text", col =>
81
89
  col.notNull().references("navigation_apps.app_id").onDelete("cascade")
@@ -100,6 +108,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
100
108
  // Create index on app_id for ui_elements
101
109
  await db.schema
102
110
  .createIndex("idx_ui_elements_app")
111
+ .ifNotExists()
103
112
  .on("ui_elements")
104
113
  .column("app_id")
105
114
  .execute();
@@ -107,6 +116,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
107
116
  // Create edge_ui_elements junction table
108
117
  await db.schema
109
118
  .createTable("edge_ui_elements")
119
+ .ifNotExists()
110
120
  .addColumn("edge_id", "integer", col =>
111
121
  col.notNull().references("navigation_edges.id").onDelete("cascade")
112
122
  )
@@ -119,6 +129,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
119
129
  // Create primary key for edge_ui_elements
120
130
  await db.schema
121
131
  .createIndex("idx_edge_ui_elements_pk")
132
+ .ifNotExists()
122
133
  .on("edge_ui_elements")
123
134
  .columns(["edge_id", "ui_element_id"])
124
135
  .unique()
@@ -127,6 +138,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
127
138
  // Create node_modals table
128
139
  await db.schema
129
140
  .createTable("node_modals")
141
+ .ifNotExists()
130
142
  .addColumn("node_id", "integer", col =>
131
143
  col.notNull().references("navigation_nodes.id").onDelete("cascade")
132
144
  )
@@ -140,6 +152,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
140
152
  // Create primary key for node_modals
141
153
  await db.schema
142
154
  .createIndex("idx_node_modals_pk")
155
+ .ifNotExists()
143
156
  .on("node_modals")
144
157
  .columns(["node_id", "stack_level"])
145
158
  .unique()
@@ -148,6 +161,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
148
161
  // Create edge_modals table
149
162
  await db.schema
150
163
  .createTable("edge_modals")
164
+ .ifNotExists()
151
165
  .addColumn("edge_id", "integer", col =>
152
166
  col.notNull().references("navigation_edges.id").onDelete("cascade")
153
167
  )
@@ -162,6 +176,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
162
176
  // Create primary key for edge_modals
163
177
  await db.schema
164
178
  .createIndex("idx_edge_modals_pk")
179
+ .ifNotExists()
165
180
  .on("edge_modals")
166
181
  .columns(["edge_id", "position", "stack_level"])
167
182
  .unique()
@@ -170,6 +185,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
170
185
  // Create scroll_positions table
171
186
  await db.schema
172
187
  .createTable("scroll_positions")
188
+ .ifNotExists()
173
189
  .addColumn("edge_id", "integer", col =>
174
190
  col.primaryKey().references("navigation_edges.id").onDelete("cascade")
175
191
  )
@@ -4,6 +4,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
4
4
  // Create accessibility_baselines table
5
5
  await db.schema
6
6
  .createTable("accessibility_baselines")
7
+ .ifNotExists()
7
8
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
8
9
  .addColumn("screen_id", "text", col => col.notNull().unique())
9
10
  .addColumn("violations_json", "text", col => col.notNull()) // JSON blob of WcagViolation[]
@@ -16,6 +17,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
16
17
  // Create index on screen_id for fast lookups
17
18
  await db.schema
18
19
  .createIndex("idx_accessibility_baselines_screen_id")
20
+ .ifNotExists()
19
21
  .on("accessibility_baselines")
20
22
  .column("screen_id")
21
23
  .execute();
@@ -23,6 +25,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
23
25
  // Create index on updated_at for cleanup queries
24
26
  await db.schema
25
27
  .createIndex("idx_accessibility_baselines_updated_at")
28
+ .ifNotExists()
26
29
  .on("accessibility_baselines")
27
30
  .column("updated_at")
28
31
  .execute();
@@ -4,6 +4,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
4
4
  // Create memory_thresholds table for per-app threshold configuration
5
5
  await db.schema
6
6
  .createTable("memory_thresholds")
7
+ .ifNotExists()
7
8
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
8
9
  .addColumn("device_id", "text", col => col.notNull())
9
10
  .addColumn("package_name", "text", col => col.notNull())
@@ -22,6 +23,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
22
23
  // Create index on device_id + package_name for fast lookups
23
24
  await db.schema
24
25
  .createIndex("idx_memory_thresholds_device_package")
26
+ .ifNotExists()
25
27
  .on("memory_thresholds")
26
28
  .columns(["device_id", "package_name"])
27
29
  .execute();
@@ -29,6 +31,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
29
31
  // Create memory_baselines table for adaptive baseline tracking
30
32
  await db.schema
31
33
  .createTable("memory_baselines")
34
+ .ifNotExists()
32
35
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
33
36
  .addColumn("device_id", "text", col => col.notNull())
34
37
  .addColumn("package_name", "text", col => col.notNull())
@@ -48,6 +51,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
48
51
  // Create unique index on device_id + package_name + tool_name
49
52
  await db.schema
50
53
  .createIndex("idx_memory_baselines_device_package_tool")
54
+ .ifNotExists()
51
55
  .on("memory_baselines")
52
56
  .columns(["device_id", "package_name", "tool_name"])
53
57
  .unique()
@@ -56,6 +60,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
56
60
  // Create memory_audit_results table to store audit outcomes
57
61
  await db.schema
58
62
  .createTable("memory_audit_results")
63
+ .ifNotExists()
59
64
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
60
65
  .addColumn("device_id", "text", col => col.notNull())
61
66
  .addColumn("session_id", "text", col => col.notNull())
@@ -92,6 +97,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
92
97
  // Create index on device_id + timestamp for historical queries
93
98
  await db.schema
94
99
  .createIndex("idx_memory_audit_results_device_timestamp")
100
+ .ifNotExists()
95
101
  .on("memory_audit_results")
96
102
  .columns(["device_id", "timestamp"])
97
103
  .execute();
@@ -99,6 +105,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
99
105
  // Create index on package_name + timestamp for app-specific queries
100
106
  await db.schema
101
107
  .createIndex("idx_memory_audit_results_package_timestamp")
108
+ .ifNotExists()
102
109
  .on("memory_audit_results")
103
110
  .columns(["package_name", "timestamp"])
104
111
  .execute();
@@ -106,6 +113,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
106
113
  // Create index on passed for filtering failures
107
114
  await db.schema
108
115
  .createIndex("idx_memory_audit_results_passed")
116
+ .ifNotExists()
109
117
  .on("memory_audit_results")
110
118
  .column("passed")
111
119
  .execute();
@@ -3,6 +3,7 @@ import { Kysely } from "kysely";
3
3
  export async function up(db: Kysely<any>): Promise<void> {
4
4
  await db.schema
5
5
  .createTable("recomposition_metrics")
6
+ .ifNotExists()
6
7
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
7
8
  .addColumn("device_id", "text", col => col.notNull())
8
9
  .addColumn("session_id", "text", col => col.notNull())
@@ -25,12 +26,14 @@ export async function up(db: Kysely<any>): Promise<void> {
25
26
 
26
27
  await db.schema
27
28
  .createIndex("idx_recomposition_metrics_timestamp")
29
+ .ifNotExists()
28
30
  .on("recomposition_metrics")
29
31
  .column("timestamp")
30
32
  .execute();
31
33
 
32
34
  await db.schema
33
35
  .createIndex("idx_recomposition_metrics_composable")
36
+ .ifNotExists()
34
37
  .on("recomposition_metrics")
35
38
  .columns(["package_name", "composable_id", "timestamp"])
36
39
  .execute();
@@ -3,6 +3,7 @@ import type { Kysely } from "kysely";
3
3
  export async function up(db: Kysely<unknown>): Promise<void> {
4
4
  await db.schema
5
5
  .createTable("prediction_outcomes")
6
+ .ifNotExists()
6
7
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
7
8
  .addColumn("app_id", "text", col =>
8
9
  col.notNull().references("navigation_apps.app_id").onDelete("cascade")
@@ -28,30 +29,35 @@ export async function up(db: Kysely<unknown>): Promise<void> {
28
29
 
29
30
  await db.schema
30
31
  .createIndex("idx_prediction_outcomes_app")
32
+ .ifNotExists()
31
33
  .on("prediction_outcomes")
32
34
  .column("app_id")
33
35
  .execute();
34
36
 
35
37
  await db.schema
36
38
  .createIndex("idx_prediction_outcomes_from")
39
+ .ifNotExists()
37
40
  .on("prediction_outcomes")
38
41
  .column("from_screen")
39
42
  .execute();
40
43
 
41
44
  await db.schema
42
45
  .createIndex("idx_prediction_outcomes_predicted")
46
+ .ifNotExists()
43
47
  .on("prediction_outcomes")
44
48
  .column("predicted_screen")
45
49
  .execute();
46
50
 
47
51
  await db.schema
48
52
  .createIndex("idx_prediction_outcomes_tool")
53
+ .ifNotExists()
49
54
  .on("prediction_outcomes")
50
55
  .column("tool_name")
51
56
  .execute();
52
57
 
53
58
  await db.schema
54
59
  .createTable("prediction_transition_stats")
60
+ .ifNotExists()
55
61
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
56
62
  .addColumn("app_id", "text", col =>
57
63
  col.notNull().references("navigation_apps.app_id").onDelete("cascade")
@@ -72,6 +78,7 @@ export async function up(db: Kysely<unknown>): Promise<void> {
72
78
 
73
79
  await db.schema
74
80
  .createIndex("idx_prediction_transition_key")
81
+ .ifNotExists()
75
82
  .on("prediction_transition_stats")
76
83
  .columns(["app_id", "from_screen", "to_screen", "tool_name", "tool_args"])
77
84
  .unique()
@@ -3,6 +3,7 @@ import type { Kysely } from "kysely";
3
3
  export async function up(db: Kysely<unknown>): Promise<void> {
4
4
  await db.schema
5
5
  .createTable("feature_flags")
6
+ .ifNotExists()
6
7
  .addColumn("key", "text", col => col.primaryKey())
7
8
  .addColumn("enabled", "integer", col => col.notNull().defaultTo(0))
8
9
  .addColumn("config_json", "text")
@@ -3,6 +3,7 @@ import type { Kysely } from "kysely";
3
3
  export async function up(db: Kysely<unknown>): Promise<void> {
4
4
  await db.schema
5
5
  .createTable("test_executions")
6
+ .ifNotExists()
6
7
  .addColumn("id", "integer", col => col.primaryKey().autoIncrement())
7
8
  .addColumn("test_class", "text", col => col.notNull())
8
9
  .addColumn("test_method", "text", col => col.notNull())
@@ -28,12 +29,14 @@ export async function up(db: Kysely<unknown>): Promise<void> {
28
29
 
29
30
  await db.schema
30
31
  .createIndex("idx_test_executions_lookup")
32
+ .ifNotExists()
31
33
  .on("test_executions")
32
34
  .columns(["test_class", "test_method"])
33
35
  .execute();
34
36
 
35
37
  await db.schema
36
38
  .createIndex("idx_test_executions_timestamp")
39
+ .ifNotExists()
37
40
  .on("test_executions")
38
41
  .column("timestamp")
39
42
  .execute();