@elizaos/plugin-health 2.0.0-beta.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 (162) hide show
  1. package/README.md +107 -0
  2. package/dist/actions/index.d.ts +20 -0
  3. package/dist/actions/index.d.ts.map +1 -0
  4. package/dist/actions/index.js +5 -0
  5. package/dist/actions/index.js.map +1 -0
  6. package/dist/anchors/index.d.ts +19 -0
  7. package/dist/anchors/index.d.ts.map +1 -0
  8. package/dist/anchors/index.js +9 -0
  9. package/dist/anchors/index.js.map +1 -0
  10. package/dist/connectors/contract-stubs.d.ts +112 -0
  11. package/dist/connectors/contract-stubs.d.ts.map +1 -0
  12. package/dist/connectors/contract-stubs.js +1 -0
  13. package/dist/connectors/contract-stubs.js.map +1 -0
  14. package/dist/connectors/index.d.ts +28 -0
  15. package/dist/connectors/index.d.ts.map +1 -0
  16. package/dist/connectors/index.js +202 -0
  17. package/dist/connectors/index.js.map +1 -0
  18. package/dist/contracts/circadian-default.d.ts +15 -0
  19. package/dist/contracts/circadian-default.d.ts.map +1 -0
  20. package/dist/contracts/circadian-default.js +30 -0
  21. package/dist/contracts/circadian-default.js.map +1 -0
  22. package/dist/contracts/circadian.d.ts +92 -0
  23. package/dist/contracts/circadian.d.ts.map +1 -0
  24. package/dist/contracts/circadian.js +14 -0
  25. package/dist/contracts/circadian.js.map +1 -0
  26. package/dist/contracts/health.d.ts +9 -0
  27. package/dist/contracts/health.d.ts.map +1 -0
  28. package/dist/contracts/health.js +21 -0
  29. package/dist/contracts/health.js.map +1 -0
  30. package/dist/contracts/lifeops-connector-degradation.d.ts +9 -0
  31. package/dist/contracts/lifeops-connector-degradation.d.ts.map +1 -0
  32. package/dist/contracts/lifeops-connector-degradation.js +17 -0
  33. package/dist/contracts/lifeops-connector-degradation.js.map +1 -0
  34. package/dist/contracts/lifeops.d.ts +3123 -0
  35. package/dist/contracts/lifeops.d.ts.map +1 -0
  36. package/dist/contracts/lifeops.js +635 -0
  37. package/dist/contracts/lifeops.js.map +1 -0
  38. package/dist/contracts/permissions.d.ts +39 -0
  39. package/dist/contracts/permissions.d.ts.map +1 -0
  40. package/dist/contracts/permissions.js +1 -0
  41. package/dist/contracts/permissions.js.map +1 -0
  42. package/dist/default-packs/bedtime.d.ts +14 -0
  43. package/dist/default-packs/bedtime.d.ts.map +1 -0
  44. package/dist/default-packs/bedtime.js +48 -0
  45. package/dist/default-packs/bedtime.js.map +1 -0
  46. package/dist/default-packs/contract-stubs.d.ts +161 -0
  47. package/dist/default-packs/contract-stubs.d.ts.map +1 -0
  48. package/dist/default-packs/contract-stubs.js +1 -0
  49. package/dist/default-packs/contract-stubs.js.map +1 -0
  50. package/dist/default-packs/index.d.ts +18 -0
  51. package/dist/default-packs/index.d.ts.map +1 -0
  52. package/dist/default-packs/index.js +39 -0
  53. package/dist/default-packs/index.js.map +1 -0
  54. package/dist/default-packs/sleep-recap.d.ts +14 -0
  55. package/dist/default-packs/sleep-recap.d.ts.map +1 -0
  56. package/dist/default-packs/sleep-recap.js +51 -0
  57. package/dist/default-packs/sleep-recap.js.map +1 -0
  58. package/dist/default-packs/wake-up.d.ts +14 -0
  59. package/dist/default-packs/wake-up.d.ts.map +1 -0
  60. package/dist/default-packs/wake-up.js +61 -0
  61. package/dist/default-packs/wake-up.js.map +1 -0
  62. package/dist/health-bridge/health-bridge.d.ts +57 -0
  63. package/dist/health-bridge/health-bridge.d.ts.map +1 -0
  64. package/dist/health-bridge/health-bridge.js +558 -0
  65. package/dist/health-bridge/health-bridge.js.map +1 -0
  66. package/dist/health-bridge/health-connectors.d.ts +23 -0
  67. package/dist/health-bridge/health-connectors.d.ts.map +1 -0
  68. package/dist/health-bridge/health-connectors.js +1018 -0
  69. package/dist/health-bridge/health-connectors.js.map +1 -0
  70. package/dist/health-bridge/health-oauth.d.ts +62 -0
  71. package/dist/health-bridge/health-oauth.d.ts.map +1 -0
  72. package/dist/health-bridge/health-oauth.js +432 -0
  73. package/dist/health-bridge/health-oauth.js.map +1 -0
  74. package/dist/health-bridge/health-provider-registry.d.ts +89 -0
  75. package/dist/health-bridge/health-provider-registry.d.ts.map +1 -0
  76. package/dist/health-bridge/health-provider-registry.js +141 -0
  77. package/dist/health-bridge/health-provider-registry.js.map +1 -0
  78. package/dist/health-bridge/health-records.d.ts +14 -0
  79. package/dist/health-bridge/health-records.d.ts.map +1 -0
  80. package/dist/health-bridge/health-records.js +45 -0
  81. package/dist/health-bridge/health-records.js.map +1 -0
  82. package/dist/health-bridge/index.d.ts +22 -0
  83. package/dist/health-bridge/index.d.ts.map +1 -0
  84. package/dist/health-bridge/index.js +7 -0
  85. package/dist/health-bridge/index.js.map +1 -0
  86. package/dist/health-bridge/service-normalize-health.d.ts +3 -0
  87. package/dist/health-bridge/service-normalize-health.d.ts.map +1 -0
  88. package/dist/health-bridge/service-normalize-health.js +96 -0
  89. package/dist/health-bridge/service-normalize-health.js.map +1 -0
  90. package/dist/index.d.ts +41 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +62 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/screen-time/index.d.ts +23 -0
  95. package/dist/screen-time/index.d.ts.map +1 -0
  96. package/dist/screen-time/index.js +1 -0
  97. package/dist/screen-time/index.js.map +1 -0
  98. package/dist/sleep/awake-probability.d.ts +11 -0
  99. package/dist/sleep/awake-probability.d.ts.map +1 -0
  100. package/dist/sleep/awake-probability.js +163 -0
  101. package/dist/sleep/awake-probability.js.map +1 -0
  102. package/dist/sleep/circadian-rules.d.ts +45 -0
  103. package/dist/sleep/circadian-rules.d.ts.map +1 -0
  104. package/dist/sleep/circadian-rules.js +258 -0
  105. package/dist/sleep/circadian-rules.js.map +1 -0
  106. package/dist/sleep/index.d.ts +21 -0
  107. package/dist/sleep/index.d.ts.map +1 -0
  108. package/dist/sleep/index.js +11 -0
  109. package/dist/sleep/index.js.map +1 -0
  110. package/dist/sleep/sleep-cycle-dispatch.d.ts +75 -0
  111. package/dist/sleep/sleep-cycle-dispatch.d.ts.map +1 -0
  112. package/dist/sleep/sleep-cycle-dispatch.js +102 -0
  113. package/dist/sleep/sleep-cycle-dispatch.js.map +1 -0
  114. package/dist/sleep/sleep-cycle.d.ts +38 -0
  115. package/dist/sleep/sleep-cycle.d.ts.map +1 -0
  116. package/dist/sleep/sleep-cycle.js +418 -0
  117. package/dist/sleep/sleep-cycle.js.map +1 -0
  118. package/dist/sleep/sleep-episode-store.d.ts +25 -0
  119. package/dist/sleep/sleep-episode-store.d.ts.map +1 -0
  120. package/dist/sleep/sleep-episode-store.js +69 -0
  121. package/dist/sleep/sleep-episode-store.js.map +1 -0
  122. package/dist/sleep/sleep-episode-types.d.ts +38 -0
  123. package/dist/sleep/sleep-episode-types.d.ts.map +1 -0
  124. package/dist/sleep/sleep-episode-types.js +14 -0
  125. package/dist/sleep/sleep-episode-types.js.map +1 -0
  126. package/dist/sleep/sleep-recap.d.ts +19 -0
  127. package/dist/sleep/sleep-recap.d.ts.map +1 -0
  128. package/dist/sleep/sleep-recap.js +1 -0
  129. package/dist/sleep/sleep-recap.js.map +1 -0
  130. package/dist/sleep/sleep-regularity.d.ts +19 -0
  131. package/dist/sleep/sleep-regularity.d.ts.map +1 -0
  132. package/dist/sleep/sleep-regularity.js +242 -0
  133. package/dist/sleep/sleep-regularity.js.map +1 -0
  134. package/dist/sleep/sleep-wake-events.d.ts +58 -0
  135. package/dist/sleep/sleep-wake-events.d.ts.map +1 -0
  136. package/dist/sleep/sleep-wake-events.js +135 -0
  137. package/dist/sleep/sleep-wake-events.js.map +1 -0
  138. package/dist/sleep/source-reliability.d.ts +38 -0
  139. package/dist/sleep/source-reliability.d.ts.map +1 -0
  140. package/dist/sleep/source-reliability.js +62 -0
  141. package/dist/sleep/source-reliability.js.map +1 -0
  142. package/dist/util/index.d.ts +10 -0
  143. package/dist/util/index.d.ts.map +1 -0
  144. package/dist/util/index.js +3 -0
  145. package/dist/util/index.js.map +1 -0
  146. package/dist/util/normalize.d.ts +22 -0
  147. package/dist/util/normalize.d.ts.map +1 -0
  148. package/dist/util/normalize.js +62 -0
  149. package/dist/util/normalize.js.map +1 -0
  150. package/dist/util/time-util.d.ts +10 -0
  151. package/dist/util/time-util.d.ts.map +1 -0
  152. package/dist/util/time-util.js +14 -0
  153. package/dist/util/time-util.js.map +1 -0
  154. package/dist/util/time.d.ts +17 -0
  155. package/dist/util/time.d.ts.map +1 -0
  156. package/dist/util/time.js +152 -0
  157. package/dist/util/time.js.map +1 -0
  158. package/dist/util/token-encryption.d.ts +42 -0
  159. package/dist/util/token-encryption.d.ts.map +1 -0
  160. package/dist/util/token-encryption.js +96 -0
  161. package/dist/util/token-encryption.js.map +1 -0
  162. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # `@elizaos/plugin-health`
