@loom-framework/core 0.1.0-alpha.153 → 0.1.0-alpha.155

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 (94) hide show
  1. package/builtin-skills/app-skill/SKILL.md +6 -2
  2. package/builtin-skills/app-skill/references/notification.md +123 -0
  3. package/builtin-skills/app-skill/references/process-builder.md +38 -0
  4. package/builtin-skills/app-skill/references/process.md +72 -4
  5. package/dist/backend/ai/engine.d.ts.map +1 -1
  6. package/dist/backend/ai/engine.js +27 -6
  7. package/dist/backend/ai/engine.js.map +1 -1
  8. package/dist/backend/auth/rbac.d.ts +2 -0
  9. package/dist/backend/auth/rbac.d.ts.map +1 -1
  10. package/dist/backend/auth/rbac.js +4 -0
  11. package/dist/backend/auth/rbac.js.map +1 -1
  12. package/dist/backend/index.d.ts +4 -0
  13. package/dist/backend/index.d.ts.map +1 -1
  14. package/dist/backend/index.js +48 -1
  15. package/dist/backend/index.js.map +1 -1
  16. package/dist/backend/notifications/interpolate.d.ts +6 -0
  17. package/dist/backend/notifications/interpolate.d.ts.map +1 -0
  18. package/dist/backend/notifications/interpolate.js +11 -0
  19. package/dist/backend/notifications/interpolate.js.map +1 -0
  20. package/dist/backend/notifications/notification-storage.d.ts +25 -0
  21. package/dist/backend/notifications/notification-storage.d.ts.map +1 -0
  22. package/dist/backend/notifications/notification-storage.js +158 -0
  23. package/dist/backend/notifications/notification-storage.js.map +1 -0
  24. package/dist/backend/process/engine.d.ts +18 -0
  25. package/dist/backend/process/engine.d.ts.map +1 -1
  26. package/dist/backend/process/engine.js +65 -0
  27. package/dist/backend/process/engine.js.map +1 -1
  28. package/dist/backend/process/metrics-store.d.ts +30 -0
  29. package/dist/backend/process/metrics-store.d.ts.map +1 -0
  30. package/dist/backend/process/metrics-store.js +106 -0
  31. package/dist/backend/process/metrics-store.js.map +1 -0
  32. package/dist/backend/process/queue.d.ts +2 -0
  33. package/dist/backend/process/queue.d.ts.map +1 -1
  34. package/dist/backend/process/queue.js +14 -0
  35. package/dist/backend/process/queue.js.map +1 -1
  36. package/dist/backend/routes/auth-routes.js +2 -2
  37. package/dist/backend/routes/auth-routes.js.map +1 -1
  38. package/dist/backend/routes/index.d.ts +2 -0
  39. package/dist/backend/routes/index.d.ts.map +1 -1
  40. package/dist/backend/routes/index.js +1 -0
  41. package/dist/backend/routes/index.js.map +1 -1
  42. package/dist/backend/routes/notification-routes.d.ts +22 -0
  43. package/dist/backend/routes/notification-routes.d.ts.map +1 -0
  44. package/dist/backend/routes/notification-routes.js +128 -0
  45. package/dist/backend/routes/notification-routes.js.map +1 -0
  46. package/dist/backend/routes/process-routes.d.ts.map +1 -1
  47. package/dist/backend/routes/process-routes.js +67 -1
  48. package/dist/backend/routes/process-routes.js.map +1 -1
  49. package/dist/cli/commands/generate-notification.d.ts +9 -0
  50. package/dist/cli/commands/generate-notification.d.ts.map +1 -0
  51. package/dist/cli/commands/generate-notification.js +24 -0
  52. package/dist/cli/commands/generate-notification.js.map +1 -0
  53. package/dist/cli/commands/init.js +6 -1
  54. package/dist/cli/commands/init.js.map +1 -1
  55. package/dist/cli/commands/notification.d.ts +8 -0
  56. package/dist/cli/commands/notification.d.ts.map +1 -0
  57. package/dist/cli/commands/notification.js +175 -0
  58. package/dist/cli/commands/notification.js.map +1 -0
  59. package/dist/cli/commands/process.d.ts.map +1 -1
  60. package/dist/cli/commands/process.js +147 -0
  61. package/dist/cli/commands/process.js.map +1 -1
  62. package/dist/cli/generators/capability-generator.d.ts.map +1 -1
  63. package/dist/cli/generators/capability-generator.js +85 -2
  64. package/dist/cli/generators/capability-generator.js.map +1 -1
  65. package/dist/cli/helpers/app-tsx-wiring.d.ts +11 -0
  66. package/dist/cli/helpers/app-tsx-wiring.d.ts.map +1 -1
  67. package/dist/cli/helpers/app-tsx-wiring.js +113 -0
  68. package/dist/cli/helpers/app-tsx-wiring.js.map +1 -1
  69. package/dist/cli/index.d.ts.map +1 -1
  70. package/dist/cli/index.js +2 -0
  71. package/dist/cli/index.js.map +1 -1
  72. package/dist/cli/templates/process-management-page.d.ts.map +1 -1
  73. package/dist/cli/templates/process-management-page.js +143 -30
  74. package/dist/cli/templates/process-management-page.js.map +1 -1
  75. package/dist/config.d.ts +128 -0
  76. package/dist/config.d.ts.map +1 -1
  77. package/dist/config.js +10 -0
  78. package/dist/config.js.map +1 -1
  79. package/dist/index.d.ts +2 -1
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js.map +1 -1
  82. package/dist/types/ai.d.ts +6 -0
  83. package/dist/types/ai.d.ts.map +1 -1
  84. package/dist/types/event.d.ts +18 -4
  85. package/dist/types/event.d.ts.map +1 -1
  86. package/dist/types/index.d.ts +1 -0
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/dist/types/notification.d.ts +31 -0
  89. package/dist/types/notification.d.ts.map +1 -0
  90. package/dist/types/notification.js +5 -0
  91. package/dist/types/notification.js.map +1 -0
  92. package/dist/types/process.d.ts +43 -1
  93. package/dist/types/process.d.ts.map +1 -1
  94. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
  name: {{projectName}}
