happy2 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/happy2-server/PLUGINS.md +11 -5
- package/packages/happy2-server/dist/modules/agent/agentChatGetContext.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentChatGetContext.js +1 -1
- package/packages/happy2-server/dist/modules/agent/agentChatGetContext.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentConversationCreate.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentConversationCreate.js +1 -1
- package/packages/happy2-server/dist/modules/agent/agentConversationCreate.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentCreate.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentCreate.js +2 -2
- package/packages/happy2-server/dist/modules/agent/agentCreate.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentDefaultCreate.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentDefaultCreate.js +1 -1
- package/packages/happy2-server/dist/modules/agent/agentDefaultCreate.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageCommitChange.js +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageCommitChange.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageCreate.d.ts +4 -3
- package/packages/happy2-server/dist/modules/agent/agentImageCreate.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageCreate.js +73 -23
- package/packages/happy2-server/dist/modules/agent/agentImageCreate.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageDeactivate.d.ts +15 -0
- package/packages/happy2-server/dist/modules/agent/agentImageDeactivate.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentImageDeactivate.js +92 -0
- package/packages/happy2-server/dist/modules/agent/agentImageDeactivate.js.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentImageDockerfileGetForHost.d.ts +12 -0
- package/packages/happy2-server/dist/modules/agent/agentImageDockerfileGetForHost.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentImageDockerfileGetForHost.js +28 -0
- package/packages/happy2-server/dist/modules/agent/agentImageDockerfileGetForHost.js.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentImageFindDefinition.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageFindDefinition.js +2 -2
- package/packages/happy2-server/dist/modules/agent/agentImageFindDefinition.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGet.js +2 -2
- package/packages/happy2-server/dist/modules/agent/agentImageGet.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.js +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGetChangeContext.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGetReadyDefault.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageGetReadyDefault.js +2 -2
- package/packages/happy2-server/dist/modules/agent/agentImageGetReadyDefault.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageList.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageList.js +2 -1
- package/packages/happy2-server/dist/modules/agent/agentImageList.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageListForHost.d.ts +17 -0
- package/packages/happy2-server/dist/modules/agent/agentImageListForHost.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentImageListForHost.js +38 -0
- package/packages/happy2-server/dist/modules/agent/agentImageListForHost.js.map +1 -0
- package/packages/happy2-server/dist/modules/agent/agentImageListRequestedBuildIds.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageListRequestedBuildIds.js +2 -2
- package/packages/happy2-server/dist/modules/agent/agentImageListRequestedBuildIds.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageRequestBuild.js +3 -3
- package/packages/happy2-server/dist/modules/agent/agentImageRequestBuild.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.d.ts +4 -3
- package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.js +10 -6
- package/packages/happy2-server/dist/modules/agent/agentImageSetDefault.js.map +1 -1
- package/packages/happy2-server/dist/modules/agent/agentImageTakeBuild.js +2 -2
- package/packages/happy2-server/dist/modules/agent/agentImageTakeBuild.js.map +1 -1
- package/packages/happy2-server/dist/modules/agents/service.d.ts +21 -2
- package/packages/happy2-server/dist/modules/agents/service.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/agents/service.js +14 -0
- package/packages/happy2-server/dist/modules/agents/service.js.map +1 -1
- package/packages/happy2-server/dist/modules/draft/draftList.d.ts +8 -0
- package/packages/happy2-server/dist/modules/draft/draftList.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/draft/draftList.js +27 -0
- package/packages/happy2-server/dist/modules/draft/draftList.js.map +1 -0
- package/packages/happy2-server/dist/modules/draft/draftUpdate.d.ts +16 -0
- package/packages/happy2-server/dist/modules/draft/draftUpdate.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/draft/draftUpdate.js +64 -0
- package/packages/happy2-server/dist/modules/draft/draftUpdate.js.map +1 -0
- package/packages/happy2-server/dist/modules/draft/types.d.ts +7 -0
- package/packages/happy2-server/dist/modules/draft/types.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/draft/types.js +2 -0
- package/packages/happy2-server/dist/modules/draft/types.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/environmentManagementServer.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/plugin/environmentManagementServer.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/environmentManagementServer.test.js +183 -0
- package/packages/happy2-server/dist/modules/plugin/environmentManagementServer.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/impl/apiPermissions.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/impl/apiPermissions.js +22 -0
- package/packages/happy2-server/dist/modules/plugin/impl/apiPermissions.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.js +7 -1
- package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.test.d.ts +2 -0
- package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.test.d.ts.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.test.js +37 -0
- package/packages/happy2-server/dist/modules/plugin/packageLinkDownloader.test.js.map +1 -0
- package/packages/happy2-server/dist/modules/plugin/pluginInstall.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstall.js +2 -2
- package/packages/happy2-server/dist/modules/plugin/pluginInstall.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js +5 -1
- package/packages/happy2-server/dist/modules/plugin/pluginInstallationGetRuntimeConfiguration.js.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/types.d.ts +2 -2
- package/packages/happy2-server/dist/modules/plugin/types.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/plugin/types.js +3 -0
- package/packages/happy2-server/dist/modules/plugin/types.js.map +1 -1
- package/packages/happy2-server/dist/modules/schema.d.ts +276 -0
- package/packages/happy2-server/dist/modules/schema.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/schema.js +14 -0
- package/packages/happy2-server/dist/modules/schema.js.map +1 -1
- package/packages/happy2-server/dist/modules/sync/syncGetDifference.d.ts.map +1 -1
- package/packages/happy2-server/dist/modules/sync/syncGetDifference.js +2 -0
- package/packages/happy2-server/dist/modules/sync/syncGetDifference.js.map +1 -1
- package/packages/happy2-server/dist/routes/collaboration.d.ts.map +1 -1
- package/packages/happy2-server/dist/routes/collaboration.js +38 -1
- package/packages/happy2-server/dist/routes/collaboration.js.map +1 -1
- package/packages/happy2-server/dist/routes/pluginHost.d.ts +3 -1
- package/packages/happy2-server/dist/routes/pluginHost.d.ts.map +1 -1
- package/packages/happy2-server/dist/routes/pluginHost.js +113 -0
- package/packages/happy2-server/dist/routes/pluginHost.js.map +1 -1
- package/packages/happy2-server/dist/web/assets/{index-Dn5SZu3y.js → index-BT_VezYx.js} +20 -20
- package/packages/happy2-server/dist/web/index.html +1 -1
- package/packages/happy2-server/drizzle/0030_personal_synced_drafts.sql +11 -0
- package/packages/happy2-server/drizzle/0031_agent_image_deactivation.sql +1 -0
- package/packages/happy2-server/drizzle/meta/_journal.json +14 -0
- package/packages/happy2-server/plugins/README.md +3 -1
- package/packages/happy2-server/plugins/environment-management/container/Dockerfile +6 -0
- package/packages/happy2-server/plugins/environment-management/plugin.json +17 -0
- package/packages/happy2-server/plugins/environment-management/plugin.png +0 -0
- package/packages/happy2-server/plugins/environment-management/server.mjs +234 -0
- package/packages/happy2-server/plugins/environment-management/skills/happy2-environment-management/SKILL.md +41 -0
- package/packages/happy2-server/plugins/plugin-developer/skills/happy2-plugin-development/references/host-api.md +25 -0
- package/packages/happy2-server/plugins/plugin-developer/skills/happy2-plugin-development/references/package-format.md +3 -0
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
background: #131217;
|
|
14
14
|
}
|
|
15
15
|
</style>
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-BT_VezYx.js"></script>
|
|
17
17
|
<link rel="stylesheet" crossorigin href="/assets/index-Dys3sWv8.css">
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
CREATE TABLE `drafts` (
|
|
2
|
+
`user_id` text NOT NULL,
|
|
3
|
+
`chat_id` text NOT NULL,
|
|
4
|
+
`text` text DEFAULT '' NOT NULL,
|
|
5
|
+
`sync_sequence` integer DEFAULT 0 NOT NULL,
|
|
6
|
+
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
7
|
+
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
8
|
+
PRIMARY KEY(`user_id`, `chat_id`),
|
|
9
|
+
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
10
|
+
FOREIGN KEY (`chat_id`) REFERENCES `chats`(`id`) ON UPDATE no action ON DELETE cascade
|
|
11
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE `agent_images` ADD `deleted_at` text;
|
|
@@ -211,6 +211,20 @@
|
|
|
211
211
|
"when": 1784433600000,
|
|
212
212
|
"tag": "0029_plugin_management_requests",
|
|
213
213
|
"breakpoints": true
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"idx": 30,
|
|
217
|
+
"version": "6",
|
|
218
|
+
"when": 1784437200000,
|
|
219
|
+
"tag": "0030_personal_synced_drafts",
|
|
220
|
+
"breakpoints": true
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"idx": 31,
|
|
224
|
+
"version": "6",
|
|
225
|
+
"when": 1784444400000,
|
|
226
|
+
"tag": "0031_agent_image_deactivation",
|
|
227
|
+
"breakpoints": true
|
|
214
228
|
}
|
|
215
229
|
]
|
|
216
230
|
}
|
|
@@ -7,7 +7,9 @@ Each child directory is one immutable, built-in plugin package. See
|
|
|
7
7
|
tool. `chat-management` demonstrates installation-bound chat and referenced-user
|
|
8
8
|
capabilities: it updates the current chat, manages channel membership, and creates
|
|
9
9
|
private channels with either an informational opening message or an agent-triggering
|
|
10
|
-
prompt. `
|
|
10
|
+
prompt. `environment-management` lets agents inspect, build, select, and safely
|
|
11
|
+
deactivate Dockerfile-backed agent environments while retaining their manifests.
|
|
12
|
+
`plugin-developer` provides Happy2 plugin authoring/install documentation
|
|
11
13
|
and chat-scoped MCP tools that request administrator approval for linked install
|
|
12
14
|
or uninstall actions. Product plugins should be added here as separate,
|
|
13
15
|
reviewable changes.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"displayName": "Environment Management",
|
|
5
|
+
"shortName": "environment-management",
|
|
6
|
+
"description": "Lets an agent inspect, create, select, and safely deactivate Happy agent environments.",
|
|
7
|
+
"variables": [],
|
|
8
|
+
"container": {
|
|
9
|
+
"dockerfile": "container/Dockerfile",
|
|
10
|
+
"permissions": ["environments:read", "environments:manage", "environments:deactivate"]
|
|
11
|
+
},
|
|
12
|
+
"mcp": {
|
|
13
|
+
"type": "stdio",
|
|
14
|
+
"command": "node",
|
|
15
|
+
"args": ["/plugin/server.mjs"]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
|
|
3
|
+
const lines = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
4
|
+
|
|
5
|
+
for await (const line of lines) {
|
|
6
|
+
if (!line.trim()) continue;
|
|
7
|
+
let request;
|
|
8
|
+
try {
|
|
9
|
+
request = JSON.parse(line);
|
|
10
|
+
} catch {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (request.id === undefined) continue;
|
|
14
|
+
const response = await handle(request).catch((error) => ({
|
|
15
|
+
result: {
|
|
16
|
+
isError: true,
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
text:
|
|
21
|
+
error instanceof Error
|
|
22
|
+
? error.message
|
|
23
|
+
: "The environment operation failed.",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", id: request.id, ...response })}\n`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function handle(request) {
|
|
32
|
+
if (request.method === "initialize") {
|
|
33
|
+
return {
|
|
34
|
+
result: {
|
|
35
|
+
protocolVersion: request.params?.protocolVersion ?? "2025-06-18",
|
|
36
|
+
capabilities: { tools: {} },
|
|
37
|
+
serverInfo: { name: "happy2-environment-management", version: "1.0.0" },
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (request.method === "ping") return { result: {} };
|
|
42
|
+
if (request.method === "tools/list") return { result: { tools: toolDefinitions() } };
|
|
43
|
+
if (request.method !== "tools/call")
|
|
44
|
+
return {
|
|
45
|
+
error: { code: -32601, message: `Method not found: ${String(request.method)}` },
|
|
46
|
+
};
|
|
47
|
+
const input = request.params?.arguments ?? {};
|
|
48
|
+
switch (request.params?.name) {
|
|
49
|
+
case "happy2_environments_list":
|
|
50
|
+
return { result: await listEnvironments() };
|
|
51
|
+
case "happy2_environment_get_dockerfile":
|
|
52
|
+
return { result: await getDockerfile(input) };
|
|
53
|
+
case "happy2_environment_create":
|
|
54
|
+
return { result: await createEnvironment(input) };
|
|
55
|
+
case "happy2_environment_set_default":
|
|
56
|
+
return { result: await setDefaultEnvironment(input) };
|
|
57
|
+
case "happy2_environment_deactivate":
|
|
58
|
+
return { result: await deactivateEnvironment(input) };
|
|
59
|
+
default:
|
|
60
|
+
return {
|
|
61
|
+
error: {
|
|
62
|
+
code: -32601,
|
|
63
|
+
message: `Tool not found: ${String(request.params?.name)}`,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function toolDefinitions() {
|
|
70
|
+
const environmentId = {
|
|
71
|
+
type: "string",
|
|
72
|
+
minLength: 1,
|
|
73
|
+
maxLength: 128,
|
|
74
|
+
description: "The environment ID returned by happy2_environments_list or creation.",
|
|
75
|
+
};
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
name: "happy2_environments_list",
|
|
79
|
+
title: "List agent environments",
|
|
80
|
+
description:
|
|
81
|
+
"Lists active and inactive Happy agent environments, their build status, and the current default environment.",
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {},
|
|
85
|
+
additionalProperties: false,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "happy2_environment_get_dockerfile",
|
|
90
|
+
title: "Read an environment Dockerfile",
|
|
91
|
+
description:
|
|
92
|
+
"Returns the retained immutable Dockerfile and active state for one Happy agent environment.",
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: "object",
|
|
95
|
+
properties: { environmentId },
|
|
96
|
+
required: ["environmentId"],
|
|
97
|
+
additionalProperties: false,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "happy2_environment_create",
|
|
102
|
+
title: "Create or reactivate an agent environment",
|
|
103
|
+
description:
|
|
104
|
+
"Creates an immutable Happy agent environment and queues its Docker image build. The exact definition of an inactive environment is reactivated under the same ID and rebuilt. Creation returns before the build is ready.",
|
|
105
|
+
inputSchema: {
|
|
106
|
+
type: "object",
|
|
107
|
+
properties: {
|
|
108
|
+
name: {
|
|
109
|
+
type: "string",
|
|
110
|
+
minLength: 1,
|
|
111
|
+
maxLength: 100,
|
|
112
|
+
description: "A concise human-readable environment name.",
|
|
113
|
+
},
|
|
114
|
+
dockerfile: {
|
|
115
|
+
type: "string",
|
|
116
|
+
minLength: 1,
|
|
117
|
+
maxLength: 262144,
|
|
118
|
+
description: "The complete Dockerfile used to build the environment.",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
required: ["name", "dockerfile"],
|
|
122
|
+
additionalProperties: false,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "happy2_environment_set_default",
|
|
127
|
+
title: "Set the default agent environment",
|
|
128
|
+
description:
|
|
129
|
+
"Selects a ready environment as the default for agents created in the future. Existing agents keep their assigned environment.",
|
|
130
|
+
inputSchema: {
|
|
131
|
+
type: "object",
|
|
132
|
+
properties: { environmentId },
|
|
133
|
+
required: ["environmentId"],
|
|
134
|
+
additionalProperties: false,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "happy2_environment_deactivate",
|
|
139
|
+
title: "Deactivate an unused agent environment",
|
|
140
|
+
description:
|
|
141
|
+
"Deactivates a custom environment only when it is unused. Happy permanently retains its manifest and Dockerfile so the same definition can be reactivated and rebuilt later.",
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: "object",
|
|
144
|
+
properties: { environmentId },
|
|
145
|
+
required: ["environmentId"],
|
|
146
|
+
additionalProperties: false,
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function listEnvironments() {
|
|
153
|
+
const result = await callHost("/environments");
|
|
154
|
+
return toolResult(
|
|
155
|
+
`Found ${result.environments.length} agent environment${result.environments.length === 1 ? "" : "s"}.`,
|
|
156
|
+
result,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function getDockerfile(input) {
|
|
161
|
+
const environmentId = requiredString(input, "environmentId");
|
|
162
|
+
const result = await callHost(`/environments/${encodeURIComponent(environmentId)}/dockerfile`);
|
|
163
|
+
return toolResult(`Read the Dockerfile for ${result.environment.name}.`, result);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function createEnvironment(input) {
|
|
167
|
+
const name = requiredString(input, "name");
|
|
168
|
+
const dockerfile = requiredString(input, "dockerfile", false);
|
|
169
|
+
const result = await callHost("/environments/createEnvironment", {
|
|
170
|
+
method: "POST",
|
|
171
|
+
body: { name, dockerfile },
|
|
172
|
+
});
|
|
173
|
+
return toolResult(
|
|
174
|
+
`Environment ${result.environment.name} is active; its image build is ${result.environment.status}.`,
|
|
175
|
+
result,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function setDefaultEnvironment(input) {
|
|
180
|
+
const environmentId = requiredString(input, "environmentId");
|
|
181
|
+
const result = await callHost(
|
|
182
|
+
`/environments/${encodeURIComponent(environmentId)}/setDefaultEnvironment`,
|
|
183
|
+
{ method: "POST", body: {} },
|
|
184
|
+
);
|
|
185
|
+
return toolResult(`Set ${result.environment.name} as the default environment.`, result);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function deactivateEnvironment(input) {
|
|
189
|
+
const environmentId = requiredString(input, "environmentId");
|
|
190
|
+
const result = await callHost(
|
|
191
|
+
`/environments/${encodeURIComponent(environmentId)}/deactivateEnvironment`,
|
|
192
|
+
{ method: "POST", body: {} },
|
|
193
|
+
);
|
|
194
|
+
return toolResult(`Deactivated environment ${result.environmentId}.`, result);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function requiredString(input, name, trim = true) {
|
|
198
|
+
if (!input || typeof input !== "object" || Array.isArray(input))
|
|
199
|
+
throw new Error("Tool arguments must be an object.");
|
|
200
|
+
const value = input[name];
|
|
201
|
+
if (typeof value !== "string" || !value.trim())
|
|
202
|
+
throw new Error(`${name} must be a non-empty string.`);
|
|
203
|
+
return trim ? value.trim() : value;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function toolResult(text, structuredContent) {
|
|
207
|
+
return {
|
|
208
|
+
content: [{ type: "text", text }],
|
|
209
|
+
structuredContent,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function callHost(path, options = {}) {
|
|
214
|
+
const apiUrl = process.env.HAPPY2_PLUGIN_API_URL;
|
|
215
|
+
const token = process.env.HAPPY2_PLUGIN_API_TOKEN;
|
|
216
|
+
if (!apiUrl || !token) throw new Error("Happy did not provide plugin host credentials.");
|
|
217
|
+
const response = await fetch(new URL(path, `${apiUrl}/`), {
|
|
218
|
+
method: options.method ?? "GET",
|
|
219
|
+
headers: {
|
|
220
|
+
authorization: `Bearer ${token}`,
|
|
221
|
+
...(options.body === undefined ? {} : { "content-type": "application/json" }),
|
|
222
|
+
},
|
|
223
|
+
...(options.body === undefined ? {} : { body: JSON.stringify(options.body) }),
|
|
224
|
+
});
|
|
225
|
+
const payload = await response.json().catch(() => undefined);
|
|
226
|
+
if (!response.ok) {
|
|
227
|
+
const message =
|
|
228
|
+
payload && typeof payload.message === "string"
|
|
229
|
+
? payload.message
|
|
230
|
+
: `Happy environment API returned HTTP ${response.status}.`;
|
|
231
|
+
throw new Error(message);
|
|
232
|
+
}
|
|
233
|
+
return payload;
|
|
234
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: happy2-environment-management
|
|
3
|
+
description: Inspect, create, select, and safely deactivate Happy agent environments. Use when a user asks to change the default Docker image or environment, inspect an environment Dockerfile, build or reactivate an agent environment, or deactivate an unused custom environment.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Happy2 environment management
|
|
7
|
+
|
|
8
|
+
Treat an environment as an immutable Dockerfile-backed agent image. Use the
|
|
9
|
+
environment tools for the server-wide catalog; do not edit container state or
|
|
10
|
+
claim that changing the default rewrites an existing agent.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
1. Call `happy2_environments_list` before referring to an existing environment.
|
|
15
|
+
2. Call `happy2_environment_get_dockerfile` when the current Dockerfile matters
|
|
16
|
+
or when a new environment should be derived from an existing definition.
|
|
17
|
+
3. Create with a complete, reproducible Dockerfile and a concise distinct name.
|
|
18
|
+
Creation queues an asynchronous image build. Creating the exact definition
|
|
19
|
+
of an inactive environment reactivates the retained manifest and queues a
|
|
20
|
+
fresh build under the same environment ID.
|
|
21
|
+
4. Poll `happy2_environments_list` until the new environment is `ready` before
|
|
22
|
+
calling `happy2_environment_set_default`. Report a `failed` status rather
|
|
23
|
+
than repeatedly creating equivalent definitions.
|
|
24
|
+
5. Explain that the default applies to agents created later. Existing agents
|
|
25
|
+
retain their assigned environment.
|
|
26
|
+
6. Deactivate only the exact custom environment the user requested. Happy
|
|
27
|
+
rejects deactivation while an environment is the default, assigned to an
|
|
28
|
+
agent or live runtime, selected by a plugin, queued/building, or built in.
|
|
29
|
+
Deactivation never deletes its manifest or Dockerfile; inactive definitions
|
|
30
|
+
remain readable and can be reactivated and rebuilt.
|
|
31
|
+
|
|
32
|
+
## Safety
|
|
33
|
+
|
|
34
|
+
- Create, set, or deactivate only when the user explicitly requests that mutation.
|
|
35
|
+
- Never guess an environment ID; resolve it from the list response.
|
|
36
|
+
- Inspect the Dockerfile before copying or modifying an unfamiliar environment.
|
|
37
|
+
- Do not put credentials, tokens, private keys, or user data in a Dockerfile.
|
|
38
|
+
- Prefer pinned, reproducible dependencies when the user supplies or approves
|
|
39
|
+
exact versions. Do not silently invent version requirements.
|
|
40
|
+
- If a name matches multiple environments, ask which ID the user means before a
|
|
41
|
+
mutation.
|
|
@@ -20,6 +20,31 @@ Authorization: Bearer …
|
|
|
20
20
|
|
|
21
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
22
|
|
|
23
|
+
## Agent environments
|
|
24
|
+
|
|
25
|
+
Manifest permissions: `environments:read` for listing and Dockerfile reads;
|
|
26
|
+
`environments:manage` for creation and default selection;
|
|
27
|
+
`environments:deactivate` separately for safe deactivation.
|
|
28
|
+
|
|
29
|
+
```http
|
|
30
|
+
GET /environments
|
|
31
|
+
GET /environments/:environmentId/dockerfile
|
|
32
|
+
POST /environments/createEnvironment
|
|
33
|
+
POST /environments/:environmentId/setDefaultEnvironment
|
|
34
|
+
POST /environments/:environmentId/deactivateEnvironment
|
|
35
|
+
Authorization: Bearer …
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Creation accepts `{ "name": string, "dockerfile": string }`, creates an immutable
|
|
39
|
+
definition, and queues its image build. Creating the same inactive definition
|
|
40
|
+
reactivates its retained manifest and queues a fresh build under the same ID.
|
|
41
|
+
Only a ready environment can become the default. Deactivation accepts an empty
|
|
42
|
+
body and rejects built-ins, queued or active builds, the default, agent
|
|
43
|
+
assignments and bindings, and plugin container-image selections. It never
|
|
44
|
+
deletes the immutable manifest or Dockerfile. `GET /environments` supplies
|
|
45
|
+
active state, IDs, and lifecycle status required to drive those operations
|
|
46
|
+
without exposing build logs or provider identifiers.
|
|
47
|
+
|
|
23
48
|
## Request linked installation
|
|
24
49
|
|
|
25
50
|
Manifest permission: `plugins:request-install`
|
|
@@ -124,6 +124,9 @@ Variable keys use environment-variable syntax. Each installation must provide ev
|
|
|
124
124
|
|
|
125
125
|
Supported local host permissions:
|
|
126
126
|
|
|
127
|
+
- `environments:read`: list agent environments and read one immutable Dockerfile.
|
|
128
|
+
- `environments:manage`: create an agent environment and select a ready default.
|
|
129
|
+
- `environments:deactivate`: deactivate an unused custom agent environment without deleting its retained manifest or Dockerfile.
|
|
127
130
|
- `plugins:list`: read non-secret installed-plugin identity and health.
|
|
128
131
|
- `plugins:request-install`: during a contextual agent tool call, stage a linked ZIP and create a durable approval in that exact chat.
|
|
129
132
|
- `plugins:request-uninstall`: during a contextual agent tool call, create a durable approval to remove one exact installation.
|