reflectt-node 0.1.15 → 0.1.16

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 (214) hide show
  1. package/README.md +54 -0
  2. package/defaults/TEAM-ROLES.starter.yaml +87 -0
  3. package/defaults/lane-templates/ops.json +32 -0
  4. package/defaults/lane-templates/workflow.json +32 -0
  5. package/defaults/reviewer-routing.yaml +34 -0
  6. package/dist/activationEvents.d.ts +7 -1
  7. package/dist/activationEvents.d.ts.map +1 -1
  8. package/dist/activationEvents.js +29 -3
  9. package/dist/activationEvents.js.map +1 -1
  10. package/dist/activity-stream-normalizer.d.ts +37 -0
  11. package/dist/activity-stream-normalizer.d.ts.map +1 -0
  12. package/dist/activity-stream-normalizer.js +101 -0
  13. package/dist/activity-stream-normalizer.js.map +1 -0
  14. package/dist/agent-exec-guardrail.d.ts +9 -0
  15. package/dist/agent-exec-guardrail.d.ts.map +1 -0
  16. package/dist/agent-exec-guardrail.js +24 -0
  17. package/dist/agent-exec-guardrail.js.map +1 -0
  18. package/dist/agent-exec-guardrail.test.d.ts +2 -0
  19. package/dist/agent-exec-guardrail.test.d.ts.map +1 -0
  20. package/dist/agent-exec-guardrail.test.js +55 -0
  21. package/dist/agent-exec-guardrail.test.js.map +1 -0
  22. package/dist/agent-interface.d.ts +137 -0
  23. package/dist/agent-interface.d.ts.map +1 -0
  24. package/dist/agent-interface.js +463 -0
  25. package/dist/agent-interface.js.map +1 -0
  26. package/dist/agent-notifications.d.ts +51 -0
  27. package/dist/agent-notifications.d.ts.map +1 -0
  28. package/dist/agent-notifications.js +104 -0
  29. package/dist/agent-notifications.js.map +1 -0
  30. package/dist/agent-runs.d.ts +29 -2
  31. package/dist/agent-runs.d.ts.map +1 -1
  32. package/dist/agent-runs.js +118 -8
  33. package/dist/agent-runs.js.map +1 -1
  34. package/dist/artifact-mirror.d.ts.map +1 -1
  35. package/dist/artifact-mirror.js +4 -1
  36. package/dist/artifact-mirror.js.map +1 -1
  37. package/dist/assignment.d.ts.map +1 -1
  38. package/dist/assignment.js +54 -2
  39. package/dist/assignment.js.map +1 -1
  40. package/dist/boardHealthWorker.d.ts.map +1 -1
  41. package/dist/boardHealthWorker.js +15 -1
  42. package/dist/boardHealthWorker.js.map +1 -1
  43. package/dist/canvas-auto-state.d.ts +58 -0
  44. package/dist/canvas-auto-state.d.ts.map +1 -0
  45. package/dist/canvas-auto-state.js +89 -0
  46. package/dist/canvas-auto-state.js.map +1 -0
  47. package/dist/canvas-routes.d.ts +36 -0
  48. package/dist/canvas-routes.d.ts.map +1 -0
  49. package/dist/canvas-routes.js +47 -0
  50. package/dist/canvas-routes.js.map +1 -0
  51. package/dist/capability-readiness.d.ts +28 -0
  52. package/dist/capability-readiness.d.ts.map +1 -0
  53. package/dist/capability-readiness.js +162 -0
  54. package/dist/capability-readiness.js.map +1 -0
  55. package/dist/channels.d.ts.map +1 -1
  56. package/dist/channels.js +1 -0
  57. package/dist/channels.js.map +1 -1
  58. package/dist/cli.js +179 -4
  59. package/dist/cli.js.map +1 -1
  60. package/dist/cloud.d.ts +5 -0
  61. package/dist/cloud.d.ts.map +1 -1
  62. package/dist/cloud.js +485 -18
  63. package/dist/cloud.js.map +1 -1
  64. package/dist/comms-routing-policy.d.ts +31 -0
  65. package/dist/comms-routing-policy.d.ts.map +1 -0
  66. package/dist/comms-routing-policy.js +128 -0
  67. package/dist/comms-routing-policy.js.map +1 -0
  68. package/dist/config.d.ts.map +1 -1
  69. package/dist/config.js +1 -0
  70. package/dist/config.js.map +1 -1
  71. package/dist/continuity-loop.d.ts.map +1 -1
  72. package/dist/continuity-loop.js +26 -0
  73. package/dist/continuity-loop.js.map +1 -1
  74. package/dist/cost-enforcement.d.ts.map +1 -1
  75. package/dist/cost-enforcement.js +22 -0
  76. package/dist/cost-enforcement.js.map +1 -1
  77. package/dist/db.d.ts.map +1 -1
  78. package/dist/db.js +56 -5
  79. package/dist/db.js.map +1 -1
  80. package/dist/doctor.js +2 -2
  81. package/dist/events.d.ts +4 -2
  82. package/dist/events.d.ts.map +1 -1
  83. package/dist/events.js +22 -1
  84. package/dist/events.js.map +1 -1
  85. package/dist/executionSweeper.d.ts.map +1 -1
  86. package/dist/executionSweeper.js +155 -0
  87. package/dist/executionSweeper.js.map +1 -1
  88. package/dist/health.d.ts +21 -1
  89. package/dist/health.d.ts.map +1 -1
  90. package/dist/health.js +164 -19
  91. package/dist/health.js.map +1 -1
  92. package/dist/inbox.d.ts +4 -0
  93. package/dist/inbox.d.ts.map +1 -1
  94. package/dist/inbox.js +38 -1
  95. package/dist/inbox.js.map +1 -1
  96. package/dist/index.js +90 -14
  97. package/dist/index.js.map +1 -1
  98. package/dist/insight-auto-tagger.d.ts +58 -0
  99. package/dist/insight-auto-tagger.d.ts.map +1 -0
  100. package/dist/insight-auto-tagger.js +331 -0
  101. package/dist/insight-auto-tagger.js.map +1 -0
  102. package/dist/insight-task-bridge.d.ts +9 -0
  103. package/dist/insight-task-bridge.d.ts.map +1 -1
  104. package/dist/insight-task-bridge.js +43 -7
  105. package/dist/insight-task-bridge.js.map +1 -1
  106. package/dist/insights.d.ts +6 -0
  107. package/dist/insights.d.ts.map +1 -1
  108. package/dist/insights.js +13 -0
  109. package/dist/insights.js.map +1 -1
  110. package/dist/lane-config.d.ts.map +1 -1
  111. package/dist/lane-config.js +1 -0
  112. package/dist/lane-config.js.map +1 -1
  113. package/dist/lane-template-successor.d.ts +13 -0
  114. package/dist/lane-template-successor.d.ts.map +1 -0
  115. package/dist/lane-template-successor.js +132 -0
  116. package/dist/lane-template-successor.js.map +1 -0
  117. package/dist/local-whisper.d.ts +21 -0
  118. package/dist/local-whisper.d.ts.map +1 -0
  119. package/dist/local-whisper.js +137 -0
  120. package/dist/local-whisper.js.map +1 -0
  121. package/dist/macos-accessibility.d.ts +50 -0
  122. package/dist/macos-accessibility.d.ts.map +1 -0
  123. package/dist/macos-accessibility.js +185 -0
  124. package/dist/macos-accessibility.js.map +1 -0
  125. package/dist/manage.d.ts.map +1 -1
  126. package/dist/manage.js +47 -1
  127. package/dist/manage.js.map +1 -1
  128. package/dist/mcp.d.ts.map +1 -1
  129. package/dist/mcp.js +123 -0
  130. package/dist/mcp.js.map +1 -1
  131. package/dist/notification-worker.d.ts +66 -0
  132. package/dist/notification-worker.d.ts.map +1 -0
  133. package/dist/notification-worker.js +232 -0
  134. package/dist/notification-worker.js.map +1 -0
  135. package/dist/openclaw-usage-sync.d.ts +28 -0
  136. package/dist/openclaw-usage-sync.d.ts.map +1 -0
  137. package/dist/openclaw-usage-sync.js +161 -0
  138. package/dist/openclaw-usage-sync.js.map +1 -0
  139. package/dist/policy.js +1 -1
  140. package/dist/policy.js.map +1 -1
  141. package/dist/pr-link-reconciler.d.ts +61 -0
  142. package/dist/pr-link-reconciler.d.ts.map +1 -0
  143. package/dist/pr-link-reconciler.js +127 -0
  144. package/dist/pr-link-reconciler.js.map +1 -0
  145. package/dist/preflight.js +2 -2
  146. package/dist/presence-narrator.d.ts +52 -0
  147. package/dist/presence-narrator.d.ts.map +1 -0
  148. package/dist/presence-narrator.js +193 -0
  149. package/dist/presence-narrator.js.map +1 -0
  150. package/dist/presence.d.ts +2 -0
  151. package/dist/presence.d.ts.map +1 -1
  152. package/dist/presence.js +23 -3
  153. package/dist/presence.js.map +1 -1
  154. package/dist/product-observation-source.d.ts +52 -0
  155. package/dist/product-observation-source.d.ts.map +1 -0
  156. package/dist/product-observation-source.js +326 -0
  157. package/dist/product-observation-source.js.map +1 -0
  158. package/dist/reflection-automation.d.ts +25 -0
  159. package/dist/reflection-automation.d.ts.map +1 -1
  160. package/dist/reflection-automation.js +163 -42
  161. package/dist/reflection-automation.js.map +1 -1
  162. package/dist/review-autoclose.d.ts +62 -0
  163. package/dist/review-autoclose.d.ts.map +1 -0
  164. package/dist/review-autoclose.js +75 -0
  165. package/dist/review-autoclose.js.map +1 -0
  166. package/dist/sentry-webhook.d.ts +69 -0
  167. package/dist/sentry-webhook.d.ts.map +1 -0
  168. package/dist/sentry-webhook.js +88 -0
  169. package/dist/sentry-webhook.js.map +1 -0
  170. package/dist/sentry.d.ts +29 -0
  171. package/dist/sentry.d.ts.map +1 -0
  172. package/dist/sentry.js +86 -0
  173. package/dist/sentry.js.map +1 -0
  174. package/dist/server.d.ts.map +1 -1
  175. package/dist/server.js +5125 -230
  176. package/dist/server.js.map +1 -1
  177. package/dist/stale-candidate-reconciler.d.ts +69 -0
  178. package/dist/stale-candidate-reconciler.d.ts.map +1 -0
  179. package/dist/stale-candidate-reconciler.js +236 -0
  180. package/dist/stale-candidate-reconciler.js.map +1 -0
  181. package/dist/system-loop-state.d.ts +1 -1
  182. package/dist/system-loop-state.d.ts.map +1 -1
  183. package/dist/system-loop-state.js +1 -0
  184. package/dist/system-loop-state.js.map +1 -1
  185. package/dist/taskPrecheck.d.ts.map +1 -1
  186. package/dist/taskPrecheck.js +47 -2
  187. package/dist/taskPrecheck.js.map +1 -1
  188. package/dist/tasks.d.ts.map +1 -1
  189. package/dist/tasks.js +130 -0
  190. package/dist/tasks.js.map +1 -1
  191. package/dist/trust-events.d.ts +61 -0
  192. package/dist/trust-events.d.ts.map +1 -0
  193. package/dist/trust-events.js +148 -0
  194. package/dist/trust-events.js.map +1 -0
  195. package/dist/types.d.ts +1 -0
  196. package/dist/types.d.ts.map +1 -1
  197. package/dist/usage-tracking.d.ts +6 -0
  198. package/dist/usage-tracking.d.ts.map +1 -1
  199. package/dist/usage-tracking.js +14 -0
  200. package/dist/usage-tracking.js.map +1 -1
  201. package/dist/voice-sessions.d.ts +51 -0
  202. package/dist/voice-sessions.d.ts.map +1 -0
  203. package/dist/voice-sessions.js +143 -0
  204. package/dist/voice-sessions.js.map +1 -0
  205. package/dist/workflow-templates.d.ts.map +1 -1
  206. package/dist/workflow-templates.js +16 -1
  207. package/dist/workflow-templates.js.map +1 -1
  208. package/dist/working-contract.d.ts +22 -1
  209. package/dist/working-contract.d.ts.map +1 -1
  210. package/dist/working-contract.js +31 -2
  211. package/dist/working-contract.js.map +1 -1
  212. package/package.json +4 -4
  213. package/public/dashboard.js +12 -4
  214. package/public/docs.md +98 -10