3
3
  description: |
4
4
  ⚠️ TODO: 根据下方 [TODO] 标记补全触发短语。阅读 references/models.md 中的数据模型和 AI 按钮定义,
5
- 编写触发短语,包含:用户语言中的常见增删改查动词、各数据模型相关的操作、AI 按钮的标签<!-- AUTH_DESC --><!-- EVENTS_DESC --><!-- PROCESS_DESC -->
5
+ 编写触发短语,包含:用户语言中的常见增删改查动词、各数据模型相关的操作、AI 按钮的标签<!-- AUTH_DESC --><!-- EVENTS_DESC --><!-- PROCESS_DESC --><!-- NOTIFICATION_DESC -->
6
6
  格式:"This skill should be used when the user asks to '短语1', '短语2',
7
7
  or any request about <此项目管理的内容> in the {{projectName}} project."
8
8
  version: 1.0.0
@@ -19,6 +19,7 @@ version: 1.0.0
19
19
  <!-- AUTH_OVERVIEW -->
20
20
  <!-- EVENTS_OVERVIEW -->
21
21
  <!-- PROCESS_OVERVIEW -->
22
+ <!-- NOTIFICATION_OVERVIEW -->
22
23
 
23
24
  ## Usage Scenarios
24
25
 
@@ -27,11 +28,13 @@ version: 1.0.0
27
28
  - data-semantics.md — 当前项目的数据模型名称列表、write 的 --data JSON 构造规则(字段类型格式、enum 取值约束、贴合业务的真实示例值)、read 的 --filter JSON 构造规则(优先用 enum/boolean 字段筛选、跨模型关联查询)。
28
29
  <!-- AUTH_SCENARIOS_LOAD -->
29
30
  <!-- PROCESS_SCENARIOS_LOAD -->
31
+ <!-- NOTIFICATION_SCENARIOS_LOAD -->
30
32
 
31
33
  [TODO: 生成5-10个典型用户请求,每个格式:用户说的话 → 对应的 `loom data` CLI 命令。每个数据模型至少包含一个场景。]
32
34
  <!-- AUTH_SCENARIOS -->
33
35
  <!-- EVENTS_SCENARIOS -->
34
36
  <!-- PROCESS_SCENARIOS -->
37
+ <!-- NOTIFICATION_SCENARIOS -->
35
38
 
36
39
  ## Technical Reference
37
40
 
@@ -40,4 +43,5 @@ version: 1.0.0
40
43
  - 语义引导(示例数据生成、筛选选择、关系推断):**references/data-semantics.md**
41
44
  <!-- AUTH_REF -->
42
45
  <!-- EVENTS_REF -->
