@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.
- package/README.md +107 -0
- package/dist/actions/index.d.ts +20 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +5 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/anchors/index.d.ts +19 -0
- package/dist/anchors/index.d.ts.map +1 -0
- package/dist/anchors/index.js +9 -0
- package/dist/anchors/index.js.map +1 -0
- package/dist/connectors/contract-stubs.d.ts +112 -0
- package/dist/connectors/contract-stubs.d.ts.map +1 -0
- package/dist/connectors/contract-stubs.js +1 -0
- package/dist/connectors/contract-stubs.js.map +1 -0
- package/dist/connectors/index.d.ts +28 -0
- package/dist/connectors/index.d.ts.map +1 -0
- package/dist/connectors/index.js +202 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/contracts/circadian-default.d.ts +15 -0
- package/dist/contracts/circadian-default.d.ts.map +1 -0
- package/dist/contracts/circadian-default.js +30 -0
- package/dist/contracts/circadian-default.js.map +1 -0
- package/dist/contracts/circadian.d.ts +92 -0
- package/dist/contracts/circadian.d.ts.map +1 -0
- package/dist/contracts/circadian.js +14 -0
- package/dist/contracts/circadian.js.map +1 -0
- package/dist/contracts/health.d.ts +9 -0
- package/dist/contracts/health.d.ts.map +1 -0
- package/dist/contracts/health.js +21 -0
- package/dist/contracts/health.js.map +1 -0
- package/dist/contracts/lifeops-connector-degradation.d.ts +9 -0
- package/dist/contracts/lifeops-connector-degradation.d.ts.map +1 -0
- package/dist/contracts/lifeops-connector-degradation.js +17 -0
- package/dist/contracts/lifeops-connector-degradation.js.map +1 -0
- package/dist/contracts/lifeops.d.ts +3123 -0
- package/dist/contracts/lifeops.d.ts.map +1 -0
- package/dist/contracts/lifeops.js +635 -0
- package/dist/contracts/lifeops.js.map +1 -0
- package/dist/contracts/permissions.d.ts +39 -0
- package/dist/contracts/permissions.d.ts.map +1 -0
- package/dist/contracts/permissions.js +1 -0
- package/dist/contracts/permissions.js.map +1 -0
- package/dist/default-packs/bedtime.d.ts +14 -0
- package/dist/default-packs/bedtime.d.ts.map +1 -0
- package/dist/default-packs/bedtime.js +48 -0
- package/dist/default-packs/bedtime.js.map +1 -0
- package/dist/default-packs/contract-stubs.d.ts +161 -0
- package/dist/default-packs/contract-stubs.d.ts.map +1 -0
- package/dist/default-packs/contract-stubs.js +1 -0
- package/dist/default-packs/contract-stubs.js.map +1 -0
- package/dist/default-packs/index.d.ts +18 -0
- package/dist/default-packs/index.d.ts.map +1 -0
- package/dist/default-packs/index.js +39 -0
- package/dist/default-packs/index.js.map +1 -0
- package/dist/default-packs/sleep-recap.d.ts +14 -0
- package/dist/default-packs/sleep-recap.d.ts.map +1 -0
- package/dist/default-packs/sleep-recap.js +51 -0
- package/dist/default-packs/sleep-recap.js.map +1 -0
- package/dist/default-packs/wake-up.d.ts +14 -0
- package/dist/default-packs/wake-up.d.ts.map +1 -0
- package/dist/default-packs/wake-up.js +61 -0
- package/dist/default-packs/wake-up.js.map +1 -0
- package/dist/health-bridge/health-bridge.d.ts +57 -0
- package/dist/health-bridge/health-bridge.d.ts.map +1 -0
- package/dist/health-bridge/health-bridge.js +558 -0
- package/dist/health-bridge/health-bridge.js.map +1 -0
- package/dist/health-bridge/health-connectors.d.ts +23 -0
- package/dist/health-bridge/health-connectors.d.ts.map +1 -0
- package/dist/health-bridge/health-connectors.js +1018 -0
- package/dist/health-bridge/health-connectors.js.map +1 -0
- package/dist/health-bridge/health-oauth.d.ts +62 -0
- package/dist/health-bridge/health-oauth.d.ts.map +1 -0
- package/dist/health-bridge/health-oauth.js +432 -0
- package/dist/health-bridge/health-oauth.js.map +1 -0
- package/dist/health-bridge/health-provider-registry.d.ts +89 -0
- package/dist/health-bridge/health-provider-registry.d.ts.map +1 -0
- package/dist/health-bridge/health-provider-registry.js +141 -0
- package/dist/health-bridge/health-provider-registry.js.map +1 -0
- package/dist/health-bridge/health-records.d.ts +14 -0
- package/dist/health-bridge/health-records.d.ts.map +1 -0
- package/dist/health-bridge/health-records.js +45 -0
- package/dist/health-bridge/health-records.js.map +1 -0
- package/dist/health-bridge/index.d.ts +22 -0
- package/dist/health-bridge/index.d.ts.map +1 -0
- package/dist/health-bridge/index.js +7 -0
- package/dist/health-bridge/index.js.map +1 -0
- package/dist/health-bridge/service-normalize-health.d.ts +3 -0
- package/dist/health-bridge/service-normalize-health.d.ts.map +1 -0
- package/dist/health-bridge/service-normalize-health.js +96 -0
- package/dist/health-bridge/service-normalize-health.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/screen-time/index.d.ts +23 -0
- package/dist/screen-time/index.d.ts.map +1 -0
- package/dist/screen-time/index.js +1 -0
- package/dist/screen-time/index.js.map +1 -0
- package/dist/sleep/awake-probability.d.ts +11 -0
- package/dist/sleep/awake-probability.d.ts.map +1 -0
- package/dist/sleep/awake-probability.js +163 -0
- package/dist/sleep/awake-probability.js.map +1 -0
- package/dist/sleep/circadian-rules.d.ts +45 -0
- package/dist/sleep/circadian-rules.d.ts.map +1 -0
- package/dist/sleep/circadian-rules.js +258 -0
- package/dist/sleep/circadian-rules.js.map +1 -0
- package/dist/sleep/index.d.ts +21 -0
- package/dist/sleep/index.d.ts.map +1 -0
- package/dist/sleep/index.js +11 -0
- package/dist/sleep/index.js.map +1 -0
- package/dist/sleep/sleep-cycle-dispatch.d.ts +75 -0
- package/dist/sleep/sleep-cycle-dispatch.d.ts.map +1 -0
- package/dist/sleep/sleep-cycle-dispatch.js +102 -0
- package/dist/sleep/sleep-cycle-dispatch.js.map +1 -0
- package/dist/sleep/sleep-cycle.d.ts +38 -0
- package/dist/sleep/sleep-cycle.d.ts.map +1 -0
- package/dist/sleep/sleep-cycle.js +418 -0
- package/dist/sleep/sleep-cycle.js.map +1 -0
- package/dist/sleep/sleep-episode-store.d.ts +25 -0
- package/dist/sleep/sleep-episode-store.d.ts.map +1 -0
- package/dist/sleep/sleep-episode-store.js +69 -0
- package/dist/sleep/sleep-episode-store.js.map +1 -0
- package/dist/sleep/sleep-episode-types.d.ts +38 -0
- package/dist/sleep/sleep-episode-types.d.ts.map +1 -0
- package/dist/sleep/sleep-episode-types.js +14 -0
- package/dist/sleep/sleep-episode-types.js.map +1 -0
- package/dist/sleep/sleep-recap.d.ts +19 -0
- package/dist/sleep/sleep-recap.d.ts.map +1 -0
- package/dist/sleep/sleep-recap.js +1 -0
- package/dist/sleep/sleep-recap.js.map +1 -0
- package/dist/sleep/sleep-regularity.d.ts +19 -0
- package/dist/sleep/sleep-regularity.d.ts.map +1 -0
- package/dist/sleep/sleep-regularity.js +242 -0
- package/dist/sleep/sleep-regularity.js.map +1 -0
- package/dist/sleep/sleep-wake-events.d.ts +58 -0
- package/dist/sleep/sleep-wake-events.d.ts.map +1 -0
- package/dist/sleep/sleep-wake-events.js +135 -0
- package/dist/sleep/sleep-wake-events.js.map +1 -0
- package/dist/sleep/source-reliability.d.ts +38 -0
- package/dist/sleep/source-reliability.d.ts.map +1 -0
- package/dist/sleep/source-reliability.js +62 -0
- package/dist/sleep/source-reliability.js.map +1 -0
- package/dist/util/index.d.ts +10 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +3 -0
- package/dist/util/index.js.map +1 -0
- package/dist/util/normalize.d.ts +22 -0
- package/dist/util/normalize.d.ts.map +1 -0
- package/dist/util/normalize.js +62 -0
- package/dist/util/normalize.js.map +1 -0
- package/dist/util/time-util.d.ts +10 -0
- package/dist/util/time-util.d.ts.map +1 -0
- package/dist/util/time-util.js +14 -0
- package/dist/util/time-util.js.map +1 -0
- package/dist/util/time.d.ts +17 -0
- package/dist/util/time.d.ts.map +1 -0
- package/dist/util/time.js +152 -0
- package/dist/util/time.js.map +1 -0
- package/dist/util/token-encryption.d.ts +42 -0
- package/dist/util/token-encryption.d.ts.map +1 -0
- package/dist/util/token-encryption.js +96 -0
- package/dist/util/token-encryption.js.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
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":[]}
|