loki-mode 10.7.1 → 10.9.1

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 (185) hide show
  1. package/README.md +2 -2
  2. package/SKILL.md +2 -2
  3. package/VERSION +1 -1
  4. package/autonomy/loki +20 -32
  5. package/autonomy/run.sh +9 -5
  6. package/autonomy/tui.sh +5 -1
  7. package/dashboard/__init__.py +1 -1
  8. package/dashboard/api_phases.py +1 -1
  9. package/dashboard/api_start.py +0 -1
  10. package/dashboard/server.py +28 -146
  11. package/docs/COCKPIT-SPEC.md +3 -1
  12. package/docs/DASHBOARD-9.12-EVIDENCE.md +1 -1
  13. package/docs/DASHBOARD-ARCHITECTURE.md +13 -11
  14. package/docs/DASHBOARD_V2_CHECKLIST.md +2 -0
  15. package/docs/INSTALLATION.md +12 -11
  16. package/docs/MERGE-DEDUP-MAP.md +1 -1
  17. package/docs/MERGE-ROUTE-MAP.md +1 -1
  18. package/docs/MERGE3-PLAN.md +2 -2
  19. package/docs/R3-COST-OBSERVABILITY-DESIGN.md +2 -2
  20. package/docs/R4-TRUST-TRAJECTORY-DESIGN.md +1 -1
  21. package/docs/R5-AUTO-WIKI-DESIGN.md +1 -1
  22. package/docs/R6-ROLLBACK-CHECKPOINT-PLAN.md +1 -1
  23. package/docs/RARV-C-100X-PLAN.md +3 -3
  24. package/docs/SONNET5-DEFAULT-PLAN.md +2 -2
  25. package/docs/SYNERGY-TASKS.md +1 -1
  26. package/docs/TOOL-INTEGRATION.md +1 -1
  27. package/docs/TOP-100-BACKLOG.md +1 -1
  28. package/docs/alternative-installations.md +1 -1
  29. package/docs/architecture/ADR-001-runtime-migration.md +1 -1
  30. package/docs/architecture/DASHBOARD_V2_ARCHITECTURE.md +2 -0
  31. package/docs/audit-logging.md +2 -0
  32. package/docs/authentication.md +2 -0
  33. package/docs/authorization.md +2 -0
  34. package/docs/certification/02-enterprise-features/lab.md +2 -0
  35. package/docs/certification/02-enterprise-features/lesson.md +2 -0
  36. package/docs/certification/04-production-deployment/lab.md +2 -0
  37. package/docs/certification/04-production-deployment/lesson.md +2 -0
  38. package/docs/control-plane-migration.md +97 -0
  39. package/docs/dashboard-guide.md +6 -7
  40. package/docs/dev/release-checklist.md +9 -11
  41. package/docs/enterprise/integration-cookbook.md +2 -0
  42. package/docs/enterprise/migration.md +1 -1
  43. package/docs/enterprise/performance.md +3 -1
  44. package/docs/enterprise/sdk-guide.md +2 -0
  45. package/docs/enterprise/security.md +2 -0
  46. package/docs/plans/FORGE-AUTONOMOUS-QUEUE.md +2 -2
  47. package/docs/research-2026-07/OBSERVABILITY-TOOL-SPEC.md +1 -1
  48. package/docs/retrospectives/v7.5.15-honesty-audit.md +2 -2
  49. package/docs/test-scenarios/enterprise-scenarios.md +2 -2
  50. package/docs/v10/ARCHITECT-CUTS.md +9 -9
  51. package/docs/v10/BACKLOG.md +7 -7
  52. package/docs/v10/BOARD.md +25 -25
  53. package/docs/v10/CONTROL-PLANE.md +4 -4
  54. package/docs/v10/CP-ENTERPRISE-UI.md +270 -9
  55. package/docs/v10/D51-PHASE-B.md +1 -1
  56. package/docs/v10/DECISIONS.md +3 -3
  57. package/docs/v10/DEPS.md +10 -10
  58. package/docs/v10/FAILURE-CLASSES.md +66 -1
  59. package/docs/v10/LEGACY-REMOVAL.md +2 -2
  60. package/docs/v10/METRICS.md +6 -0
  61. package/docs/v10/SWARM.md +2 -2
  62. package/loki-ts/data/model-pricing.json +6 -6
  63. package/loki-ts/dist/cockpit.js +11 -11
  64. package/loki-ts/dist/loki.js +819 -809
  65. package/loki-ts/package.json +1 -1
  66. package/magic/core/design_tokens.py +1 -2
  67. package/magic/core/generator.py +2 -2
  68. package/magic/tokens/README.md +1 -3
  69. package/mcp/__init__.py +1 -1
  70. package/package.json +3 -8
  71. package/packages/control-plane/dist/server.js +17954 -5696
  72. package/packages/control-plane/drizzle/0004_cpe03_local_repos_actions.sql +17 -0
  73. package/packages/control-plane/drizzle/meta/0004_snapshot.json +542 -0
  74. package/packages/control-plane/drizzle/meta/_journal.json +9 -2
  75. package/packages/control-plane/package.json +4 -1
  76. package/packages/control-plane/src/db/schema.ts +19 -0
  77. package/packages/control-plane/src/server/app.ts +11 -22
  78. package/packages/control-plane/src/server/audit.ts +15 -0
  79. package/packages/control-plane/src/server/auth.ts +7 -1
  80. package/packages/control-plane/src/server/legacy/routes-audit.ts +50 -0
  81. package/packages/control-plane/src/server/legacy/routes-control.ts +26 -0
  82. package/packages/control-plane/src/server/legacy/routes-memory.ts +30 -0
  83. package/packages/control-plane/src/server/legacy/routes-metrics.ts +18 -0
  84. package/packages/control-plane/src/server/legacy/routes.ts +237 -0
  85. package/packages/control-plane/src/server/legacy/shim.ts +201 -0
  86. package/packages/control-plane/src/server/repos.ts +27 -0
  87. package/packages/control-plane/src/server/routes/artifacts.ts +104 -0
  88. package/packages/control-plane/src/server/routes/audit.ts +17 -0
  89. package/packages/control-plane/src/server/routes/checkpoints.ts +171 -0
  90. package/packages/control-plane/src/server/routes/config.ts +319 -0
  91. package/packages/control-plane/src/server/routes/control.ts +75 -0
  92. package/packages/control-plane/src/server/routes/cost.ts +70 -0
  93. package/packages/control-plane/src/server/routes/cost_ledger.ts +210 -0
  94. package/packages/control-plane/src/server/routes/fleet.ts +101 -0
  95. package/packages/control-plane/src/server/routes/index.ts +71 -0
  96. package/packages/control-plane/src/server/routes/integrations.ts +123 -0
  97. package/packages/control-plane/src/server/routes/memory.ts +219 -0
  98. package/packages/control-plane/src/server/routes/merge_risk.ts +209 -0
  99. package/packages/control-plane/src/server/routes/metrics.ts +93 -0
  100. package/packages/control-plane/src/server/routes/notify.ts +48 -0
  101. package/packages/control-plane/src/server/routes/providers.ts +111 -0
  102. package/packages/control-plane/src/server/routes/session_control.ts +155 -0
  103. package/packages/control-plane/src/server/routes/start.ts +39 -0
  104. package/packages/control-plane/src/server/routes/stats.ts +76 -0
  105. package/packages/control-plane/src/server/routes/stream.ts +85 -0
  106. package/packages/control-plane/src/server/routes/verify.ts +66 -0
  107. package/packages/control-plane/src/server/spawn.ts +79 -0
  108. package/packages/control-plane/src/shipper/discover.ts +19 -1
  109. package/packages/control-plane/ui/dist/assets/index-BQbFv65M.css +1 -0
  110. package/packages/control-plane/ui/dist/assets/index-Dbhu244h.js +155 -0
  111. package/packages/control-plane/ui/dist/index.html +2 -2
  112. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  113. package/references/magic-modules-patterns.md +2 -2
  114. package/skills/factory-operations.md +3 -3
  115. package/skills/magic-modules.md +1 -1
  116. package/skills/release-cadence.md +1 -1
  117. package/tools/audit-docs.py +1 -1
  118. package/tools/index-codebase.py +1 -1
  119. package/web-app/dist/assets/{AdminPage-BJSU5hY1.js → AdminPage-DqMnfZrH.js} +1 -1
  120. package/web-app/dist/assets/{Avatar-CSOSpw9c.js → Avatar-BEof29du.js} +1 -1
  121. package/web-app/dist/assets/{Badge-COr7vj0D.js → Badge-WD53OL5m.js} +1 -1
  122. package/web-app/dist/assets/{Button-DGoWFERp.js → Button-Rzk5flhU.js} +1 -1
  123. package/web-app/dist/assets/{CockpitPage-CBpWkNXY.js → CockpitPage-Bqz3PCMh.js} +1 -1
  124. package/web-app/dist/assets/{ComparePage-BwT8vqrL.js → ComparePage-Byo2NzAZ.js} +1 -1
  125. package/web-app/dist/assets/{ErrorBoundary-D7SicDDA.js → ErrorBoundary-BuE0kH3W.js} +1 -1
  126. package/web-app/dist/assets/{EvidenceReceiptPanel-bx-5liG2.js → EvidenceReceiptPanel-CKFHOPBx.js} +1 -1
  127. package/web-app/dist/assets/{GitHubIssuesPanel-BAeeWLqY.js → GitHubIssuesPanel-Df_kTMqI.js} +1 -1
  128. package/web-app/dist/assets/{GitHubPRsPanel-CssD8lGI.js → GitHubPRsPanel-CouvcKrZ.js} +1 -1
  129. package/web-app/dist/assets/{HomePage-SL5PT3m5.js → HomePage-dEpLzj0x.js} +2 -2
  130. package/web-app/dist/assets/{LoginPage-C8hFOZOM.js → LoginPage-6DVjUND5.js} +1 -1
  131. package/web-app/dist/assets/{MagicPage-xHbHkrPf.js → MagicPage-BDQ9MOfY.js} +1 -1
  132. package/web-app/dist/assets/{MetricsPage-B_2CKFcC.js → MetricsPage-CXiJ04G_.js} +1 -1
  133. package/web-app/dist/assets/{NotFoundPage-CXwXMq35.js → NotFoundPage-BaXhZvyj.js} +1 -1
  134. package/web-app/dist/assets/{ProjectPage-AaisMQI-.js → ProjectPage-BzE4V7Ti.js} +3 -3
  135. package/web-app/dist/assets/{ProjectsPage-Cej5ResX.js → ProjectsPage-ipf6TLMX.js} +1 -1
  136. package/web-app/dist/assets/{SettingsPage-DKv4mn9H.js → SettingsPage-BDxkUKN6.js} +1 -1
  137. package/web-app/dist/assets/{ShowcasePage-Dkiyzne4.js → ShowcasePage-YQXD72SM.js} +1 -1
  138. package/web-app/dist/assets/{SystemSettingsPage-DaBLQ5dU.js → SystemSettingsPage-Dou7zHS0.js} +1 -1
  139. package/web-app/dist/assets/{TeamsPage-B2yUr31k.js → TeamsPage-CQarfcYr.js} +1 -1
  140. package/web-app/dist/assets/{TemplatesPage-CfYiANhU.js → TemplatesPage-CPi1R8Xj.js} +1 -1
  141. package/web-app/dist/assets/{TerminalOutput-CMXoexLM.js → TerminalOutput-WiGhWdYD.js} +1 -1
  142. package/web-app/dist/assets/{activity-B0dzoZtY.js → activity-DOa7ejQA.js} +1 -1
  143. package/web-app/dist/assets/{bell-DFOTaSoo.js → bell-CX-VAlYN.js} +1 -1
  144. package/web-app/dist/assets/{bot-Dz-WSQyP.js → bot-EDXaZmHc.js} +1 -1
  145. package/web-app/dist/assets/{check-L1QIRueJ.js → check-CnBdKk3L.js} +1 -1
  146. package/web-app/dist/assets/{chevron-left-1TrnIEZS.js → chevron-left-BJ_ydRQW.js} +1 -1
  147. package/web-app/dist/assets/{circle-alert-8Bf6xEDx.js → circle-alert-tz8ufhc_.js} +1 -1
  148. package/web-app/dist/assets/{clock-DB8NE6P5.js → clock-DFBZPSsH.js} +1 -1
  149. package/web-app/dist/assets/{cloud-DUSL3wZS.js → cloud-uy3p_5Q7.js} +1 -1
  150. package/web-app/dist/assets/{code-xml-DbjryWNl.js → code-xml-3CbYD9YL.js} +1 -1
  151. package/web-app/dist/assets/{database-DrezrMSs.js → database-YiNBXc9c.js} +1 -1
  152. package/web-app/dist/assets/{dollar-sign-CGbaLMzR.js → dollar-sign-D0wBa4Cv.js} +1 -1
  153. package/web-app/dist/assets/{file-code-corner-Dfypa-r4.js → file-code-corner-DDdZVZ5v.js} +1 -1
  154. package/web-app/dist/assets/{file-plus-CzV5L2Gd.js → file-plus-D09LTBqt.js} +1 -1
  155. package/web-app/dist/assets/{globe-BoYjTwPQ.js → globe-BirTPwff.js} +1 -1
  156. package/web-app/dist/assets/{hammer-WO-HuiyJ.js → hammer-DaE5qgnd.js} +1 -1
  157. package/web-app/dist/assets/{index-CjIOUjnd.js → index-D8t7KnQf.js} +3 -3
  158. package/web-app/dist/assets/{layers-Bn6jtKNk.js → layers-DVVrckRY.js} +1 -1
  159. package/web-app/dist/assets/{loader-circle-gERWRnmW.js → loader-circle-2-nMGmcb.js} +1 -1
  160. package/web-app/dist/assets/{lock-BIiMLJq8.js → lock-D0Xj43pC.js} +1 -1
  161. package/web-app/dist/assets/{package-dLvDSVys.js → package-BB7S3egm.js} +1 -1
  162. package/web-app/dist/assets/{plus-BHM3ZLhZ.js → plus-BLhoMrn3.js} +1 -1
  163. package/web-app/dist/assets/{refresh-cw-BAp_alv6.js → refresh-cw-DMc2uPLw.js} +1 -1
  164. package/web-app/dist/assets/{rotate-ccw-CBhwq_MG.js → rotate-ccw-DM3IP9x7.js} +1 -1
  165. package/web-app/dist/assets/{scroll-text-DoS-6dfU.js → scroll-text-lH2uW7rB.js} +1 -1
  166. package/web-app/dist/assets/{server-5JgdDWQO.js → server-BkerZcdR.js} +1 -1
  167. package/web-app/dist/assets/{shield-alert-DjmlLT34.js → shield-alert-B8ohcUfu.js} +1 -1
  168. package/web-app/dist/assets/{thumbs-up-BtiEXl3p.js → thumbs-up-CTIxLzPD.js} +1 -1
  169. package/web-app/dist/assets/{trash-2-ClsWU_Vg.js → trash-2-C3zIpsH5.js} +1 -1
  170. package/web-app/dist/assets/{trending-down-DPS4M7_X.js → trending-down-BTT7wV4Y.js} +1 -1
  171. package/web-app/dist/assets/{trending-up-D6OJ38-V.js → trending-up-BzHdCDvF.js} +1 -1
  172. package/web-app/dist/assets/{upload-DOCzLUpF.js → upload-HxR34-A8.js} +1 -1
  173. package/web-app/dist/assets/{usePolling-CljQTWj_.js → usePolling-DDj6Fupy.js} +1 -1
  174. package/web-app/dist/assets/{user-C0G82Weu.js → user-qH5y9yNy.js} +1 -1
  175. package/web-app/dist/index.html +1 -1
  176. package/dashboard/static/assets/mermaid.min.js +0 -2030
  177. package/dashboard/static/cost.html +0 -344
  178. package/dashboard/static/favicon.svg +0 -5
  179. package/dashboard/static/index.html +0 -15577
  180. package/dashboard/static/proofs.html +0 -194
  181. package/dashboard/static/start.html +0 -131
  182. package/dashboard/static/trust.html +0 -325
  183. package/packages/control-plane/src/server/actions.ts +0 -60
  184. package/packages/control-plane/ui/dist/assets/index-DHDI_dHM.css +0 -1
  185. package/packages/control-plane/ui/dist/assets/index-DaQr0MPS.js +0 -129