43
- <!-- PROCESS_REF -->
46
+ <!-- PROCESS_REF -->
47
+ <!-- NOTIFICATION_REF -->
@@ -0,0 +1,123 @@
1
+ # Notification Commands Reference
2
+
3
+ ## Overview
4
+
5
+ Loom provides a built-in notification system for persistent server-side notifications. Notifications are user-scoped and support CRUD operations via both HTTP API and CLI.
6
+
7
+ ## CLI Commands
8
+
9
+ ### List notifications
10
+ ```bash
11
+ loom notification list [--unread] [--limit 20] [--offset 0] --token <TOKEN>
12
+ ```
13
+
14
+ ### Mark as read
15
+ ```bash
16
+ loom notification read <id> --token <TOKEN>
17
+ ```
18
+
19
+ ### Mark all as read
20
+ ```bash
21
+ loom notification read-all --token <TOKEN>
22
+ ```
23
+
24
+ ### Delete notification
25
+ ```bash
26
+ loom notification delete <id> --token <TOKEN>
27
+ ```
28
+
29
+ ### Clear all notifications
30
+ ```bash
31
+ loom notification clear --token <TOKEN>
32
+ ```
33
+
34
+ ### Send notification (admin only)
35
+ ```bash
36
+ loom notification send --userId <userId> --type <type> --title <title> [--description DESC] --token <TOKEN>
37
+ ```
38
+
39
+ ## HTTP API
40
+
41
+ | Method | Path | Auth | Permission | Description |
42
+ |--------|------|------|------------|-------------|
43
+ | GET | `/api/v1/notifications` | Required | Own only | List (paginated) |
44
+ | GET | `/api/v1/notifications/unread-count` | Required | Own only | Unread count |
45
+ | PUT | `/api/v1/notifications/:id/read` | Required | Own only | Mark read |
46
+ | PUT | `/api/v1/notifications/read-all` | Required | Own only | Mark all read |
47
+ | DELETE | `/api/v1/notifications/:id` | Required | Own only | Delete single |
48
+ | DELETE | `/api/v1/notifications` | Required | Own only | Clear all |
49
+ | POST | `/api/v1/notifications` | Required | Admin | Create notification |
50
+
51
+ ## Notification Types
52
+
53
+ - `success` — Green, operation completed successfully
54
+ - `error` — Red, operation failed
55
+ - `warning` — Orange, attention needed
56
+ - `info` — Blue, informational
57
+
58
+ ## Source Types
59
+
60
+ - `system` — Generated by Loom framework
61
+ - `event` — Generated by EventBus subscription
62
+ - `cli` — Created via CLI command
63
+
64
+ ## EventBus notify Handler
65
+
66
+ Configure automatic notification generation from events in `loom.config.ts`:
67
+
68
+ ```typescript
69
+ export default defineConfig({
70
+ events: {
71
+ subscriptions: [
72
+ {
73
+ pattern: 'data:create:orders',
74
+ handler: 'notify',
75
+ config: {
76
+ type: 'success',
77
+ title: 'New Order Created',
78
+ description: 'Order {{id}} created in orders model',
79
+ },
80
+ },
81
+ {
82
+ pattern: 'user:login',
83
+ handler: 'notify',
84
+ config: {
85
+ type: 'info',
86
+ title: 'User Logged In',
87
+ broadcastAll: true,
88
+ },
89
+ },
90
+ ],
91
+ },
92
+ });
93
+ ```
94
+
95
+ ### Config Options
96
+
97
+ | Field | Type | Required | Description |
98
+ |-------|------|----------|-------------|
99
+ | `type` | `'success' \| 'error' \| 'warning' \| 'info'` | Yes | Notification severity |
100
+ | `title` | `string` | Yes | Notification title (supports `{{var}}` interpolation) |
101
+ | `description` | `string` | No | Notification body (supports `{{var}}` interpolation) |
102
+ | `broadcastAll` | `boolean` | No | Broadcast to all users when event has no userId (default: false) |
103
+
104
+ ### Interpolation
105
+
106
+ Title and description support `{{var}}` interpolation from event payload:
107
+ - `{{id}}` — Record ID
108
+ - `{{model}}` — Model name
109
+ - Any field from the event payload
110
+
111
+ Missing variables are replaced with empty string.
112
+
113
+ ### Behavior
114
+
115
+ - If event has `userId`: notification sent to that user only
116
+ - If event has no `userId` and `broadcastAll: true`: sent to all users (capped at 100)
117
+ - If event has no `userId` and `broadcastAll: false` (default): notification is skipped
118
+
119
+ ## Permissions
120
+
121
+ - Users can only read/modify their own notifications
122
+ - Only admin users can create notifications for other users via POST API or `loom notification send`
123
+ - Notifications are auto-pruned after 30 days or when exceeding 500 items
@@ -63,6 +63,9 @@ loom process add --name "weekly-report" \
63
63
  --cron "0 9 * * 1" \
64
64
  --process "weekly-report" \
65
65
  --owner admin
