happy2 0.0.11 → 0.0.12

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 (133) hide show
  1. package/README.md +10 -0
  2. package/package.json +1 -1
  3. package/packages/happy2-server/PLUGINS.md +106 -34
  4. package/packages/happy2-server/README.md +11 -0
  5. package/packages/happy2-server/dist/daemon.d.ts +39 -0
  6. package/packages/happy2-server/dist/daemon.d.ts.map +1 -0
  7. package/packages/happy2-server/dist/daemon.js +302 -0
  8. package/packages/happy2-server/dist/daemon.js.map +1 -0
  9. package/packages/happy2-server/dist/daemon.test.d.ts +2 -0
  10. package/packages/happy2-server/dist/daemon.test.d.ts.map +1 -0
  11. package/packages/happy2-server/dist/daemon.test.js +245 -0
  12. package/packages/happy2-server/dist/daemon.test.js.map +1 -0
  13. package/packages/happy2-server/dist/index.d.ts +1 -1
  14. package/packages/happy2-server/dist/index.d.ts.map +1 -1
  15. package/packages/happy2-server/dist/index.js +1 -1
  16. package/packages/happy2-server/dist/index.js.map +1 -1
  17. package/packages/happy2-server/dist/modules/auth/tokens.d.ts +7 -0
  18. package/packages/happy2-server/dist/modules/auth/tokens.d.ts.map +1 -1
  19. package/packages/happy2-server/dist/modules/auth/tokens.js +33 -0
  20. package/packages/happy2-server/dist/modules/auth/tokens.js.map +1 -1
  21. package/packages/happy2-server/dist/modules/auth/tokens.test.d.ts +2 -0
  22. package/packages/happy2-server/dist/modules/auth/tokens.test.d.ts.map +1 -0
  23. package/packages/happy2-server/dist/modules/auth/tokens.test.js +28 -0
  24. package/packages/happy2-server/dist/modules/auth/tokens.test.js.map +1 -0
  25. package/packages/happy2-server/dist/modules/config/defaults.d.ts.map +1 -1
  26. package/packages/happy2-server/dist/modules/config/defaults.js +2 -0
  27. package/packages/happy2-server/dist/modules/config/defaults.js.map +1 -1
  28. package/packages/happy2-server/dist/modules/config/loader.d.ts.map +1 -1
  29. package/packages/happy2-server/dist/modules/config/loader.js +5 -0
  30. package/packages/happy2-server/dist/modules/config/loader.js.map +1 -1
  31. package/packages/happy2-server/dist/modules/config/loader.test.js +15 -0
  32. package/packages/happy2-server/dist/modules/config/loader.test.js.map +1 -1
  33. package/packages/happy2-server/dist/modules/config/type.d.ts +2 -0
  34. package/packages/happy2-server/dist/modules/config/type.d.ts.map +1 -1
  35. package/packages/happy2-server/dist/modules/plugin/catalog.d.ts.map +1 -1
  36. package/packages/happy2-server/dist/modules/plugin/catalog.js +45 -4
  37. package/packages/happy2-server/dist/modules/plugin/catalog.js.map +1 -1
  38. package/packages/happy2-server/dist/modules/plugin/catalog.test.js +33 -0
  39. package/packages/happy2-server/dist/modules/plugin/catalog.test.js.map +1 -1
  40. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.d.ts.map +1 -1
  41. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.js +14 -1
  42. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.js.map +1 -1
  43. package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.d.ts +3 -0
  44. package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.d.ts.map +1 -0
  45. package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.js +12 -0
  46. package/packages/happy2-server/dist/modules/plugin/impl/effectiveContainer.js.map +1 -0
  47. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.d.ts.map +1 -1
  48. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.js +11 -0
  49. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.js.map +1 -1
  50. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.d.ts.map +1 -1
  51. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.js +15 -1
  52. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.js.map +1 -1
  53. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.d.ts +10 -0
  54. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.d.ts.map +1 -0
  55. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.js +20 -0
  56. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceAuthorize.js.map +1 -0
  57. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.d.ts +12 -0
  58. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.d.ts.map +1 -0
  59. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.js +44 -0
  60. package/packages/happy2-server/dist/modules/plugin/pluginContainerInstanceInvalidate.js.map +1 -0
  61. package/packages/happy2-server/dist/modules/plugin/pluginInstall.d.ts.map +1 -1
  62. package/packages/happy2-server/dist/modules/plugin/pluginInstall.js +10 -5
  63. package/packages/happy2-server/dist/modules/plugin/pluginInstall.js.map +1 -1
  64. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.d.ts.map +1 -1
  65. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js +18 -7
  66. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js.map +1 -1
  67. package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.d.ts +14 -0
  68. package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.d.ts.map +1 -0
  69. package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.js +20 -0
  70. package/packages/happy2-server/dist/modules/plugin/pluginInstallationListForHost.js.map +1 -0
  71. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.d.ts +1 -0
  72. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.d.ts.map +1 -1
  73. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.js +1 -0
  74. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUpdateStatus.js.map +1 -1
  75. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.d.ts +11 -0
  76. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.d.ts.map +1 -0
  77. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.js +43 -0
  78. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsList.js.map +1 -0
  79. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.d.ts +15 -0
  80. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.d.ts.map +1 -0
  81. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.js +37 -0
  82. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsListReady.js.map +1 -0
  83. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.d.ts +16 -0
  84. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.d.ts.map +1 -0
  85. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.js +71 -0
  86. package/packages/happy2-server/dist/modules/plugin/pluginMcpToolsReplace.js.map +1 -0
  87. package/packages/happy2-server/dist/modules/plugin/runtime.d.ts +19 -0
  88. package/packages/happy2-server/dist/modules/plugin/runtime.d.ts.map +1 -1
  89. package/packages/happy2-server/dist/modules/plugin/runtime.js +87 -2
  90. package/packages/happy2-server/dist/modules/plugin/runtime.js.map +1 -1
  91. package/packages/happy2-server/dist/modules/plugin/service.d.ts +12 -4
  92. package/packages/happy2-server/dist/modules/plugin/service.d.ts.map +1 -1
  93. package/packages/happy2-server/dist/modules/plugin/service.js +216 -170
  94. package/packages/happy2-server/dist/modules/plugin/service.js.map +1 -1
  95. package/packages/happy2-server/dist/modules/plugin/types.d.ts +40 -3
  96. package/packages/happy2-server/dist/modules/plugin/types.d.ts.map +1 -1
  97. package/packages/happy2-server/dist/modules/plugin/types.js +1 -0
  98. package/packages/happy2-server/dist/modules/plugin/types.js.map +1 -1
  99. package/packages/happy2-server/dist/modules/sandbox/index.d.ts +1 -1
  100. package/packages/happy2-server/dist/modules/sandbox/index.d.ts.map +1 -1
  101. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.d.ts +8 -1
  102. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.d.ts.map +1 -1
  103. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.js +101 -1
  104. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.js.map +1 -1
  105. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.test.js +78 -2
  106. package/packages/happy2-server/dist/modules/sandbox/localOciSandboxProvider.test.js.map +1 -1
  107. package/packages/happy2-server/dist/modules/sandbox/types.d.ts +16 -0
  108. package/packages/happy2-server/dist/modules/sandbox/types.d.ts.map +1 -1
  109. package/packages/happy2-server/dist/modules/schema.d.ts +394 -0
  110. package/packages/happy2-server/dist/modules/schema.d.ts.map +1 -1
  111. package/packages/happy2-server/dist/modules/schema.js +15 -0
  112. package/packages/happy2-server/dist/modules/schema.js.map +1 -1
  113. package/packages/happy2-server/dist/routes/pluginHost.d.ts +6 -0
  114. package/packages/happy2-server/dist/routes/pluginHost.d.ts.map +1 -0
  115. package/packages/happy2-server/dist/routes/pluginHost.js +37 -0
  116. package/packages/happy2-server/dist/routes/pluginHost.js.map +1 -0
  117. package/packages/happy2-server/dist/routes/plugins.d.ts.map +1 -1
  118. package/packages/happy2-server/dist/routes/plugins.js +12 -0
  119. package/packages/happy2-server/dist/routes/plugins.js.map +1 -1
  120. package/packages/happy2-server/dist/runner.js +20 -1
  121. package/packages/happy2-server/dist/runner.js.map +1 -1
  122. package/packages/happy2-server/dist/server.d.ts +2 -0
  123. package/packages/happy2-server/dist/server.d.ts.map +1 -1
  124. package/packages/happy2-server/dist/server.js +20 -1
  125. package/packages/happy2-server/dist/server.js.map +1 -1
  126. package/packages/happy2-server/dist/systemService.d.ts.map +1 -1
  127. package/packages/happy2-server/dist/systemService.js +16 -1
  128. package/packages/happy2-server/dist/systemService.js.map +1 -1
  129. package/packages/happy2-server/dist/systemService.test.js +15 -1
  130. package/packages/happy2-server/dist/systemService.test.js.map +1 -1
  131. package/packages/happy2-server/drizzle/0022_plugin_container_runtime_tools.sql +16 -0
  132. package/packages/happy2-server/drizzle/meta/_journal.json +7 -0
  133. package/packages/happy2-server/happy2.example.toml +8 -0