@@ -0,0 +1,47 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) Reflectt AI
3
+ import { emitActivationEvent } from './activationEvents.js';
4
+ // ── Constants (moved from server.ts) ──
5
+ export const CANVAS_STATES = [
6
+ 'floor', 'listening', 'thinking', 'rendering', 'ambient', 'decision', 'urgent', 'handoff', 'presenting',
7
+ ];
8
+ export const SENSOR_VALUES = [
9
+ 'voice_active', 'screen_share', 'camera', 'typing', 'idle', 'scroll', 'hover', 'focus',
10
+ ];
11
+ // ── Plugin ──
12
+ export async function canvasReadRoutes(app, deps) {
13
+ // GET /canvas/states — valid state + sensor values (discovery)
14
+ app.get('/canvas/states', async (request) => {
15
+ const query = request.query;
16
+ const userId = typeof query.userId === 'string' && query.userId.trim()
17
+ ? query.userId.trim()
18
+ : 'anonymous';
19
+ emitActivationEvent('canvas_opened', userId).catch(() => { });
20
+ return ({
21
+ states: CANVAS_STATES,
22
+ sensors: SENSOR_VALUES,
23
+ schema: {
24
+ state: 'floor | listening | thinking | rendering | ambient | decision | urgent | handoff',
25
+ sensors: 'null | mic | camera | mic+camera (non-dismissable trust indicator)',
26
+ agentId: 'required — which agent is driving the canvas',
27
+ payload: 'optional — text, media, decision, agents, summary',
28
+ },
29
+ });
30
+ });
31
+ // GET /canvas/slots — current active slots
32
+ app.get('/canvas/slots', async () => {
33
+ return {
34
+ slots: deps.canvasSlots.getActive(),
35
+ stats: deps.canvasSlots.getStats(),
36
+ };
37
+ });
38
+ // GET /canvas/slots/all — all slots including stale (debug)
39
+ app.get('/canvas/slots/all', async () => {
40
+ return { slots: deps.canvasSlots.getAll() };
41
+ });
42
+ // GET /canvas/rejections — recent render rejections (debug)
43
+ app.get('/canvas/rejections', async () => {
44
+ return { rejections: deps.getRecentRejections() };
45
+ });
46
+ }
47
+ //# sourceMappingURL=canvas-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-routes.js","sourceRoot":"","sources":["../src/canvas-routes.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,4BAA4B;AAgB5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AA0B3D,yCAAyC;AAEzC,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY;CACxG,CAAA;AACD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO;CACvF,CAAA;AAED,eAAe;AAEf,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAoB,EAAE,IAAqB;IAEhF,+DAA+D;IAC/D,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAgC,CAAA;QACtD,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE;YACpE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE;YACrB,CAAC,CAAC,WAAW,CAAA;QACf,mBAAmB,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC5D,OAAO,CAAC;YACR,MAAM,EAAE,aAAa;YACrB,OAAO,EAAE,aAAa;YACtB,MAAM,EAAE;gBACN,KAAK,EAAE,kFAAkF;gBACzF,OAAO,EAAE,oEAAoE;gBAC7E,OAAO,EAAE,8CAA8C;gBACvD,OAAO,EAAE,mDAAmD;aAC7D;SACF,CAAC,CAAA;IACF,CAAC,CAAC,CAAA;IAEF,2CAA2C;IAC3C,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAClC,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE;YACnC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE;SACnC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,4DAA4D;IAC5D,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACtC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,4DAA4D;IAC5D,GAAG,CAAC,GAAG,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;QACvC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAA;IACnD,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ export type ReadinessStatus = 'ready' | 'degraded' | 'not_ready' | 'unknown';
2
+ export interface CapabilityReadiness {
3
+ capability: string;
4
+ status: ReadinessStatus;
5
+ last_success_at: number | null;
6
+ last_error: string | null;
7
+ dependencies: DependencyCheck[];
8
+ hint: string | null;
9
+ }
10
+ export interface DependencyCheck {
11
+ name: string;
12
+ status: 'ok' | 'missing' | 'error';
13
+ detail?: string;
14
+ }
15
+ export interface ReadinessReport {
16
+ overall: ReadinessStatus;
17
+ capabilities: CapabilityReadiness[];
18
+ checked_at: number;
19
+ }
20
+ export declare function getCapabilityReadiness(opts: {
21
+ cloudConnected: boolean;
22
+ cloudUrl: string;
23
+ webhooks: Array<{
24
+ provider: string;
25
+ active: boolean;
26
+ }>;
27
+ }): ReadinessReport;
28
+ //# sourceMappingURL=capability-readiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-readiness.d.ts","sourceRoot":"","sources":["../src/capability-readiness.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAA;AAE5E,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,eAAe,CAAA;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,YAAY,EAAE,eAAe,EAAE,CAAA;IAC/B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,OAAO,CAAA;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,YAAY,EAAE,mBAAmB,EAAE,CAAA;IACnC,UAAU,EAAE,MAAM,CAAA;CACnB;AAsKD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,cAAc,EAAE,OAAO,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CACvD,GAAG,eAAe,CAgBlB"}
@@ -0,0 +1,162 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Capability readiness contract — per-capability status with dependency checks.
3
+ // Powers GET /capabilities/readiness and cloud UI badges.
4
+ // ── Browser ──────────────────────────────────────────────────────────────────
5
+ function checkBrowserReadiness() {
6
+ const deps = [];
7
+ const errors = [];
8
+ // Check if Stagehand package is available
9
+ try {
10
+ require.resolve('@browserbasehq/stagehand');
11
+ deps.push({ name: 'stagehand_package', status: 'ok' });
12
+ }
13
+ catch {
14
+ deps.push({ name: 'stagehand_package', status: 'missing', detail: '@browserbasehq/stagehand not installed' });
15
+ errors.push('Stagehand package not installed');
16
+ }
17
+ // Check for ANTHROPIC_API_KEY or OPENAI_API_KEY (required by Stagehand)
18
+ const hasAnthropicKey = !!(process.env.ANTHROPIC_API_KEY);
19
+ const hasOpenAIKey = !!(process.env.OPENAI_API_KEY);
20
+ if (hasAnthropicKey || hasOpenAIKey) {
21
+ deps.push({ name: 'llm_api_key', status: 'ok', detail: hasAnthropicKey ? 'ANTHROPIC_API_KEY set' : 'OPENAI_API_KEY set' });
22
+ }
23
+ else {
24
+ deps.push({ name: 'llm_api_key', status: 'missing', detail: 'ANTHROPIC_API_KEY or OPENAI_API_KEY required for Stagehand' });
25
+ errors.push('LLM API key missing (ANTHROPIC_API_KEY or OPENAI_API_KEY)');
26
+ }
27
+ // Check BROWSERBASE_API_KEY (optional — cloud browser)
28
+ const hasBrowserbaseKey = !!(process.env.BROWSERBASE_API_KEY);
29
+ deps.push({
30
+ name: 'browserbase_api_key',
31
+ status: hasBrowserbaseKey ? 'ok' : 'missing',
32
+ detail: hasBrowserbaseKey ? 'BROWSERBASE_API_KEY set' : 'Optional — uses local browser if absent',
33
+ });
34
+ const status = errors.length === 0 ? 'ready'
35
+ : errors.some(e => e.includes('package')) ? 'not_ready'
36
+ : 'degraded';
37
+ return {
38
+ capability: 'browser',
39
+ status,
40
+ last_success_at: null,
41
+ last_error: errors.length > 0 ? errors[0] : null,
42
+ dependencies: deps,
43
+ hint: status !== 'ready'
44
+ ? 'Install @browserbasehq/stagehand and set ANTHROPIC_API_KEY to enable browser automation.'
45
+ : null,
46
+ };
47
+ }
48
+ // ── Email ─────────────────────────────────────────────────────────────────────
49
+ function checkEmailReadiness(cloudConnected, cloudUrl, webhooks) {
50
+ const deps = [];
51
+ const errors = [];
52
+ // Cloud connection required for relay
53
+ deps.push({
54
+ name: 'cloud_connection',
55
+ status: cloudConnected ? 'ok' : 'missing',
56
+ detail: cloudConnected ? `Connected to ${cloudUrl}` : 'Not enrolled with Reflectt Cloud',
57
+ });
58
+ if (!cloudConnected)
59
+ errors.push('Cloud connection required for email relay');
60
+ // Check inbound webhook route (resend)
61
+ const resendWebhook = webhooks.find(w => w.provider === 'resend' && w.active);
62
+ deps.push({
63
+ name: 'inbound_webhook',
64
+ status: resendWebhook ? 'ok' : 'missing',
65
+ detail: resendWebhook ? 'Resend inbound webhook active' : 'No active Resend inbound webhook configured',
66
+ });
67
+ if (!resendWebhook)
68
+ errors.push('Resend inbound webhook not configured — replies will not be received');
69
+ const status = errors.length === 0 ? 'ready'
70
+ : !cloudConnected ? 'not_ready'
71
+ : 'degraded';
72
+ return {
73
+ capability: 'email',
74
+ status,
75
+ last_success_at: null,
76
+ last_error: errors.length > 0 ? errors[0] : null,
77
+ dependencies: deps,
78
+ hint: status !== 'ready'
79
+ ? !cloudConnected
80
+ ? 'Enroll this host with Reflectt Cloud to enable email relay.'
81
+ : 'Configure a Resend inbound webhook via POST /provisioning/webhooks to receive replies.'
82
+ : null,
83
+ };
84
+ }
85
+ // ── SMS ───────────────────────────────────────────────────────────────────────
86
+ function checkSmsReadiness(cloudConnected, cloudUrl, webhooks) {
87
+ const deps = [];
88
+ const errors = [];
89
+ deps.push({
90
+ name: 'cloud_connection',
91
+ status: cloudConnected ? 'ok' : 'missing',
92
+ detail: cloudConnected ? `Connected to ${cloudUrl}` : 'Not enrolled with Reflectt Cloud',
93
+ });
94
+ if (!cloudConnected)
95
+ errors.push('Cloud connection required for SMS relay');
96
+ // Check for Twilio inbound webhook route
97
+ const twilioWebhook = webhooks.find(w => (w.provider === 'twilio' || w.provider === 'sms') && w.active);
98
+ deps.push({
99
+ name: 'inbound_webhook',
100
+ status: twilioWebhook ? 'ok' : 'missing',
101
+ detail: twilioWebhook ? 'SMS inbound webhook active' : 'No active SMS inbound webhook configured',
102
+ });
103
+ if (!twilioWebhook)
104
+ errors.push('SMS inbound webhook not configured — replies will not be received');
105
+ const status = errors.length === 0 ? 'ready'
106
+ : !cloudConnected ? 'not_ready'
107
+ : 'degraded';
108
+ return {
109
+ capability: 'sms',
110
+ status,
111
+ last_success_at: null,
112
+ last_error: errors.length > 0 ? errors[0] : null,
113
+ dependencies: deps,
114
+ hint: status !== 'ready'
115
+ ? !cloudConnected
116
+ ? 'Enroll this host with Reflectt Cloud to enable SMS relay.'
117
+ : 'Configure a Twilio inbound webhook via POST /provisioning/webhooks to receive SMS replies.'
118
+ : null,
119
+ };
120
+ }
121
+ // ── Calendar ──────────────────────────────────────────────────────────────────
122
+ function checkCalendarReadiness() {
123
+ const deps = [];
124
+ const errors = [];
125
+ // Calendar is always locally available (no external deps required for basic scheduling)
126
+ deps.push({ name: 'calendar_module', status: 'ok', detail: 'Local calendar storage active' });
127
+ // Optional: Google Calendar sync env var
128
+ const hasGoogleCal = !!(process.env.GOOGLE_CALENDAR_CLIENT_ID && process.env.GOOGLE_CALENDAR_CLIENT_SECRET);
129
+ deps.push({
130
+ name: 'google_calendar_sync',
131
+ status: hasGoogleCal ? 'ok' : 'missing',
132
+ detail: hasGoogleCal
133
+ ? 'Google Calendar credentials configured'
134
+ : 'Optional — GOOGLE_CALENDAR_CLIENT_ID + GOOGLE_CALENDAR_CLIENT_SECRET for sync',
135
+ });
136
+ // iCal import is always available
137
+ deps.push({ name: 'ical_import', status: 'ok', detail: 'iCal import/export available' });
138
+ return {
139
+ capability: 'calendar',
140
+ status: errors.length === 0 ? 'ready' : 'degraded',
141
+ last_success_at: null,
142
+ last_error: errors.length > 0 ? errors[0] : null,
143
+ dependencies: deps,
144
+ hint: null,
145
+ };
146
+ }
147
+ // ── Main readiness check ──────────────────────────────────────────────────────
148
+ export function getCapabilityReadiness(opts) {
149
+ const capabilities = [
150
+ checkBrowserReadiness(),
151
+ checkEmailReadiness(opts.cloudConnected, opts.cloudUrl, opts.webhooks),
152
+ checkSmsReadiness(opts.cloudConnected, opts.cloudUrl, opts.webhooks),
153
+ checkCalendarReadiness(),
154
+ ];
155
+ // Overall: ready if all ready, degraded if any degraded, not_ready if any not_ready
156
+ const overall = capabilities.some(c => c.status === 'not_ready') ? 'not_ready'
157
+ : capabilities.some(c => c.status === 'degraded') ? 'degraded'
158
+ : capabilities.every(c => c.status === 'ready') ? 'ready'
159
+ : 'unknown';
160
+ return { overall, capabilities, checked_at: Date.now() };
161
+ }
162
+ //# sourceMappingURL=capability-readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-readiness.js","sourceRoot":"","sources":["../src/capability-readiness.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;EAUtB,CAAA;AAEV,eAAO,MAAM,qBAAqB,gGAAiD,CAAA;AAEnF,eAAO,MAAM,2BAA2B,UAOvC,CAAA"}
1
+ {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;EAUtB,CAAA;AAEV,eAAO,MAAM,qBAAqB,gGAAiD,CAAA;AAEnF,eAAO,MAAM,2BAA2B,UAQvC,CAAA"}
package/dist/channels.js CHANGED
@@ -14,6 +14,7 @@ export const CHANNEL_DEFINITIONS = [
14
14
  export const DEFAULT_CHAT_CHANNELS = CHANNEL_DEFINITIONS.map(channel => channel.id);
15
15
  export const DEFAULT_INBOX_SUBSCRIPTIONS = [
16
16
  'general',
17
+ 'canvas',
17
18
  'decisions',
18
19
  'shipping',
19
20
  'reviews',
@@ -1 +1 @@
1
- {"version":3,"file":"channels.js","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,4BAA4B;AAE5B,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAClC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE;IACtC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE;IACpC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAClC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE;IACpC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE;IAC1B,wEAAwE;IACxE,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,kBAAkB,EAAE;IAC5C,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE;CAC1B,CAAA;AAEV,MAAM,CAAC,MAAM,qBAAqB,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;AAEnF,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,SAAS;IACT,WAAW;IACX,UAAU;IACV,SAAS;IACT,UAAU;IACV,UAAU;CACX,CAAA"}
1
+ {"version":3,"file":"channels.js","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,4BAA4B;AAE5B,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAClC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE;IACtC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE;IACpC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAClC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE;IACpC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE;IAC1B,wEAAwE;IACxE,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,kBAAkB,EAAE;IAC5C,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE;CAC1B,CAAA;AAEV,MAAM,CAAC,MAAM,qBAAqB,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;AAEnF,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,SAAS;IACT,QAAQ;IACR,WAAW;IACX,UAAU;IACV,SAAS;IACT,UAAU;IACV,UAAU;CACX,CAAA"}
package/dist/cli.js CHANGED
@@ -114,10 +114,105 @@ function buildServerEnv(config) {
114
114
  }
115
115
  return env;
116
116
  }
117
- function startServerDetached(config) {
117
+ /**
118
+ * Check if dist/ is stale compared to src/ (i.e. source files were modified after last build).
119
+ * Returns a warning message if stale, or null if fresh.
120
+ */
121
+ function checkBuildFreshness() {
122
+ const __filename = fileURLToPath(import.meta.url);
123
+ const projectRoot = join(dirname(__filename), '..');
124
+ const distDir = join(projectRoot, 'dist');
125
+ const srcDir = join(projectRoot, 'src');
126
+ if (!existsSync(distDir)) {
127
+ return `❌ Build output missing: ${distDir} does not exist. Run 'npm run build' before starting.`;
128
+ }
129
+ const distIndex = join(distDir, 'server.js');
130
+ if (!existsSync(distIndex)) {
131
+ return `❌ Build output incomplete: dist/server.js not found. Run 'npm run build' before starting.`;
132
+ }
133
+ try {
134
+ const distMtime = statSync(distIndex).mtimeMs;
135
+ // Check a few key source files — if any are newer than dist, build is stale
136
+ const checkFiles = ['server.ts', 'cli.ts', 'config.ts', 'chat.ts'];
137
+ for (const file of checkFiles) {
138
+ const srcFile = join(srcDir, file);
139
+ if (existsSync(srcFile)) {
140
+ const srcMtime = statSync(srcFile).mtimeMs;
141
+ if (srcMtime > distMtime) {
142
+ return `⚠️ Build may be stale: src/${file} is newer than dist/server.js. Run 'npm run build' to rebuild.`;
143
+ }
144
+ }
145
+ }
146
+ }
147
+ catch {
148
+ // If stat fails, don't block startup
149
+ }
150
+ return null;
151
+ }
152
+ /**
153
+ * Auto-rebuild dist/ when stale or missing.
154
+ * Returns true if rebuild succeeded, false if it failed.
155
+ */
156
+ function autoRebuild(projectRoot) {
157
+ console.log('🔨 Build is stale or missing — auto-rebuilding...');
158
+ try {
159
+ execSync('npm run build', { cwd: projectRoot, stdio: 'inherit', timeout: 60_000 });
160
+ console.log('✅ Build complete');
161
+ return true;
162
+ }
163
+ catch (err) {
164
+ console.error('❌ Auto-rebuild failed:', err.message);
165
+ return false;
166
+ }
167
+ }
168
+ function startServerDetached(config, forceTsx = false) {
118
169
  const { projectRoot, serverPath, useNode } = getRuntimePaths();
170
+ // --tsx flag: always use tsx, skip dist entirely
171
+ if (forceTsx) {
172
+ const tsxPath = join(projectRoot, 'src', 'index.ts');
173
+ if (!existsSync(tsxPath)) {
174
+ throw new Error(`Source file not found: ${tsxPath}`);
175
+ }
176
+ const child = spawn('npx', ['tsx', tsxPath], {
177
+ env: buildServerEnv(config),
178
+ detached: true,
179
+ stdio: 'ignore',
180
+ cwd: projectRoot,
181
+ });
182
+ child.unref();
183
+ writeFileSync(PID_FILE, String(child.pid));
184
+ return child.pid;
185
+ }
119
186
  if (!existsSync(serverPath)) {
120
- throw new Error(`Server file not found: ${serverPath}`);
187
+ // Try auto-rebuild before giving up
188
+ if (useNode && autoRebuild(projectRoot)) {
189
+ // Re-check after rebuild
190
+ if (!existsSync(serverPath)) {
191
+ throw new Error(`Server file still not found after rebuild: ${serverPath}`);
192
+ }
193
+ }
194
+ else if (useNode) {
195
+ throw new Error(`Server file not found: ${serverPath}. Auto-rebuild failed.`);
196
+ }
197
+ else {
198
+ throw new Error(`Server file not found: ${serverPath}`);
199
+ }
200
+ }
201
+ // Check build freshness for compiled mode — auto-rebuild if stale
202
+ if (useNode) {
203
+ const warning = checkBuildFreshness();
204
+ if (warning) {
205
+ if (warning.startsWith('❌') || warning.startsWith('⚠️')) {
206
+ if (!autoRebuild(projectRoot)) {
207
+ console.warn(warning);
208
+ if (warning.startsWith('❌')) {
209
+ throw new Error('Cannot start: build output is missing and auto-rebuild failed.');
210
+ }
211
+ // Stale warning but rebuild failed — continue with stale dist and warn
212
+ console.warn('⚠️ Continuing with potentially stale build');
213
+ }
214
+ }
215
+ }
121
216
  }
122
217
  const cmd = useNode ? 'node' : 'npx';
123
218
  const args = useNode ? [serverPath] : ['tsx', serverPath];
@@ -488,6 +583,7 @@ program
488
583
  .command('start')
489
584
  .description('Start the reflectt server')
490
585
  .option('-d, --detach', 'Run in background')
586
+ .option('--tsx', 'Use tsx (TypeScript) directly — no build step needed')
491
587
  .action(async (options) => {
492
588
  if (!existsSync(REFLECTT_HOME)) {
493
589
  console.log('📦 First run — initializing reflectt...');
@@ -545,9 +641,88 @@ program
545
641
  // Port not responding — safe to start
546
642
  }
547
643
  const { projectRoot, serverPath, useNode } = getRuntimePaths();
644
+ // --tsx flag: always use tsx, skip dist entirely
645
+ if (options.tsx) {
646
+ const tsxPath = join(projectRoot, 'src', 'index.ts');
647
+ if (!existsSync(tsxPath)) {
648
+ console.error(`❌ Source file not found: ${tsxPath}`);
649
+ console.error(' --tsx requires a source checkout (not an npm install)');
650
+ process.exit(1);
651
+ }
652
+ if (options.detach) {
653
+ const pid = startServerDetached(config, true);
654
+ const clientHost2 = (config.host === '0.0.0.0' || config.host === '::') ? '127.0.0.1' : config.host;
655
+ console.log(`⏳ Starting reflectt server via tsx (PID: ${pid})...`);
656
+ let healthy = false;
657
+ for (let i = 0; i < 20; i++) {
658
+ await new Promise(r => setTimeout(r, 500));
659
+ try {
660
+ const ctrl = new AbortController();
661
+ const t = setTimeout(() => ctrl.abort(), 2000);
662
+ const r = await fetch(`http://${clientHost2}:${config.port}/health`, { signal: ctrl.signal });
663
+ clearTimeout(t);
664
+ if (r.ok) {
665
+ healthy = true;
666
+ break;
667
+ }
668
+ }
669
+ catch { /* not ready */ }
670
+ }
671
+ console.log(healthy ? '✅ Server is running (tsx mode)!' : '⚠️ Server started but not responding yet');
672
+ process.exit(0);
673
+ }
674
+ console.log('🚀 Starting reflectt server (tsx mode — no build step)...');
675
+ const env = buildServerEnv(config);
676
+ const child = spawn('npx', ['tsx', tsxPath], {
677
+ env,
678
+ stdio: 'inherit',
679
+ cwd: projectRoot,
680
+ });
681
+ child.on('exit', (code) => process.exit(code ?? 1));
682
+ return;
683
+ }
548
684
  if (!existsSync(serverPath)) {
549
- console.error(`❌ Server file not found: ${serverPath}`);
550
- process.exit(1);
685
+ // Auto-rebuild if dist is missing
686
+ if (useNode) {
687
+ console.log(`Server file not found: ${serverPath}`);
688
+ if (autoRebuild(projectRoot)) {
689
+ if (!existsSync(serverPath)) {
690
+ console.error('❌ Build succeeded but server file still missing');
691
+ process.exit(1);
692
+ }
693
+ }
694
+ else {
695
+ // Rebuild failed — try tsx fallback if source exists
696
+ const tsxFallback = join(projectRoot, 'src', 'index.ts');
697
+ if (existsSync(tsxFallback)) {
698
+ console.log('💡 Falling back to tsx (source mode)...');
699
+ const env = buildServerEnv(config);
700
+ const child = spawn('npx', ['tsx', tsxFallback], {
701
+ env,
702
+ stdio: 'inherit',
703
+ cwd: projectRoot,
704
+ });
705
+ child.on('exit', (code) => process.exit(code ?? 1));
706
+ return;
707
+ }
708
+ console.error('❌ Cannot start: no dist/ and no src/. Is this a valid reflectt-node checkout?');
709
+ process.exit(1);
710
+ }
711
+ }
712
+ else {
713
+ console.error(`❌ Server file not found: ${serverPath}`);
714
+ process.exit(1);
715
+ }
716
+ }
717
+ // Auto-rebuild if stale
718
+ if (useNode) {
719
+ const warning = checkBuildFreshness();
720
+ if (warning && (warning.startsWith('❌') || warning.startsWith('⚠️'))) {
721
+ if (!autoRebuild(projectRoot)) {
722
+ console.warn(warning);
723
+ console.warn('⚠️ Continuing with potentially stale build');
724
+ }
725
+ }
551
726
  }
552
727
  const env = buildServerEnv(config);
553
728
  const cmd = useNode ? 'node' : 'npx';