66
+
67
+ # Step 5: Initialize metrics view config (if PROCESS.md has ## Metrics section)
68
+ loom process init-metrics weekly-report
66
69
  ```
67
70
 
68
71
  ### 4. Verify
@@ -117,6 +120,41 @@ How this process should improve:
117
120
  - Use `loom data` commands for data operations, not direct file I/O
118
121
  - Include error handling in Decision Points
119
122
 
123
+ ## Metrics Definition
124
+
125
+ When defining `## Metrics` in PROCESS.md, follow these guidelines so the system can properly track and visualize them:
126
+
127
+ ### Format
128
+
129
+ Each metric should include:
130
+ - **Name**: A clear, concise identifier (e.g., "错题 review 率")
131
+ - **Meaning**: What this metric measures and why it matters
132
+ - **Direction**: Whether the metric should increase, decrease, or approach a target
133
+ - `increasing` = higher is better (e.g., success rate)
134
+ - `decreasing` = lower is better (e.g., error count)
135
+ - `target` = should approach a specific value (e.g., 100% coverage)
136
+ - **Target** (optional): The goal value
137
+ - **Unit** (optional): Measurement unit (e.g., "%", "条", "次")
138
+
139
+ ### Example
140
+
141
+ ```markdown
142
+ ## Metrics
143
+
144
+ - **错题 review 率**: 每次触发后,是否成功将错题写入 review_plans。方向:趋近目标值。目标:100%。单位:%。
145
+ - **错题重复出现率**: 统计相同错误模式的错题数量趋势。方向:越低越好。单位:条。
146
+ ```
147
+
148
+ ### After Registration
149
+
150
+ After registering a full process with `--process`, initialize the metrics view config:
151
+
152
+ ```bash
153
+ loom process init-metrics <name>
154
+ ```
155
+
156
+ This reads the `## Metrics` section and generates dashboard chart configuration. If you modify the metrics later, re-run with `--force` to regenerate.
157
+
120
158
  ## Common Cron Patterns
121
159
 
122
160
  | Pattern | Schedule |
@@ -153,6 +153,72 @@ Create PROCESS.md scaffold directory (for full process mode). Called by AI, not
153
153
  loom process generate daily-report --description "Daily report generator"
154
154
  ```
155
155
 
156
+ ### `loom process metrics-report <name>`
157
+
158
+ Report a business metric snapshot. Used by AI agent during process execution.
159
+
160
+ ```bash
161
+ # Basic report
162
+ loom process metrics-report my-process --metric-name "成功率" --value 0.95 --unit "%"
163
+
164
+ # With target and dimensions
165
+ loom process metrics-report my-process \
166
+ --metric-name "错题重复率" \
167
+ --value 3 \
168
+ --unit "条" \
169
+ --target 0 \
170
+ --dimensions '{"subject":"数学"}' \
171
+ --run-id $LOOM_RUN_ID
172
+ ```
173
+
174
+ **Options:**
175
+ | Flag | Required | Description |
176
+ |------|----------|-------------|
177
+ | `--metric-name` | Yes | Human-readable metric name |
178
+ | `--value` | Yes | Numeric metric value |
179
+ | `--run-id` | No | Run ID (defaults to LOOM_RUN_ID env var) |
180
+ | `--timestamp` | No | ISO timestamp (defaults to now) |
181
+ | `--dimensions` | No | Dimension labels as JSON |
182
+ | `--target` | No | Target value for goal-line |
183
+ | `--unit` | No | Unit label (e.g., "%", "条") |
184
+ | `--token` | No | Auth token (or set LOOM_TOKEN) |
185
+ | `--server` | No | Server URL (or set LOOM_SERVER) |
186
+
187
+ ### `loom process metrics-set-view-config <name>`
188
+
189
+ Set or update the business metrics view configuration (G2 chart specs).
190
+
191
+ ```bash
192
+ # From JSON string
193
+ loom process metrics-set-view-config my-process --config '{"version":1,"metrics":[...],"charts":[...]}'
194
+
195
+ # From file
196
+ loom process metrics-set-view-config my-process --config @./view-config.json
197
+ ```
198
+
199
+ **Options:**
200
+ | Flag | Required | Description |
201
+ |------|----------|-------------|
202
+ | `--config` | Yes | View config JSON (use @file to read from file) |
203
+ | `--token` | No | Auth token (or set LOOM_TOKEN) |
204
+ | `--server` | No | Server URL (or set LOOM_SERVER) |
205
+
206
+ ### `loom process init-metrics <name>`
207
+
208
+ Initialize the metrics view config from PROCESS.md's `## Metrics` section. Run after `loom process add`.
209
+
210
+ ```bash
211
+ loom process init-metrics my-process
212
+ loom process init-metrics my-process --force # Overwrite existing config
213
+ ```
214
+
215
+ **Options:**
216
+ | Flag | Required | Description |
217
+ |------|----------|-------------|
218
+ | `--force` | No | Overwrite existing view config |
219
+ | `--token` | No | Auth token (or set LOOM_TOKEN) |
220
+ | `--server` | No | Server URL (or set LOOM_SERVER) |
221
+
156
222
  ### `loom process export <name>`