package/README.md CHANGED
@@ -49,6 +49,16 @@ Open [http://127.0.0.1:3000](http://127.0.0.1:3000) in your browser. Happy (2)
49
49
  stores its database, files, generated secrets, agent workspaces, and private Rig
50
50
  runtime under `.happy2` in the directory where you start it.
51
51
 
52
+ Run it in the background without installing an operating-system service with:
53
+
54
+ ```sh
55
+ npx happy2 daemon start
56
+ npx happy2 daemon stop
57
+ ```
58
+
59
+ The daemon stores `happy2.pid` and `happy2.log` under `./.happy2`. Stopping it
60
+ terminates the daemon process tree and removes the PID file.
61
+
52
62
  Keep Happy (2) running across reboots with:
53
63
 
54
64
  ```sh
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "happy2",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "Happy (2) desktop web app and server bundle",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,6 +1,7 @@
1
1
  # Server plugins
2
2
 
3
- Happy (2) plugins package Agent Skills, an MCP server, or both. This first
3
+ Happy (2) plugins package Agent Skills, a persistent container command, an MCP
4
+ server, or any useful combination of those pieces. This first
4
5
  server-side implementation installs only packages bundled with the server. It
5
6
  already keeps catalog discovery, durable system plugins, immutable package/image
6
7
  snapshots, and independent runtime installations separate so a later remote
@@ -10,25 +11,30 @@ Plugin management is system-wide and administrator-only. The first installation
10
11
  of a catalog package creates one durable system-plugin record and one immutable
11
12
  package snapshot; later installations reuse that plugin identity and snapshot.
12
13
  Every installation has its own CUID2, variables, selected image, lifecycle, and
13
- dedicated container when it is a local stdio MCP. Remote MCP configuration is
14
+ dedicated container when it has a local runtime. Remote MCP configuration is
14
15
  persisted and health-checked independently per installation. Ready MCP
15
- installations expose their tools to Rig as durable external functions on every
16
- agent submission. Happy executes each durable call against the originating
16
+ installations expose their durably cached tools to Rig as external functions on
17
+ every agent submission. Happy executes each durable call against the originating
17
18
  installation and resolves the result back into the paused Rig run. This feature
18
19
  does not yet inject installed skills, and it does not yet implement upgrade,
19
20
  uninstall, marketplace download, or OAuth flows.
20
21
 
21
- Tool discovery is bounded to 15 seconds per agent submission, and one MCP tool
22
- execution is bounded to 30 seconds so a stalled plugin cannot indefinitely block
23
- turn submission or Rig's global event consumer. Before execution, Happy claims a
24
- 45-second database lease keyed by Rig session and call ID. Other server instances
25
- wait for that lease or replay its completed result instead of concurrently
26
- invoking the same tool. The first terminal outcome, including an MCP error or
27
- timeout, is persisted and reused for every later event delivery; Happy does not
28
- automatically retry an ambiguous failure because the first request may already
29
- have produced an external side effect. A process crash after the MCP side effect
30
- but before the outcome is committed can still cause one lease-expiry replay, so
31
- plugin tools with external side effects should themselves be idempotent.
22
+ MCP tools are discovered during each runtime activation and atomically replace
23
+ that installation's SQLite cache before it becomes ready. Local discovery runs
24
+ after every container creation, and remote discovery runs on every server
25
+ restart. Rig function discovery reads only this cache rather than opening every
26
+ MCP server again per submission. Each discovery page is bounded to 15
27
+ seconds, and one MCP tool execution is bounded to 30 seconds so a stalled plugin
28
+ cannot indefinitely block turn submission or Rig's global event consumer. Before
29
+ execution, Happy claims a 45-second database lease keyed by Rig session and call
30
+ ID. Other server instances wait for that lease or replay its completed result
31
+ instead of concurrently invoking the same tool. The first terminal outcome,
32
+ including an MCP error or timeout, is persisted and reused for every later event
33
+ delivery; Happy does not automatically retry an ambiguous failure because the
34
+ first request may already have produced an external side effect. A process crash
35
+ after the MCP side effect but before the outcome is committed can still cause one
36
+ lease-expiry replay, so plugin tools with external side effects should themselves
37
+ be idempotent.
32
38
 
33
39
  Rig sessions use Full access so durable external functions are executable without
34
40
  an unresolved permission prompt. Agent code still runs inside Happy's dedicated,
@@ -91,7 +97,13 @@ available.
91
97
  "description": "Region used for project queries.",
92
98
  "kind": "text"
93
99
  }
94
- ]
100
+ ],
101
+ "container": {
102
+ "dockerfile": "container/Dockerfile",
103
+ "command": "/plugin/bin/indexer",
104
+ "args": ["--watch"],
105
+ "permissions": ["plugins:list"]
106
+ }
95
107
  }
96
108
  ```
97
109
 
@@ -101,10 +113,18 @@ The durable system plugin and every installation receive separate CUID2 IDs.
101
113
  Variable keys are environment variable names. Every declared variable is
102
114
  required for each installation. Secret values are encrypted with AES-256-GCM
103
115
  and are never returned by catalog or installation reads; text values are stored
104
- as ordinary configuration. Both kinds are supplied to a stdio process as
105
- environment variables.
116
+ as ordinary configuration. Both kinds are supplied to configured local
117
+ processes as environment variables.
118
+
119
+ A package must contain at least one skill, `container`, or `mcp` definition.
120
+ `container.command` is optional when the same container exposes a stdio MCP;
121
+ otherwise it is required. A command and stdio MCP run alongside each other in
122
+ the same dedicated installation container. Container variables are supplied to
123
+ each configured process, not persisted in the image or container definition.
106
124
 
107
- A package must contain at least one skill or an `mcp` definition.
125
+ `container.permissions` is an exact allowlist of host API capabilities. The
126
+ currently supported permission is `plugins:list`. Unknown and duplicate
127
+ permissions are rejected when the package is loaded.
108
128
 
109
129
  The bundled `hello` package is the minimal skill-plus-MCP example. It declares no
110
130
  variables or MCP authentication, so an administrator can install it with an
@@ -118,10 +138,12 @@ container.
118
138
  "mcp": {
119
139
  "type": "stdio",
120
140
  "command": "/plugin/bin/project-mcp",
121
- "args": ["--stdio"],
122
- "container": {
123
- "dockerfile": "container/Dockerfile"
124
- }
141
+ "args": ["--stdio"]
142
+ },
143
+ "container": {
144
+ "dockerfile": "container/Dockerfile",
145
+ "args": [],
146
+ "permissions": []
125
147
  }
126
148
  }
