@legioncodeinc/hive 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 (190) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +262 -0
  3. package/dist/cli-commands.d.ts +41 -0
  4. package/dist/cli-commands.js +76 -0
  5. package/dist/cli-commands.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +46 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/daemon/dashboard/app.js +118 -0
  10. package/dist/daemon/dashboard/host.d.ts +90 -0
  11. package/dist/daemon/dashboard/host.js +172 -0
  12. package/dist/daemon/dashboard/host.js.map +1 -0
  13. package/dist/daemon/dashboard/web-assets.d.ts +88 -0
  14. package/dist/daemon/dashboard/web-assets.js +195 -0
  15. package/dist/daemon/dashboard/web-assets.js.map +1 -0
  16. package/dist/daemon/fleet-status.d.ts +15 -0
  17. package/dist/daemon/fleet-status.js +56 -0
  18. package/dist/daemon/fleet-status.js.map +1 -0
  19. package/dist/daemon/gate.d.ts +55 -0
  20. package/dist/daemon/gate.js +128 -0
  21. package/dist/daemon/gate.js.map +1 -0
  22. package/dist/daemon/proxy.d.ts +38 -0
  23. package/dist/daemon/proxy.js +126 -0
  24. package/dist/daemon/proxy.js.map +1 -0
  25. package/dist/daemon/registry.d.ts +31 -0
  26. package/dist/daemon/registry.js +120 -0
  27. package/dist/daemon/registry.js.map +1 -0
  28. package/dist/daemon/server.d.ts +41 -0
  29. package/dist/daemon/server.js +126 -0
  30. package/dist/daemon/server.js.map +1 -0
  31. package/dist/daemon/setup-auth.d.ts +37 -0
  32. package/dist/daemon/setup-auth.js +51 -0
  33. package/dist/daemon/setup-auth.js.map +1 -0
  34. package/dist/daemon/telemetry-proxy.d.ts +47 -0
  35. package/dist/daemon/telemetry-proxy.js +63 -0
  36. package/dist/daemon/telemetry-proxy.js.map +1 -0
  37. package/dist/dashboard/contracts.d.ts +235 -0
  38. package/dist/dashboard/contracts.js +43 -0
  39. package/dist/dashboard/contracts.js.map +1 -0
  40. package/dist/dashboard/web/app.d.ts +44 -0
  41. package/dist/dashboard/web/app.js +179 -0
  42. package/dist/dashboard/web/app.js.map +1 -0
  43. package/dist/dashboard/web/boot-route.d.ts +23 -0
  44. package/dist/dashboard/web/boot-route.js +29 -0
  45. package/dist/dashboard/web/boot-route.js.map +1 -0
  46. package/dist/dashboard/web/build-graph-button.d.ts +46 -0
  47. package/dist/dashboard/web/build-graph-button.js +81 -0
  48. package/dist/dashboard/web/build-graph-button.js.map +1 -0
  49. package/dist/dashboard/web/buzzing-screen.d.ts +30 -0
  50. package/dist/dashboard/web/buzzing-screen.js +135 -0
  51. package/dist/dashboard/web/buzzing-screen.js.map +1 -0
  52. package/dist/dashboard/web/folder-picker.d.ts +54 -0
  53. package/dist/dashboard/web/folder-picker.js +125 -0
  54. package/dist/dashboard/web/folder-picker.js.map +1 -0
  55. package/dist/dashboard/web/graph-layout.d.ts +101 -0
  56. package/dist/dashboard/web/graph-layout.js +0 -0
  57. package/dist/dashboard/web/graph-layout.js.map +1 -0
  58. package/dist/dashboard/web/harness-strip.d.ts +38 -0
  59. package/dist/dashboard/web/harness-strip.js +65 -0
  60. package/dist/dashboard/web/harness-strip.js.map +1 -0
  61. package/dist/dashboard/web/health-rail.d.ts +26 -0
  62. package/dist/dashboard/web/health-rail.js +61 -0
  63. package/dist/dashboard/web/health-rail.js.map +1 -0
  64. package/dist/dashboard/web/main.d.ts +22 -0
  65. package/dist/dashboard/web/main.js +51 -0
  66. package/dist/dashboard/web/main.js.map +1 -0
  67. package/dist/dashboard/web/needs-project.d.ts +51 -0
  68. package/dist/dashboard/web/needs-project.js +69 -0
  69. package/dist/dashboard/web/needs-project.js.map +1 -0
  70. package/dist/dashboard/web/page-frame.d.ts +95 -0
  71. package/dist/dashboard/web/page-frame.js +98 -0
  72. package/dist/dashboard/web/page-frame.js.map +1 -0
  73. package/dist/dashboard/web/pages/coming-soon.d.ts +23 -0
  74. package/dist/dashboard/web/pages/coming-soon.js +19 -0
  75. package/dist/dashboard/web/pages/coming-soon.js.map +1 -0
  76. package/dist/dashboard/web/pages/dashboard.d.ts +32 -0
  77. package/dist/dashboard/web/pages/dashboard.js +205 -0
  78. package/dist/dashboard/web/pages/dashboard.js.map +1 -0
  79. package/dist/dashboard/web/pages/graph.d.ts +72 -0
  80. package/dist/dashboard/web/pages/graph.js +362 -0
  81. package/dist/dashboard/web/pages/graph.js.map +1 -0
  82. package/dist/dashboard/web/pages/harnesses.d.ts +65 -0
  83. package/dist/dashboard/web/pages/harnesses.js +210 -0
  84. package/dist/dashboard/web/pages/harnesses.js.map +1 -0
  85. package/dist/dashboard/web/pages/health.d.ts +22 -0
  86. package/dist/dashboard/web/pages/health.js +91 -0
  87. package/dist/dashboard/web/pages/health.js.map +1 -0
  88. package/dist/dashboard/web/pages/lifecycle-panel.d.ts +60 -0
  89. package/dist/dashboard/web/pages/lifecycle-panel.js +187 -0
  90. package/dist/dashboard/web/pages/lifecycle-panel.js.map +1 -0
  91. package/dist/dashboard/web/pages/logs.d.ts +55 -0
  92. package/dist/dashboard/web/pages/logs.js +311 -0
  93. package/dist/dashboard/web/pages/logs.js.map +1 -0
  94. package/dist/dashboard/web/pages/memories.d.ts +35 -0
  95. package/dist/dashboard/web/pages/memories.js +439 -0
  96. package/dist/dashboard/web/pages/memories.js.map +1 -0
  97. package/dist/dashboard/web/pages/projects.d.ts +38 -0
  98. package/dist/dashboard/web/pages/projects.js +325 -0
  99. package/dist/dashboard/web/pages/projects.js.map +1 -0
  100. package/dist/dashboard/web/pages/roi-chart.d.ts +52 -0
  101. package/dist/dashboard/web/pages/roi-chart.js +133 -0
  102. package/dist/dashboard/web/pages/roi-chart.js.map +1 -0
  103. package/dist/dashboard/web/pages/roi.d.ts +93 -0
  104. package/dist/dashboard/web/pages/roi.js +375 -0
  105. package/dist/dashboard/web/pages/roi.js.map +1 -0
  106. package/dist/dashboard/web/pages/settings.d.ts +103 -0
  107. package/dist/dashboard/web/pages/settings.js +420 -0
  108. package/dist/dashboard/web/pages/settings.js.map +1 -0
  109. package/dist/dashboard/web/pages/sync.d.ts +59 -0
  110. package/dist/dashboard/web/pages/sync.js +280 -0
  111. package/dist/dashboard/web/pages/sync.js.map +1 -0
  112. package/dist/dashboard/web/panels.d.ts +178 -0
  113. package/dist/dashboard/web/panels.js +471 -0
  114. package/dist/dashboard/web/panels.js.map +1 -0
  115. package/dist/dashboard/web/primitives.d.ts +80 -0
  116. package/dist/dashboard/web/primitives.js +208 -0
  117. package/dist/dashboard/web/primitives.js.map +1 -0
  118. package/dist/dashboard/web/readiness-splash.d.ts +39 -0
  119. package/dist/dashboard/web/readiness-splash.js +201 -0
  120. package/dist/dashboard/web/readiness-splash.js.map +1 -0
  121. package/dist/dashboard/web/registry.d.ts +96 -0
  122. package/dist/dashboard/web/registry.js +99 -0
  123. package/dist/dashboard/web/registry.js.map +1 -0
  124. package/dist/dashboard/web/router.d.ts +48 -0
  125. package/dist/dashboard/web/router.js +76 -0
  126. package/dist/dashboard/web/router.js.map +1 -0
  127. package/dist/dashboard/web/scope-context.d.ts +155 -0
  128. package/dist/dashboard/web/scope-context.js +266 -0
  129. package/dist/dashboard/web/scope-context.js.map +1 -0
  130. package/dist/dashboard/web/service-icons.d.ts +33 -0
  131. package/dist/dashboard/web/service-icons.js +80 -0
  132. package/dist/dashboard/web/service-icons.js.map +1 -0
  133. package/dist/dashboard/web/setup-gate.d.ts +116 -0
  134. package/dist/dashboard/web/setup-gate.js +272 -0
  135. package/dist/dashboard/web/setup-gate.js.map +1 -0
  136. package/dist/dashboard/web/sidebar.d.ts +63 -0
  137. package/dist/dashboard/web/sidebar.js +91 -0
  138. package/dist/dashboard/web/sidebar.js.map +1 -0
  139. package/dist/dashboard/web/use-fleet-telemetry.d.ts +111 -0
  140. package/dist/dashboard/web/use-fleet-telemetry.js +278 -0
  141. package/dist/dashboard/web/use-fleet-telemetry.js.map +1 -0
  142. package/dist/dashboard/web/wire.d.ts +1937 -0
  143. package/dist/dashboard/web/wire.js +1837 -0
  144. package/dist/dashboard/web/wire.js.map +1 -0
  145. package/dist/errors.d.ts +5 -0
  146. package/dist/errors.js +11 -0
  147. package/dist/errors.js.map +1 -0
  148. package/dist/install/registry.d.ts +35 -0
  149. package/dist/install/registry.js +110 -0
  150. package/dist/install/registry.js.map +1 -0
  151. package/dist/lock.d.ts +10 -0
  152. package/dist/lock.js +87 -0
  153. package/dist/lock.js.map +1 -0
  154. package/dist/service/commands.d.ts +15 -0
  155. package/dist/service/commands.js +49 -0
  156. package/dist/service/commands.js.map +1 -0
  157. package/dist/service/index.d.ts +38 -0
  158. package/dist/service/index.js +174 -0
  159. package/dist/service/index.js.map +1 -0
  160. package/dist/service/platform.d.ts +37 -0
  161. package/dist/service/platform.js +67 -0
  162. package/dist/service/platform.js.map +1 -0
  163. package/dist/service/templates.d.ts +10 -0
  164. package/dist/service/templates.js +120 -0
  165. package/dist/service/templates.js.map +1 -0
  166. package/dist/shared/constants.d.ts +15 -0
  167. package/dist/shared/constants.js +19 -0
  168. package/dist/shared/constants.js.map +1 -0
  169. package/dist/shared/daemon-routing.d.ts +11 -0
  170. package/dist/shared/daemon-routing.js +38 -0
  171. package/dist/shared/daemon-routing.js.map +1 -0
  172. package/dist/shared/fleet-readiness.d.ts +18 -0
  173. package/dist/shared/fleet-readiness.js +9 -0
  174. package/dist/shared/fleet-readiness.js.map +1 -0
  175. package/dist/shared/fleet-telemetry.d.ts +68 -0
  176. package/dist/shared/fleet-telemetry.js +61 -0
  177. package/dist/shared/fleet-telemetry.js.map +1 -0
  178. package/dist/shared/lifecycle-flags.d.ts +34 -0
  179. package/dist/shared/lifecycle-flags.js +39 -0
  180. package/dist/shared/lifecycle-flags.js.map +1 -0
  181. package/dist/shared/memory-types.d.ts +55 -0
  182. package/dist/shared/memory-types.js +75 -0
  183. package/dist/shared/memory-types.js.map +1 -0
  184. package/dist/shared/service-status.d.ts +82 -0
  185. package/dist/shared/service-status.js +97 -0
  186. package/dist/shared/service-status.js.map +1 -0
  187. package/dist/telemetry/emit.d.ts +197 -0
  188. package/dist/telemetry/emit.js +196 -0
  189. package/dist/telemetry/emit.js.map +1 -0
  190. package/package.json +50 -0