157
223
 
158
224
  Export process definition as JSON.
@@ -208,10 +274,12 @@ When auth is enabled, processes need a service token to operate:
208
274
 
209
275
  1. Trigger fires → entry enqueued
210
276
  2. Queue slot available → process starts
211
- 3. AI prompt built (PROCESS.md + references + event context)
212
- 4. Claude Code engine executes with timeout
213
- 5. Result logged to `.loom/process-logs/{name}/{runId}.json`
214
- 6. Event emitted: `process:started`, `process:completed`, or `process:failed`
277
+ 3. AI prompt built (PROCESS.md + references + event context + metrics protocol)
278
+ 4. Claude Code engine executes with timeout, env vars injected: LOOM_SERVER, LOOM_PROCESS_NAME, LOOM_RUN_ID
279
+ 5. Agent may call `loom process metrics-report` to report business metrics during execution
280
+ 6. Result logged to `.loom/process-logs/{name}/{runId}.json`
281
+ 7. Metric snapshots stored in `.loom/process-metrics/{name}/metrics.jsonl`
282
+ 8. Event emitted: `process:started`, `process:completed`, or `process:failed`
215
283
 
216
284
  ## Concurrency
217
285
 
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/backend/ai/engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAM5F,wCAAwC;AACxC,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,cAAc,GAAG,iBAAiB,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEnH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAE3D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,QAAQ;IAC/C,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,MAAM,CAAC,CAAe;gBAElB,OAAO,EAAE,uBAAuB;IAM5C,OAAO,CAAC,GAAG;IAUX;;OAEG;IACI,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,cAAc,CAAC,OAAO,CAAC;IAoJ5E;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAUvC;;OAEG;IACH,OAAO,IAAI,IAAI;CAQhB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAC5C,MAAM,CAQR"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/backend/ai/engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAM5F,wCAAwC;AACxC,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,cAAc,GAAG,iBAAiB,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEnH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AAE3D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,QAAQ;IAC/C,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,MAAM,CAAC,CAAe;gBAElB,OAAO,EAAE,uBAAuB;IAM5C,OAAO,CAAC,GAAG;IAUX;;OAEG;IACI,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,cAAc,CAAC,OAAO,CAAC;IA2K5E;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAUvC;;OAEG;IACH,OAAO,IAAI,IAAI;CAQhB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAC5C,MAAM,CAQR"}
@@ -7,8 +7,8 @@
7
7
  import { spawn } from 'child_process';
8
8
  import path from 'path';
9
9
  import { parseClaudeOutput } from './output-parser.js';
