happy2 0.0.13 → 0.0.14

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 (213) hide show
  1. package/package.json +1 -1
  2. package/packages/happy2-server/PLUGINS.md +196 -42
  3. package/packages/happy2-server/dist/index.d.ts +1 -0
  4. package/packages/happy2-server/dist/index.d.ts.map +1 -1
  5. package/packages/happy2-server/dist/index.js +1 -0
  6. package/packages/happy2-server/dist/index.js.map +1 -1
  7. package/packages/happy2-server/dist/modules/agent/agentSkillHomeGet.d.ts +4 -0
  8. package/packages/happy2-server/dist/modules/agent/agentSkillHomeGet.d.ts.map +1 -0
  9. package/packages/happy2-server/dist/modules/agent/agentSkillHomeGet.js +15 -0
  10. package/packages/happy2-server/dist/modules/agent/agentSkillHomeGet.js.map +1 -0
  11. package/packages/happy2-server/dist/modules/agent/agentSkillHomeGet.test.d.ts +2 -0
  12. package/packages/happy2-server/dist/modules/agent/agentSkillHomeGet.test.d.ts.map +1 -0
  13. package/packages/happy2-server/dist/modules/agent/agentSkillHomeGet.test.js +17 -0
  14. package/packages/happy2-server/dist/modules/agent/agentSkillHomeGet.test.js.map +1 -0
  15. package/packages/happy2-server/dist/modules/agent/agentTurnGetPluginContext.d.ts +23 -0
  16. package/packages/happy2-server/dist/modules/agent/agentTurnGetPluginContext.d.ts.map +1 -0
  17. package/packages/happy2-server/dist/modules/agent/agentTurnGetPluginContext.js +70 -0
  18. package/packages/happy2-server/dist/modules/agent/agentTurnGetPluginContext.js.map +1 -0
  19. package/packages/happy2-server/dist/modules/agents/service.d.ts +2 -4
  20. package/packages/happy2-server/dist/modules/agents/service.d.ts.map +1 -1
  21. package/packages/happy2-server/dist/modules/agents/service.js +7 -7
  22. package/packages/happy2-server/dist/modules/agents/service.js.map +1 -1
  23. package/packages/happy2-server/dist/modules/auth/tokens.d.ts +15 -0
  24. package/packages/happy2-server/dist/modules/auth/tokens.d.ts.map +1 -1
  25. package/packages/happy2-server/dist/modules/auth/tokens.js +74 -6
  26. package/packages/happy2-server/dist/modules/auth/tokens.js.map +1 -1
  27. package/packages/happy2-server/dist/modules/auth/tokens.test.js +57 -0
  28. package/packages/happy2-server/dist/modules/auth/tokens.test.js.map +1 -1
  29. package/packages/happy2-server/dist/modules/chat/channelCreateWithMembers.d.ts +19 -0
  30. package/packages/happy2-server/dist/modules/chat/channelCreateWithMembers.d.ts.map +1 -0
  31. package/packages/happy2-server/dist/modules/chat/channelCreateWithMembers.js +87 -0
  32. package/packages/happy2-server/dist/modules/chat/channelCreateWithMembers.js.map +1 -0
  33. package/packages/happy2-server/dist/modules/chat/channelMembersUpdate.d.ts +15 -0
  34. package/packages/happy2-server/dist/modules/chat/channelMembersUpdate.d.ts.map +1 -0
  35. package/packages/happy2-server/dist/modules/chat/channelMembersUpdate.js +38 -0
  36. package/packages/happy2-server/dist/modules/chat/channelMembersUpdate.js.map +1 -0
  37. package/packages/happy2-server/dist/modules/chat/chatAppendAudit.d.ts +1 -1
  38. package/packages/happy2-server/dist/modules/chat/chatAppendAudit.d.ts.map +1 -1
  39. package/packages/happy2-server/dist/modules/plugin/catalog.d.ts.map +1 -1
  40. package/packages/happy2-server/dist/modules/plugin/catalog.js +3 -3
  41. package/packages/happy2-server/dist/modules/plugin/catalog.js.map +1 -1
  42. package/packages/happy2-server/dist/modules/plugin/catalog.test.js +2 -2
  43. package/packages/happy2-server/dist/modules/plugin/catalog.test.js.map +1 -1
  44. package/packages/happy2-server/dist/modules/plugin/impl/apiPermissions.d.ts +5 -0
  45. package/packages/happy2-server/dist/modules/plugin/impl/apiPermissions.d.ts.map +1 -0
  46. package/packages/happy2-server/dist/modules/plugin/impl/apiPermissions.js +106 -0
  47. package/packages/happy2-server/dist/modules/plugin/impl/apiPermissions.js.map +1 -0
  48. package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.d.ts.map +1 -1
  49. package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.js +10 -1
  50. package/packages/happy2-server/dist/modules/plugin/impl/asInstallation.js.map +1 -1
  51. package/packages/happy2-server/dist/modules/plugin/impl/asManagementRequest.d.ts +3 -0
  52. package/packages/happy2-server/dist/modules/plugin/impl/asManagementRequest.d.ts.map +1 -0
  53. package/packages/happy2-server/dist/modules/plugin/impl/asManagementRequest.js +68 -0
  54. package/packages/happy2-server/dist/modules/plugin/impl/asManagementRequest.js.map +1 -0
  55. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.d.ts.map +1 -1
  56. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.js +10 -2
  57. package/packages/happy2-server/dist/modules/plugin/impl/asPlugin.js.map +1 -1
  58. package/packages/happy2-server/dist/modules/plugin/impl/installationSelection.d.ts +19 -0
  59. package/packages/happy2-server/dist/modules/plugin/impl/installationSelection.d.ts.map +1 -1
  60. package/packages/happy2-server/dist/modules/plugin/impl/installationSelection.js +1 -0
  61. package/packages/happy2-server/dist/modules/plugin/impl/installationSelection.js.map +1 -1
  62. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.d.ts.map +1 -1
  63. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.js +4 -2
  64. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.js.map +1 -1
  65. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.test.js +14 -0
  66. package/packages/happy2-server/dist/modules/plugin/impl/installedManifest.test.js.map +1 -1
  67. package/packages/happy2-server/dist/modules/plugin/impl/managementRequestSelection.d.ts +345 -0
  68. package/packages/happy2-server/dist/modules/plugin/impl/managementRequestSelection.d.ts.map +1 -0
  69. package/packages/happy2-server/dist/modules/plugin/impl/managementRequestSelection.js +22 -0
  70. package/packages/happy2-server/dist/modules/plugin/impl/managementRequestSelection.js.map +1 -0
  71. package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.d.ts +16 -0
  72. package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.d.ts.map +1 -0
  73. package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.js +67 -0
  74. package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.js.map +1 -0
  75. package/packages/happy2-server/dist/modules/plugin/packageStore.d.ts +14 -1
  76. package/packages/happy2-server/dist/modules/plugin/packageStore.d.ts.map +1 -1
  77. package/packages/happy2-server/dist/modules/plugin/packageStore.js +112 -1
  78. package/packages/happy2-server/dist/modules/plugin/packageStore.js.map +1 -1
  79. package/packages/happy2-server/dist/modules/plugin/packageStore.test.d.ts +2 -0
  80. package/packages/happy2-server/dist/modules/plugin/packageStore.test.d.ts.map +1 -0
  81. package/packages/happy2-server/dist/modules/plugin/packageStore.test.js +50 -0
  82. package/packages/happy2-server/dist/modules/plugin/packageStore.test.js.map +1 -0
  83. package/packages/happy2-server/dist/modules/plugin/pluginAgentCallContextGet.d.ts +5 -0
  84. package/packages/happy2-server/dist/modules/plugin/pluginAgentCallContextGet.d.ts.map +1 -0
  85. package/packages/happy2-server/dist/modules/plugin/pluginAgentCallContextGet.js +26 -0
  86. package/packages/happy2-server/dist/modules/plugin/pluginAgentCallContextGet.js.map +1 -0
  87. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.d.ts.map +1 -1
  88. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.js +7 -3
  89. package/packages/happy2-server/dist/modules/plugin/pluginCatalogList.js.map +1 -1
  90. package/packages/happy2-server/dist/modules/plugin/pluginDeveloperServer.test.d.ts +2 -0
  91. package/packages/happy2-server/dist/modules/plugin/pluginDeveloperServer.test.d.ts.map +1 -0
  92. package/packages/happy2-server/dist/modules/plugin/pluginDeveloperServer.test.js +44 -0
  93. package/packages/happy2-server/dist/modules/plugin/pluginDeveloperServer.test.js.map +1 -0
  94. package/packages/happy2-server/dist/modules/plugin/pluginInstall.d.ts +4 -2
  95. package/packages/happy2-server/dist/modules/plugin/pluginInstall.d.ts.map +1 -1
  96. package/packages/happy2-server/dist/modules/plugin/pluginInstall.js +19 -2
  97. package/packages/happy2-server/dist/modules/plugin/pluginInstall.js.map +1 -1
  98. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetContainerName.d.ts +7 -0
  99. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetContainerName.d.ts.map +1 -0
  100. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetContainerName.js +18 -0
  101. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetContainerName.js.map +1 -0
  102. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRequestUninstallContext.d.ts +13 -0
  103. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRequestUninstallContext.d.ts.map +1 -0
  104. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRequestUninstallContext.js +35 -0
  105. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRequestUninstallContext.js.map +1 -0
  106. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.d.ts.map +1 -1
  107. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js +3 -1
  108. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js.map +1 -1
  109. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetUninstallContext.d.ts +6 -0
  110. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetUninstallContext.d.ts.map +1 -0
  111. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetUninstallContext.js +17 -0
  112. package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetUninstallContext.js.map +1 -0
  113. package/packages/happy2-server/dist/modules/plugin/pluginInstallationPermissionsUpdate.d.ts +18 -0
  114. package/packages/happy2-server/dist/modules/plugin/pluginInstallationPermissionsUpdate.d.ts.map +1 -0
  115. package/packages/happy2-server/dist/modules/plugin/pluginInstallationPermissionsUpdate.js +92 -0
  116. package/packages/happy2-server/dist/modules/plugin/pluginInstallationPermissionsUpdate.js.map +1 -0
  117. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUninstall.d.ts +16 -0
  118. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUninstall.d.ts.map +1 -0
  119. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUninstall.js +71 -0
  120. package/packages/happy2-server/dist/modules/plugin/pluginInstallationUninstall.js.map +1 -0
  121. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestBeginInstall.d.ts +21 -0
  122. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestBeginInstall.d.ts.map +1 -0
  123. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestBeginInstall.js +71 -0
  124. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestBeginInstall.js.map +1 -0
  125. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestBeginUninstall.d.ts +12 -0
  126. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestBeginUninstall.d.ts.map +1 -0
  127. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestBeginUninstall.js +56 -0
  128. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestBeginUninstall.js.map +1 -0
  129. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCompleteInstall.d.ts +11 -0
  130. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCompleteInstall.d.ts.map +1 -0
  131. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCompleteInstall.js +44 -0
  132. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCompleteInstall.js.map +1 -0
  133. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCompleteUninstall.d.ts +10 -0
  134. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCompleteUninstall.d.ts.map +1 -0
  135. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCompleteUninstall.js +41 -0
  136. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCompleteUninstall.js.map +1 -0
  137. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCreateInstall.d.ts +26 -0
  138. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCreateInstall.d.ts.map +1 -0
  139. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCreateInstall.js +78 -0
  140. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCreateInstall.js.map +1 -0
  141. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCreateUninstall.d.ts +25 -0
  142. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCreateUninstall.d.ts.map +1 -0
  143. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCreateUninstall.js +76 -0
  144. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestCreateUninstall.js.map +1 -0
  145. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestDeny.d.ts +11 -0
  146. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestDeny.d.ts.map +1 -0
  147. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestDeny.js +48 -0
  148. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestDeny.js.map +1 -0
  149. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestGetPackage.d.ts +12 -0
  150. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestGetPackage.d.ts.map +1 -0
  151. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestGetPackage.js +42 -0
  152. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestGetPackage.js.map +1 -0
  153. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestList.d.ts +5 -0
  154. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestList.d.ts.map +1 -0
  155. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestList.js +18 -0
  156. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestList.js.map +1 -0
  157. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestListTerminalIds.d.ts +4 -0
  158. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestListTerminalIds.d.ts.map +1 -0
  159. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestListTerminalIds.js +11 -0
  160. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestListTerminalIds.js.map +1 -0
  161. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestRecoverProcessing.d.ts +5 -0
  162. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestRecoverProcessing.d.ts.map +1 -0
  163. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestRecoverProcessing.js +75 -0
  164. package/packages/happy2-server/dist/modules/plugin/pluginManagementRequestRecoverProcessing.js.map +1 -0
  165. package/packages/happy2-server/dist/modules/plugin/pluginSkillPackageListReady.d.ts +12 -0
  166. package/packages/happy2-server/dist/modules/plugin/pluginSkillPackageListReady.d.ts.map +1 -0
  167. package/packages/happy2-server/dist/modules/plugin/pluginSkillPackageListReady.js +33 -0
  168. package/packages/happy2-server/dist/modules/plugin/pluginSkillPackageListReady.js.map +1 -0
  169. package/packages/happy2-server/dist/modules/plugin/service.d.ts +108 -7
  170. package/packages/happy2-server/dist/modules/plugin/service.d.ts.map +1 -1
  171. package/packages/happy2-server/dist/modules/plugin/service.js +463 -26
  172. package/packages/happy2-server/dist/modules/plugin/service.js.map +1 -1
  173. package/packages/happy2-server/dist/modules/plugin/types.d.ts +75 -9
  174. package/packages/happy2-server/dist/modules/plugin/types.d.ts.map +1 -1
  175. package/packages/happy2-server/dist/modules/plugin/types.js +9 -0
  176. package/packages/happy2-server/dist/modules/plugin/types.js.map +1 -1
  177. package/packages/happy2-server/dist/modules/schema.d.ts +4224 -3264
  178. package/packages/happy2-server/dist/modules/schema.d.ts.map +1 -1
  179. package/packages/happy2-server/dist/modules/schema.js +35 -0
  180. package/packages/happy2-server/dist/modules/schema.js.map +1 -1
  181. package/packages/happy2-server/dist/routes/pluginHost.d.ts +2 -1
  182. package/packages/happy2-server/dist/routes/pluginHost.d.ts.map +1 -1
  183. package/packages/happy2-server/dist/routes/pluginHost.js +288 -6
  184. package/packages/happy2-server/dist/routes/pluginHost.js.map +1 -1
  185. package/packages/happy2-server/dist/routes/plugins.d.ts.map +1 -1
  186. package/packages/happy2-server/dist/routes/plugins.js +229 -3
  187. package/packages/happy2-server/dist/routes/plugins.js.map +1 -1
  188. package/packages/happy2-server/dist/server.d.ts +2 -0
  189. package/packages/happy2-server/dist/server.d.ts.map +1 -1
  190. package/packages/happy2-server/dist/server.js +9 -7
  191. package/packages/happy2-server/dist/server.js.map +1 -1
  192. package/packages/happy2-server/dist/web/assets/index-Dn5SZu3y.js +39 -0
  193. package/packages/happy2-server/dist/web/assets/{index-BaPUPGPe.css → index-Dys3sWv8.css} +1 -1
  194. package/packages/happy2-server/dist/web/index.html +2 -2
  195. package/packages/happy2-server/drizzle/0028_plugin_api_permissions.sql +1 -0
  196. package/packages/happy2-server/drizzle/0029_plugin_management_requests.sql +35 -0
  197. package/packages/happy2-server/drizzle/meta/_journal.json +14 -0
  198. package/packages/happy2-server/plugins/README.md +7 -3
  199. package/packages/happy2-server/plugins/chat-management/plugin.json +3 -3
  200. package/packages/happy2-server/plugins/chat-management/server.mjs +184 -17
  201. package/packages/happy2-server/plugins/plugin-developer/container/Dockerfile +6 -0
  202. package/packages/happy2-server/plugins/plugin-developer/plugin.json +17 -0
  203. package/packages/happy2-server/plugins/plugin-developer/plugin.png +0 -0
  204. package/packages/happy2-server/plugins/plugin-developer/server.mjs +155 -0
  205. package/packages/happy2-server/plugins/plugin-developer/skills/happy2-plugin-development/SKILL.md +59 -0
  206. package/packages/happy2-server/plugins/plugin-developer/skills/happy2-plugin-development/references/host-api.md +63 -0
  207. package/packages/happy2-server/plugins/plugin-developer/skills/happy2-plugin-development/references/installing.md +86 -0
  208. package/packages/happy2-server/plugins/plugin-developer/skills/happy2-plugin-development/references/package-format.md +137 -0
  209. package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.d.ts +0 -7
  210. package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.d.ts.map +0 -1
  211. package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.js +0 -15
  212. package/packages/happy2-server/dist/modules/agent/agentChatGetIdBySession.js.map +0 -1
  213. package/packages/happy2-server/dist/web/assets/index-BnhFxR3U.js +0 -39