@@ -0,0 +1,174 @@
1
+ import { execFile } from "node:child_process";
2
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { installCommands, legacyUninstallCommands, uninstallCommands } from "./commands.js";
5
+ import { legacyUnitPath, resolveServiceContext, resolveServicePlan } from "./platform.js";
6
+ import { renderUnit } from "./templates.js";
7
+ const SERVICE_COMMAND_TIMEOUT_MS = 15_000;
8
+ export function createExecFileRunner() {
9
+ return {
10
+ run(command, args, options = {}) {
11
+ const timeout = options.timeoutMs ?? SERVICE_COMMAND_TIMEOUT_MS;
12
+ return new Promise((resolve) => {
13
+ execFile(command, [...args], { timeout }, (error, stdout, stderr) => {
14
+ if (error === null) {
15
+ resolve({ ok: true, code: 0, stdout, stderr });
16
+ return;
17
+ }
18
+ const codeValue = typeof error.code === "number" ? error.code : null;
19
+ resolve({
20
+ ok: false,
21
+ code: codeValue,
22
+ stdout,
23
+ stderr,
24
+ detail: error.message
25
+ });
26
+ });
27
+ });
28
+ }
29
+ };
30
+ }
31
+ export function createNodeServiceFs() {
32
+ return {
33
+ mkdirp(path) {
34
+ mkdirSync(path, { recursive: true });
35
+ },
36
+ writeFile(path, content) {
37
+ writeFileSync(path, content, "utf8");
38
+ },
39
+ removeFile(path) {
40
+ rmSync(path, { force: true });
41
+ }
42
+ };
43
+ }
44
+ function liveUid() {
45
+ try {
46
+ const getuid = process.getuid;
47
+ return typeof getuid === "function" ? getuid() : 0;
48
+ }
49
+ catch {
50
+ return 0;
51
+ }
52
+ }
53
+ function stagedWindowsTaskPath(home) {
54
+ return `${home}/.honeycomb/hive/hive-task.xml`;
55
+ }
56
+ function scopePhrase(plan) {
57
+ switch (plan.manager) {
58
+ case "launchd":
59
+ return "launchd";
60
+ case "systemd":
61
+ return "systemd";
62
+ case "schtasks":
63
+ return "schtasks";
64
+ }
65
+ }
66
+ async function runAll(runner, commands) {
67
+ let firstFailure = null;
68
+ for (const command of commands) {
69
+ const result = await runner.run(command.command, command.args, { timeoutMs: SERVICE_COMMAND_TIMEOUT_MS });
70
+ if (!result.ok && firstFailure === null) {
71
+ firstFailure = command;
72
+ }
73
+ }
74
+ return { allOk: firstFailure === null, firstFailure };
75
+ }
76
+ function withResolvedUnitPath(plan) {
77
+ if (plan.manager !== "schtasks" || plan.unitPath !== "")
78
+ return plan;
79
+ return {
80
+ ...plan,
81
+ unitPath: stagedWindowsTaskPath(plan.home)
82
+ };
83
+ }
84
+ export function createServiceModule(deps) {
85
+ const runner = deps.runner ?? createExecFileRunner();
86
+ const fs = deps.fs ?? createNodeServiceFs();
87
+ const uid = deps.uid ?? liveUid();
88
+ const environment = deps.environment ?? resolveServiceContext(deps.execPath);
89
+ function plan() {
90
+ return resolveServicePlan(environment);
91
+ }
92
+ return {
93
+ async install() {
94
+ let resolvedPlan;
95
+ try {
96
+ resolvedPlan = withResolvedUnitPath(plan());
97
+ }
98
+ catch (error) {
99
+ return {
100
+ ok: false,
101
+ message: `Could not register hive service: ${error instanceof Error ? error.message : "unknown error"}.`
102
+ };
103
+ }
104
+ // Decision #32 migration: best-effort deregister the legacy `hive` unit and
105
+ // remove its unit file, so a re-run never leaves two units racing over one daemon.
106
+ // Expected to fail harmlessly when no legacy unit exists; never blocks the install.
107
+ await runAll(runner, legacyUninstallCommands(resolvedPlan, uid));
108
+ try {
109
+ const legacyPath = legacyUnitPath(resolvedPlan);
110
+ if (legacyPath !== "")
111
+ fs.removeFile(legacyPath);
112
+ }
113
+ catch {
114
+ // Best-effort migration cleanup only; a remove failure never blocks the install.
115
+ }
116
+ const needsUnitFile = resolvedPlan.unitPath !== "" || resolvedPlan.manager === "schtasks";
117
+ if (needsUnitFile) {
118
+ try {
119
+ fs.mkdirp(dirname(resolvedPlan.unitPath));
120
+ fs.writeFile(resolvedPlan.unitPath, renderUnit(resolvedPlan));
121
+ }
122
+ catch (error) {
123
+ return {
124
+ ok: false,
125
+ message: `Could not write hive unit file at ${resolvedPlan.unitPath}: ${error instanceof Error ? error.message : "unknown error"}.`
126
+ };
127
+ }
128
+ }
129
+ const { allOk, firstFailure } = await runAll(runner, installCommands(resolvedPlan, uid));
130
+ if (!allOk) {
131
+ return {
132
+ ok: false,
133
+ message: `Registered hive unit but a service-manager command failed (${firstFailure?.command ?? "unknown"}).`
134
+ };
135
+ }
136
+ return {
137
+ ok: true,
138
+ message: `hive registered as a ${scopePhrase(resolvedPlan)} service and started. It will restart on crash and start on boot/login.`
139
+ };
140
+ },
141
+ async uninstall() {
142
+ let resolvedPlan;
143
+ try {
144
+ resolvedPlan = withResolvedUnitPath(plan());
145
+ }
146
+ catch (error) {
147
+ return {
148
+ ok: false,
149
+ message: `Could not unregister hive service: ${error instanceof Error ? error.message : "unknown error"}.`
150
+ };
151
+ }
152
+ const { allOk, firstFailure } = await runAll(runner, uninstallCommands(resolvedPlan, uid));
153
+ try {
154
+ if (resolvedPlan.unitPath !== "")
155
+ fs.removeFile(resolvedPlan.unitPath);
156
+ }
157
+ catch {
158
+ // A stale unit file should not block uninstall feedback.
159
+ }
160
+ if (!allOk) {
161
+ return {
162
+ ok: false,
163
+ message: `Removed hive unit file; a deregister command (${firstFailure?.command ?? "unknown"}) reported an error.`
164
+ };
165
+ }
166
+ return {
167
+ ok: true,
168
+ message: `hive service unregistered (${scopePhrase(resolvedPlan)}). It will not start on next boot/login.`
169
+ };
170
+ }
171
+ };
172
+ }
173
+ export { resolveServiceContext, resolveServicePlan } from "./platform.js";
174
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export type ServicePlatform = "darwin" | "linux" | "win32";
2
+ export type ServiceManager = "launchd" | "systemd" | "schtasks";
3
+ /**
4
+ * Decision #32 (2026-07-02, nectar `library/requirements/PRD-DECISIONS-AND-DEFAULTS.md`):
5
+ * fleet-wide OS service naming uses the product short name `hive` with a
6
+ * reverse-DNS launchd label, superseding the shipped `thehive` names.
7
+ */
8
+ export declare const SERVICE_LABEL: "com.legioncode.hive";
9
+ export declare const SYSTEMD_UNIT_NAME: "hive.service";
10
+ export declare const WINDOWS_TASK_NAME: "hive";
11
+ /** The pre-decision-#32 names, deregistered on install (migration path). */
12
+ export declare const LEGACY_SERVICE_LABEL: "thehive";
13
+ export declare const LEGACY_SYSTEMD_UNIT_NAME: "thehive.service";
14
+ export declare const LEGACY_WINDOWS_TASK_NAME: "thehive";
15
+ export interface ServiceEnvironment {
16
+ readonly platform: NodeJS.Platform;
17
+ readonly home: string;
18
+ readonly execPath: string;
19
+ }
20
+ export interface ServicePlan {
21
+ readonly platform: ServicePlatform;
22
+ readonly manager: ServiceManager;
23
+ readonly unitPath: string;
24
+ readonly label: string;
25
+ readonly execPath: string;
26
+ readonly home: string;
27
+ }
28
+ export declare function resolveServiceContext(execPath: string): ServiceEnvironment;
29
+ export declare function normalizePlatform(platform: NodeJS.Platform): ServicePlatform | null;
30
+ /**
31
+ * The on-disk unit path the PRE-decision-#32 install would have used for this
32
+ * plan's platform. Install removes it (best-effort) so a re-run migrates a
33
+ * legacy unit instead of leaving two units racing over one daemon. Empty when
34
+ * the platform keeps no unit file (Windows).
35
+ */
36
+ export declare function legacyUnitPath(plan: ServicePlan): string;
37
+ export declare function resolveServicePlan(environment: ServiceEnvironment): ServicePlan;
@@ -0,0 +1,67 @@
1
+ import { homedir } from "node:os";
2
+ /**
3
+ * Decision #32 (2026-07-02, nectar `library/requirements/PRD-DECISIONS-AND-DEFAULTS.md`):
4
+ * fleet-wide OS service naming uses the product short name `hive` with a
5
+ * reverse-DNS launchd label, superseding the shipped `thehive` names.
6
+ */
7
+ export const SERVICE_LABEL = "com.legioncode.hive";
8
+ export const SYSTEMD_UNIT_NAME = "hive.service";
9
+ export const WINDOWS_TASK_NAME = "hive";
10
+ /** The pre-decision-#32 names, deregistered on install (migration path). */
11
+ export const LEGACY_SERVICE_LABEL = "thehive";
12
+ export const LEGACY_SYSTEMD_UNIT_NAME = "thehive.service";
13
+ export const LEGACY_WINDOWS_TASK_NAME = "thehive";
14
+ export function resolveServiceContext(execPath) {
15
+ return {
16
+ platform: process.platform,
17
+ home: homedir(),
18
+ execPath
19
+ };
20
+ }
21
+ export function normalizePlatform(platform) {
22
+ if (platform === "darwin" || platform === "linux" || platform === "win32")
23
+ return platform;
24
+ return null;
25
+ }
26
+ function unitPathFor(plan) {
27
+ switch (plan.platform) {
28
+ case "darwin":
29
+ return `${plan.home}/Library/LaunchAgents/${SERVICE_LABEL}.plist`;
30
+ case "linux":
31
+ return `${plan.home}/.config/systemd/user/${SYSTEMD_UNIT_NAME}`;
32
+ case "win32":
33
+ return "";
34
+ }
35
+ }
36
+ /**
37
+ * The on-disk unit path the PRE-decision-#32 install would have used for this
38
+ * plan's platform. Install removes it (best-effort) so a re-run migrates a
39
+ * legacy unit instead of leaving two units racing over one daemon. Empty when
40
+ * the platform keeps no unit file (Windows).
41
+ */
42
+ export function legacyUnitPath(plan) {
43
+ switch (plan.platform) {
44
+ case "darwin":
45
+ return `${plan.home}/Library/LaunchAgents/${LEGACY_SERVICE_LABEL}.plist`;
46
+ case "linux":
47
+ return `${plan.home}/.config/systemd/user/${LEGACY_SYSTEMD_UNIT_NAME}`;
48
+ case "win32":
49
+ return "";
50
+ }
51
+ }
52
+ export function resolveServicePlan(environment) {
53
+ const platform = normalizePlatform(environment.platform);
54
+ if (platform === null) {
55
+ throw new Error(`unsupported platform: ${environment.platform}`);
56
+ }
57
+ const manager = platform === "darwin" ? "launchd" : platform === "linux" ? "systemd" : "schtasks";
58
+ return {
59
+ platform,
60
+ manager,
61
+ unitPath: unitPathFor({ platform, home: environment.home }),
62
+ label: SERVICE_LABEL,
63
+ execPath: environment.execPath,
64
+ home: environment.home
65
+ };
66
+ }
67
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/service/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAKlC;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,qBAA8B,CAAC;AAC5D,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAuB,CAAC;AACzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAe,CAAC;AAEjD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAkB,CAAC;AACvD,MAAM,CAAC,MAAM,wBAAwB,GAAG,iBAA0B,CAAC;AACnE,MAAM,CAAC,MAAM,wBAAwB,GAAG,SAAkB,CAAC;AAiB3D,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,OAAO,EAAE;QACf,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAyB;IACzD,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,QAAQ,CAAC;IAC3F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,IAAiD;IACpE,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,KAAK,QAAQ;YACX,OAAO,GAAG,IAAI,CAAC,IAAI,yBAAyB,aAAa,QAAQ,CAAC;QACpE,KAAK,OAAO;YACV,OAAO,GAAG,IAAI,CAAC,IAAI,yBAAyB,iBAAiB,EAAE,CAAC;QAClE,KAAK,OAAO;YACV,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,IAAiB;IAC9C,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,KAAK,QAAQ;YACX,OAAO,GAAG,IAAI,CAAC,IAAI,yBAAyB,oBAAoB,QAAQ,CAAC;QAC3E,KAAK,OAAO;YACV,OAAO,GAAG,IAAI,CAAC,IAAI,yBAAyB,wBAAwB,EAAE,CAAC;QACzE,KAAK,OAAO;YACV,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,WAA+B;IAChE,MAAM,QAAQ,GAAG,iBAAiB,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACzD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,yBAAyB,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,OAAO,GAAmB,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;IAClH,OAAO;QACL,QAAQ;QACR,OAAO;QACP,QAAQ,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;QAC3D,KAAK,EAAE,aAAa;QACpB,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,IAAI,EAAE,WAAW,CAAC,IAAI;KACvB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type ServicePlan } from "./platform.js";
2
+ export declare const HIVE_START_COMMAND: "start";
3
+ export declare const RESTART_SEC: 5;
4
+ export declare const WINDOWS_RESTART_INTERVAL: "PT1M";
5
+ export declare function quoteSystemdToken(value: string): string;
6
+ export declare function escapeXml(value: string): string;
7
+ export declare function renderLaunchdPlist(plan: ServicePlan): string;
8
+ export declare function renderSystemdUnit(plan: ServicePlan): string;
9
+ export declare function renderScheduledTaskXml(plan: ServicePlan): string;
10
+ export declare function renderUnit(plan: ServicePlan): string;
@@ -0,0 +1,120 @@
1
+ import { WINDOWS_TASK_NAME } from "./platform.js";
2
+ export const HIVE_START_COMMAND = "start";
3
+ export const RESTART_SEC = 5;
4
+ export const WINDOWS_RESTART_INTERVAL = "PT1M";
5
+ export function quoteSystemdToken(value) {
6
+ return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
7
+ }
8
+ export function escapeXml(value) {
9
+ return value
10
+ .replaceAll("&", "&")
11
+ .replaceAll("<", "&lt;")
12
+ .replaceAll(">", "&gt;")
13
+ .replaceAll('"', "&quot;")
14
+ .replaceAll("'", "&apos;");
15
+ }
16
+ export function renderLaunchdPlist(plan) {
17
+ const node = escapeXml(process.execPath);
18
+ const exec = escapeXml(plan.execPath);
19
+ const home = escapeXml(plan.home);
20
+ const label = escapeXml(plan.label);
21
+ return `<?xml version="1.0" encoding="UTF-8"?>
22
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
23
+ <plist version="1.0">
24
+ <dict>
25
+ <key>Label</key>
26
+ <string>${label}</string>
27
+ <key>ProgramArguments</key>
28
+ <array>
29
+ <string>${node}</string>
30
+ <string>${exec}</string>
31
+ <string>${HIVE_START_COMMAND}</string>
32
+ </array>
33
+ <key>RunAtLoad</key>
34
+ <true/>
35
+ <key>KeepAlive</key>
36
+ <true/>
37
+ <key>ThrottleInterval</key>
38
+ <integer>${RESTART_SEC}</integer>
39
+ <key>ProcessType</key>
40
+ <string>Background</string>
41
+ <key>StandardOutPath</key>
42
+ <string>${home}/.honeycomb/hive/launchd.out.log</string>
43
+ <key>StandardErrorPath</key>
44
+ <string>${home}/.honeycomb/hive/launchd.err.log</string>
45
+ </dict>
46
+ </plist>
47
+ `;
48
+ }
49
+ export function renderSystemdUnit(plan) {
50
+ const execStart = `${quoteSystemdToken(process.execPath)} ${quoteSystemdToken(plan.execPath)} ${HIVE_START_COMMAND}`;
51
+ return `[Unit]
52
+ Description=hive portal daemon
53
+ After=network.target
54
+
55
+ [Service]
56
+ Type=simple
57
+ ExecStart=${execStart}
58
+ Restart=always
59
+ RestartSec=${RESTART_SEC}
60
+ StartLimitIntervalSec=0
61
+
62
+ [Install]
63
+ WantedBy=default.target
64
+ `;
65
+ }
66
+ export function renderScheduledTaskXml(plan) {
67
+ const node = escapeXml(process.execPath);
68
+ const exec = escapeXml(plan.execPath);
69
+ return `<?xml version="1.0" encoding="UTF-16"?>
70
+ <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
71
+ <RegistrationInfo>
72
+ <Description>hive portal daemon</Description>
73
+ <URI>\\${escapeXml(WINDOWS_TASK_NAME)}</URI>
74
+ </RegistrationInfo>
75
+ <Triggers>
76
+ <LogonTrigger>
77
+ <Enabled>true</Enabled>
78
+ </LogonTrigger>
79
+ </Triggers>
80
+ <Principals>
81
+ <Principal id="Author">
82
+ <LogonType>InteractiveToken</LogonType>
83
+ <RunLevel>LeastPrivilege</RunLevel>
84
+ </Principal>
85
+ </Principals>
86
+ <Settings>
87
+ <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
88
+ <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
89
+ <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
90
+ <AllowHardTerminate>true</AllowHardTerminate>
91
+ <StartWhenAvailable>true</StartWhenAvailable>
92
+ <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
93
+ <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
94
+ <Enabled>true</Enabled>
95
+ <Hidden>false</Hidden>
96
+ <RestartOnFailure>
97
+ <Interval>${WINDOWS_RESTART_INTERVAL}</Interval>
98
+ <Count>999</Count>
99
+ </RestartOnFailure>
100
+ </Settings>
101
+ <Actions Context="Author">
102
+ <Exec>
103
+ <Command>${node}</Command>
104
+ <Arguments>"${exec}" ${HIVE_START_COMMAND}</Arguments>
105
+ </Exec>
106
+ </Actions>
107
+ </Task>
108
+ `;
109
+ }
110
+ export function renderUnit(plan) {
111
+ switch (plan.manager) {
112
+ case "launchd":
113
+ return renderLaunchdPlist(plan);
114
+ case "systemd":
115
+ return renderSystemdUnit(plan);
116
+ case "schtasks":
117
+ return renderScheduledTaskXml(plan);
118
+ }
119
+ }
120
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/service/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAoB,MAAM,eAAe,CAAC;AAEpE,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAgB,CAAC;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAU,CAAC;AACtC,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAe,CAAC;AAExD,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,OAAO,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAiB;IAClD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO;;;;;WAKE,KAAK;;;YAGJ,IAAI;YACJ,IAAI;YACJ,kBAAkB;;;;;;;YAOlB,WAAW;;;;WAIZ,IAAI;;WAEJ,IAAI;;;CAGd,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAiB;IACjD,MAAM,SAAS,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,kBAAkB,EAAE,CAAC;IACrH,OAAO;;;;;;YAMG,SAAS;;aAER,WAAW;;;;;CAKvB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAiB;IACtD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO;;;;aAII,SAAS,CAAC,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;kBAwBvB,wBAAwB;;;;;;iBAMzB,IAAI;oBACD,IAAI,KAAK,kBAAkB;;;;CAI9C,CAAC;AACF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAiB;IAC1C,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,KAAK,SAAS;YACZ,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAClC,KAAK,SAAS;YACZ,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,UAAU;YACb,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ export declare const HIVE_HOST: "127.0.0.1";
2
+ export declare const HIVE_PORT: 3853;
3
+ export declare const HIVE_VERSION: string;
4
+ /** Hard-pinned loopback origin for doctor's status page (fs-AC-2). Never derived from registry or env. */
5
+ export declare const DOCTOR_STATUS_URL: "http://127.0.0.1:3852/status.json";
6
+ /**
7
+ * Hard-pinned loopback origin for doctor's fleet-telemetry SSE stream (hive PRD-004/005;
8
+ * doctor ADR-0001 decision 3). Same status page (`:3852`), the `/events` route. Never derived
9
+ * from the registry or env — mirrors {@link DOCTOR_STATUS_URL}'s fixed-constant posture so the
10
+ * server-side relay (`daemon/telemetry-proxy.ts`) can never be pointed at an attacker-chosen origin.
11
+ */
12
+ export declare const DOCTOR_EVENTS_URL: "http://127.0.0.1:3852/events";
13
+ export declare const HONEYCOMB_HOME_DIR: string;
14
+ export declare const HIVE_PID_PATH: string;
15
+ export declare const HIVE_LOCK_PATH: string;
@@ -0,0 +1,19 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ import packageJson from "../../package.json" with { type: "json" };
4
+ export const HIVE_HOST = "127.0.0.1";
5
+ export const HIVE_PORT = 3853;
6
+ export const HIVE_VERSION = packageJson.version;
7
+ /** Hard-pinned loopback origin for doctor's status page (fs-AC-2). Never derived from registry or env. */
8
+ export const DOCTOR_STATUS_URL = "http://127.0.0.1:3852/status.json";
9
+ /**
10
+ * Hard-pinned loopback origin for doctor's fleet-telemetry SSE stream (hive PRD-004/005;
11
+ * doctor ADR-0001 decision 3). Same status page (`:3852`), the `/events` route. Never derived
12
+ * from the registry or env — mirrors {@link DOCTOR_STATUS_URL}'s fixed-constant posture so the
13
+ * server-side relay (`daemon/telemetry-proxy.ts`) can never be pointed at an attacker-chosen origin.
14
+ */
15
+ export const DOCTOR_EVENTS_URL = "http://127.0.0.1:3852/events";
16
+ export const HONEYCOMB_HOME_DIR = join(homedir(), ".honeycomb");
17
+ export const HIVE_PID_PATH = join(HONEYCOMB_HOME_DIR, "hive.pid");
18
+ export const HIVE_LOCK_PATH = join(HONEYCOMB_HOME_DIR, "hive.lock");
19
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,WAAW,MAAM,oBAAoB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAEnE,MAAM,CAAC,MAAM,SAAS,GAAG,WAAoB,CAAC;AAC9C,MAAM,CAAC,MAAM,SAAS,GAAG,IAAa,CAAC;AACvC,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC;AAEhD,0GAA0G;AAC1G,MAAM,CAAC,MAAM,iBAAiB,GAAG,mCAA4C,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,8BAAuC,CAAC;AAEzE,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare const DEFAULT_DAEMON_BASES: Readonly<{
2
+ readonly honeycomb: "http://127.0.0.1:3850";
3
+ readonly nectar: "http://127.0.0.1:3854";
4
+ }>;
5
+ export type DaemonName = keyof typeof DEFAULT_DAEMON_BASES;
6
+ export type DaemonBases = Record<DaemonName, string>;
7
+ export declare function resolveEndpointOwner(endpointPath: string): DaemonName;
8
+ export declare function normalizeBaseUrl(baseUrl: string): string;
9
+ /** True iff `baseUrl` parses as an absolute URL whose host is a trusted loopback name. */
10
+ export declare function isLoopbackBaseUrl(baseUrl: string): boolean;
11
+ export declare function normalizeDaemonBases(bases?: Partial<Record<DaemonName, string>>): DaemonBases;
@@ -0,0 +1,38 @@
1
+ export const DEFAULT_DAEMON_BASES = Object.freeze({
2
+ honeycomb: "http://127.0.0.1:3850",
3
+ nectar: "http://127.0.0.1:3854"
4
+ });
5
+ const HIVE_GRAPH_PREFIX = "/api/hive-graph";
6
+ export function resolveEndpointOwner(endpointPath) {
7
+ return endpointPath === HIVE_GRAPH_PREFIX || endpointPath.startsWith(`${HIVE_GRAPH_PREFIX}/`)
8
+ ? "nectar"
9
+ : "honeycomb";
10
+ }
11
+ export function normalizeBaseUrl(baseUrl) {
12
+ return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
13
+ }
14
+ /**
15
+ * The only hostnames a daemon base is trusted to resolve to. hive aggregates every workload
16
+ * daemon over loopback HTTP by construction (`DAEMON_HOST`/`HIVE_HOST` are always
17
+ * `127.0.0.1`); a registry entry naming any other host is rejected rather than trusted, so a
18
+ * tampered `doctor.daemons.json` (or a compromised daemon registration) cannot redirect the
19
+ * server-side proxy (`src/daemon/proxy.ts`) — and the session/memory data it carries in request
20
+ * bodies — to an attacker-controlled origin.
21
+ */
22
+ const LOOPBACK_HOSTNAMES = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
23
+ /** True iff `baseUrl` parses as an absolute URL whose host is a trusted loopback name. */
24
+ export function isLoopbackBaseUrl(baseUrl) {
25
+ try {
26
+ return LOOPBACK_HOSTNAMES.has(new URL(baseUrl).hostname);
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ export function normalizeDaemonBases(bases = {}) {
33
+ return {
34
+ honeycomb: normalizeBaseUrl(bases.honeycomb ?? DEFAULT_DAEMON_BASES.honeycomb),
35
+ nectar: normalizeBaseUrl(bases.nectar ?? DEFAULT_DAEMON_BASES.nectar)
36
+ };
37
+ }
38
+ //# sourceMappingURL=daemon-routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-routing.js","sourceRoot":"","sources":["../../src/shared/daemon-routing.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,SAAS,EAAE,uBAAuB;IAClC,MAAM,EAAE,uBAAuB;CACvB,CAAC,CAAC;AAKZ,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAE5C,MAAM,UAAU,oBAAoB,CAAC,YAAoB;IACvD,OAAO,YAAY,KAAK,iBAAiB,IAAI,YAAY,CAAC,UAAU,CAAC,GAAG,iBAAiB,GAAG,CAAC;QAC3F,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,WAAW,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAE/E,0FAA0F;AAC1F,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAA6C,EAAE;IAClF,OAAO;QACL,SAAS,EAAE,gBAAgB,CAAC,KAAK,CAAC,SAAS,IAAI,oBAAoB,CAAC,SAAS,CAAC;QAC9E,MAAM,EAAE,gBAAgB,CAAC,KAAK,CAAC,MAAM,IAAI,oBAAoB,CAAC,MAAM,CAAC;KACtE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ export type FleetHealth = "ok" | "degraded" | "unreachable" | "unknown";
2
+ export type FleetDaemonStatus = {
3
+ readonly name: string;
4
+ readonly health: FleetHealth;
5
+ /** Opaque pass-through of doctor's per-daemon escalation record; hive does not interpret it. */
6
+ readonly escalation: unknown;
7
+ };
8
+ export type FleetStatusResponse = {
9
+ readonly supervisor: "reachable";
10
+ readonly health: FleetHealth;
11
+ readonly daemons: ReadonlyArray<FleetDaemonStatus>;
12
+ readonly asOf: string;
13
+ } | {
14
+ readonly supervisor: "unreachable";
15
+ readonly daemons: readonly [];
16
+ };
17
+ export declare const V1_REQUIRED_PEERS: readonly ["honeycomb"];
18
+ export declare function isFleetReady(status: FleetStatusResponse): boolean;
@@ -0,0 +1,9 @@
1
+ export const V1_REQUIRED_PEERS = ["honeycomb"];
2
+ export function isFleetReady(status) {
3
+ if (status.supervisor !== "reachable")
4
+ return false;
5
+ if (status.health !== "ok")
6
+ return false;
7
+ return V1_REQUIRED_PEERS.every((name) => status.daemons.some((daemon) => daemon.name === name && daemon.health === "ok"));
8
+ }
9
+ //# sourceMappingURL=fleet-readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet-readiness.js","sourceRoot":"","sources":["../../src/shared/fleet-readiness.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,WAAW,CAAU,CAAC;AAExD,MAAM,UAAU,YAAY,CAAC,MAA2B;IACtD,IAAI,MAAM,CAAC,UAAU,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IACpD,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CACtC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,CAChF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Shared fleet-TELEMETRY shapes — hive PRD-004/PRD-005, mirroring doctor's
3
+ * `src/telemetry/schema.ts` (Contract C in `library/ledger/EXECUTION_LEDGER.md`).
4
+ *
5
+ * hive does not depend on the doctor package (each fleet member is its own published
6
+ * npm package), so this module is a hand-kept, browser-and-server-safe COPY of the wire shape
7
+ * doctor's SSE stream (`GET http://127.0.0.1:3852/events`, event `fleet-telemetry`) actually
8
+ * emits. Keep it in lockstep with doctor's schema.ts if that contract ever changes.
9
+ *
10
+ * `metrics` is deliberately `Readonly<Record<string, number>>`: honeycomb ships three counters
11
+ * (`actionsTaken`, `filesProcessed`, `memoriesCreated`), nectar ships five
12
+ * (`filesRegistered`, `nectarsMinted`, `descriptionsGenerated`, `hiveGraphVersions`,
13
+ * `embeddingsComputed`) — every reader built on this module (PRD-005b's metrics render, PRD-004c's
14
+ * derivation) is schema-tolerant by construction: it never hardcodes one service's key names.
15
+ */
16
+ /** Coarse fleet-visible health for one service (matches `../daemon/fleet-status.ts`'s `FleetHealth`). */
17
+ export type FleetHealth = "ok" | "degraded" | "unreachable" | "unknown";
18
+ /** A schema-tolerant metrics snapshot: whatever counters a service's telemetry DB reports, camelCased. */
19
+ export type ServiceMetrics = Readonly<Record<string, number>>;
20
+ /** Why a service's telemetry read was skipped this doctor poll tick (fault isolation, sd-AC-9). */
21
+ export type TelemetryFaultReason = "missing" | "locked" | "malformed" | "read-error";
22
+ /** Deep Lake connection/stats fields carried on one service's fleet model (PRD-005b hm-AC-5/hm-AC-6). */
23
+ export interface FleetDeeplakeStats {
24
+ readonly connected: boolean | null;
25
+ readonly lastCommunicationAt: string | null;
26
+ }
27
+ /**
28
+ * One service's merged fleet-model row, as doctor's poll loop emits it: the static
29
+ * "should exist" registry entry plus its live runtime status. A registered-but-silent service
30
+ * appears here with `health: "unknown"` and `lastSeen: null` (never omitted, never a false
31
+ * `active` — sd-AC-2).
32
+ */
33
+ export interface FleetServiceModel {
34
+ readonly name: string;
35
+ readonly health: FleetHealth;
36
+ /** ISO-8601 of the last confirmed check-in, or `null` when never seen. Stops advancing (not cleared) on disconnect. */
37
+ readonly lastSeen: string | null;
38
+ readonly metrics: ServiceMetrics;
39
+ /** `null` when the service has no telemetry DB, or has one but never checked in. */
40
+ readonly deeplake: FleetDeeplakeStats | null;
41
+ /** Non-null when this service's telemetry DB was skipped THIS tick, isolated from the rest of the fleet. */
42
+ readonly telemetryFault: TelemetryFaultReason | null;
43
+ }
44
+ /** One forwarded log line, tagged with its originating service (PRD-005c). */
45
+ export interface FleetLogEntry {
46
+ readonly service: string;
47
+ readonly ts: string;
48
+ readonly level: string;
49
+ readonly message: string;
50
+ }
51
+ /**
52
+ * The single `fleet-telemetry` SSE event payload. `logs` is a BOUNDED SLICE of only the new rows
53
+ * since the previous tick (never a full history), so every consumer built on this stays
54
+ * memory-bounded by construction (PRD-005 parent index's hard constraint).
55
+ */
56
+ export interface FleetTelemetryEvent {
57
+ readonly asOf: string;
58
+ readonly services: readonly FleetServiceModel[];
59
+ readonly logs: readonly FleetLogEntry[];
60
+ }
61
+ /** The one SSE event name doctor's stream ever emits (mirrors doctor's `ingestion/sse.ts`). */
62
+ export declare const FLEET_TELEMETRY_EVENT_NAME: "fleet-telemetry";
63
+ /**
64
+ * Defensively parse one `fleet-telemetry` SSE frame's `data:` JSON (or the same shape from any
65
+ * future JSON transport). Returns `null` on anything malformed rather than throwing, so one bad
66
+ * frame never crashes the consuming hook (mirrors `fleet-status.ts`'s `safeParse`-and-degrade posture).
67
+ */
68
+ export declare function parseFleetTelemetryEvent(raw: string): FleetTelemetryEvent | null;