10
- /** Default timeout for Claude Code processes (2 minutes) */
11
- const DEFAULT_PROCESS_TIMEOUT_MS = 120_000;
10
+ /** Default timeout for Claude Code processes (60 minutes) */
11
+ const DEFAULT_PROCESS_TIMEOUT_MS = 3_600_000;
12
12
  /**
13
13
  * ClaudeCodeEngine - Spawns Claude Code in headless mode
14
14
  *
@@ -93,6 +93,9 @@ export class ClaudeCodeEngine {
93
93
  ...process.env,
94
94
  CLAUDE_PLUGIN_ROOT: pluginRoot,
95
95
  ...(options.userToken ? { LOOM_TOKEN: options.userToken } : {}),
96
+ ...(options.serverUrl ? { LOOM_SERVER: options.serverUrl } : {}),
97
+ ...(options.processName ? { LOOM_PROCESS_NAME: options.processName } : {}),
98
+ ...(options.runId ? { LOOM_RUN_ID: options.runId } : {}),
96
99
  },
97
100
  });
98
101
  // Track active process for cleanup
@@ -105,12 +108,23 @@ export class ClaudeCodeEngine {
105
108
  this.log('STDERR', options.sessionId, text.trim());
106
109
  });
107
110
  // Wait for process completion with timeout
111
+ // Track error separately to prevent unhandled rejection when generator consumer
112
+ // (e.g. SSE route) has already stopped reading due to client disconnect.
113
+ let completionError;
108
114
  let timeoutHandle;
109
- const completionPromise = new Promise((resolve, reject) => {
115
+ const completionPromise = new Promise((resolve) => {
116
+ const fail = (err) => {
117
+ completionError = err;
118
+ // Do NOT reject the promise — this prevents unhandled rejection
119
+ // when the generator consumer (SSE route) has already returned.
120
+ // The error is captured in completionError and yielded as an error chunk.
121
+ resolve();
122
+ };
110
123
  timeoutHandle = setTimeout(() => {
111
124
  childProcess.kill('SIGTERM');
112
125
  setTimeout(() => childProcess.kill('SIGKILL'), 5_000);
113
- reject(new Error(`Claude Code process timed out after ${timeout}ms`));
126
+ this.log('PROCESS_EXIT', options.sessionId, `Process timed out after ${timeout}ms`);
127
+ fail(new Error(`Claude Code process timed out after ${timeout}ms`));
114
128
  }, timeout);
115
129
  childProcess.on('close', (code) => {
116
130
  if (timeoutHandle)
@@ -125,7 +139,7 @@ export class ClaudeCodeEngine {
125
139
  if (timeoutHandle)
126
140
  clearTimeout(timeoutHandle);
127
141
  this.activeProcesses.delete(options.sessionId);
128
- reject(err);
142
+ fail(err);
129
143
  });
130
144
  });
131
145
  // Send prompt via stdin then close
@@ -163,8 +177,15 @@ export class ClaudeCodeEngine {
163
177
  error: error instanceof Error ? error.message : String(error),
164
178
  };
165
179
  }
166
- // Wait for process completion with timeout
180
+ // Wait for process completion (safe — never rejects, error captured in completionError)
167
181
  await completionPromise;
182
+ // Yield timeout/exit error if process didn't finish cleanly
183
+ if (completionError) {
184
+ yield {
185
+ type: 'error',
186
+ error: completionError.message,
187
+ };
188
+ }
168
189
  yield { type: 'done' };
169
190
  }
170
191
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/backend/ai/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/backend/ai/engine.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,8 @@ export declare function getRequiredLevel(method: string, config: AuthConfig): Au
15
15
  export declare function resolvePermission(model: string, roleName: string, config: AuthConfig): AuthPermissionLevel;
16
16
  /** Check if user level meets required level */
17
17
  export declare function hasPermission(userLevel: AuthPermissionLevel, requiredLevel: AuthPermissionLevel): boolean;
18
+ /** Check if a role has admin-level wildcard permission */
19
+ export declare function isAdmin(role: string, config: AuthConfig): boolean;
18
20
  /** Extend FastifyRequest with user info */