@@ -0,0 +1,17 @@
1
+ CREATE TABLE IF NOT EXISTS `actions` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+ `ts` text NOT NULL,
4
+ `actor` text NOT NULL,
5
+ `kind` text NOT NULL,
6
+ `target` text,
7
+ `result` text NOT NULL,
8
+ `detail` text
9
+ );
10
+ --> statement-breakpoint
11
+ CREATE INDEX IF NOT EXISTS `actions_ts` ON `actions` (`ts`);--> statement-breakpoint
12
+ CREATE TABLE IF NOT EXISTS `local_repos` (
13
+ `source_id` text PRIMARY KEY NOT NULL,
14
+ `realpath` text NOT NULL,
15
+ `name` text NOT NULL,
16
+ `discovered_at` text NOT NULL
17
+ );
@@ -0,0 +1,542 @@
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "df1eef76-5d0f-48f4-a4e7-909789b0bfed",
5
+ "prevId": "c1492d55-5d08-4208-940a-38fba6b33b3c",
6
+ "tables": {
7
+ "actions": {
8
+ "name": "actions",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "integer",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": true
16
+ },
17
+ "ts": {
18
+ "name": "ts",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "actor": {
25
+ "name": "actor",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "kind": {
32
+ "name": "kind",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false
37
+ },
38
+ "target": {
39
+ "name": "target",
40
+ "type": "text",
41
+ "primaryKey": false,
42
+ "notNull": false,
43
+ "autoincrement": false
44
+ },
45
+ "result": {
46
+ "name": "result",
47
+ "type": "text",
48
+ "primaryKey": false,
49
+ "notNull": true,
50
+ "autoincrement": false
51
+ },
52
+ "detail": {
53
+ "name": "detail",
54
+ "type": "text",
55
+ "primaryKey": false,
56
+ "notNull": false,
57
+ "autoincrement": false
58
+ }
59
+ },
60
+ "indexes": {
61
+ "actions_ts": {
62
+ "name": "actions_ts",
63
+ "columns": [
64
+ "ts"
65
+ ],
66
+ "isUnique": false
67
+ }
68
+ },
69
+ "foreignKeys": {},
70
+ "compositePrimaryKeys": {},
71
+ "uniqueConstraints": {},
72
+ "checkConstraints": {}
73
+ },
74
+ "audit": {
75
+ "name": "audit",
76
+ "columns": {
77
+ "id": {
78
+ "name": "id",
79
+ "type": "integer",
80
+ "primaryKey": true,
81
+ "notNull": true,
82
+ "autoincrement": true
83
+ },
84
+ "ts": {
85
+ "name": "ts",
86
+ "type": "text",
87
+ "primaryKey": false,
88
+ "notNull": true,
89
+ "autoincrement": false
90
+ },
91
+ "action": {
92
+ "name": "action",
93
+ "type": "text",
94
+ "primaryKey": false,
95
+ "notNull": true,
96
+ "autoincrement": false
97
+ },
98
+ "actor": {
99
+ "name": "actor",
100
+ "type": "text",
101
+ "primaryKey": false,
102
+ "notNull": true,
103
+ "autoincrement": false
104
+ },
105
+ "detail": {
106
+ "name": "detail",
107
+ "type": "text",
108
+ "primaryKey": false,
109
+ "notNull": true,
110
+ "autoincrement": false
111
+ }
112
+ },
113
+ "indexes": {},
114
+ "foreignKeys": {},
115
+ "compositePrimaryKeys": {},
116
+ "uniqueConstraints": {},
117
+ "checkConstraints": {}
118
+ },
119
+ "events": {
120
+ "name": "events",
121
+ "columns": {
122
+ "source_id": {
123
+ "name": "source_id",
124
+ "type": "text",
125
+ "primaryKey": false,
126
+ "notNull": true,
127
+ "autoincrement": false
128
+ },
129
+ "run_id": {
130
+ "name": "run_id",
131
+ "type": "text",
132
+ "primaryKey": false,
133
+ "notNull": true,
134
+ "autoincrement": false
135
+ },
136
+ "seq": {
137
+ "name": "seq",
138
+ "type": "integer",
139
+ "primaryKey": false,
140
+ "notNull": true,
141
+ "autoincrement": false
142
+ },
143
+ "ts": {
144
+ "name": "ts",
145
+ "type": "text",
146
+ "primaryKey": false,
147
+ "notNull": true,
148
+ "autoincrement": false
149
+ },
150
+ "type": {
151
+ "name": "type",
152
+ "type": "text",
153
+ "primaryKey": false,
154
+ "notNull": true,
155
+ "autoincrement": false
156
+ },
157
+ "stage": {
158
+ "name": "stage",
159
+ "type": "text",
160
+ "primaryKey": false,
161
+ "notNull": false,
162
+ "autoincrement": false
163
+ },
164
+ "data": {
165
+ "name": "data",
166
+ "type": "text",
167
+ "primaryKey": false,
168
+ "notNull": true,
169
+ "autoincrement": false
170
+ },
171
+ "line_sha256": {
172
+ "name": "line_sha256",
173
+ "type": "text",
174
+ "primaryKey": false,
175
+ "notNull": true,
176
+ "autoincrement": false
177
+ },
178
+ "received_at": {
179
+ "name": "received_at",
180
+ "type": "text",
181
+ "primaryKey": false,
182
+ "notNull": true,
183
+ "autoincrement": false
184
+ }
185
+ },
186
+ "indexes": {
187
+ "events_run_seq": {
188
+ "name": "events_run_seq",
189
+ "columns": [
190
+ "run_id",
191
+ "seq"
192
+ ],
193
+ "isUnique": false
194
+ },
195
+ "events_type_ts": {
196
+ "name": "events_type_ts",
197
+ "columns": [
198
+ "type",
199
+ "ts"
200
+ ],
201
+ "isUnique": false
202
+ }
203
+ },
204
+ "foreignKeys": {},
205
+ "compositePrimaryKeys": {
206
+ "events_source_id_run_id_seq_pk": {
207
+ "columns": [
208
+ "source_id",
209
+ "run_id",
210
+ "seq"
211
+ ],
212
+ "name": "events_source_id_run_id_seq_pk"
213
+ }
214
+ },
215
+ "uniqueConstraints": {},
216
+ "checkConstraints": {}
217
+ },
218
+ "local_repos": {
219
+ "name": "local_repos",
220
+ "columns": {
221
+ "source_id": {
222
+ "name": "source_id",
223
+ "type": "text",
224
+ "primaryKey": true,
225
+ "notNull": true,
226
+ "autoincrement": false
227
+ },
228
+ "realpath": {
229
+ "name": "realpath",
230
+ "type": "text",
231
+ "primaryKey": false,
232
+ "notNull": true,
233
+ "autoincrement": false
234
+ },
235
+ "name": {
236
+ "name": "name",
237
+ "type": "text",
238
+ "primaryKey": false,
239
+ "notNull": true,
240
+ "autoincrement": false
241
+ },
242
+ "discovered_at": {
243
+ "name": "discovered_at",
244
+ "type": "text",
245
+ "primaryKey": false,
246
+ "notNull": true,
247
+ "autoincrement": false
248
+ }
249
+ },
250
+ "indexes": {},
251
+ "foreignKeys": {},
252
+ "compositePrimaryKeys": {},
253
+ "uniqueConstraints": {},
254
+ "checkConstraints": {}
255
+ },
256
+ "runs": {
257
+ "name": "runs",
258
+ "columns": {
259
+ "source_id": {
260
+ "name": "source_id",
261
+ "type": "text",
262
+ "primaryKey": false,
263
+ "notNull": true,
264
+ "autoincrement": false
265
+ },
266
+ "run_id": {
267
+ "name": "run_id",
268
+ "type": "text",
269
+ "primaryKey": false,
270
+ "notNull": true,
271
+ "autoincrement": false
272
+ },
273
+ "origin_repo": {
274
+ "name": "origin_repo",
275
+ "type": "text",
276
+ "primaryKey": false,
277
+ "notNull": false,
278
+ "autoincrement": false
279
+ },
280
+ "issue_ref": {
281
+ "name": "issue_ref",
282
+ "type": "text",
283
+ "primaryKey": false,
284
+ "notNull": false,
285
+ "autoincrement": false
286
+ },
287
+ "task_source": {
288
+ "name": "task_source",
289
+ "type": "text",
290
+ "primaryKey": false,
291
+ "notNull": false,
292
+ "autoincrement": false
293
+ },
294
+ "provider": {
295
+ "name": "provider",
296
+ "type": "text",
297
+ "primaryKey": false,
298
+ "notNull": false,
299
+ "autoincrement": false
300
+ },
301
+ "model": {
302
+ "name": "model",
303
+ "type": "text",
304
+ "primaryKey": false,
305
+ "notNull": false,
306
+ "autoincrement": false
307
+ },
308
+ "started_at": {
309
+ "name": "started_at",
310
+ "type": "text",
311
+ "primaryKey": false,
312
+ "notNull": false,
313
+ "autoincrement": false
314
+ },
315
+ "ended_at": {
316
+ "name": "ended_at",
317
+ "type": "text",
318
+ "primaryKey": false,
319
+ "notNull": false,
320
+ "autoincrement": false
321
+ },
322
+ "verdict": {
323
+ "name": "verdict",
324
+ "type": "text",
325
+ "primaryKey": false,
326
+ "notNull": false,
327
+ "autoincrement": false
328
+ },
329
+ "pr_url": {
330
+ "name": "pr_url",
331
+ "type": "text",
332
+ "primaryKey": false,
333
+ "notNull": false,
334
+ "autoincrement": false
335
+ },
336
+ "pr_draft": {
337
+ "name": "pr_draft",
338
+ "type": "integer",
339
+ "primaryKey": false,
340
+ "notNull": false,
341
+ "autoincrement": false
342
+ },
343
+ "cost_usd": {
344
+ "name": "cost_usd",
345
+ "type": "real",
346
+ "primaryKey": false,
347
+ "notNull": false,
348
+ "autoincrement": false
349
+ },
350
+ "partial_usd": {
351
+ "name": "partial_usd",
352
+ "type": "real",
353
+ "primaryKey": false,
354
+ "notNull": true,
355
+ "autoincrement": false
356
+ },
357
+ "measured_sessions": {
358
+ "name": "measured_sessions",
359
+ "type": "integer",
360
+ "primaryKey": false,
361
+ "notNull": true,
362
+ "autoincrement": false
363
+ },
364
+ "total_sessions": {
365
+ "name": "total_sessions",
366
+ "type": "integer",
367
+ "primaryKey": false,
368
+ "notNull": true,
369
+ "autoincrement": false
370
+ },
371
+ "input_tokens": {
372
+ "name": "input_tokens",
373
+ "type": "integer",
374
+ "primaryKey": false,
375
+ "notNull": true,
376
+ "autoincrement": false
377
+ },
378
+ "output_tokens": {
379
+ "name": "output_tokens",
380
+ "type": "integer",
381
+ "primaryKey": false,
382
+ "notNull": true,
383
+ "autoincrement": false
384
+ },
385
+ "wall_s": {
386
+ "name": "wall_s",
387
+ "type": "real",
388
+ "primaryKey": false,
389
+ "notNull": false,
390
+ "autoincrement": false
391
+ },
392
+ "last_seq": {
393
+ "name": "last_seq",
394
+ "type": "integer",
395
+ "primaryKey": false,
396
+ "notNull": true,
397
+ "autoincrement": false
398
+ },
399
+ "last_event_at": {
400
+ "name": "last_event_at",
401
+ "type": "text",
402
+ "primaryKey": false,
403
+ "notNull": false,
404
+ "autoincrement": false
405
+ },
406
+ "tampered": {
407
+ "name": "tampered",
408
+ "type": "integer",
409
+ "primaryKey": false,
410
+ "notNull": true,
411
+ "autoincrement": false
412
+ },
413
+ "conflict": {
414
+ "name": "conflict",
415
+ "type": "integer",
416
+ "primaryKey": false,
417
+ "notNull": true,
418
+ "autoincrement": false,
419
+ "default": 0
420
+ },
421
+ "group_id": {
422
+ "name": "group_id",
423
+ "type": "text",
424
+ "primaryKey": false,
425
+ "notNull": false,
426
+ "autoincrement": false
427
+ },
428
+ "unit_id": {
429
+ "name": "unit_id",
430
+ "type": "text",
431
+ "primaryKey": false,
432
+ "notNull": false,
433
+ "autoincrement": false
434
+ },
435
+ "attested": {
436
+ "name": "attested",
437
+ "type": "integer",
438
+ "primaryKey": false,
439
+ "notNull": false,
440
+ "autoincrement": false
441
+ },
442
+ "integrity_reasons": {
443
+ "name": "integrity_reasons",
444
+ "type": "text",
445
+ "primaryKey": false,
446
+ "notNull": false,
447
+ "autoincrement": false
448
+ },
449
+ "sig_checked": {
450
+ "name": "sig_checked",
451
+ "type": "integer",
452
+ "primaryKey": false,
453
+ "notNull": false,
454
+ "autoincrement": false
455
+ },
456
+ "integrity_key_fp": {
457
+ "name": "integrity_key_fp",
458
+ "type": "text",
459
+ "primaryKey": false,
460
+ "notNull": false,
461
+ "autoincrement": false
462
+ }
463
+ },
464
+ "indexes": {
465
+ "runs_started": {
466
+ "name": "runs_started",
467
+ "columns": [
468
+ "started_at"
469
+ ],
470
+ "isUnique": false
471
+ },
472
+ "runs_verdict": {
473
+ "name": "runs_verdict",
474
+ "columns": [
475
+ "verdict"
476
+ ],
477
+ "isUnique": false
478
+ },
479
+ "runs_group": {
480
+ "name": "runs_group",
481
+ "columns": [
482
+ "group_id"
483
+ ],
484
+ "isUnique": false
485
+ }
486
+ },
487
+ "foreignKeys": {},
488
+ "compositePrimaryKeys": {
489
+ "runs_source_id_run_id_pk": {
490
+ "columns": [
491
+ "source_id",
492
+ "run_id"
493
+ ],
494
+ "name": "runs_source_id_run_id_pk"
495
+ }
496
+ },
497
+ "uniqueConstraints": {},
498
+ "checkConstraints": {}
499
+ },
500
+ "sources": {
501
+ "name": "sources",
502
+ "columns": {
503
+ "id": {
504
+ "name": "id",
505
+ "type": "text",
506
+ "primaryKey": true,
507
+ "notNull": true,
508
+ "autoincrement": false
509
+ },
510
+ "first_seen": {
511
+ "name": "first_seen",
512
+ "type": "text",
513
+ "primaryKey": false,
514
+ "notNull": true,
515
+ "autoincrement": false
516
+ },
517
+ "last_seen": {
518
+ "name": "last_seen",
519
+ "type": "text",
520
+ "primaryKey": false,
521
+ "notNull": true,
522
+ "autoincrement": false
523
+ }
524
+ },
525
+ "indexes": {},
526
+ "foreignKeys": {},
527
+ "compositePrimaryKeys": {},
528
+ "uniqueConstraints": {},
529
+ "checkConstraints": {}
530
+ }
531
+ },
532
+ "views": {},
533
+ "enums": {},
534
+ "_meta": {
535
+ "schemas": {},
536
+ "tables": {},
537
+ "columns": {}
538
+ },
539
+ "internal": {
540
+ "indexes": {}
541
+ }
542
+ }
@@ -26,9 +26,16 @@
26
26
  {
27
27
  "idx": 3,
28
28
  "version": "6",
29
- "when": 1791132412148,
29
+ "when": 1791049000000,
30
30
  "tag": "0003_integrity",
31
31
  "breakpoints": true
32
+ },
33
+ {
34
+ "idx": 4,
35
+ "version": "6",
36
+ "when": 1791050000000,
37
+ "tag": "0004_cpe03_local_repos_actions",
38
+ "breakpoints": true
32
39
  }