@@ -13,8 +13,8 @@
13
13
  background: #131217;
14
14
  }
15
15
  </style>
16
- <script type="module" crossorigin src="/assets/index-BnhFxR3U.js"></script>
17
- <link rel="stylesheet" crossorigin href="/assets/index-BaPUPGPe.css">
16
+ <script type="module" crossorigin src="/assets/index-Dn5SZu3y.js"></script>
17
+ <link rel="stylesheet" crossorigin href="/assets/index-Dys3sWv8.css">
18
18
  </head>
19
19
  <body>
20
20
  <div id="root"></div>
@@ -0,0 +1 @@
1
+ ALTER TABLE `plugin_installations` ADD `granted_permissions_json` text DEFAULT '[]' NOT NULL;
@@ -0,0 +1,35 @@
1
+ CREATE TABLE `plugin_management_requests` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `action` text NOT NULL,
4
+ `status` text DEFAULT 'pending' NOT NULL,
5
+ `chat_id` text NOT NULL,
6
+ `actor_user_id` text,
7
+ `agent_user_id` text,
8
+ `requester_installation_id` text,
9
+ `call_id` text NOT NULL,
10
+ `display_name` text NOT NULL,
11
+ `short_name` text NOT NULL,
12
+ `description` text NOT NULL,
13
+ `reason` text,
14
+ `source_kind` text,
15
+ `source_reference` text,
16
+ `package_digest` text,
17
+ `package_directory` text,
18
+ `target_installation_id` text,
19
+ `installation_id` text,
20
+ `resolved_by_user_id` text,
21
+ `resolved_at` text,
22
+ `last_error` text,
23
+ `sync_sequence` integer DEFAULT 0 NOT NULL,
24
+ `created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
25
+ `updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
26
+ FOREIGN KEY (`chat_id`) REFERENCES `chats`(`id`) ON UPDATE no action ON DELETE cascade,
27
+ FOREIGN KEY (`actor_user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE set null,
28
+ FOREIGN KEY (`agent_user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE set null,
29
+ FOREIGN KEY (`requester_installation_id`) REFERENCES `plugin_installations`(`id`) ON UPDATE no action ON DELETE set null,
30
+ FOREIGN KEY (`resolved_by_user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE set null
31
+ );
32
+ --> statement-breakpoint
33
+ CREATE INDEX `plugin_management_requests_chat_index` ON `plugin_management_requests` (`chat_id`,`created_at`);
34
+ --> statement-breakpoint
35
+ CREATE UNIQUE INDEX `plugin_management_requests_call_unique` ON `plugin_management_requests` (`requester_installation_id`,`call_id`,`action`);
@@ -197,6 +197,20 @@
197
197
  "when": 1784427000000,
198
198
  "tag": "0027_chat_agent_effort",
199
199
  "breakpoints": true
200
+ },
201
+ {
202
+ "idx": 28,
203
+ "version": "6",
204
+ "when": 1784430000000,
205
+ "tag": "0028_plugin_api_permissions",
206
+ "breakpoints": true
207
+ },
208
+ {
209
+ "idx": 29,
210
+ "version": "6",
211
+ "when": 1784433600000,
212
+ "tag": "0029_plugin_management_requests",
213
+ "breakpoints": true
200
214
  }
201
215
  ]
202
216
  }
@@ -4,6 +4,10 @@ Each child directory is one immutable, built-in plugin package. See
4
4
  [`../PLUGINS.md`](../PLUGINS.md) for the manifest and package contract.
5
5
 
6
6
  `hello` is the minimal built-in example with both a skill and a bundled stdio MCP
7
- tool. `chat-management` demonstrates a chat-scoped Plugin API capability without
8
- accepting a chat identifier from tool arguments. Product plugins should be added
9
- here as separate, reviewable changes.
7
+ tool. `chat-management` demonstrates installation-bound chat and referenced-user
8
+ capabilities: it updates the current chat, manages channel membership, and creates
9
+ private channels with either an informational opening message or an agent-triggering
10
+ prompt. `plugin-developer` provides Happy2 plugin authoring/install documentation
11
+ and chat-scoped MCP tools that request administrator approval for linked install
12
+ or uninstall actions. Product plugins should be added here as separate,
13
+ reviewable changes.
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "displayName": "Chat Management",
5
5
  "shortName": "chat-management",
6
- "description": "Lets an agent update the title and description of its current chat.",
6
+ "description": "Lets an agent update its current chat, manage channel members, and create new channels with an initial people or agent message.",
7
7
  "variables": [],
8
8
  "container": {
9
9
  "dockerfile": "container/Dockerfile",
10
- "permissions": ["chats:update"]
10
+ "permissions": ["chats:update", "channels:manage"]
11
11
  },
12
12
  "mcp": {
13
13
  "type": "stdio",
@@ -1,6 +1,8 @@
1
1
  import { createInterface } from "node:readline";
2
+ import { randomUUID } from "node:crypto";
2
3
 
3
4
  const CHAT_META_KEY = "happy2/chat";
5
+ const USERS_META_KEY = "happy2/users";
4
6
  const lines = createInterface({ input: process.stdin, crlfDelay: Infinity });
5
7
 
6
8
  for await (const line of lines) {
@@ -32,7 +34,7 @@ async function handle(request) {
32
34
  result: {
33
35
  protocolVersion: request.params?.protocolVersion ?? "2025-06-18",
34
36
  capabilities: { tools: {} },
35
- serverInfo: { name: "happy2-chat-management", version: "1.0.0" },
37
+ serverInfo: { name: "happy2-chat-management", version: "1.1.0" },
36
38
  },
37
39
  };
38
40
  }
@@ -66,48 +68,213 @@ async function handle(request) {
66
68
  additionalProperties: false,
67
69
  },
68
70
  },
71
+ {
72
+ name: "channel_members_update",
73
+ title: "Add or remove channel members",
74
+ description:
75
+ "Adds or removes users from the current channel. This never changes direct-message membership. Identify users by the @username shown in the triggering conversation; only users supplied in Happy's signed metadata are available.",
76
+ inputSchema: {
77
+ type: "object",
78
+ properties: {
79
+ addUsers: {
80
+ type: "array",
81
+ maxItems: 100,
82
+ uniqueItems: true,
83
+ items: { type: "string", minLength: 1 },
84
+ description: "Usernames (with or without @) to add.",
85
+ },
86
+ removeUsers: {
87
+ type: "array",
88
+ maxItems: 100,
89
+ uniqueItems: true,
90
+ items: { type: "string", minLength: 1 },
91
+ description: "Usernames (with or without @) to remove.",
92
+ },
93
+ },
94
+ anyOf: [{ required: ["addUsers"] }, { required: ["removeUsers"] }],
95
+ additionalProperties: false,
96
+ },
97
+ },
98
+ {
99
+ name: "channel_create",
100
+ title: "Create a channel",
101
+ description:
102
+ "Creates a private channel owned by the user who triggered this turn, adds selected referenced users, and optionally posts an initial message. An agents message starts the current agent working; a people message only shares context and does not trigger inference.",
103
+ inputSchema: {
104
+ type: "object",
105
+ properties: {
106
+ name: {
107
+ type: "string",
108
+ minLength: 1,
109
+ maxLength: 100,
110
+ description: "Channel title.",
111
+ },
112
+ description: {
113
+ type: "string",
114
+ minLength: 1,
115
+ maxLength: 500,
116
+ description: "Optional channel description.",
117
+ },
118
+ members: {
119
+ type: "array",
120
+ maxItems: 100,
121
+ uniqueItems: true,
122
+ items: { type: "string", minLength: 1 },
123
+ description:
124
+ "Referenced usernames (with or without @) to add. The triggering user is already the owner.",
125
+ },
126
+ initialMessage: {
127
+ type: "object",
128
+ properties: {
129
+ text: {
130
+ type: "string",
131
+ minLength: 1,
132
+ maxLength: 40000,
133
+ description:
134
+ "A copied or rephrased opening prompt or informational message.",
135
+ },
136
+ audience: {
137
+ type: "string",
138
+ enum: ["agents", "people"],
139
+ description:
140
+ "agents starts the current agent; people posts without inference.",
141
+ },
142
+ },
143
+ required: ["text", "audience"],
144
+ additionalProperties: false,
145
+ },
146
+ },
147
+ required: ["name"],
148
+ additionalProperties: false,
149
+ },
150
+ },
69
151
  ],
70
152
  },
71
153
  };
72
154
  }
73
155
  if (request.method === "tools/call" && request.params?.name === "chat_update")
74
156
  return { result: await updateChat(request.params) };
157
+ if (request.method === "tools/call" && request.params?.name === "channel_members_update")
158
+ return { result: await updateChannelMembers(request.params) };
159
+ if (request.method === "tools/call" && request.params?.name === "channel_create")
160
+ return { result: await createChannel(request.params) };
75
161
  return {
76
162
  error: { code: -32601, message: `Method not found: ${String(request.method)}` },
77
163
  };
78
164
  }
79
165
 
80
166
  async function updateChat(params) {
167
+ const { chat } = capabilityContext(params);
168
+ const input = params.arguments;
169
+ if (!input || typeof input !== "object" || Array.isArray(input))
170
+ throw new Error("A chat update is required.");
171
+ const result = await callHost("/chats/updateChat", chat.token, input);
172
+ return {
173
+ content: [
174
+ {
175
+ type: "text",
176
+ text: `Updated chat ${result.chat.id}.`,
177
+ },
178
+ ],
179
+ structuredContent: { chat: result.chat },
180
+ };
181
+ }
182
+
183
+ async function updateChannelMembers(params) {
184
+ const { chat, users } = capabilityContext(params);
185
+ const input = params.arguments;
186
+ if (!input || typeof input !== "object" || Array.isArray(input))
187
+ throw new Error("A channel membership update is required.");
188
+ const add = resolveUsers(input.addUsers ?? [], users, "addUsers");
189
+ const remove = resolveUsers(input.removeUsers ?? [], users, "removeUsers");
190
+ if (!add.length && !remove.length)
191
+ throw new Error("At least one user must be added or removed.");
192
+ const result = await callHost("/channels/updateMembers", chat.token, { add, remove });
193
+ return {
194
+ content: [
195
+ {
196
+ type: "text",
197
+ text: `Updated members of channel ${result.chatId}: added ${result.addedUserIds.length}, removed ${result.removedUserIds.length}.`,
198
+ },
199
+ ],
200
+ structuredContent: result,
201
+ };
202
+ }
203
+
204
+ async function createChannel(params) {
205
+ const { chat, users } = capabilityContext(params);
206
+ const input = params.arguments;
207
+ if (!input || typeof input !== "object" || Array.isArray(input))
208
+ throw new Error("A channel definition is required.");
209
+ const members = resolveUsers(input.members ?? [], users, "members");
210
+ const result = await callHost("/channels/createChannel", chat.token, {
211
+ ...input,
212
+ members,
213
+ idempotencyKey: randomUUID(),
214
+ });
215
+ return {
216
+ content: [
217
+ {
218
+ type: "text",
219
+ text: `Created channel ${result.chat.id}${result.initialMessage ? " and posted its initial message" : ""}.`,
220
+ },
221
+ ],
222
+ structuredContent: result,
223
+ };
224
+ }
225
+
226
+ function capabilityContext(params) {
81
227
  const chat = params?._meta?.[CHAT_META_KEY];
82
228
  if (!chat || typeof chat.id !== "string" || typeof chat.token !== "string")
83
229
  throw new Error("This tool must be called from an active Happy chat.");
230
+ const users = params?._meta?.[USERS_META_KEY];
231
+ if (!Array.isArray(users)) throw new Error("Happy did not provide referenced-user metadata.");
232
+ return { chat, users };
233
+ }
234
+
235
+ function resolveUsers(selectors, users, name) {
236
+ if (!Array.isArray(selectors)) throw new Error(`${name} must be an array.`);
237
+ const resolved = selectors.map((selector) => {
238
+ if (typeof selector !== "string" || !selector.trim())
239
+ throw new Error(`${name} must contain usernames.`);
240
+ const normalized = selector.trim().replace(/^@/, "").toLowerCase();
241
+ const matches = users.filter(
242
+ (user) =>
243
+ user &&
244
+ typeof user === "object" &&
245
+ (user.id === selector.trim() ||
246
+ (typeof user.username === "string" &&
247
+ user.username.toLowerCase() === normalized)),
248
+ );
249
+ if (matches.length !== 1)
250
+ throw new Error(`User ${selector} is not uniquely available in this turn.`);
251
+ const user = matches[0];
252
+ if (typeof user.id !== "string" || typeof user.token !== "string")
253
+ throw new Error(`User ${selector} has malformed capability metadata.`);
254
+ return { id: user.id, token: user.token };
255
+ });
256
+ if (new Set(resolved.map(({ id }) => id)).size !== resolved.length)
257
+ throw new Error(`${name} contains a duplicate user.`);
258
+ return resolved;
259
+ }
260
+
261
+ async function callHost(path, chatToken, body) {
84
262
  const apiUrl = process.env.HAPPY2_PLUGIN_API_URL;
85
263
  const runtimeToken = process.env.HAPPY2_PLUGIN_API_TOKEN;
86
264
  if (!apiUrl || !runtimeToken) throw new Error("The Happy Plugin API is unavailable.");
87
- const input = params.arguments;
88
- if (!input || typeof input !== "object" || Array.isArray(input))
89
- throw new Error("A chat update is required.");
90
- const response = await fetch(`${apiUrl}/chats/updateChat`, {
265
+ const response = await fetch(`${apiUrl}${path}`, {
91
266
  method: "POST",
92
267
  headers: {
93
268
  authorization: `Bearer ${runtimeToken}`,
94
269
  "content-type": "application/json",
95
- "x-happy2-chat-token": chat.token,
270
+ "x-happy2-chat-token": chatToken,
96
271
  },
97
- body: JSON.stringify(input),
272
+ body: JSON.stringify(body),
98
273
  });
99
274
  const result = await response.json().catch(() => undefined);
100
275
  if (!response.ok)
101
276
  throw new Error(
102
- typeof result?.message === "string" ? result.message : "The chat could not be updated.",
277
+ typeof result?.message === "string" ? result.message : "The chat action failed.",
103
278
  );
104
- return {
105
- content: [
106
- {
107
- type: "text",
108
- text: `Updated chat ${result.chat.id}.`,
109
- },
110
- ],
111
- structuredContent: { chat: result.chat },
112
- };
279
+ return result;
113
280
  }
@@ -0,0 +1,6 @@
1
+ FROM node:22-alpine
2
+
3
+ WORKDIR /plugin
4
+ COPY server.mjs /plugin/server.mjs
5
+
6
+ CMD ["sleep", "infinity"]
@@ -0,0 +1,17 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "version": "1.0.0",
4
+ "displayName": "Plugin Developer",
5
+ "shortName": "plugin-developer",
6
+ "description": "Helps agents design, validate, inspect, and request installation of Happy2 plugins.",
7
+ "variables": [],
8
+ "container": {
9
+ "dockerfile": "container/Dockerfile",
10
+ "permissions": ["plugins:list", "plugins:request-install", "plugins:request-uninstall"]
11
+ },
12
+ "mcp": {
13
+ "type": "stdio",
14
+ "command": "node",
15
+ "args": ["/plugin/server.mjs"]
16
+ }
17
+ }
@@ -0,0 +1,155 @@
1
+ import { createInterface } from "node:readline";
2
+
3
+ async function handle(request) {
4
+ if (request.method === "initialize") {
5
+ return {
6
+ result: {
7
+ protocolVersion: request.params?.protocolVersion ?? "2025-06-18",
8
+ capabilities: { tools: {} },
9
+ serverInfo: { name: "happy2-plugin-developer", version: "1.0.0" },
10
+ },
11
+ };
12
+ }
13
+ if (request.method === "ping") return { result: {} };
14
+ if (request.method === "tools/list") return { result: { tools } };
15
+ if (request.method === "tools/call") return callTool(request.params);
16
+ return { error: { code: -32601, message: `Method not found: ${String(request.method)}` } };
17
+ }
18
+
19
+ const tools = [
20
+ {
21
+ name: "happy2_plugins_list",
22
+ title: "List installed Happy2 plugins",
23
+ description:
24
+ "Lists installed Happy2 plugin identities, versions, installation IDs, and health.",
25
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
26
+ },
27
+ {
28
+ name: "happy2_plugin_install_from_link",
29
+ title: "Request Happy2 plugin installation",
30
+ description:
31
+ "Downloads and validates a Happy2 plugin ZIP link, then posts a human approval request in the current chat. It never installs without approval.",
32
+ inputSchema: {
33
+ type: "object",
34
+ properties: {
35
+ sourceUrl: {
36
+ type: "string",
37
+ description: "Public HTTPS URL of a Happy2 plugin ZIP package.",
38
+ },
39
+ reason: {
40
+ type: "string",
41
+ description: "Short explanation of why this chat needs the plugin.",
42
+ },
43
+ },
44
+ required: ["sourceUrl"],
45
+ additionalProperties: false,
46
+ },
47
+ },
48
+ {
49
+ name: "happy2_plugin_uninstall",
50
+ title: "Request Happy2 plugin uninstall",
51
+ description:
52
+ "Posts a human approval request in the current chat to uninstall one Happy2 plugin installation. It never uninstalls without approval.",
53
+ inputSchema: {
54
+ type: "object",
55
+ properties: {
56
+ installationId: {
57
+ type: "string",
58
+ description: "Installation ID returned by happy2_plugins_list.",
59
+ },
60
+ reason: {
61
+ type: "string",
62
+ description: "Short explanation of why this installation should be removed.",
63
+ },
64
+ },
65
+ required: ["installationId"],
66
+ additionalProperties: false,
67
+ },
68
+ },
69
+ ];
70
+
71
+ const lines = createInterface({ input: process.stdin, crlfDelay: Infinity });
72
+
73
+ for await (const line of lines) {
74
+ if (!line.trim()) continue;
75
+ let request;
76
+ try {
77
+ request = JSON.parse(line);
78
+ } catch {
79
+ continue;
80
+ }
81
+ if (request.id === undefined) continue;
82
+ const response = await handle(request).catch((error) => ({
83
+ result: {
84
+ isError: true,
85
+ content: [
86
+ { type: "text", text: error instanceof Error ? error.message : String(error) },
87
+ ],
88
+ },
89
+ }));
90
+ process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", id: request.id, ...response })}\n`);
91
+ }
92
+
93
+ async function callTool(params) {
94
+ if (params?.name === "happy2_plugins_list") {
95
+ const result = await hostRequest("GET", "/plugins");
96
+ return textResult(JSON.stringify(result, null, 2));
97
+ }
98
+ if (params?.name === "happy2_plugin_install_from_link") {
99
+ const sourceUrl = text(params.arguments?.sourceUrl, "sourceUrl", 4_096);
100
+ const reason = optionalText(params.arguments?.reason, "reason", 1_000);
101
+ const result = await hostRequest("POST", "/plugin-install-requests", {
102
+ sourceUrl,
103
+ ...(reason ? { reason } : {}),
104
+ });
105
+ return textResult(
106
+ `Happy2 posted an installation approval in this chat. Request: ${JSON.stringify(result.approval)}`,
107
+ );
108
+ }
109
+ if (params?.name === "happy2_plugin_uninstall") {
110
+ const installationId = text(params.arguments?.installationId, "installationId", 128);
111
+ const reason = optionalText(params.arguments?.reason, "reason", 1_000);
112
+ const result = await hostRequest("POST", "/plugin-uninstall-requests", {
113
+ installationId,
114
+ ...(reason ? { reason } : {}),
115
+ });
116
+ return textResult(
117
+ `Happy2 posted an uninstall approval in this chat. Request: ${JSON.stringify(result.approval)}`,
118
+ );
119
+ }
120
+ return { result: { isError: true, content: [{ type: "text", text: "Unknown tool" }] } };
121
+ }
122
+
123
+ async function hostRequest(method, path, body) {
124
+ const base = process.env.HAPPY2_PLUGIN_API_URL;
125
+ const token = process.env.HAPPY2_PLUGIN_API_TOKEN;
126
+ if (!base || !token) throw new Error("Happy2 plugin host API is unavailable");
127
+ const response = await fetch(new URL(path, base), {
128
+ method,
129
+ headers: {
130
+ authorization: `Bearer ${token}`,
131
+ ...(body ? { "content-type": "application/json" } : {}),
132
+ },
133
+ ...(body ? { body: JSON.stringify(body) } : {}),
134
+ });
135
+ const result = await response.json().catch(() => undefined);
136
+ if (!response.ok)
137
+ throw new Error(
138
+ result?.message ?? `Happy2 plugin host API returned HTTP ${response.status}`,
139
+ );
140
+ return result;
141
+ }
142
+
143
+ function textResult(text) {
144
+ return { result: { content: [{ type: "text", text }] } };
145
+ }
146
+
147
+ function text(value, name, maximum) {
148
+ if (typeof value !== "string" || !value.trim() || value.length > maximum)
149
+ throw new Error(`${name} must contain between 1 and ${maximum} characters`);
150
+ return value.trim();
151
+ }
152
+
153
+ function optionalText(value, name, maximum) {
154
+ return value === undefined ? undefined : text(value, name, maximum);
155
+ }
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: happy2-plugin-development
3
+ description: Build, package, validate, install, inspect, and troubleshoot Happy2 server plugins. Use when a user asks to create a Happy2 plugin, add Agent Skills or an MCP server to one, package a plugin ZIP, install from a ZIP or HTTPS link, understand plugin permissions and containers, or diagnose plugin installation/runtime health.
4
+ ---
5
+
6
+ # Happy2 plugin development
7
+
8
+ Build against Happy2's server-plugin contract. Do not substitute Codex, Claude, browser-extension, or Conductor plugin formats; they are unrelated.
9
+
10
+ ## Start with the product boundary
11
+
12
+ 1. Identify the useful capability and decide whether it belongs in an Agent Skill, an MCP tool server, a persistent container command, or a combination.
13
+ 2. Keep the package focused. One plugin may contain several closely related skills or tools, but do not make it a miscellaneous bundle.
14
+ 3. Treat installation as system-wide administrator state. A chat agent may request installation, but Happy2 installs only after a human administrator approves the chat card.
15
+ 4. Never claim that MCP elicitation itself grants Happy2 authority. Happy2 owns the durable approval, audit, package snapshot, and runtime lifecycle.
16
+
17
+ Read [references/package-format.md](references/package-format.md) before authoring `plugin.json` or arranging files. Read [references/installing.md](references/installing.md) before packaging, installing, updating, or uninstalling. Read [references/host-api.md](references/host-api.md) before requesting host capabilities from a local plugin container.
18
+
19
+ ## Choose components
20
+
21
+ - Use a skill for reusable instructions, project conventions, workflows, references, scripts, and assets that an agent should load into context.
22
+ - Use MCP for typed operations the agent should call. Keep tool schemas closed, concrete, bounded, and explicit about side effects.
23
+ - Use a persistent container command for an indexer, watcher, worker, or daemon that must stay alive for the installation lifetime.
24
+ - Combine a command and stdio MCP only when they genuinely share one immutable package and isolated installation container.
25
+ - Use remote MCP only for an already-hosted public HTTPS MCP endpoint with static header-template authentication. Happy2 does not add OAuth on behalf of a plugin.
26
+
27
+ ## Build workflow
28
+
29
+ 1. Create a kebab-case package directory and make `plugin.json.shortName` match it.
30
+ 2. Add a square `plugin.png`; prefer 1024×1024.
31
+ 3. Write schema-version-1 `plugin.json` with strict SemVer, user-facing metadata, and only supported fields.
32
+ 4. Put each skill at `skills/<skill-name>/SKILL.md`; match its frontmatter `name` to the directory.
33
+ 5. For local MCP or commands, add a package-relative Dockerfile and ensure the image contains `/bin/sh`.
34
+ 6. Make stdio MCP write newline-delimited JSON-RPC only to stdout. Send logs to stderr.
35
+ 7. Declare the smallest exact host permission allowlist. Unknown permissions make the package invalid.
36
+ 8. Create a ZIP whose root is the package root, or whose only top-level directory is the package root.
37
+ 9. Install directly as an administrator, or use `happy2_plugin_install_from_link` to create a chat approval for a public HTTPS ZIP.
38
+ 10. Inspect installation health and correct the package/configuration rather than hiding a failed state.
39
+
40
+ ## Security invariants
41
+
42
+ - Do not include symlinks, device files, traversal paths, encrypted ZIP entries, or generated dependency caches.
43
+ - Never bake secrets into the ZIP, image, manifest, URL, arguments, or skill.
44
+ - Declare required variables in the manifest. Happy2 encrypts `secret` values and injects both secret and text values only into configured processes.
45
+ - Do not ask an agent to collect a plugin secret in chat. Plugins requiring variables or an administrator-selected image must use the direct administrator install flow.
46
+ - Assume package files become immutable after the first system installation. A changed link does not silently rewrite an installed plugin.
47
+ - Treat the package icon, display name, and description as untrusted publisher material that Happy2 validates and shows in approval UI.
48
+ - A plugin runtime token is not a user session. It grants only manifest-declared host capabilities for one live container incarnation.
49
+ - A contextual chat token is short-lived and bound to the originating Rig session, external-tool call, agent, human actor, and chat. Never persist or forward it.
50
+
51
+ ## Completion checklist
52
+
53
+ - `plugin.json`, `plugin.png`, and at least one skill/container/MCP component exist.
54
+ - Short name, directory name, skill names, referenced paths, variables, headers, permissions, and SemVer validate.
55
+ - The ZIP stays within Happy2's package limits and contains no unsafe entry.
56
+ - MCP initialization, ping, paginated tool listing, and representative tool calls work.
57
+ - Side-effecting tools have bounded inputs, clear descriptions, and their own idempotency where external ambiguity matters.
58
+ - Installation reaches `ready`, or a specific expected failure is explained.
59
+ - The result is tested in a fresh agent turn so Rig receives the current durable tool catalog.
@@ -0,0 +1,63 @@
1
+ # Capability-scoped plugin host API
2
+
3
+ ## Runtime environment
4
+
5
+ Local plugin processes receive:
6
+
7
+ - `HAPPY2_PLUGIN_API_URL`: the dedicated capability-only host listener.
8
+ - `HAPPY2_PLUGIN_API_TOKEN`: an RS256 token for one installed plugin and live container incarnation.
9
+
10
+ Send `Authorization: Bearer <token>`. Do not persist, log, return, or forward either value.
11
+
12
+ ## List plugins
13
+
14
+ Manifest permission: `plugins:list`
15
+
16
+ ```http
17
+ GET /plugins
18
+ Authorization: Bearer …
19
+ ```
20
+
21
+ The response includes the calling installation ID and non-secret installation identity, short name, version, and status. It does not expose variables, users, filesystem paths, package internals, or administrator APIs.
22
+
23
+ ## Request linked installation
24
+
25
+ Manifest permission: `plugins:request-install`
26
+
27
+ ```http
28
+ POST /plugin-install-requests
29
+ Authorization: Bearer …
30
+ Content-Type: application/json
31
+
32
+ {
33
+ "sourceUrl": "https://downloads.example.com/plugin.zip",
34
+ "reason": "Adds the formatter requested in this chat."
35
+ }
36
+ ```
37
+
38
+ This endpoint additionally requires a short-lived contextual token issued only while Happy2 executes an MCP tool for a running Rig turn. The token binds the request to the external-tool call, session, agent, human actor, and chat. A persistent plugin command or a non-contextual health probe receives 403 even if its base manifest declares the permission.
39
+
40
+ The endpoint downloads, extracts, fully validates, and snapshots the package before it creates the approval. It returns HTTP 202 and an approval summary. It does not install synchronously.
41
+
42
+ ## Request uninstall
43
+
44
+ Manifest permission: `plugins:request-uninstall`
45
+
46
+ ```http
47
+ POST /plugin-uninstall-requests
48
+ Authorization: Bearer …
49
+ Content-Type: application/json
50
+
51
+ {
52
+ "installationId": "the installation ID from GET /plugins",
53
+ "reason": "The user no longer needs this integration."
54
+ }
55
+ ```
56
+
57
+ This endpoint has the same contextual-call requirement. It snapshots the installed plugin's validated name, description, and icon into a pending chat card. Removal begins only after a chat-member server administrator approves it.
58
+
59
+ ## Trust model
60
+
61
+ Manifest permissions are exact capabilities, not descriptive labels. Happy2 verifies the token signature, installation, container-incarnation ID, database health, and matching live OCI container on every host request. Stopping, replacing, failing, or uninstalling that incarnation invalidates the token without a process-local revocation list.
62
+
63
+ The host listener is deliberately separate from `/v0`. A plugin cannot exchange its capability for a human session, choose a different chat for approval, or call arbitrary product APIs.