2
+
3
+ Owns the health, sleep, circadian-regularity, and screen-time domain for
4
+ elizaOS. Extracted from `@elizaos/app-lifeops` so the same domain can serve
5
+ other apps without bringing the LifeOps runtime along.
6
+
7
+ ## What this plugin owns
8
+
9
+ ### Connectors
10
+
11
+ Six connector contributions registered against the LifeOps
12
+ `ConnectorRegistry`:
13
+
14
+ - `apple_health`
15
+ - `google_fit`
16
+ - `strava`
17
+ - `fitbit`
18
+ - `withings`
19
+ - `oura`
20
+
21
+ Each pair-and-disconnect flow, dispatch surface, and credential boundary
22
+ lives under `src/connectors/`. Connectors return typed `DispatchResult` —
23
+ not booleans.
24
+
25
+ ### Anchors
26
+
27
+ Four anchors registered against the `AnchorRegistry`:
28
+
29
+ - `wake.observed`
30
+ - `wake.confirmed`
31
+ - `bedtime.target`
32
+ - `nap.start`
33
+
34
+ Anchors back the `relative_to_anchor` trigger on
35
+ `ScheduledTask`s — for example, `morning-brief` fires `relative_to_anchor`
36
+ on `wake.confirmed` with a small offset.
37
+
38
+ ### Bus families
39
+
40
+ Eight families registered against the `FamilyRegistry` and published on the
41
+ `ActivitySignalBus`:
42
+
43
+ - `health.sleep.detected`
44
+ - `health.sleep.ended`
45
+ - `health.wake.observed`
46
+ - `health.wake.confirmed`
47
+ - `health.nap.detected`
48
+ - `health.bedtime.imminent`
49
+ - `health.regularity.changed`
50
+ - `health.workout.completed`
51
+
52
+ ### Default packs
53
+
54
+ - `bedtime` — fires before the user's target bedtime.
55
+ - `wake-up` — fires when wake is observed/confirmed.
56
+ - `sleep-recap` — recap after sleep ends.
57
+
58
+ Each pack is a `ScheduledTask` (or set thereof) consuming the LifeOps spine.
59
+ The plugin registers them lazily — only when at least one health connector
60
+ pairs.
61
+
62
+ ### Domain logic
63
+
64
+ - `src/sleep/` — sleep / circadian / regularity engines.
65
+ - `src/screen-time/` — screen-time aggregation.
66
+ - `src/health-bridge/` — proxied surfaces consumed by LifeOps
67
+ (`/api/lifeops/health/summary`, `/api/lifeops/health/sync`).
68
+
69
+ ## How LifeOps consumes plugin-health
70
+
71
+ LifeOps does not import internal modules. Consumption goes through:
72
+
73
+ 1. **Connector contributions** — registered into LifeOps's
74
+ `ConnectorRegistry` at boot via `registerHealthConnectors(runtime)`.
75
+ 2. **Anchor contributions** — registered via `registerHealthAnchors(runtime)`
76
+ into the `AnchorRegistry`.
77
+ 3. **Bus families** — registered via `registerHealthBusFamilies(runtime)`
78
+ into `FamilyRegistry`.
79
+ 4. **Default packs** — registered via `registerHealthDefaultPacks(runtime)`.
80
+ 5. **Public exports** — `detectHealthBackend`, sleep utilities, screen-time
81
+ helpers exported from `@elizaos/plugin-health` and re-exported by
82
+ `app-lifeops` only where the surface is part of the LifeOps public API.
83
+
84
+ If the LifeOps runtime registries are not available at boot, the plugin
85
+ logs a single skip line and contributes nothing. This is the soft-dependency
86
+ posture.
87
+
88
+ ## Soft-dependency posture
89
+
90
+ `plugin-health` does not require `app-lifeops`. Other apps can consume the
91
+ plugin by registering their own implementations of:
92
+
93
+ - `ConnectorRegistry` (with `register` / `get` / `list`)
94
+ - `AnchorRegistry` (with `register` / `resolve`)
95
+ - `FamilyRegistry` (with `register`)
96
+ - A `ScheduledTaskRunner` that accepts the default packs
97
+
98
+ The contracts the plugin builds against live in `src/contracts/health.ts`
99
+ and `plugins/app-lifeops/docs/audit/wave1-interfaces.md` §1, §3.
100
+
101
+ ## Where to look next
102
+
103
+ - Plugin entry: `src/index.ts`.
104
+ - LifeOps consumption: `plugins/app-lifeops/README.md`.
105
+ - Frozen contracts: `plugins/app-lifeops/docs/audit/wave1-interfaces.md`
106
+ §5 (this plugin's contributions) and §3 (the connector / channel /
107
+ transport contracts the plugin implements).
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Health-related agent actions exposed by plugin-health.
3
+ *
4
+ * Wave-1 (W1-B) move: `actions/health.ts` and `actions/screen-time.ts` are
5
+ * still owned by app-lifeops because they instantiate `LifeOpsService`
6
+ * directly (`new LifeOpsService(runtime)`) — moving the construction surface
7
+ * into plugin-health would create a circular package dependency since
8
+ * `LifeOpsService` lives in app-lifeops.
9
+ *
10
+ * The pure-domain helpers those actions delegate to (`health-bridge.ts`,
11
+ * `health-connectors.ts`, sleep / circadian / awake-probability inference)
12
+ * have been moved into plugin-health. Wave-2 (W2-A: scenario-named action
13
+ * migration onto `ScheduledTask`) is responsible for the action move +
14
+ * `LifeOpsService` decoupling.
15
+ *
16
+ * For now, app-lifeops continues to register both actions on its own plugin
17
+ * surface. plugin-health exposes no actions of its own at Wave-1.
18
+ */
19
+ export declare const HEALTH_ACTIONS_DEFERRED_TO_WAVE_2: true;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,iCAAiC,EAAG,IAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ const HEALTH_ACTIONS_DEFERRED_TO_WAVE_2 = true;
2
+ export {
3
+ HEALTH_ACTIONS_DEFERRED_TO_WAVE_2
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/actions/index.ts"],"sourcesContent":["/**\n * Health-related agent actions exposed by plugin-health.\n *\n * Wave-1 (W1-B) move: `actions/health.ts` and `actions/screen-time.ts` are\n * still owned by app-lifeops because they instantiate `LifeOpsService`\n * directly (`new LifeOpsService(runtime)`) — moving the construction surface\n * into plugin-health would create a circular package dependency since\n * `LifeOpsService` lives in app-lifeops.\n *\n * The pure-domain helpers those actions delegate to (`health-bridge.ts`,\n * `health-connectors.ts`, sleep / circadian / awake-probability inference)\n * have been moved into plugin-health. Wave-2 (W2-A: scenario-named action\n * migration onto `ScheduledTask`) is responsible for the action move +\n * `LifeOpsService` decoupling.\n *\n * For now, app-lifeops continues to register both actions on its own plugin\n * surface. plugin-health exposes no actions of its own at Wave-1.\n */\n\nexport const HEALTH_ACTIONS_DEFERRED_TO_WAVE_2 = true as const;\n"],"mappings":"AAmBO,MAAM,oCAAoC;","names":[]}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Anchor contributions exposed by plugin-health.
3
+ *
4
+ * The actual `registerHealthAnchors` implementation + the `HEALTH_ANCHORS`
5
+ * tuple live in `../connectors/index.ts` (alongside the connector / bus-
6
+ * family registration entry points so a single registry-detection pass
7
+ * runs all three at boot). This file re-exports them so external callers
8
+ * can import from `@elizaos/plugin-health/anchors`.
9
+ *
10
+ * Per `IMPLEMENTATION_PLAN.md` §3.2: BOTH `wake.observed` AND `wake.confirmed`
11
+ * are registered as separate anchors — `observed` = first signal that fits
12
+ * a wake pattern, `confirmed` = sustained signal that survives the
13
+ * `WAKE_CONFIRM_WINDOW_MS` hysteresis window in `circadian-rules.ts`.
14
+ *
15
+ * Per `wave1-interfaces.md` §5.2: the anchor set is
16
+ * `["wake.observed", "wake.confirmed", "bedtime.target", "nap.start"]`.
17
+ */
18
+ export { type AnchorContribution, type AnchorRegistry, HEALTH_ANCHORS, registerHealthAnchors, } from "../connectors/index.js";
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/anchors/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,cAAc,EACd,qBAAqB,GACtB,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import {
2
+ HEALTH_ANCHORS,
3
+ registerHealthAnchors
4
+ } from "../connectors/index.js";
5
+ export {
6
+ HEALTH_ANCHORS,
7
+ registerHealthAnchors
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/anchors/index.ts"],"sourcesContent":["/**\n * Anchor contributions exposed by plugin-health.\n *\n * The actual `registerHealthAnchors` implementation + the `HEALTH_ANCHORS`\n * tuple live in `../connectors/index.ts` (alongside the connector / bus-\n * family registration entry points so a single registry-detection pass\n * runs all three at boot). This file re-exports them so external callers\n * can import from `@elizaos/plugin-health/anchors`.\n *\n * Per `IMPLEMENTATION_PLAN.md` §3.2: BOTH `wake.observed` AND `wake.confirmed`\n * are registered as separate anchors — `observed` = first signal that fits\n * a wake pattern, `confirmed` = sustained signal that survives the\n * `WAKE_CONFIRM_WINDOW_MS` hysteresis window in `circadian-rules.ts`.\n *\n * Per `wave1-interfaces.md` §5.2: the anchor set is\n * `[\"wake.observed\", \"wake.confirmed\", \"bedtime.target\", \"nap.start\"]`.\n */\n\nexport {\n type AnchorContribution,\n type AnchorRegistry,\n HEALTH_ANCHORS,\n registerHealthAnchors,\n} from \"../connectors/index.js\";\n"],"mappings":"AAkBA;AAAA,EAGE;AAAA,EACA;AAAA,OACK;","names":[]}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Wave-1 stubs for the W1-F connector / channel / signal-bus contracts.
3
+ *
4
+ * These mirror `wave1-interfaces.md` §3 byte-identically. When W1-F lands the
5
+ * concrete `ConnectorRegistry` / `AnchorRegistry` / `ActivitySignalBus` types
6
+ * in their owning module, every `import` from this file should be replaced
7
+ * with the real path; nothing else needs to change because the shapes here
8
+ * are the frozen contract.
9
+ *
10
+ * No runtime behaviour lives here — types only.
11
+ */
12
+ export type ConnectorMode = "local" | "cloud";
13
+ export interface ConnectorStatus {
14
+ state: "ok" | "degraded" | "disconnected";
15
+ message?: string;
16
+ observedAt: string;
17
+ }
18
+ export type DispatchResult = {
19
+ ok: true;
20
+ messageId?: string;
21
+ } | {
22
+ ok: false;
23
+ reason: "disconnected" | "rate_limited" | "auth_expired" | "unknown_recipient" | "transport_error";
24
+ retryAfterMinutes?: number;
25
+ userActionable: boolean;
26
+ message?: string;
27
+ };
28
+ /**
29
+ * OAuth surface a connector contribution may advertise. URL provided by the
30
+ * connector contribution; the dispatcher does not hardcode. Health-bridge
31
+ * connectors (Strava, Fitbit, Withings, Oura) populate this so the OAuth
32
+ * driver iterates the registry — see `health-bridge/health-provider-registry.ts`.
33
+ */
34
+ export interface ConnectorOAuthConfig {
35
+ readonly authorizeUrl: string;
36
+ readonly tokenUrl: string;
37
+ readonly revokeUrl?: string | null;
38
+ readonly scopes?: readonly string[];
39
+ }
40
+ export interface ConnectorContribution {
41
+ kind: string;
42
+ capabilities: string[];
43
+ modes: ConnectorMode[];
44
+ describe: {
45
+ label: string;
46
+ };
47
+ /** URL provided by the connector contribution; the dispatcher does not hardcode. */
48
+ oauth?: ConnectorOAuthConfig;
49
+ /** URL provided by the connector contribution; the dispatcher does not hardcode. */
50
+ apiBaseUrl?: string;
51
+ start(): Promise<void>;
52
+ disconnect(): Promise<void>;
53
+ verify(): Promise<boolean>;
54
+ status(): Promise<ConnectorStatus>;
55
+ send?(payload: unknown): Promise<DispatchResult>;
56
+ read?(query: unknown): Promise<unknown>;
57
+ requiresApproval?: boolean;
58
+ }
59
+ export interface ConnectorRegistry {
60
+ register(c: ConnectorContribution): void;
61
+ list(filter?: {
62
+ capability?: string;
63
+ mode?: ConnectorMode;
64
+ }): ConnectorContribution[];
65
+ get(kind: string): ConnectorContribution | null;
66
+ byCapability(capability: string): ConnectorContribution[];
67
+ }
68
+ /**
69
+ * Registry surface exposed by W1-A's `ScheduledTask` runner for anchor key
70
+ * registration. plugin-health contributes `wake.observed`, `wake.confirmed`,
71
+ * `bedtime.target`, `nap.start` per `wave1-interfaces.md` §5.2.
72
+ *
73
+ * `wake.observed` and `wake.confirmed` are intentionally separate (per
74
+ * `IMPLEMENTATION_PLAN.md` §3.2): `observed` = first signal that fits a wake
75
+ * pattern, `confirmed` = sustained signal that survives the
76
+ * `WAKE_CONFIRM_WINDOW_MS` hysteresis window in `circadian-rules.ts`.
77
+ */
78
+ export interface AnchorRegistry {
79
+ register(anchor: AnchorContribution): void;
80
+ list(): AnchorContribution[];
81
+ get(anchorKey: string): AnchorContribution | null;
82
+ }
83
+ export interface AnchorContribution {
84
+ anchorKey: string;
85
+ description: string;
86
+ source: "plugin-health" | string;
87
+ }
88
+ /**
89
+ * Bus-family registry for `ActivitySignalBus`. plugin-health publishes the
90
+ * health-prefixed families documented in `wave1-interfaces.md` §5.3.
91
+ */
92
+ export interface BusFamilyRegistry {
93
+ register(family: BusFamilyContribution): void;
94
+ list(): BusFamilyContribution[];
95
+ }
96
+ export interface BusFamilyContribution {
97
+ family: string;
98
+ description: string;
99
+ source: "plugin-health" | string;
100
+ }
101
+ /**
102
+ * The runtime surface plugin-health expects to find on `IAgentRuntime`. All
103
+ * four registries are optional (`undefined` when W1-A / W1-F have not landed
104
+ * yet); registration callers tolerate a missing registry by logging a one-
105
+ * line skip reason.
106
+ */
107
+ export interface RuntimeWithHealthRegistries {
108
+ connectorRegistry?: ConnectorRegistry;
109
+ anchorRegistry?: AnchorRegistry;
110
+ busFamilyRegistry?: BusFamilyRegistry;
111
+ }
112
+ //# sourceMappingURL=contract-stubs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-stubs.d.ts","sourceRoot":"","sources":["../../src/connectors/contract-stubs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=contract-stubs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Connector / anchor / bus-family registration entry point.
3
+ *
4
+ * Per `wave1-interfaces.md` §5.1 / §5.2 / §5.3, plugin-health contributes:
5
+ *
6
+ * - 6 ConnectorContributions: apple_health, google_fit, strava, fitbit,
7
+ * withings, oura
8
+ * - 4 anchors: wake.observed, wake.confirmed, bedtime.target, nap.start
9
+ * - 8 bus families: health.sleep.detected, health.sleep.ended,
10
+ * health.wake.observed, health.wake.confirmed, health.nap.detected,
11
+ * health.bedtime.imminent, health.regularity.changed,
12
+ * health.workout.completed
13
+ *
14
+ * Registration is best-effort: if W1-A / W1-F's runtime registries have not
15
+ * landed yet, this module logs a one-line skip and continues. The connector
16
+ * / anchor / bus-family identifiers are still exported as constants so
17
+ * other Wave-1 agents can reference them.
18
+ */
19
+ import type { RuntimeWithHealthRegistries } from "./contract-stubs.js";
20
+ export * from "./contract-stubs.js";
21
+ type RuntimeHealthRegistryHost = object & RuntimeWithHealthRegistries;
22
+ export declare const HEALTH_CONNECTOR_KINDS: readonly ["apple_health", "google_fit", "strava", "fitbit", "withings", "oura"];
23
+ export declare const HEALTH_ANCHORS: readonly ["wake.observed", "wake.confirmed", "bedtime.target", "nap.start"];
24
+ export declare const HEALTH_BUS_FAMILIES: readonly ["health.sleep.detected", "health.sleep.ended", "health.wake.observed", "health.wake.confirmed", "health.nap.detected", "health.bedtime.imminent", "health.regularity.changed", "health.workout.completed"];
25
+ export declare function registerHealthConnectors(runtime: RuntimeHealthRegistryHost): void;
26
+ export declare function registerHealthAnchors(runtime: RuntimeHealthRegistryHost): void;
27
+ export declare function registerHealthBusFamilies(runtime: RuntimeHealthRegistryHost): void;
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/connectors/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAUV,2BAA2B,EAC5B,MAAM,qBAAqB,CAAC;AAE7B,cAAc,qBAAqB,CAAC;AAEpC,KAAK,yBAAyB,GAAG,MAAM,GAAG,2BAA2B,CAAC;AAEtE,eAAO,MAAM,sBAAsB,iFAOG,CAAC;AAEvC,eAAO,MAAM,cAAc,6EAKW,CAAC;AAEvC,eAAO,MAAM,mBAAmB,sNASM,CAAC;AA+JvC,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,yBAAyB,GACjC,IAAI,CAoBN;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,yBAAyB,GACjC,IAAI,CAuBN;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,yBAAyB,GACjC,IAAI,CAoBN"}
@@ -0,0 +1,202 @@
1
+ import { logger } from "@elizaos/core";
2
+ import { getHealthProviderSpec } from "../health-bridge/health-provider-registry.js";
3
+ export * from "./contract-stubs.js";
4
+ const HEALTH_CONNECTOR_KINDS = [
5
+ "apple_health",
6
+ "google_fit",
7
+ "strava",
8
+ "fitbit",
9
+ "withings",
10
+ "oura"
11
+ ];
12
+ const HEALTH_ANCHORS = [
13
+ "wake.observed",
14
+ "wake.confirmed",
15
+ "bedtime.target",
16
+ "nap.start"
17
+ ];
18
+ const HEALTH_BUS_FAMILIES = [
19
+ "health.sleep.detected",
20
+ "health.sleep.ended",
21
+ "health.wake.observed",
22
+ "health.wake.confirmed",
23
+ "health.nap.detected",
24
+ "health.bedtime.imminent",
25
+ "health.regularity.changed",
26
+ "health.workout.completed"
27
+ ];
28
+ const HEALTH_CONNECTOR_CAPABILITIES = {
29
+ apple_health: [
30
+ "health.sleep.read",
31
+ "health.activity.read",
32
+ "health.workouts.read",
33
+ "health.body.read",
34
+ "health.vitals.read"
35
+ ],
36
+ google_fit: [
37
+ "health.sleep.read",
38
+ "health.activity.read",
39
+ "health.workouts.read",
40
+ "health.body.read",
41
+ "health.vitals.read"
42
+ ],
43
+ strava: ["health.activity.read", "health.workouts.read"],
44
+ fitbit: [
45
+ "health.sleep.read",
46
+ "health.activity.read",
47
+ "health.workouts.read",
48
+ "health.body.read",
49
+ "health.vitals.read",
50
+ "health.readiness.read"
51
+ ],
52
+ withings: ["health.sleep.read", "health.body.read", "health.vitals.read"],
53
+ oura: [
54
+ "health.sleep.read",
55
+ "health.activity.read",
56
+ "health.workouts.read",
57
+ "health.readiness.read"
58
+ ]
59
+ };
60
+ const CONNECTOR_LABELS = {
61
+ apple_health: "Apple Health (HealthKit)",
62
+ google_fit: "Google Fit",
63
+ strava: "Strava",
64
+ fitbit: "Fitbit",
65
+ withings: "Withings",
66
+ oura: "Oura"
67
+ };
68
+ function buildConnectorContribution(kind) {
69
+ const stubStatus = async () => ({
70
+ state: "disconnected",
71
+ message: "plugin-health Wave-1 stub: full dispatcher wiring lands when W1-F's runtime context shape is finalised.",
72
+ observedAt: (/* @__PURE__ */ new Date()).toISOString()
73
+ });
74
+ const stubSend = async () => ({
75
+ ok: false,
76
+ reason: "transport_error",
77
+ userActionable: true,
78
+ message: "plugin-health Wave-1 stub: connector send is not yet wired; configure via the legacy lifeops health-connectors path."
79
+ });
80
+ const providerSpec = getHealthProviderSpec(kind);
81
+ const oauth = providerSpec ? {
82
+ authorizeUrl: providerSpec.oauth.authorizeUrl,
83
+ tokenUrl: providerSpec.oauth.tokenUrl,
84
+ revokeUrl: providerSpec.oauth.revokeUrl,
85
+ scopes: providerSpec.oauth.defaultScopes
86
+ } : void 0;
87
+ const apiBaseUrl = providerSpec?.apiBaseUrl;
88
+ return {
89
+ kind,
90
+ capabilities: [...HEALTH_CONNECTOR_CAPABILITIES[kind]],
91
+ modes: kind === "apple_health" ? ["local"] : kind === "google_fit" ? ["local", "cloud"] : ["cloud"],
92
+ describe: { label: CONNECTOR_LABELS[kind] },
93
+ oauth,
94
+ apiBaseUrl,
95
+ start: async () => {
96
+ },
97
+ disconnect: async () => {
98
+ },
99
+ verify: async () => false,
100
+ status: stubStatus,
101
+ send: stubSend,
102
+ read: async () => null
103
+ };
104
+ }
105
+ function buildAnchorContribution(anchorKey) {
106
+ return {
107
+ anchorKey,
108
+ description: `plugin-health anchor: ${anchorKey}`,
109
+ source: "plugin-health"
110
+ };
111
+ }
112
+ function buildBusFamilyContribution(family) {
113
+ return {
114
+ family,
115
+ description: `plugin-health bus family: ${family}`,
116
+ source: "plugin-health"
117
+ };
118
+ }
119
+ function getConnectorRegistry(runtime) {
120
+ return runtime.connectorRegistry;
121
+ }
122
+ function getAnchorRegistry(runtime) {
123
+ return runtime.anchorRegistry;
124
+ }
125
+ function getBusFamilyRegistry(runtime) {
126
+ return runtime.busFamilyRegistry;
127
+ }
128
+ function registerHealthConnectors(runtime) {
129
+ const registry = getConnectorRegistry(runtime);
130
+ if (!registry) {
131
+ logger.info(
132
+ { src: "plugin:health", waiting_on: "W1-F connectorRegistry" },
133
+ "Skipping plugin-health connector registration (registry not yet available)"
134
+ );
135
+ return;
136
+ }
137
+ for (const kind of HEALTH_CONNECTOR_KINDS) {
138
+ registry.register(buildConnectorContribution(kind));
139
+ }
140
+ logger.info(
141
+ {
142
+ src: "plugin:health",
143
+ registered: HEALTH_CONNECTOR_KINDS.length,
144
+ kinds: HEALTH_CONNECTOR_KINDS
145
+ },
146
+ "Registered plugin-health connectors"
147
+ );
148
+ }
149
+ function registerHealthAnchors(runtime) {
150
+ const registry = getAnchorRegistry(runtime);
151
+ if (!registry) {
152
+ logger.info(
153
+ { src: "plugin:health", waiting_on: "W1-A anchorRegistry" },
154
+ "Skipping plugin-health anchor registration (registry not yet available)"
155
+ );
156
+ return;
157
+ }
158
+ for (const anchorKey of HEALTH_ANCHORS) {
159
+ if (registry.get(anchorKey)) {
160
+ continue;
161
+ }
162
+ registry.register(buildAnchorContribution(anchorKey));
163
+ }
164
+ logger.info(
165
+ {
166
+ src: "plugin:health",
167
+ registered: HEALTH_ANCHORS.length,
168
+ anchors: HEALTH_ANCHORS
169
+ },
170
+ "Registered plugin-health anchors"
171
+ );
172
+ }
173
+ function registerHealthBusFamilies(runtime) {
174
+ const registry = getBusFamilyRegistry(runtime);
175
+ if (!registry) {
176
+ logger.info(
177
+ { src: "plugin:health", waiting_on: "W1-A or W2-D busFamilyRegistry" },
178
+ "Skipping plugin-health bus-family registration (registry not yet available)"
179
+ );
180
+ return;
181
+ }
182
+ for (const family of HEALTH_BUS_FAMILIES) {
183
+ registry.register(buildBusFamilyContribution(family));
184
+ }
185
+ logger.info(
186
+ {
187
+ src: "plugin:health",
188
+ registered: HEALTH_BUS_FAMILIES.length,
189
+ families: HEALTH_BUS_FAMILIES
190
+ },
191
+ "Registered plugin-health bus families"
192
+ );
193
+ }
194
+ export {
195
+ HEALTH_ANCHORS,
196
+ HEALTH_BUS_FAMILIES,
197
+ HEALTH_CONNECTOR_KINDS,
198
+ registerHealthAnchors,
199
+ registerHealthBusFamilies,
200
+ registerHealthConnectors
201
+ };
202
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/connectors/index.ts"],"sourcesContent":["/**\n * Connector / anchor / bus-family registration entry point.\n *\n * Per `wave1-interfaces.md` §5.1 / §5.2 / §5.3, plugin-health contributes:\n *\n * - 6 ConnectorContributions: apple_health, google_fit, strava, fitbit,\n * withings, oura\n * - 4 anchors: wake.observed, wake.confirmed, bedtime.target, nap.start\n * - 8 bus families: health.sleep.detected, health.sleep.ended,\n * health.wake.observed, health.wake.confirmed, health.nap.detected,\n * health.bedtime.imminent, health.regularity.changed,\n * health.workout.completed\n *\n * Registration is best-effort: if W1-A / W1-F's runtime registries have not\n * landed yet, this module logs a one-line skip and continues. The connector\n * / anchor / bus-family identifiers are still exported as constants so\n * other Wave-1 agents can reference them.\n */\n\nimport { logger } from \"@elizaos/core\";\nimport { getHealthProviderSpec } from \"../health-bridge/health-provider-registry.js\";\nimport type {\n AnchorContribution,\n AnchorRegistry,\n BusFamilyContribution,\n BusFamilyRegistry,\n ConnectorContribution,\n ConnectorOAuthConfig,\n ConnectorRegistry,\n ConnectorStatus,\n DispatchResult,\n RuntimeWithHealthRegistries,\n} from \"./contract-stubs.js\";\n\nexport * from \"./contract-stubs.js\";\n\ntype RuntimeHealthRegistryHost = object & RuntimeWithHealthRegistries;\n\nexport const HEALTH_CONNECTOR_KINDS = [\n \"apple_health\",\n \"google_fit\",\n \"strava\",\n \"fitbit\",\n \"withings\",\n \"oura\",\n] as const satisfies readonly string[];\n\nexport const HEALTH_ANCHORS = [\n \"wake.observed\",\n \"wake.confirmed\",\n \"bedtime.target\",\n \"nap.start\",\n] as const satisfies readonly string[];\n\nexport const HEALTH_BUS_FAMILIES = [\n \"health.sleep.detected\",\n \"health.sleep.ended\",\n \"health.wake.observed\",\n \"health.wake.confirmed\",\n \"health.nap.detected\",\n \"health.bedtime.imminent\",\n \"health.regularity.changed\",\n \"health.workout.completed\",\n] as const satisfies readonly string[];\n\n/**\n * Capability strings published by plugin-health connectors. Matches the\n * `LIFEOPS_HEALTH_CONNECTOR_CAPABILITIES` set in `../contracts/health.js` so a\n * planner querying `connectorRegistry.byCapability(\"health.sleep.read\")`\n * resolves the correct contributors.\n */\nconst HEALTH_CONNECTOR_CAPABILITIES: Record<\n (typeof HEALTH_CONNECTOR_KINDS)[number],\n readonly string[]\n> = {\n apple_health: [\n \"health.sleep.read\",\n \"health.activity.read\",\n \"health.workouts.read\",\n \"health.body.read\",\n \"health.vitals.read\",\n ],\n google_fit: [\n \"health.sleep.read\",\n \"health.activity.read\",\n \"health.workouts.read\",\n \"health.body.read\",\n \"health.vitals.read\",\n ],\n strava: [\"health.activity.read\", \"health.workouts.read\"],\n fitbit: [\n \"health.sleep.read\",\n \"health.activity.read\",\n \"health.workouts.read\",\n \"health.body.read\",\n \"health.vitals.read\",\n \"health.readiness.read\",\n ],\n withings: [\"health.sleep.read\", \"health.body.read\", \"health.vitals.read\"],\n oura: [\n \"health.sleep.read\",\n \"health.activity.read\",\n \"health.workouts.read\",\n \"health.readiness.read\",\n ],\n};\n\nconst CONNECTOR_LABELS: Record<\n (typeof HEALTH_CONNECTOR_KINDS)[number],\n string\n> = {\n apple_health: \"Apple Health (HealthKit)\",\n google_fit: \"Google Fit\",\n strava: \"Strava\",\n fitbit: \"Fitbit\",\n withings: \"Withings\",\n oura: \"Oura\",\n};\n\n/**\n * Wave-1 placeholder dispatcher. The actual `start` / `verify` / `status` /\n * `read` implementations live in `health-bridge.ts` + `health-connectors.ts`\n * and require a fully-wired runtime context (credentials store, OAuth\n * sessions, repository factory) that the W1-F generic ConnectorRegistry\n * hasn't standardised yet.\n *\n * Until W1-F publishes the runtime context shape, the contribution emits\n * `disconnected` for status checks and `transport_error` for send/read so\n * downstream task scheduling treats the connector as unavailable rather\n * than silently no-op'ing.\n */\nfunction buildConnectorContribution(\n kind: (typeof HEALTH_CONNECTOR_KINDS)[number],\n): ConnectorContribution {\n const stubStatus = async (): Promise<ConnectorStatus> => ({\n state: \"disconnected\",\n message:\n \"plugin-health Wave-1 stub: full dispatcher wiring lands when W1-F's runtime context shape is finalised.\",\n observedAt: new Date().toISOString(),\n });\n const stubSend = async (): Promise<DispatchResult> => ({\n ok: false,\n reason: \"transport_error\",\n userActionable: true,\n message:\n \"plugin-health Wave-1 stub: connector send is not yet wired; configure via the legacy lifeops health-connectors path.\",\n });\n // URL provided by the connector contribution; the dispatcher does not\n // hardcode. The OAuth-bridged providers (strava / fitbit / withings / oura)\n // surface their authorize / token / api-base URLs from the canonical\n // health-provider registry.\n const providerSpec = getHealthProviderSpec(kind);\n const oauth: ConnectorOAuthConfig | undefined = providerSpec\n ? {\n authorizeUrl: providerSpec.oauth.authorizeUrl,\n tokenUrl: providerSpec.oauth.tokenUrl,\n revokeUrl: providerSpec.oauth.revokeUrl,\n scopes: providerSpec.oauth.defaultScopes,\n }\n : undefined;\n const apiBaseUrl = providerSpec?.apiBaseUrl;\n return {\n kind,\n capabilities: [...HEALTH_CONNECTOR_CAPABILITIES[kind]],\n modes:\n kind === \"apple_health\"\n ? [\"local\"]\n : kind === \"google_fit\"\n ? [\"local\", \"cloud\"]\n : [\"cloud\"],\n describe: { label: CONNECTOR_LABELS[kind] },\n oauth,\n apiBaseUrl,\n start: async () => {\n // Wave-1 stub — concrete start lives in `health-bridge.ts` /\n // `health-connectors.ts` and is invoked through the legacy\n // app-lifeops mixin path until W1-F's generic dispatcher lands.\n },\n disconnect: async () => {\n // Wave-1 stub — concrete disconnect lives in `health-oauth.ts`.\n },\n verify: async () => false,\n status: stubStatus,\n send: stubSend,\n read: async () => null,\n };\n}\n\nfunction buildAnchorContribution(anchorKey: string): AnchorContribution {\n return {\n anchorKey,\n description: `plugin-health anchor: ${anchorKey}`,\n source: \"plugin-health\",\n };\n}\n\nfunction buildBusFamilyContribution(family: string): BusFamilyContribution {\n return {\n family,\n description: `plugin-health bus family: ${family}`,\n source: \"plugin-health\",\n };\n}\n\nfunction getConnectorRegistry(\n runtime: RuntimeHealthRegistryHost,\n): ConnectorRegistry | undefined {\n return runtime.connectorRegistry;\n}\n\nfunction getAnchorRegistry(\n runtime: RuntimeHealthRegistryHost,\n): AnchorRegistry | undefined {\n return runtime.anchorRegistry;\n}\n\nfunction getBusFamilyRegistry(\n runtime: RuntimeHealthRegistryHost,\n): BusFamilyRegistry | undefined {\n return runtime.busFamilyRegistry;\n}\n\nexport function registerHealthConnectors(\n runtime: RuntimeHealthRegistryHost,\n): void {\n const registry = getConnectorRegistry(runtime);\n if (!registry) {\n logger.info(\n { src: \"plugin:health\", waiting_on: \"W1-F connectorRegistry\" },\n \"Skipping plugin-health connector registration (registry not yet available)\",\n );\n return;\n }\n for (const kind of HEALTH_CONNECTOR_KINDS) {\n registry.register(buildConnectorContribution(kind));\n }\n logger.info(\n {\n src: \"plugin:health\",\n registered: HEALTH_CONNECTOR_KINDS.length,\n kinds: HEALTH_CONNECTOR_KINDS,\n },\n \"Registered plugin-health connectors\",\n );\n}\n\nexport function registerHealthAnchors(\n runtime: RuntimeHealthRegistryHost,\n): void {\n const registry = getAnchorRegistry(runtime);\n if (!registry) {\n logger.info(\n { src: \"plugin:health\", waiting_on: \"W1-A anchorRegistry\" },\n \"Skipping plugin-health anchor registration (registry not yet available)\",\n );\n return;\n }\n for (const anchorKey of HEALTH_ANCHORS) {\n if (registry.get(anchorKey)) {\n continue;\n }\n registry.register(buildAnchorContribution(anchorKey));\n }\n logger.info(\n {\n src: \"plugin:health\",\n registered: HEALTH_ANCHORS.length,\n anchors: HEALTH_ANCHORS,\n },\n \"Registered plugin-health anchors\",\n );\n}\n\nexport function registerHealthBusFamilies(\n runtime: RuntimeHealthRegistryHost,\n): void {\n const registry = getBusFamilyRegistry(runtime);\n if (!registry) {\n logger.info(\n { src: \"plugin:health\", waiting_on: \"W1-A or W2-D busFamilyRegistry\" },\n \"Skipping plugin-health bus-family registration (registry not yet available)\",\n );\n return;\n }\n for (const family of HEALTH_BUS_FAMILIES) {\n registry.register(buildBusFamilyContribution(family));\n }\n logger.info(\n {\n src: \"plugin:health\",\n registered: HEALTH_BUS_FAMILIES.length,\n families: HEALTH_BUS_FAMILIES,\n },\n \"Registered plugin-health bus families\",\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Default `CircadianInsightContract` registered by `plugin-health` during
3
+ * `init`. Consumers (e.g. `app-lifeops` SCHEDULE / SCHEDULED_TASK) read
4
+ * through this contract instead of importing plugin-health internals.
5
+ *
6
+ * The default implementation is intentionally conservative: it returns
7
+ * `state=null` / `recommendedAtIso=null` until a richer impl is registered
8
+ * (e.g. by app-lifeops once its scheduler tick produces a fresh insight).
9
+ * This keeps the contract honest — callers can always tell whether
10
+ * inference is calibrated, and never mistake an uninitialized field for a
11
+ * meaningful zero.
12
+ */
13
+ import type { CircadianInsightContract } from "./circadian.js";
14
+ export declare function createDefaultCircadianInsightContract(): CircadianInsightContract;
15
+ //# sourceMappingURL=circadian-default.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circadian-default.d.ts","sourceRoot":"","sources":["../../src/contracts/circadian-default.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,wBAAwB,EAGzB,MAAM,gBAAgB,CAAC;AAExB,wBAAgB,qCAAqC,IAAI,wBAAwB,CAyBhF"}
@@ -0,0 +1,30 @@
1
+ function createDefaultCircadianInsightContract() {
2
+ return {
3
+ async getCurrentSleepWindow() {
4
+ return {
5
+ state: null,
6
+ confidence: 0,
7
+ lastWakeAtIso: null,
8
+ currentSleepStartedAtIso: null,
9
+ bedtimeTargetAtIso: null
10
+ };
11
+ },
12
+ async inferOptimalSchedulingWindow() {
13
+ return {
14
+ recommendedAtIso: null,
15
+ nextMealLabel: null,
16
+ windowStartIso: null,
17
+ windowEndIso: null,
18
+ confidence: 0,
19
+ reason: "circadian inference not calibrated"
20
+ };
21
+ },
22
+ async getLatestInsight() {
23
+ return null;
24
+ }
25
+ };
26
+ }
27
+ export {
28
+ createDefaultCircadianInsightContract
29
+ };
30
+ //# sourceMappingURL=circadian-default.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/contracts/circadian-default.ts"],"sourcesContent":["/**\n * Default `CircadianInsightContract` registered by `plugin-health` during\n * `init`. Consumers (e.g. `app-lifeops` SCHEDULE / SCHEDULED_TASK) read\n * through this contract instead of importing plugin-health internals.\n *\n * The default implementation is intentionally conservative: it returns\n * `state=null` / `recommendedAtIso=null` until a richer impl is registered\n * (e.g. by app-lifeops once its scheduler tick produces a fresh insight).\n * This keeps the contract honest — callers can always tell whether\n * inference is calibrated, and never mistake an uninitialized field for a\n * meaningful zero.\n */\n\nimport type {\n CircadianInsightContract,\n SchedulingWindow,\n SleepWindow,\n} from \"./circadian.js\";\n\nexport function createDefaultCircadianInsightContract(): CircadianInsightContract {\n return {\n async getCurrentSleepWindow(): Promise<SleepWindow> {\n return {\n state: null,\n confidence: 0,\n lastWakeAtIso: null,\n currentSleepStartedAtIso: null,\n bedtimeTargetAtIso: null,\n };\n },\n async inferOptimalSchedulingWindow(): Promise<SchedulingWindow> {\n return {\n recommendedAtIso: null,\n nextMealLabel: null,\n windowStartIso: null,\n windowEndIso: null,\n confidence: 0,\n reason: \"circadian inference not calibrated\",\n };\n },\n async getLatestInsight() {\n return null;\n },\n };\n}\n"],"mappings":"AAmBO,SAAS,wCAAkE;AAChF,SAAO;AAAA,IACL,MAAM,wBAA8C;AAClD,aAAO;AAAA,QACL,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,0BAA0B;AAAA,QAC1B,oBAAoB;AAAA,MACtB;AAAA,IACF;AAAA,IACA,MAAM,+BAA0D;AAC9D,aAAO;AAAA,QACL,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,gBAAgB;AAAA,QAChB,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,MAAM,mBAAmB;AACvB,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}