33
40
  ]
34
- }
41
+ }
@@ -12,9 +12,12 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "drizzle-orm": "^0.45.3",
15
- "hono": "^4.13.12"
15
+ "hono": "^4.13.12",
16
+ "yaml": "^2.9.1"
16
17
  },
17
18
  "devDependencies": {
19
+ "@playwright/test": "1.58.1",
20
+ "axe-core": "4.13.0",
18
21
  "drizzle-kit": "^0.31.11"
19
22
  }
20
23
  }
@@ -68,3 +68,22 @@ export const audit = sqliteTable("audit", {
68
68
  actor: text("actor").notNull(),
69
69
  detail: text("detail", { mode: "json" }).notNull(),
70
70
  });
71
+
72
+ // LOCAL-ONLY: written by local discovery (shipper/discover.ts), never by /v1/ingest. realpath is never returned over the API.
73
+ export const localRepos = sqliteTable("local_repos", {
74
+ sourceId: text("source_id").primaryKey(),
75
+ realpath: text("realpath").notNull(),
76
+ name: text("name").notNull(),
77
+ discoveredAt: text("discovered_at").notNull(),
78
+ });
79
+
80
+ // Audit trail of UI-initiated actions (start, stop, retry, resume, answer, config write).
81
+ export const actions = sqliteTable("actions", {
82
+ id: integer("id").primaryKey({ autoIncrement: true }),
83
+ ts: text("ts").notNull(),
84
+ actor: text("actor").notNull(),
85
+ kind: text("kind").notNull(),
86
+ target: text("target"),
87
+ result: text("result").notNull(),
88
+ detail: text("detail"),
89
+ }, (t) => [index("actions_ts").on(t.ts)]);
@@ -5,10 +5,13 @@ import { openDb } from "../db/migrate.ts";
5
5
  import { ingest } from "./ingest.ts";