19
21
  declare module 'fastify' {
20
22
  interface FastifyRequest {
@@ -1 +1 @@
1
- {"version":3,"file":"rbac.d.ts","sourceRoot":"","sources":["../../../src/backend/auth/rbac.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAwB,MAAM,qBAAqB,CAAC;AAoBjG,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,mBAAmB,CAOxF;AASD,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,GACjB,mBAAmB,CAcrB;AAED,+CAA+C;AAC/C,wBAAgB,aAAa,CAAC,SAAS,EAAE,mBAAmB,EAAE,aAAa,EAAE,mBAAmB,GAAG,OAAO,CAEzG;AAED,2CAA2C;AAC3C,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,IAAI,CAAC,EAAE;YACL,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;YACjB,IAAI,EAAE,MAAM,CAAC;YACb,mFAAmF;YACnF,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;KACH;CACF;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,IAGnD,SAAS,cAAc,EAAE,OAAO,YAAY,mBA8D3D"}
1
+ {"version":3,"file":"rbac.d.ts","sourceRoot":"","sources":["../../../src/backend/auth/rbac.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAwB,MAAM,qBAAqB,CAAC;AAoBjG,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,mBAAmB,CAOxF;AASD,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,GACjB,mBAAmB,CAcrB;AAED,+CAA+C;AAC/C,wBAAgB,aAAa,CAAC,SAAS,EAAE,mBAAmB,EAAE,aAAa,EAAE,mBAAmB,GAAG,OAAO,CAEzG;AAED,0DAA0D;AAC1D,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAEjE;AAED,2CAA2C;AAC3C,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,IAAI,CAAC,EAAE;YACL,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;YACjB,IAAI,EAAE,MAAM,CAAC;YACb,mFAAmF;YACnF,KAAK,CAAC,EAAE,MAAM,CAAC;SAChB,CAAC;KACH;CACF;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,IAGnD,SAAS,cAAc,EAAE,OAAO,YAAY,mBA8D3D"}
@@ -58,6 +58,10 @@ export function resolvePermission(model, roleName, config) {
58
58
  export function hasPermission(userLevel, requiredLevel) {
59
59
  return LEVEL_HIERARCHY[userLevel] >= LEVEL_HIERARCHY[requiredLevel];
60
60
  }
61
+ /** Check if a role has admin-level wildcard permission */
62
+ export function isAdmin(role, config) {
63
+ return hasPermission(resolvePermission('*', role, config), 'admin');
64
+ }
61
65
  export function createAuthMiddleware(options) {
62
66
  const { config } = options;
63
67
  return async (request, reply) => {
@@ -1 +1 @@
1
- {"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../../src/backend/auth/rbac.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../../src/backend/auth/rbac.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,7 @@ import { TokenStore } from './auth/token-store.js';
16
16
  import { EventBus } from './events/event-bus.js';
17
17
  import { EventRegistry } from './events/event-registry.js';
18
18
  import { ProcessEngine } from './process/engine.js';
19
+ import { NotificationStorage } from './notifications/notification-storage.js';
19
20
  export interface LoomServerOptions {
20
21
  /** Project root directory containing loom.config.ts */
21
22
  projectRoot: string;
@@ -40,6 +41,7 @@ export declare class LoomServer {
40
41
  private eventBus?;
41
42
  private eventRegistry?;
42
43
  private processEngine?;
44
+ private notificationStorage?;
43
45
  private projectRoot;
44
46
  private options;
45
47
  constructor(options: LoomServerOptions);
@@ -71,6 +73,8 @@ export declare class LoomServer {
71
73
  getEventRegistry(): EventRegistry | undefined;
72
74
  /** Expose process engine for testing */
73
75
  getProcessEngine(): ProcessEngine | undefined;
76
+ /** Expose notification storage for testing */
77
+ getNotificationStorage(): NotificationStorage | undefined;
74
78
  }
75
79
  /**
76
80
  * Create and start a LoomServer from a project root
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAM9B,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUvD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,kEAAkE;IAClE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,qEAAqE;IACrE,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,mBAAmB;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAoB;gBAEvB,OAAO,EAAE,iBAAiB;IAKtC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAyPjC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,0CAA0C;IAC1C,UAAU,IAAI,UAAU,CAAC,OAAO,OAAO,CAAC;IAIxC,gCAAgC;IAChC,SAAS,IAAI,UAAU;IAIvB,iCAAiC;IACjC,UAAU,IAAI,WAAW;IAIzB,oCAAoC;IACpC,YAAY,IAAI,SAAS,GAAG,SAAS;IAIrC,qCAAqC;IACrC,aAAa,IAAI,UAAU,GAAG,SAAS;IAIvC,mCAAmC;IACnC,WAAW,IAAI,QAAQ,GAAG,SAAS;IAInC,wCAAwC;IACxC,gBAAgB,IAAI,aAAa,GAAG,SAAS;IAI7C,wCAAwC;IACxC,gBAAgB,IAAI,aAAa,GAAG,SAAS;CAG9C;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAK1E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAM9B,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUvD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAI9E,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,kEAAkE;IAClE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,qEAAqE;IACrE,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,mBAAmB;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,mBAAmB,CAAC,CAAsB;IAClD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAoB;gBAEvB,OAAO,EAAE,iBAAiB;IAKtC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoSjC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,0CAA0C;IAC1C,UAAU,IAAI,UAAU,CAAC,OAAO,OAAO,CAAC;IAIxC,gCAAgC;IAChC,SAAS,IAAI,UAAU;IAIvB,iCAAiC;IACjC,UAAU,IAAI,WAAW;IAIzB,oCAAoC;IACpC,YAAY,IAAI,SAAS,GAAG,SAAS;IAIrC,qCAAqC;IACrC,aAAa,IAAI,UAAU,GAAG,SAAS;IAIvC,mCAAmC;IACnC,WAAW,IAAI,QAAQ,GAAG,SAAS;IAInC,wCAAwC;IACxC,gBAAgB,IAAI,aAAa,GAAG,SAAS;IAI7C,wCAAwC;IACxC,gBAAgB,IAAI,aAAa,GAAG,SAAS;IAI7C,8CAA8C;IAC9C,sBAAsB,IAAI,mBAAmB,GAAG,SAAS;CAG1D;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAK1E"}
@@ -16,7 +16,7 @@ import { createAdapter } from '../adapters/factory.js';
16
16
  import { ClaudeCodeEngine } from './ai/engine.js';
17
17
  import { SessionManager } from './ai/session-manager.js';
18
18
  import { AIInteractionLogger } from './observe/index.js';
19
- import { registerDataRoutes, registerHealthRoute, registerUploadRoutes, registerChatRoutes, registerSkillRoutes, registerAIConfigRoutes, registerAuthRoutes, registerEventRoutes, registerProcessRoutes } from './routes/index.js';
19
+ import { registerDataRoutes, registerHealthRoute, registerUploadRoutes, registerChatRoutes, registerSkillRoutes, registerAIConfigRoutes, registerAuthRoutes, registerEventRoutes, registerProcessRoutes, registerNotificationRoutes } from './routes/index.js';
20
20
  import { createAuthMiddleware } from './auth/rbac.js';
21
21
  import { issueServiceToken } from './auth/service-token.js';
22
22
  import { UserStore } from './auth/user-store.js';
@@ -26,6 +26,8 @@ import { EventBus } from './events/event-bus.js';
26
26
  import { EventEmittingAdapter } from './events/event-emitting-adapter.js';
27
27
  import { EventRegistry } from './events/event-registry.js';
28
28
  import { ProcessEngine } from './process/engine.js';
29
+ import { NotificationStorage } from './notifications/notification-storage.js';
30
+ import { interpolate } from './notifications/interpolate.js';
29
31
  export class LoomServer {
30
32
  config;
31
33
  engine;
@@ -38,6 +40,7 @@ export class LoomServer {
38
40
  eventBus;
39
41
  eventRegistry;
40
42
  processEngine;
43
+ notificationStorage;
41
44
  projectRoot;
42
45
  options;
43
46
  constructor(options) {
@@ -164,6 +167,16 @@ export class LoomServer {
164
167
  projectRoot: this.projectRoot,
165
168
  modelNames: this.config.data.models.map(m => m.name),
166
169
  });
170
+ // Notification system initialization
171
+ this.notificationStorage = new NotificationStorage(this.projectRoot);
172
+ await this.notificationStorage.initialize();
173
+ registerNotificationRoutes(this.fastify, {
174
+ notificationStorage: this.notificationStorage,
175
+ userStore: this.userStore,
176
+ config: this.config.auth,
177
+ });
178
+ // Prune expired notifications every 24 hours
179
+ setInterval(() => { void this.notificationStorage?.prune(); }, 24 * 60 * 60 * 1000);
167
180
  }
168
181
  // Static file serving in production
169
182
  if (serverConfig.staticDir) {
@@ -206,6 +219,7 @@ export class LoomServer {
206
219
  eventRegistry: this.eventRegistry,
207
220
  authConfig: this.config.auth,
208
221
  userStore: this.userStore,
222
+ serverUrl: `http://localhost:${this.config.server?.port || 3000}`,
209
223
  });
210
224
  await this.processEngine.initialize();
211
225
  registerProcessRoutes(this.fastify, {
@@ -258,6 +272,35 @@ export class LoomServer {
258
272
  catch { /* fire-and-forget */ }
259
273
  });
260
274
  }
275
+ else if (sub.handler === 'notify') {
276
+ const ntfCfg = sub.config;
277
+ this.eventBus.on(sub.pattern, (event) => {
278
+ if (event.pattern.startsWith('notification:'))
279
+ return;
280
+ const title = interpolate(ntfCfg.title, event.payload);
281
+ const description = ntfCfg.description
282
+ ? interpolate(ntfCfg.description, event.payload) : undefined;
283
+ if (event.userId) {
284
+ void this.notificationStorage.create({
285
+ userId: event.userId, type: ntfCfg.type,
286
+ title, description, source: 'event', eventPattern: event.pattern,
287
+ });
288
+ }
289
+ else if (ntfCfg.broadcastAll && this.userStore) {
290
+ void (async () => {
291
+ const users = await this.userStore.listUsers();
292
+ const capped = users.slice(0, 100);
293
+ if (users.length > 100) {
294
+ this.fastify.log.warn(`Notification broadcast capped at 100 users (total: ${users.length})`);
295
+ }
296
+ await this.notificationStorage.createBatch(capped.map(u => ({
297
+ userId: u.userId, type: ntfCfg.type,
298
+ title, description, source: 'event', eventPattern: event.pattern,
299
+ })));
300
+ })();
301
+ }
302
+ });
303
+ }
261
304
  }
262
305
  }
263
306
  // Graceful shutdown handlers
@@ -327,6 +370,10 @@ export class LoomServer {
327
370
  getProcessEngine() {
328
371
  return this.processEngine;
329
372
  }
373
+ /** Expose notification storage for testing */
374
+ getNotificationStorage() {
375
+ return this.notificationStorage;
376
+ }
330
377
  }
331
378
  /**
332
379
  * Create and start a LoomServer from a project root