127
149
  ```
@@ -146,22 +168,29 @@ The fixed `HOME`, `TMPDIR`, and working directory are `/tmp`, so tools that
146
168
  need a cache can still run without making the image root writable.
147
169
 
148
170
  Each installation container stays alive as that installation's plugin runtime.
149
- Each HTTP MCP session starts
171
+ The optional persistent command is started detached once for each container
172
+ incarnation and monitored through a PID marker in the container's ephemeral
173
+ `/run`. Server restart recovery adopts and resumes monitoring that same command
174
+ without double-starting it. Each HTTP MCP session starts
150
175
  the configured command with `docker exec`/`podman exec`; variables reach that
151
176
  process through Docker/Podman's environment-copy option. Values are never placed
152
177
  in command arguments, Happy's process environment, the long-lived container
153
178
  definition, or the image build; they exist only in the short-lived OCI CLI child
154
- and the MCP process. Variables that could alter the OCI client itself, such as
179
+ and the target persistent-command or MCP process. Variables that could alter the OCI client itself, such as
155
180
  `DOCKER_*`, proxy, loader, or executable-path settings, are rejected. Happy
156
181
  transparently bridges newline-delimited stdio JSON-RPC to MCP Streamable HTTP, so
157
182
  the plugin itself does not need an HTTP server.
158
183
 
159
184
  ## Stdio MCP using a selected container image
160
185
 
161
- Omit `mcp.container` when the plugin does not bundle its own Dockerfile:
186
+ Omit `container.dockerfile` when the plugin does not bundle its own Dockerfile:
162
187
 
163
188
  ```json