6
6
  import { defaultAnswerDir, writeAnswer } from "./answer.ts";
7
7
  import { listRuns, recomputeLegacy, runDetail } from "./runs.ts";
8
- import { hostGuard, isLoopbackHost, tokenGuard } from "./auth.ts";
8
+ import { hostGuard, isLoopbackHost, peerIsLoopback, tokenGuard } from "./auth.ts";
9
9
  import { backfill } from "../shipper/backfill.ts";
10
10
  import { removeRun } from "../db/prune.ts";
11
- import { planStart, registryRepos, spawnStart } from "./actions.ts";
11
+ import type { spawnStart } from "./spawn.ts";
12
+ import { syncLocalRepos } from "./repos.ts";
13
+ import { registerRoutes } from "./routes/index.ts";
14
+ import { legacyShim } from "./legacy/shim.ts";
12
15
 
13
16
  const MAX_BODY = 1_000_000;
14
17
 
@@ -73,13 +76,8 @@ export function createApp(opts: { dbPath: string; uiDir?: string; answerDir?: st
73
76
  // Machine-touching actions exist ONLY on a loopback-bound server (otherwise they are never registered: 404).
74
77
  // Each request must also come from a loopback peer (the real socket address, not the spoofable Host header; unknown peer fails closed) and carry JSON (blocks cross-site form posts).
75
78
  const act = opts.loopbackOnly ? app : new Hono();
76
- const peerIsLoopback = (c: Context): boolean => {
77
- const ip = (c.env as { requestIP?: (r: Request) => { address?: string } | null } | undefined)?.requestIP?.(c.req.raw)?.address;
78
- return typeof ip === "string" && /^(127\.\d+\.\d+\.\d+|::1|::ffff:127\.\d+\.\d+\.\d+)$/.test(ip);
79
- };
80
79
  const local = (c: Context) => peerIsLoopback(c) && isLoopbackHost(c.req.header("host")) && (c.req.header("content-type") ?? "").toLowerCase().startsWith("application/json");
81
80
  const repoDir = opts.repoDir ?? process.cwd();
82
- const inflight = new Set<string>();
83
81
  act.post("/v1/import", async (c) => {
84
82
  if (!local(c)) return c.json({ error: "loopback JSON requests only" }, 403);
85
83
  const r = await backfill({
@@ -106,21 +104,9 @@ export function createApp(opts: { dbPath: string; uiDir?: string; answerDir?: st
106
104
  const left = (sqlite.query("select count(*) n from runs").get() as { n: number }).n;
107
105
  return c.json({ ok: true, removed: r, remaining_runs: left });
108
106
  });
109
- act.get("/v1/repos", (c) => peerIsLoopback(c) ? c.json({ repos: [...new Set<string>([repoDir, ...registryRepos()])] }) : c.json({ error: "loopback only" }, 403));
110
- act.post("/v1/start", async (c) => {
111
- if (!local(c)) return c.json({ error: "loopback JSON requests only" }, 403);
112
- const text = await c.req.text();
113
- if (text.length > 20_000) return c.json({ error: "body too large" }, 413);
114
- let body: unknown;
115
- try { body = JSON.parse(text); } catch { return c.json({ error: "invalid JSON" }, 400); }
116
- const plan = planStart(body, [repoDir, ...registryRepos()], opts.startBin);
117
- if (!plan.ok) return c.json({ error: plan.error }, 400);
118
- if (inflight.has(plan.cwd)) return c.json({ error: "a run is already starting or running in this repo" }, 409);
119
- inflight.add(plan.cwd);
120
- const r = await (opts.spawnImpl ?? spawnStart)(plan.argv, plan.cwd, () => inflight.delete(plan.cwd));
121
- if ("error" in r) { inflight.delete(plan.cwd); return c.json({ error: r.error }, 500); }
122
- return c.json({ ok: true, pid: r.pid, command: plan.argv.slice(1).join(" ") });
123
- });
107
+ // Local discovery fills local_repos (never /v1/ingest). GET /v1/repos (names only, loopback guard) is mounted by routes/index.ts.
108
+ syncLocalRepos(db, repoDir);
109
+ registerRoutes({ app, act, db, repoDir, token: opts.token, peerIsLoopback, local, startBin: opts.startBin, spawnImpl: opts.spawnImpl, answerDir });
124
110
  // :id is `source:run` (run ids never contain a colon)
125
111
  app.get("/v1/runs/:id", (c) => {
126
112
  const id = c.req.param("id");
@@ -128,6 +114,9 @@ export function createApp(opts: { dbPath: string; uiDir?: string; answerDir?: st
128
114
  return i < 0 ? c.json({ error: "id must be source:run" }, 404) : detail(c, id.slice(0, i), id.slice(i + 1));
129
115
  });
130
116
 
117
+ // Legacy dashboard paths (CPE-24) are answered by the shim; mounted before the SPA fallback so index.html never shadows them.
118
+ app.route("/", legacyShim({ db, token: opts.token, repoDir }));
119
+
131
120
  // Static UI with SPA fallback. Registered last so /v1, /health and /ready always win.
132
121
  app.get("*", (c) => {
133
122
  let p: string;