@daobrew/wellness-mcp 0.1.0

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 (76) hide show
  1. package/README.md +98 -0
  2. package/SKILL.md +190 -0
  3. package/audio/earth_breathing.m4a +0 -0
  4. package/audio/earth_meditation.m4a +0 -0
  5. package/audio/earth_zhanZhuang.m4a +0 -0
  6. package/audio/fire_breathing.m4a +0 -0
  7. package/audio/fire_meditation.m4a +0 -0
  8. package/audio/fire_zhanZhuang.m4a +0 -0
  9. package/audio/metal_breathing.m4a +0 -0
  10. package/audio/metal_meditation.m4a +0 -0
  11. package/audio/metal_zhanZhuang.m4a +0 -0
  12. package/audio/water_breathing.m4a +0 -0
  13. package/audio/water_meditation.m4a +0 -0
  14. package/audio/water_zhanZhuang.m4a +0 -0
  15. package/audio/wood_breathing.m4a +0 -0
  16. package/audio/wood_meditation.m4a +0 -0
  17. package/audio/wood_zhanZhuang.m4a +0 -0
  18. package/dist/src/audio.d.ts +13 -0
  19. package/dist/src/audio.js +88 -0
  20. package/dist/src/cache.d.ts +7 -0
  21. package/dist/src/cache.js +31 -0
  22. package/dist/src/client.d.ts +22 -0
  23. package/dist/src/client.js +65 -0
  24. package/dist/src/cooldown.d.ts +5 -0
  25. package/dist/src/cooldown.js +35 -0
  26. package/dist/src/headphones.d.ts +6 -0
  27. package/dist/src/headphones.js +50 -0
  28. package/dist/src/health/google-fit.d.ts +13 -0
  29. package/dist/src/health/google-fit.js +108 -0
  30. package/dist/src/health/index.d.ts +6 -0
  31. package/dist/src/health/index.js +42 -0
  32. package/dist/src/health/oauth.d.ts +6 -0
  33. package/dist/src/health/oauth.js +69 -0
  34. package/dist/src/health/oura.d.ts +14 -0
  35. package/dist/src/health/oura.js +130 -0
  36. package/dist/src/health/sync.d.ts +7 -0
  37. package/dist/src/health/sync.js +194 -0
  38. package/dist/src/index.d.ts +2 -0
  39. package/dist/src/index.js +107 -0
  40. package/dist/src/mock.d.ts +8 -0
  41. package/dist/src/mock.js +176 -0
  42. package/dist/src/preferences.d.ts +13 -0
  43. package/dist/src/preferences.js +47 -0
  44. package/dist/src/session.d.ts +15 -0
  45. package/dist/src/session.js +40 -0
  46. package/dist/src/setup-cli.js +2 -0
  47. package/dist/src/setup.d.ts +17 -0
  48. package/dist/src/setup.js +323 -0
  49. package/dist/src/tools.d.ts +4 -0
  50. package/dist/src/tools.js +420 -0
  51. package/dist/src/types.d.ts +86 -0
  52. package/dist/src/types.js +52 -0
  53. package/dist/tests/audio.test.d.ts +1 -0
  54. package/dist/tests/audio.test.js +67 -0
  55. package/dist/tests/cache.test.d.ts +1 -0
  56. package/dist/tests/cache.test.js +61 -0
  57. package/dist/tests/client.test.d.ts +1 -0
  58. package/dist/tests/client.test.js +95 -0
  59. package/dist/tests/cooldown.test.d.ts +1 -0
  60. package/dist/tests/cooldown.test.js +66 -0
  61. package/dist/tests/e2e.test.d.ts +1 -0
  62. package/dist/tests/e2e.test.js +144 -0
  63. package/dist/tests/guards.test.d.ts +1 -0
  64. package/dist/tests/guards.test.js +169 -0
  65. package/dist/tests/headphones.test.d.ts +1 -0
  66. package/dist/tests/headphones.test.js +46 -0
  67. package/dist/tests/mock.test.d.ts +1 -0
  68. package/dist/tests/mock.test.js +194 -0
  69. package/dist/tests/preferences.test.d.ts +1 -0
  70. package/dist/tests/preferences.test.js +71 -0
  71. package/dist/tests/session.test.d.ts +1 -0
  72. package/dist/tests/session.test.js +85 -0
  73. package/dist/tests/sync.test.d.ts +1 -0
  74. package/dist/tests/sync.test.js +54 -0
  75. package/package.json +29 -0
  76. package/src/setup-cli.js +2 -0
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const node_test_1 = require("node:test");
37
+ const assert = __importStar(require("node:assert/strict"));
38
+ const cache_js_1 = require("../src/cache.js");
39
+ (0, node_test_1.describe)("cache", () => {
40
+ (0, node_test_1.beforeEach)(() => {
41
+ (0, cache_js_1.invalidate)("test_key");
42
+ });
43
+ (0, node_test_1.it)("returns null for missing key", () => {
44
+ assert.strictEqual((0, cache_js_1.get)("nonexistent"), null);
45
+ });
46
+ (0, node_test_1.it)("set/get round-trips with age_seconds", () => {
47
+ (0, cache_js_1.set)("test_key", { yin: 50, yang: 60 });
48
+ const result = (0, cache_js_1.get)("test_key");
49
+ assert.ok(result !== null);
50
+ assert.strictEqual(result.data.yin, 50);
51
+ assert.ok(result.age_seconds >= 0 && result.age_seconds < 2);
52
+ });
53
+ (0, node_test_1.it)("invalidate removes entry", () => {
54
+ (0, cache_js_1.set)("test_key", "data");
55
+ (0, cache_js_1.invalidate)("test_key");
56
+ assert.strictEqual((0, cache_js_1.get)("test_key"), null);
57
+ });
58
+ (0, node_test_1.it)("ageSeconds returns -1 for missing key", () => {
59
+ assert.strictEqual((0, cache_js_1.ageSeconds)("missing"), -1);
60
+ });
61
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const node_test_1 = require("node:test");
37
+ const assert = __importStar(require("node:assert/strict"));
38
+ const client_js_1 = require("../src/client.js");
39
+ (0, node_test_1.describe)("DaoBrewClient", () => {
40
+ (0, node_test_1.it)("constructor sets defaults", () => {
41
+ const client = new client_js_1.DaoBrewClient({ apiKey: "dbk_test123" });
42
+ assert.ok(client);
43
+ });
44
+ (0, node_test_1.it)("constructor accepts custom baseUrl and timeout", () => {
45
+ const client = new client_js_1.DaoBrewClient({
46
+ apiKey: "dbk_test",
47
+ baseUrl: "http://localhost:8000/api/v1",
48
+ timeoutMs: 5000,
49
+ });
50
+ assert.ok(client);
51
+ });
52
+ (0, node_test_1.it)("getWellnessState rejects on network error", async () => {
53
+ const client = new client_js_1.DaoBrewClient({
54
+ apiKey: "dbk_test",
55
+ baseUrl: "http://localhost:1", // Nothing listening
56
+ timeoutMs: 1000,
57
+ });
58
+ await assert.rejects(() => client.getWellnessState(), (err) => {
59
+ assert.ok(err.message.length > 0);
60
+ return true;
61
+ });
62
+ });
63
+ (0, node_test_1.it)("getElementDetail rejects on network error", async () => {
64
+ const client = new client_js_1.DaoBrewClient({
65
+ apiKey: "dbk_test",
66
+ baseUrl: "http://localhost:1",
67
+ timeoutMs: 1000,
68
+ });
69
+ await assert.rejects(() => client.getElementDetail("wood"));
70
+ });
71
+ (0, node_test_1.it)("startSession rejects on network error", async () => {
72
+ const client = new client_js_1.DaoBrewClient({
73
+ apiKey: "dbk_test",
74
+ baseUrl: "http://localhost:1",
75
+ timeoutMs: 1000,
76
+ });
77
+ await assert.rejects(() => client.startSession("fire", "text"));
78
+ });
79
+ (0, node_test_1.it)("getSessionResult rejects on network error", async () => {
80
+ const client = new client_js_1.DaoBrewClient({
81
+ apiKey: "dbk_test",
82
+ baseUrl: "http://localhost:1",
83
+ timeoutMs: 1000,
84
+ });
85
+ await assert.rejects(() => client.getSessionResult("sess_test"));
86
+ });
87
+ (0, node_test_1.it)("getSessionHistory rejects on network error", async () => {
88
+ const client = new client_js_1.DaoBrewClient({
89
+ apiKey: "dbk_test",
90
+ baseUrl: "http://localhost:1",
91
+ timeoutMs: 1000,
92
+ });
93
+ await assert.rejects(() => client.getSessionHistory(7));
94
+ });
95
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const node_test_1 = require("node:test");
37
+ const assert = __importStar(require("node:assert/strict"));
38
+ const cooldown_js_1 = require("../src/cooldown.js");
39
+ (0, node_test_1.describe)("cooldown", () => {
40
+ (0, node_test_1.beforeEach)(() => { (0, cooldown_js_1.clearAll)(); });
41
+ (0, node_test_1.it)("ambient and ondemand are independent", () => {
42
+ (0, cooldown_js_1.activate)("ambient", 60000);
43
+ assert.strictEqual((0, cooldown_js_1.isActive)("ambient"), true);
44
+ assert.strictEqual((0, cooldown_js_1.isActive)("ondemand"), false);
45
+ });
46
+ (0, node_test_1.it)("remainingMinutes returns correct value", () => {
47
+ (0, cooldown_js_1.activate)("ondemand", 120000);
48
+ const remaining = (0, cooldown_js_1.remainingMinutes)("ondemand");
49
+ assert.ok(remaining === 2, `Expected 2, got ${remaining}`);
50
+ assert.strictEqual((0, cooldown_js_1.remainingMinutes)("ambient"), 0);
51
+ });
52
+ (0, node_test_1.it)("clear resets only the specified mode", () => {
53
+ (0, cooldown_js_1.activate)("ambient", 60000);
54
+ (0, cooldown_js_1.activate)("ondemand", 60000);
55
+ (0, cooldown_js_1.clear)("ambient");
56
+ assert.strictEqual((0, cooldown_js_1.isActive)("ambient"), false);
57
+ assert.strictEqual((0, cooldown_js_1.isActive)("ondemand"), true);
58
+ });
59
+ (0, node_test_1.it)("clearAll resets both modes", () => {
60
+ (0, cooldown_js_1.activate)("ambient", 60000);
61
+ (0, cooldown_js_1.activate)("ondemand", 60000);
62
+ (0, cooldown_js_1.clearAll)();
63
+ assert.strictEqual((0, cooldown_js_1.isActive)("ambient"), false);
64
+ assert.strictEqual((0, cooldown_js_1.isActive)("ondemand"), false);
65
+ });
66
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const node_test_1 = require("node:test");
37
+ const assert = __importStar(require("node:assert/strict"));
38
+ const tools_js_1 = require("../src/tools.js");
39
+ const preferences_js_1 = require("../src/preferences.js");
40
+ const session_js_1 = require("../src/session.js");
41
+ const cooldown = __importStar(require("../src/cooldown.js"));
42
+ /**
43
+ * End-to-end verification: exercises the full mock-mode flow
44
+ * through the tool handler, covering all 9 tools and key guard paths.
45
+ * All sessions use tier: "text" to avoid spawning audio processes.
46
+ */
47
+ (0, node_test_1.describe)("e2e mock-mode flow", () => {
48
+ (0, node_test_1.before)(() => {
49
+ // Reset shared state before all e2e tests
50
+ (0, preferences_js_1.save)({ disabled: false, ambient_optin: false, headphones_trusted: false, voiceover: true, session_count: 0, preferred_volume: 0.3, cooldown_minutes: 30 });
51
+ (0, session_js_1.clearSession)();
52
+ cooldown.clearAll();
53
+ });
54
+ (0, node_test_1.it)("lists all 9 tool definitions", () => {
55
+ assert.strictEqual(tools_js_1.toolDefinitions.length, 9);
56
+ const names = tools_js_1.toolDefinitions.map(t => t.name);
57
+ assert.ok(names.includes("daobrew_get_wellness_state"));
58
+ assert.ok(names.includes("daobrew_start_breathing_session"));
59
+ assert.ok(names.includes("daobrew_stop_session"));
60
+ assert.ok(names.includes("daobrew_status"));
61
+ assert.ok(names.includes("daobrew_set_monitoring"));
62
+ assert.ok(names.includes("daobrew_connect_source"));
63
+ });
64
+ (0, node_test_1.it)("get_wellness_state returns MCP schema with cache_age_seconds", async () => {
65
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_get_wellness_state", { force_refresh: true }, true);
66
+ assert.ok(typeof result.yin === "number");
67
+ assert.ok(typeof result.yang === "number");
68
+ assert.ok(typeof result.quadrant === "string");
69
+ assert.strictEqual(result.cache_age_seconds, 0);
70
+ assert.ok(Array.isArray(result.active_elements));
71
+ });
72
+ (0, node_test_1.it)("get_element_detail returns valid detail", async () => {
73
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_get_element_detail", { element: "fire" }, true);
74
+ assert.strictEqual(result.element, "fire");
75
+ assert.ok(typeof result.score === "number");
76
+ assert.ok(typeof result.headline === "string");
77
+ });
78
+ (0, node_test_1.it)("start_breathing_session text tier returns script", async () => {
79
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
80
+ element: "wood", tier: "text", mode: "ondemand",
81
+ }, true);
82
+ assert.strictEqual(result.status, "started");
83
+ assert.ok(result.breathing_script.includes("Cycle"));
84
+ });
85
+ (0, node_test_1.it)("start_breathing_session rejects ambient without optin", async () => {
86
+ (0, preferences_js_1.save)({ disabled: false, ambient_optin: false });
87
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
88
+ element: "wood", tier: "text", mode: "ambient",
89
+ }, true);
90
+ assert.strictEqual(result.status, "requires_optin");
91
+ });
92
+ (0, node_test_1.it)("stop_session returns no_active_session when idle", async () => {
93
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_stop_session", {}, true);
94
+ assert.strictEqual(result.status, "no_active_session");
95
+ });
96
+ (0, node_test_1.it)("status returns mock mode with preferences", async () => {
97
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_status", {}, true);
98
+ assert.strictEqual(result.mode, "mock");
99
+ assert.ok(typeof result.preferences === "object");
100
+ assert.ok(typeof result.headphones === "object");
101
+ assert.ok(result.data_sources);
102
+ });
103
+ (0, node_test_1.it)("set_monitoring updates preferences", async () => {
104
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_set_monitoring", {
105
+ preferred_volume: 0.7,
106
+ }, true);
107
+ assert.strictEqual(result.status, "updated");
108
+ assert.strictEqual(result.preferences.preferred_volume, 0.7);
109
+ });
110
+ (0, node_test_1.it)("connect_source apple_watch returns install_required", async () => {
111
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_connect_source", {
112
+ source: "apple_watch",
113
+ }, true);
114
+ assert.strictEqual(result.status, "install_required");
115
+ assert.ok(result.install_url);
116
+ });
117
+ (0, node_test_1.it)("connect_source oura returns error without env var", async () => {
118
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_connect_source", {
119
+ source: "oura",
120
+ }, true);
121
+ assert.strictEqual(result.status, "error");
122
+ assert.ok(result.error.includes("DAOBREW_OURA_CLIENT_ID"));
123
+ });
124
+ (0, node_test_1.it)("get_session_result returns mock data", async () => {
125
+ const { mockStartSession } = await import("../src/mock.js");
126
+ const session = mockStartSession("earth", "text");
127
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_get_session_result", {
128
+ session_id: session.session_id,
129
+ }, true);
130
+ assert.strictEqual(result.completed, true);
131
+ assert.ok(result.summary.startsWith("[Mock]"));
132
+ });
133
+ (0, node_test_1.it)("get_session_history returns entries", async () => {
134
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_get_session_history", { days: 7 }, true);
135
+ assert.ok(Array.isArray(result));
136
+ assert.ok(result.length >= 3);
137
+ });
138
+ (0, node_test_1.it)("rejects invalid element", async () => {
139
+ await assert.rejects(() => (0, tools_js_1.handleToolCall)("daobrew_get_element_detail", { element: "invalid" }, true), /Invalid element/);
140
+ });
141
+ (0, node_test_1.it)("rejects unknown tool", async () => {
142
+ await assert.rejects(() => (0, tools_js_1.handleToolCall)("nonexistent_tool", {}, true), /Unknown tool/);
143
+ });
144
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const node_test_1 = require("node:test");
37
+ const assert = __importStar(require("node:assert/strict"));
38
+ const tools_js_1 = require("../src/tools.js");
39
+ const preferences_js_1 = require("../src/preferences.js");
40
+ const session_js_1 = require("../src/session.js");
41
+ const cooldown = __importStar(require("../src/cooldown.js"));
42
+ // Restore prefs to defaults after all tests in this file
43
+ (0, node_test_1.after)(() => {
44
+ (0, preferences_js_1.save)({ disabled: false, ambient_optin: false, preferred_volume: 0.3, cooldown_minutes: 30, headphones_trusted: false, voiceover: true, session_count: 0 });
45
+ (0, session_js_1.clearSession)();
46
+ cooldown.clearAll();
47
+ });
48
+ (0, node_test_1.describe)("start_breathing_session guard: disabled", () => {
49
+ (0, node_test_1.beforeEach)(() => {
50
+ (0, preferences_js_1.save)({ disabled: false, ambient_optin: false });
51
+ (0, session_js_1.clearSession)();
52
+ cooldown.clearAll();
53
+ });
54
+ (0, node_test_1.it)("rejects when globally disabled", async () => {
55
+ (0, preferences_js_1.save)({ disabled: true });
56
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
57
+ element: "wood", tier: "text", mode: "ondemand",
58
+ }, true);
59
+ assert.strictEqual(result.status, "disabled");
60
+ });
61
+ });
62
+ (0, node_test_1.describe)("start_breathing_session guard: session_active", () => {
63
+ (0, node_test_1.beforeEach)(() => {
64
+ (0, preferences_js_1.save)({ disabled: false, ambient_optin: true });
65
+ (0, session_js_1.clearSession)();
66
+ cooldown.clearAll();
67
+ });
68
+ (0, node_test_1.it)("rejects when a session is already running", async () => {
69
+ // Simulate an active session with PID 0 (won't be checked as alive)
70
+ (0, session_js_1.startSession)({
71
+ sessionId: "sess_guard_test", pid: 0, element: "fire",
72
+ genre: "lofi_chill_jazz", duration: 300, startTime: Date.now(), mode: "ondemand",
73
+ });
74
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
75
+ element: "wood", tier: "text", mode: "ondemand",
76
+ }, true);
77
+ assert.strictEqual(result.status, "session_active");
78
+ (0, session_js_1.clearSession)();
79
+ });
80
+ });
81
+ (0, node_test_1.describe)("start_breathing_session guard: cooldown", () => {
82
+ (0, node_test_1.beforeEach)(() => {
83
+ (0, preferences_js_1.save)({ disabled: false, ambient_optin: true });
84
+ (0, session_js_1.clearSession)();
85
+ cooldown.clearAll();
86
+ });
87
+ (0, node_test_1.it)("rejects when cooldown is active", async () => {
88
+ cooldown.activate("ondemand", 60000);
89
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
90
+ element: "wood", tier: "text", mode: "ondemand",
91
+ }, true);
92
+ assert.strictEqual(result.status, "cooldown");
93
+ assert.ok(result.remaining_minutes > 0);
94
+ cooldown.clearAll();
95
+ });
96
+ (0, node_test_1.it)("force=true bypasses cooldown", async () => {
97
+ cooldown.activate("ondemand", 60000);
98
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
99
+ element: "wood", tier: "text", mode: "ondemand", force: true,
100
+ }, true);
101
+ assert.strictEqual(result.status, "started");
102
+ cooldown.clearAll();
103
+ });
104
+ });
105
+ (0, node_test_1.describe)("start_breathing_session guard: ambient requires optin", () => {
106
+ (0, node_test_1.beforeEach)(() => {
107
+ (0, preferences_js_1.save)({ disabled: false, ambient_optin: false });
108
+ (0, session_js_1.clearSession)();
109
+ cooldown.clearAll();
110
+ });
111
+ (0, node_test_1.it)("rejects ambient without optin", async () => {
112
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
113
+ element: "wood", tier: "text", mode: "ambient",
114
+ }, true);
115
+ assert.strictEqual(result.status, "requires_optin");
116
+ });
117
+ (0, node_test_1.it)("accepts ambient with optin", async () => {
118
+ (0, preferences_js_1.save)({ ambient_optin: true });
119
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
120
+ element: "water", tier: "text", mode: "ambient",
121
+ }, true);
122
+ assert.strictEqual(result.status, "started");
123
+ cooldown.clearAll();
124
+ });
125
+ });
126
+ (0, node_test_1.describe)("start_breathing_session audio fallback", () => {
127
+ (0, node_test_1.beforeEach)(() => {
128
+ (0, preferences_js_1.save)({ disabled: false, headphones_trusted: true });
129
+ (0, session_js_1.clearSession)();
130
+ cooldown.clearAll();
131
+ });
132
+ (0, node_test_1.it)("falls back to text when audio file missing (via text tier simulation)", async () => {
133
+ // Test text tier directly since audio tier would spawn system audio processes
134
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_start_breathing_session", {
135
+ element: "metal", tier: "text", mode: "ondemand",
136
+ }, true);
137
+ assert.strictEqual(result.status, "started");
138
+ assert.ok(result.breathing_script.includes("Cycle"));
139
+ (0, session_js_1.clearSession)();
140
+ cooldown.clearAll();
141
+ });
142
+ });
143
+ (0, node_test_1.describe)("set_monitoring validation", () => {
144
+ (0, node_test_1.it)("clamps volume to 0-1 range", async () => {
145
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_set_monitoring", {
146
+ preferred_volume: 5.0,
147
+ }, true);
148
+ assert.strictEqual(result.preferences.preferred_volume, 1.0);
149
+ });
150
+ (0, node_test_1.it)("clamps negative volume to 0", async () => {
151
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_set_monitoring", {
152
+ preferred_volume: -1,
153
+ }, true);
154
+ assert.strictEqual(result.preferences.preferred_volume, 0);
155
+ });
156
+ (0, node_test_1.it)("clamps cooldown_minutes minimum to 1", async () => {
157
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_set_monitoring", {
158
+ cooldown_minutes: -5,
159
+ }, true);
160
+ assert.strictEqual(result.preferences.cooldown_minutes, 1);
161
+ });
162
+ (0, node_test_1.it)("sets ambient_optin_date when enabling ambient", async () => {
163
+ const result = await (0, tools_js_1.handleToolCall)("daobrew_set_monitoring", {
164
+ ambient_optin: true,
165
+ }, true);
166
+ assert.ok(result.preferences.ambient_optin_date);
167
+ assert.ok(!isNaN(Date.parse(result.preferences.ambient_optin_date)));
168
+ });
169
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const node_test_1 = require("node:test");
37
+ const assert = __importStar(require("node:assert/strict"));
38
+ const headphones_js_1 = require("../src/headphones.js");
39
+ (0, node_test_1.describe)("headphones", () => {
40
+ (0, node_test_1.it)("detectHeadphones() returns valid HeadphoneStatus shape", async () => {
41
+ const status = await (0, headphones_js_1.detectHeadphones)();
42
+ assert.strictEqual(typeof status.connected, "boolean");
43
+ assert.ok(["switchaudio", "system_profiler", "pactl", "none"].includes(status.detection_method));
44
+ assert.ok(status.device === null || typeof status.device === "string");
45
+ });
46
+ });
@@ -0,0 +1 @@
1
+ export {};