164
189
  {
190
+ "container": {
191
+ "args": [],
192
+ "permissions": []
193
+ },
165
194
  "mcp": {
166
195
  "type": "stdio",
167
196
  "command": "npx",
@@ -220,8 +249,8 @@ transport used for SSRF-safe address pinning.
220
249
  The request body may be omitted when the manifest declares no variables and
221
250
  does not require a selected container image.
222
251
 
223
- `containerImageId` is required only for stdio manifests without a bundled
224
- container, and it is rejected in every other case. Unknown, missing, empty, or
252
+ `containerImageId` is required for every local container manifest without a
253
+ bundled Dockerfile, and it is rejected in every other case. Unknown, missing, empty, or
225
254
  oversized variable values are rejected. The endpoint returns HTTP 202 after the
226
255
  durable system plugin (created once), immutable package/image snapshot, new
227
256
  installation, variables, audit entry, initial state, and sync event are durable.
@@ -240,9 +269,10 @@ An installation has one of these durable health states:
240
269
  - `preparing`: copying/reconciling package and image/container state.
241
270
  - `starting`: the container exists or remote endpoint is selected and MCP
242
271
  initialization/health checking is in progress.
243
- - `ready`: the MCP server completed initialization and ping (local), or returned
244
- a valid initialization response (remote). A skills-only plugin becomes ready
245
- immediately after its durable install.
272
+ - `ready`: a container-only command survived its startup probe; or a local or
273
+ remote MCP server completed initialization, ping, and durable tool discovery.
274
+ A skills-only plugin becomes ready immediately
275
+ after its durable install.
246
276
  - `broken_configuration`: stored variables, selected image state, manifest
247
277
  material, or resolved headers cannot form a valid runtime configuration.
248
278
  - `failed`: package integrity, image build, container creation, process startup,
@@ -253,8 +283,10 @@ Every transition updates `plugin_installations`, appends a `plugin.*` sync
253
283
  event, and publishes the normal server SSE hint with the `plugins` area. Clients
254
284
  must reconcile the durable catalog after a hint; the event itself is not state.
255
285
  On server restart, every installation is reconciled again. Its package path and
256
- SHA-256 digest are revalidated first; local containers are then recreated from
257
- the installed snapshot, and remote endpoints are rechecked.
286
+ SHA-256 digest are revalidated first; a running local container with matching
287
+ installation and incarnation labels is adopted, otherwise it is recreated from
288
+ the installed snapshot. Adopted persistent commands resume liveness monitoring.
289
+ Remote endpoints are rechecked.
258
290
 
259
291
  ## Read and MCP endpoints
260
292
 
@@ -277,6 +309,44 @@ the installed snapshot, and remote endpoints are rechecked.
277
309
  Streamable HTTP bridge for one ready local stdio installation. It follows MCP
278
310
  session semantics via `Mcp-Session-Id`. Happy’s existing bearer session is
279
311
  required; there is no plugin-specific OAuth exchange.
312
+ - `GET /v0/admin/pluginInstallations/:installationId/mcpTools` returns the last
313
+ successfully synchronized MCP tool schemas from SQLite. It never contacts the
314
+ MCP server. Tool discovery is replaced atomically on every runtime activation,
315
+ including each server restart.
316
+ - `GET /plugins` on the dedicated plugin host listener is the first
317
+ capability-scoped host API. It is deliberately absent from the product API
318
+ listener. A
319
+ container may call it only when its manifest grants `plugins:list` and it
320
+ presents the incarnation token supplied as `HAPPY2_PLUGIN_API_TOKEN`.
321
+
322
+ Container processes receive `HAPPY2_PLUGIN_API_URL` and
323
+ `HAPPY2_PLUGIN_API_TOKEN`. The URL is always
324
+ `http://happy2.host.internal:<plugins.host_api_port>`; the hardened container
325
+ adds `happy2.host.internal:host-gateway`, while the capability-only listener
326
+ binds `plugins.host_api_host` on that fixed port. HTTP/TCP and the OCI
327
+ `host-gateway` mapping work across Docker and Podman on macOS and Linux.
328
+ The cross-platform default bind is `0.0.0.0` because a loopback bind is not
329
+ reachable through Docker Desktop's or Podman's host gateway. Operators who
330
+ expose the host to an untrusted LAN should firewall
331
+ `plugins.host_api_port`; it is a container capability endpoint, not a public
332
+ service.
333
+
334
+ The token is an RS256 capability containing the installation ID, a random CUID2
335
+ container-incarnation ID, and the exact manifest permissions. Token bytes are
336
+ never stored. The incarnation ID is stored in `plugin_installations` and also
337
+ attached to the OCI container as `dev.happy2.plugin-instance`. On each request,
338
+ Happy verifies the signature, matches the incarnation against the ready database
339
+ row, and confirms that the correspondingly labelled container is running. A
340
+ stopped, missing, or replaced container therefore receives 403. A surviving
341
+ container and its token remain valid after a server restart; startup adopts the
342
+ matching container and refreshes its MCP tool cache instead of recreating it.
343
+ The token intentionally has no time expiration: its lifetime is exactly the
344
+ database-and-OCI incarnation lifetime, allowing a command to survive arbitrarily
345
+ many server restarts without persisting or rotating token bytes. Killing,
346
+ replacing, failing, or removing that incarnation immediately makes the token
347
+ unauthorized.
348
+ The capability is not a user session and the dedicated listener exposes no
349
+ ordinary `/v0` APIs.
280
350
 
281
351
  The bridge allows at most 128 simultaneous sessions server-wide and 16 per
282
352
  authenticated user. Idle sessions close after 15 minutes; inbound requests and
@@ -297,7 +367,9 @@ thumbhash, and SHA-256 checksum.
297
367
 
298
368
  `plugin_installations` records a separate CUID2 and foreign key to `plugins`,
299
369
  plus that instance's container/image choice, lifecycle state, error detail,
300
- installer, and timestamps. `plugin_installation_variables` records each declared
370
+ installer, tool-sync timestamp, and timestamps. `plugin_mcp_tools` contains the
371
+ last complete MCP discovery keyed by installation and tool name.
372
+ `plugin_installation_variables` records each declared
301
373
  value for one installation; secret rows contain authenticated ciphertext rather
302
374
  than plaintext. No installation uses `shortName` as identity.
303
375
 
@@ -18,6 +18,10 @@ npx happy2
18
18
  npx happy2 service start --config ./happy2.toml
19
19
  npx happy2 service stop
20
20
 
21
+ # Start or stop it as a background process in the current directory
22
+ npx happy2 daemon start --config ./happy2.toml
23
+ npx happy2 daemon stop
24
+
21
25
  # Development, with reload and no configuration file:
22
26
  pnpm dev:server
23
27
 
@@ -62,6 +66,13 @@ reinstallation. `happy2 service stop` directly stops and removes the macOS Launc
62
66
  while on Linux it prints the `sudo` commands that stop, disable, and remove the
63
67
  systemd unit.
64
68
 
69
+ `happy2 daemon start` starts the all-in-one app in a detached process group and
70
+ returns immediately. It writes `.happy2/happy2.pid` and appends output to
71
+ `.happy2/happy2.log` in the current directory. `happy2 daemon stop` sends the
72
+ whole process group a graceful termination signal, force-stops it if necessary,
73
+ and removes the PID file. Unlike `service start`, daemon mode does not arrange
74
+ automatic startup after a login or reboot.
75
+
65
76
  The service preserves the installation-time working directory, `PATH`, and
66
77
  optional `RIG_HOME`. When `--config` is supplied, its path is made
67
78
  absolute before installation. Put service secrets and SMTP environment values
@@ -0,0 +1,39 @@
1
+ export interface DaemonHost {
2
+ cwd: string;
3
+ environment: NodeJS.ProcessEnv;
4
+ executablePath: string;
5
+ executableArguments: readonly string[];
6
+ scriptPath: string;
7
+ directoryCreate(path: string): Promise<void>;
8
+ fileCreate(path: string, contents: string): Promise<boolean>;
9
+ fileExists(path: string): Promise<boolean>;
10
+ fileRead(path: string): Promise<string>;
11
+ fileRemove(path: string): Promise<void>;
12
+ processStart(input: {
13
+ arguments_: readonly string[];
14
+ cwd: string;
15
+ environment: NodeJS.ProcessEnv;
16
+ executablePath: string;
17
+ logPath: string;
18
+ pidPath: string;
19
+ }): Promise<number>;
20
+ processAlive(pid: number): boolean;
21
+ processTreeAlive(pid: number): boolean;
22
+ processTreeSignal(pid: number, signal: NodeJS.Signals): void;
23
+ wait(milliseconds: number): Promise<void>;
24
+ log(message: string): void;
25
+ }
26
+ export type ParsedDaemonCommand = {
27
+ action: "help" | "invalid" | "stop";
28
+ } | {
29
+ action: "start";
30
+ configPath?: string;
31
+ };
32
+ export declare function parseDaemonCommand(arguments_: readonly string[]): ParsedDaemonCommand;
33
+ export declare function daemonStart(options: {
34
+ configPath?: string;
35
+ }, host?: DaemonHost): Promise<void>;
36
+ export declare function daemonStop(host?: DaemonHost): Promise<void>;
37
+ export declare function daemonUsage(): string;
38
+ export declare function createDaemonHost(): DaemonHost;
39
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../sources/daemon.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,UAAU;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC,UAAU,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,YAAY,CAAC,KAAK,EAAE;QAChB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9B,GAAG,EAAE,MAAM,CAAC;QACZ,WAAW,EAAE,MAAM,CAAC,UAAU,CAAC;QAC/B,cAAc,EAAE,MAAM,CAAC;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC7D,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,MAAM,mBAAmB,GACzB;IAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,mBAAmB,CAgCrF;AAED,wBAAsB,WAAW,CAC7B,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,IAAI,GAAE,UAA+B,GACtC,OAAO,CAAC,IAAI,CAAC,CAyCf;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE,UAA+B,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BrF;AAED,wBAAgB,WAAW,IAAI,MAAM,CAQpC;AA4DD,wBAAgB,gBAAgB,IAAI,UAAU,CAuG7C"}
@@ -0,0 +1,302 @@
1
+ import { spawn } from "node:child_process";
2
+ import { close, open, writeFileSync } from "node:fs";
3
+ import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
4
+ import { isAbsolute, join, resolve } from "node:path";
5
+ import { parseArgs } from "node:util";
6
+ const daemonDirectoryName = ".happy2";
7
+ const daemonPidFileName = "happy2.pid";
8
+ const daemonLogFileName = "happy2.log";
9
+ const gracefulStopTimeoutMs = 10_000;
10
+ const forcedStopTimeoutMs = 2_000;
11
+ const processExitPollMs = 50;
12
+ export function parseDaemonCommand(arguments_) {
13
+ let positionals;
14
+ let values;
15
+ try {
16
+ const parsed = parseArgs({
17
+ args: [...arguments_],
18
+ allowPositionals: true,
19
+ options: {
20
+ config: { type: "string" },
21
+ help: { type: "boolean", short: "h" },
22
+ },
23
+ });
24
+ positionals = parsed.positionals;
25
+ values = parsed.values;
26
+ }
27
+ catch {
28
+ return { action: "invalid" };
29
+ }
30
+ const action = positionals[0];
31
+ if ((values.help || action === "help") &&
32
+ positionals.length <= 1 &&
33
+ values.config === undefined) {
34
+ return { action: "help" };
35
+ }
36
+ if (action === "start" && positionals.length === 1) {
37
+ return { action: "start", configPath: values.config };
38
+ }
39
+ if (action === "stop" && positionals.length === 1 && values.config === undefined) {
40
+ return { action: "stop" };
41
+ }
42
+ return { action: "invalid" };
43
+ }
44
+ export async function daemonStart(options, host = createDaemonHost()) {
45
+ const paths = daemonPaths(host.cwd);
46
+ await host.directoryCreate(paths.directory);
47
+ const existing = await pidFileRead(paths.pid, host);
48
+ if (existing.kind === "starting" && host.processAlive(existing.pid)) {
49
+ throw new Error(`Happy (2) daemon is already starting as process ${existing.pid}.`);
50
+ }
51
+ if (existing.kind === "pid" && host.processTreeAlive(existing.pid)) {
52
+ throw new Error(`Happy (2) is already running as daemon process ${existing.pid}.`);
53
+ }
54
+ if (existing.kind !== "missing") {
55
+ await host.fileRemove(paths.pid);
56
+ }
57
+ const configPath = await configPathResolve(options.configPath, host);
58
+ if (!(await host.fileCreate(paths.pid, `starting:${process.pid}\n`))) {
59
+ throw new Error("Happy (2) daemon is already starting.");
60
+ }
61
+ const childArguments = [
62
+ ...host.executableArguments,
63
+ host.scriptPath,
64
+ ...(configPath ? ["--config", configPath] : []),
65
+ ];
66
+ let pid;
67
+ try {
68
+ pid = await host.processStart({
69
+ arguments_: childArguments,
70
+ cwd: host.cwd,
71
+ environment: host.environment,
72
+ executablePath: host.executablePath,
73
+ logPath: paths.log,
74
+ pidPath: paths.pid,
75
+ });
76
+ }
77
+ catch (error) {
78
+ if (pid !== undefined)
79
+ signalIfAlive(pid, "SIGKILL", host);
80
+ await host.fileRemove(paths.pid);
81
+ throw error;
82
+ }
83
+ host.log(`Happy (2) daemon started as process ${pid}.`);
84
+ host.log(`PID file: ${paths.pid}`);
85
+ host.log(`Logs: ${paths.log}`);
86
+ }
87
+ export async function daemonStop(host = createDaemonHost()) {
88
+ const { pid: pidPath } = daemonPaths(host.cwd);
89
+ const state = await pidFileRead(pidPath, host);
90
+ if (state.kind === "starting" && host.processAlive(state.pid)) {
91
+ throw new Error(`Happy (2) daemon is still starting as process ${state.pid}.`);
92
+ }
93
+ if (state.kind === "missing" || state.kind === "invalid" || state.kind === "starting") {
94
+ if (state.kind !== "missing")
95
+ await host.fileRemove(pidPath);
96
+ host.log("Happy (2) daemon is not running.");
97
+ return;
98
+ }
99
+ const { pid } = state;
100
+ if (!host.processTreeAlive(pid)) {
101
+ await host.fileRemove(pidPath);
102
+ host.log(`Removed stale Happy (2) daemon PID file for process ${pid}.`);
103
+ return;
104
+ }
105
+ try {
106
+ host.processTreeSignal(pid, "SIGTERM");
107
+ if (!(await processExitWait(pid, gracefulStopTimeoutMs, host))) {
108
+ host.processTreeSignal(pid, "SIGKILL");
109
+ if (!(await processExitWait(pid, forcedStopTimeoutMs, host))) {
110
+ throw new Error(`Happy (2) daemon process ${pid} did not stop.`);
111
+ }
112
+ }
113
+ }
114
+ catch (error) {
115
+ if (host.processTreeAlive(pid))
116
+ throw error;
117
+ }
118
+ await host.fileRemove(pidPath);
119
+ host.log(`Happy (2) daemon process ${pid} was stopped.`);
120
+ }
121
+ export function daemonUsage() {
122
+ return [
123
+ "Usage:",
124
+ " happy2 daemon start [--config /path/to/happy2.toml]",
125
+ " happy2 daemon stop",
126
+ "",
127
+ "The daemon runs in the background. Its PID and logs are stored under ./.happy2.",
128
+ ].join("\n");
129
+ }
130
+ function daemonPaths(cwd) {
131
+ const directory = join(cwd, daemonDirectoryName);
132
+ return {
133
+ directory,
134
+ log: join(directory, daemonLogFileName),
135
+ pid: join(directory, daemonPidFileName),
136
+ };
137
+ }
138
+ async function configPathResolve(configPath, host) {
139
+ if (!configPath)
140
+ return undefined;
141
+ const absolute = isAbsolute(configPath) ? configPath : resolve(host.cwd, configPath);
142
+ if (!(await host.fileExists(absolute))) {
143
+ throw new Error(`Happy (2) config does not exist: ${absolute}`);
144
+ }
145
+ return absolute;
146
+ }
147
+ async function pidFileRead(path, host) {
148
+ if (!(await host.fileExists(path)))
149
+ return { kind: "missing" };
150
+ const contents = (await host.fileRead(path)).trim();
151
+ const starting = /^starting:([1-9]\d*)$/.exec(contents);
152
+ if (starting) {
153
+ const pid = Number(starting[1]);
154
+ return Number.isSafeInteger(pid) ? { kind: "starting", pid } : { kind: "invalid" };
155
+ }
156
+ if (!/^[1-9]\d*$/.test(contents))
157
+ return { kind: "invalid" };
158
+ const pid = Number(contents);
159
+ return Number.isSafeInteger(pid) ? { kind: "pid", pid } : { kind: "invalid" };
160
+ }
161
+ async function processExitWait(pid, timeoutMs, host) {
162
+ const attempts = Math.ceil(timeoutMs / processExitPollMs);
163
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
164
+ if (!host.processTreeAlive(pid))
165
+ return true;
166
+ await host.wait(processExitPollMs);
167
+ }
168
+ return !host.processTreeAlive(pid);
169
+ }
170
+ function signalIfAlive(pid, signal, host) {
171
+ if (!host.processTreeAlive(pid))
172
+ return;
173
+ try {
174
+ host.processTreeSignal(pid, signal);
175
+ }
176
+ catch {
177
+ // Preserve the original file-write error from daemonStart.
178
+ }
179
+ }
180
+ export function createDaemonHost() {
181
+ return {
182
+ cwd: process.cwd(),
183
+ environment: process.env,
184
+ executablePath: process.execPath,
185
+ executableArguments: process.execArgv,
186
+ scriptPath: resolve(process.argv[1] ?? ""),
187
+ async directoryCreate(path) {
188
+ await mkdir(path, { mode: 0o700, recursive: true });
189
+ },
190
+ async fileCreate(path, contents) {
191
+ try {
192
+ await writeFile(path, contents, { encoding: "utf8", flag: "wx", mode: 0o600 });
193
+ return true;
194
+ }
195
+ catch (error) {
196
+ if (error.code === "EEXIST")
197
+ return false;
198
+ throw error;
199
+ }
200
+ },
201
+ async fileExists(path) {
202
+ try {
203
+ await access(path);
204
+ return true;
205
+ }
206
+ catch {
207
+ return false;
208
+ }
209
+ },
210
+ async fileRead(path) {
211
+ return await readFile(path, "utf8");
212
+ },
213
+ async fileRemove(path) {
214
+ await rm(path, { force: true });
215
+ },
216
+ processAlive(pid) {
217
+ try {
218
+ process.kill(pid, 0);
219
+ return true;
220
+ }
221
+ catch (error) {
222
+ return error.code === "EPERM";
223
+ }
224
+ },
225
+ processTreeAlive(pid) {
226
+ try {
227
+ process.kill(-pid, 0);
228
+ return true;
229
+ }
230
+ catch (error) {
231
+ return error.code === "EPERM";
232
+ }
233
+ },
234
+ async processStart(input) {
235
+ const descriptor = await new Promise((resolveDescriptor, reject) => {
236
+ open(input.logPath, "a", 0o600, (error, openedDescriptor) => {
237
+ if (error)
238
+ reject(error);
239
+ else
240
+ resolveDescriptor(openedDescriptor);
241
+ });
242
+ });
243
+ try {
244
+ const child = spawn(input.executablePath, [...input.arguments_], {
245
+ cwd: input.cwd,
246
+ detached: true,
247
+ env: input.environment,
248
+ stdio: ["ignore", descriptor, descriptor],
249
+ });
250
+ const spawned = new Promise((resolveSpawn, reject) => {
251
+ child.once("error", reject);
252
+ child.once("spawn", resolveSpawn);
253
+ });
254
+ if (child.pid === undefined) {
255
+ await spawned;
256
+ throw new Error("Happy (2) daemon did not start.");
257
+ }
258
+ try {
259
+ writeFileSync(input.pidPath, `${child.pid}\n`, {
260
+ encoding: "utf8",
261
+ flag: "w",
262
+ mode: 0o600,
263
+ });
264
+ }
265
+ catch (error) {
266
+ signalProcessGroupIfAlive(child.pid, "SIGKILL");
267
+ throw error;
268
+ }
269
+ try {
270
+ await spawned;
271
+ }
272
+ catch (error) {
273
+ signalProcessGroupIfAlive(child.pid, "SIGKILL");
274
+ throw error;
275
+ }
276
+ child.unref();
277
+ return child.pid;
278
+ }
279
+ finally {
280
+ close(descriptor, () => { });
281
+ }
282
+ },
283
+ processTreeSignal(pid, signal) {
284
+ process.kill(-pid, signal);
285
+ },
286
+ async wait(milliseconds) {
287
+ await new Promise((resolveWait) => setTimeout(resolveWait, milliseconds));
288
+ },
289
+ log(message) {
290
+ console.log(message);
291
+ },
292
+ };
293
+ }
294
+ function signalProcessGroupIfAlive(pid, signal) {
295
+ try {
296
+ process.kill(-pid, signal);
297
+ }
298
+ catch {
299
+ // The process group may already have exited after a failed spawn.
300
+ }
301
+ }
302
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../sources/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=daemon.test.d.ts.map