copilot-hub 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +215 -0
- package/apps/agent-engine/.env.example +41 -0
- package/apps/agent-engine/LICENSE +21 -0
- package/apps/agent-engine/README.md +57 -0
- package/apps/agent-engine/bot-registry.example.json +28 -0
- package/apps/agent-engine/capabilities/example/index.js +3 -0
- package/apps/agent-engine/capabilities/example/manifest.json +14 -0
- package/apps/agent-engine/dist/agent-worker.js +241 -0
- package/apps/agent-engine/dist/config.js +225 -0
- package/apps/agent-engine/dist/index.js +352 -0
- package/apps/agent-engine/dist/test/project-fingerprint.test.js +40 -0
- package/apps/agent-engine/dist/test/thread-id.test.js +12 -0
- package/apps/agent-engine/package.json +28 -0
- package/apps/control-plane/.env.example +25 -0
- package/apps/control-plane/README.md +35 -0
- package/apps/control-plane/bot-registry.example.json +40 -0
- package/apps/control-plane/capabilities/example/index.js +3 -0
- package/apps/control-plane/capabilities/example/manifest.json +14 -0
- package/apps/control-plane/dist/agent-worker.js +243 -0
- package/apps/control-plane/dist/channels/channel-factory.js +21 -0
- package/apps/control-plane/dist/channels/hub-ops-commands.js +752 -0
- package/apps/control-plane/dist/channels/telegram-channel.js +743 -0
- package/apps/control-plane/dist/channels/whatsapp-channel.js +35 -0
- package/apps/control-plane/dist/config.js +230 -0
- package/apps/control-plane/dist/copilot-hub.js +138 -0
- package/apps/control-plane/dist/index.js +349 -0
- package/apps/control-plane/dist/kernel/admin-contract.js +51 -0
- package/apps/control-plane/dist/test/project-fingerprint.test.js +40 -0
- package/apps/control-plane/dist/test/thread-id.test.js +12 -0
- package/apps/control-plane/package.json +27 -0
- package/package.json +89 -0
- package/packages/contracts/README.md +10 -0
- package/packages/contracts/dist/control-plane.d.ts +24 -0
- package/packages/contracts/dist/control-plane.js +37 -0
- package/packages/contracts/dist/control-plane.js.map +1 -0
- package/packages/contracts/dist/index.d.ts +1 -0
- package/packages/contracts/dist/index.js +2 -0
- package/packages/contracts/dist/index.js.map +1 -0
- package/packages/contracts/package.json +27 -0
- package/packages/core/README.md +33 -0
- package/packages/core/dist/agent-supervisor.d.ts +39 -0
- package/packages/core/dist/agent-supervisor.js +552 -0
- package/packages/core/dist/agent-supervisor.js.map +1 -0
- package/packages/core/dist/bot-manager.d.ts +66 -0
- package/packages/core/dist/bot-manager.js +333 -0
- package/packages/core/dist/bot-manager.js.map +1 -0
- package/packages/core/dist/bot-registry.d.ts +60 -0
- package/packages/core/dist/bot-registry.js +381 -0
- package/packages/core/dist/bot-registry.js.map +1 -0
- package/packages/core/dist/bot-runtime.d.ts +135 -0
- package/packages/core/dist/bot-runtime.js +349 -0
- package/packages/core/dist/bot-runtime.js.map +1 -0
- package/packages/core/dist/bridge-service.d.ts +39 -0
- package/packages/core/dist/bridge-service.js +272 -0
- package/packages/core/dist/bridge-service.js.map +1 -0
- package/packages/core/dist/capability-manager.d.ts +18 -0
- package/packages/core/dist/capability-manager.js +335 -0
- package/packages/core/dist/capability-manager.js.map +1 -0
- package/packages/core/dist/capability-scaffold.d.ts +26 -0
- package/packages/core/dist/capability-scaffold.js +118 -0
- package/packages/core/dist/capability-scaffold.js.map +1 -0
- package/packages/core/dist/channel-factory.d.ts +6 -0
- package/packages/core/dist/channel-factory.js +22 -0
- package/packages/core/dist/channel-factory.js.map +1 -0
- package/packages/core/dist/codex-app-client.d.ts +56 -0
- package/packages/core/dist/codex-app-client.js +762 -0
- package/packages/core/dist/codex-app-client.js.map +1 -0
- package/packages/core/dist/codex-provider.d.ts +31 -0
- package/packages/core/dist/codex-provider.js +64 -0
- package/packages/core/dist/codex-provider.js.map +1 -0
- package/packages/core/dist/control-permission.d.ts +19 -0
- package/packages/core/dist/control-permission.js +106 -0
- package/packages/core/dist/control-permission.js.map +1 -0
- package/packages/core/dist/control-plane-actions.d.ts +1 -0
- package/packages/core/dist/control-plane-actions.js +2 -0
- package/packages/core/dist/control-plane-actions.js.map +1 -0
- package/packages/core/dist/example-capability.d.ts +17 -0
- package/packages/core/dist/example-capability.js +22 -0
- package/packages/core/dist/example-capability.js.map +1 -0
- package/packages/core/dist/extension-contract.d.ts +22 -0
- package/packages/core/dist/extension-contract.js +28 -0
- package/packages/core/dist/extension-contract.js.map +1 -0
- package/packages/core/dist/index.d.ts +26 -0
- package/packages/core/dist/index.js +27 -0
- package/packages/core/dist/index.js.map +1 -0
- package/packages/core/dist/instance-lock.d.ts +9 -0
- package/packages/core/dist/instance-lock.js +74 -0
- package/packages/core/dist/instance-lock.js.map +1 -0
- package/packages/core/dist/kernel-control-plane.d.ts +16 -0
- package/packages/core/dist/kernel-control-plane.js +500 -0
- package/packages/core/dist/kernel-control-plane.js.map +1 -0
- package/packages/core/dist/kernel-version.d.ts +1 -0
- package/packages/core/dist/kernel-version.js +2 -0
- package/packages/core/dist/kernel-version.js.map +1 -0
- package/packages/core/dist/project-fingerprint.d.ts +11 -0
- package/packages/core/dist/project-fingerprint.js +33 -0
- package/packages/core/dist/project-fingerprint.js.map +1 -0
- package/packages/core/dist/provider-factory.d.ts +7 -0
- package/packages/core/dist/provider-factory.js +21 -0
- package/packages/core/dist/provider-factory.js.map +1 -0
- package/packages/core/dist/secret-store.d.ts +18 -0
- package/packages/core/dist/secret-store.js +110 -0
- package/packages/core/dist/secret-store.js.map +1 -0
- package/packages/core/dist/state-store.d.ts +50 -0
- package/packages/core/dist/state-store.js +324 -0
- package/packages/core/dist/state-store.js.map +1 -0
- package/packages/core/dist/telegram-channel.d.ts +27 -0
- package/packages/core/dist/telegram-channel.js +951 -0
- package/packages/core/dist/telegram-channel.js.map +1 -0
- package/packages/core/dist/thread-id.d.ts +1 -0
- package/packages/core/dist/thread-id.js +12 -0
- package/packages/core/dist/thread-id.js.map +1 -0
- package/packages/core/dist/whatsapp-channel.d.ts +26 -0
- package/packages/core/dist/whatsapp-channel.js +36 -0
- package/packages/core/dist/whatsapp-channel.js.map +1 -0
- package/packages/core/dist/workspace-paths.d.ts +5 -0
- package/packages/core/dist/workspace-paths.js +77 -0
- package/packages/core/dist/workspace-paths.js.map +1 -0
- package/packages/core/dist/workspace-policy.d.ts +30 -0
- package/packages/core/dist/workspace-policy.js +104 -0
- package/packages/core/dist/workspace-policy.js.map +1 -0
- package/packages/core/package.json +126 -0
- package/scripts/cli.mjs +537 -0
- package/scripts/configure.mjs +254 -0
- package/scripts/ensure-shared-build.mjs +96 -0
- package/scripts/run-node-tests.mjs +52 -0
- package/scripts/supervisor.mjs +332 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import express from "express";
|
|
5
|
+
import { BotManager } from "@copilot-hub/core/bot-manager";
|
|
6
|
+
import { loadBotRegistry } from "@copilot-hub/core/bot-registry";
|
|
7
|
+
import { config } from "./config.js";
|
|
8
|
+
import { InstanceLock } from "@copilot-hub/core/instance-lock";
|
|
9
|
+
import { KernelControlPlane } from "@copilot-hub/core/kernel-control-plane";
|
|
10
|
+
import { CONTROL_ACTIONS } from "@copilot-hub/core/control-plane-actions";
|
|
11
|
+
import { KernelSecretStore } from "@copilot-hub/core/secret-store";
|
|
12
|
+
let activeWebPort = config.webPort;
|
|
13
|
+
let runtimeWebPublicBaseUrl = config.webPublicBaseUrl;
|
|
14
|
+
let shuttingDown = false;
|
|
15
|
+
let server = null;
|
|
16
|
+
let botManager = null;
|
|
17
|
+
let instanceLock = null;
|
|
18
|
+
let controlPlane = null;
|
|
19
|
+
let secretStore = null;
|
|
20
|
+
const workerScriptPath = fileURLToPath(new URL("./agent-worker.js", import.meta.url));
|
|
21
|
+
await bootstrap();
|
|
22
|
+
async function bootstrap() {
|
|
23
|
+
try {
|
|
24
|
+
if (config.instanceLockEnabled) {
|
|
25
|
+
instanceLock = new InstanceLock(config.instanceLockFilePath);
|
|
26
|
+
await instanceLock.acquire();
|
|
27
|
+
}
|
|
28
|
+
secretStore = new KernelSecretStore(config.secretStoreFilePath);
|
|
29
|
+
await secretStore.init();
|
|
30
|
+
const registry = await loadBotRegistry({
|
|
31
|
+
filePath: config.botRegistryFilePath,
|
|
32
|
+
dataDir: config.dataDir,
|
|
33
|
+
defaultWorkspaceRoot: config.defaultWorkspaceRoot,
|
|
34
|
+
defaultThreadMode: config.defaultThreadMode,
|
|
35
|
+
defaultSharedThreadId: config.defaultSharedThreadId,
|
|
36
|
+
defaultAllowedChatIds: config.defaultAllowedChatIds,
|
|
37
|
+
bootstrapTelegramToken: config.bootstrapTelegramToken,
|
|
38
|
+
defaultProviderKind: config.defaultProviderKind,
|
|
39
|
+
workspacePolicy: config.workspacePolicy,
|
|
40
|
+
resolveSecret: (name) => secretStore.getSecret(name),
|
|
41
|
+
});
|
|
42
|
+
const runtimeBots = registry.bots.filter((bot) => bot.enabled !== false && bot.id !== config.adminBotId);
|
|
43
|
+
if (runtimeBots.length !== registry.bots.filter((bot) => bot.enabled !== false).length) {
|
|
44
|
+
console.warn(`Runtime registry contains reserved id '${config.adminBotId}'. It is ignored because admin is managed by control-plane hub.`);
|
|
45
|
+
}
|
|
46
|
+
botManager = new BotManager({
|
|
47
|
+
botDefinitions: runtimeBots,
|
|
48
|
+
providerDefaults: config.providerDefaults,
|
|
49
|
+
turnActivityTimeoutMs: config.turnActivityTimeoutMs,
|
|
50
|
+
maxMessages: config.maxMessages,
|
|
51
|
+
webPublicBaseUrl: runtimeWebPublicBaseUrl,
|
|
52
|
+
projectsBaseDir: config.projectsBaseDir,
|
|
53
|
+
workerScriptPath,
|
|
54
|
+
botDataRootDir: path.join(config.dataDir, "bots"),
|
|
55
|
+
heartbeatEnabled: config.agentHeartbeatEnabled,
|
|
56
|
+
heartbeatIntervalMs: config.agentHeartbeatIntervalMs,
|
|
57
|
+
heartbeatTimeoutMs: config.agentHeartbeatTimeoutMs,
|
|
58
|
+
});
|
|
59
|
+
controlPlane = new KernelControlPlane({
|
|
60
|
+
botManager,
|
|
61
|
+
registryFilePath: registry.filePath,
|
|
62
|
+
secretStore,
|
|
63
|
+
registryLoadOptions: {
|
|
64
|
+
dataDir: config.dataDir,
|
|
65
|
+
defaultWorkspaceRoot: config.defaultWorkspaceRoot,
|
|
66
|
+
defaultThreadMode: config.defaultThreadMode,
|
|
67
|
+
defaultSharedThreadId: config.defaultSharedThreadId,
|
|
68
|
+
defaultAllowedChatIds: config.defaultAllowedChatIds,
|
|
69
|
+
bootstrapTelegramToken: config.bootstrapTelegramToken,
|
|
70
|
+
defaultProviderKind: config.defaultProviderKind,
|
|
71
|
+
workspacePolicy: config.workspacePolicy,
|
|
72
|
+
resolveSecret: (name) => secretStore.getSecret(name),
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
botManager.setKernelActionHandler((request) => controlPlane.handleAgentAction(request));
|
|
76
|
+
const app = buildApiApp({
|
|
77
|
+
botManager,
|
|
78
|
+
controlPlane,
|
|
79
|
+
registryFilePath: registry.filePath,
|
|
80
|
+
});
|
|
81
|
+
const started = await startWebServer({
|
|
82
|
+
app,
|
|
83
|
+
host: config.webHost,
|
|
84
|
+
basePort: config.webPort,
|
|
85
|
+
autoIncrement: config.webPortAutoIncrement,
|
|
86
|
+
maxAttempts: config.webPortSearchMax,
|
|
87
|
+
});
|
|
88
|
+
server = started.server;
|
|
89
|
+
activeWebPort = started.port;
|
|
90
|
+
runtimeWebPublicBaseUrl = resolveRuntimeWebPublicBaseUrl({
|
|
91
|
+
explicit: config.webPublicBaseUrlExplicit,
|
|
92
|
+
configuredBaseUrl: config.webPublicBaseUrl,
|
|
93
|
+
host: config.webHost,
|
|
94
|
+
port: activeWebPort,
|
|
95
|
+
});
|
|
96
|
+
botManager.setWebPublicBaseUrl(runtimeWebPublicBaseUrl);
|
|
97
|
+
await botManager.startAutoBots();
|
|
98
|
+
registerSignals();
|
|
99
|
+
console.log(`HTTP API listening on http://${config.webHost}:${activeWebPort}`);
|
|
100
|
+
console.log(`Bot registry loaded: ${registry.filePath}`);
|
|
101
|
+
if (instanceLock) {
|
|
102
|
+
console.log(`Instance lock acquired: ${config.instanceLockFilePath}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
const message = sanitizeError(error);
|
|
107
|
+
console.error(message);
|
|
108
|
+
await cleanupBeforeExit();
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function buildApiApp({ botManager, controlPlane, registryFilePath }) {
|
|
113
|
+
const app = express();
|
|
114
|
+
app.use(express.json({ limit: "1mb" }));
|
|
115
|
+
app.use((req, res, next) => {
|
|
116
|
+
res.setHeader("Cache-Control", "no-store");
|
|
117
|
+
next();
|
|
118
|
+
});
|
|
119
|
+
app.get("/api/health", (req, res) => {
|
|
120
|
+
res.json({
|
|
121
|
+
ok: true,
|
|
122
|
+
service: "runtime_kernel",
|
|
123
|
+
providerDefault: config.defaultProviderKind,
|
|
124
|
+
webPort: activeWebPort,
|
|
125
|
+
webPublicBaseUrl: runtimeWebPublicBaseUrl,
|
|
126
|
+
botCount: botManager.getBotCount(),
|
|
127
|
+
turnActivityTimeoutMs: config.turnActivityTimeoutMs,
|
|
128
|
+
heartbeatEnabled: config.agentHeartbeatEnabled,
|
|
129
|
+
heartbeatIntervalMs: config.agentHeartbeatIntervalMs,
|
|
130
|
+
heartbeatTimeoutMs: config.agentHeartbeatTimeoutMs,
|
|
131
|
+
registryFile: registryFilePath,
|
|
132
|
+
projectsBaseDir: config.projectsBaseDir,
|
|
133
|
+
secretStoreFile: config.secretStoreFilePath,
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
app.get("/api/extensions/contract", wrapAsync(async (req, res) => {
|
|
137
|
+
const contract = await controlPlane.runSystemAction(CONTROL_ACTIONS.EXTENSIONS_CONTRACT_GET, {});
|
|
138
|
+
res.json(contract);
|
|
139
|
+
}));
|
|
140
|
+
app.get("/api/bots", wrapAsync(async (req, res) => {
|
|
141
|
+
const bots = await botManager.listBotsLive();
|
|
142
|
+
res.json({ bots });
|
|
143
|
+
}));
|
|
144
|
+
app.post("/api/bots/:botId/delete", wrapAsync(async (req, res) => {
|
|
145
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
146
|
+
const deleteMode = parseDeleteModeFromRequest(req.body);
|
|
147
|
+
const deleted = await controlPlane.runSystemAction(CONTROL_ACTIONS.BOTS_DELETE, {
|
|
148
|
+
botId,
|
|
149
|
+
deleteMode,
|
|
150
|
+
});
|
|
151
|
+
res.json(deleted);
|
|
152
|
+
}));
|
|
153
|
+
app.post("/api/bots/:botId/project", wrapAsync(async (req, res) => {
|
|
154
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
155
|
+
const projectName = String(req.body?.projectName ?? "").trim();
|
|
156
|
+
if (!projectName) {
|
|
157
|
+
res.status(400).json({ error: "Field 'projectName' is required." });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const result = await controlPlane.runSystemAction(CONTROL_ACTIONS.BOTS_SET_PROJECT, {
|
|
161
|
+
botId,
|
|
162
|
+
projectName,
|
|
163
|
+
});
|
|
164
|
+
res.json(result);
|
|
165
|
+
}));
|
|
166
|
+
app.post("/api/bots/:botId/policy", wrapAsync(async (req, res) => {
|
|
167
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
168
|
+
const sandboxMode = String(req.body?.sandboxMode ?? "")
|
|
169
|
+
.trim()
|
|
170
|
+
.toLowerCase();
|
|
171
|
+
const approvalPolicy = String(req.body?.approvalPolicy ?? "")
|
|
172
|
+
.trim()
|
|
173
|
+
.toLowerCase();
|
|
174
|
+
if (!sandboxMode) {
|
|
175
|
+
res.status(400).json({ error: "Field 'sandboxMode' is required." });
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (!approvalPolicy) {
|
|
179
|
+
res.status(400).json({ error: "Field 'approvalPolicy' is required." });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const result = await controlPlane.runSystemAction(CONTROL_ACTIONS.BOTS_SET_POLICY, {
|
|
183
|
+
botId,
|
|
184
|
+
sandboxMode,
|
|
185
|
+
approvalPolicy,
|
|
186
|
+
});
|
|
187
|
+
res.json(result);
|
|
188
|
+
}));
|
|
189
|
+
app.post("/api/bots/:botId/reset", wrapAsync(async (req, res) => {
|
|
190
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
191
|
+
await botManager.resetWebThread(botId);
|
|
192
|
+
const bot = await botManager.getBotStatus(botId);
|
|
193
|
+
res.json({
|
|
194
|
+
bot,
|
|
195
|
+
reset: true,
|
|
196
|
+
});
|
|
197
|
+
}));
|
|
198
|
+
app.get("/api/bots/:botId/approvals", wrapAsync(async (req, res) => {
|
|
199
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
200
|
+
const threadId = String(req.query.threadId ?? "").trim() || undefined;
|
|
201
|
+
const approvals = await botManager.listBotApprovals(botId, threadId);
|
|
202
|
+
res.json({ approvals });
|
|
203
|
+
}));
|
|
204
|
+
app.post("/api/bots/:botId/approvals/:approvalId", wrapAsync(async (req, res) => {
|
|
205
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
206
|
+
const approvalId = String(req.params.approvalId ?? "").trim();
|
|
207
|
+
const threadId = String(req.body?.threadId ?? "").trim();
|
|
208
|
+
const decision = String(req.body?.decision ?? "").trim();
|
|
209
|
+
if (!threadId) {
|
|
210
|
+
res.status(400).json({ error: "Field 'threadId' is required." });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (!decision) {
|
|
214
|
+
res.status(400).json({ error: "Field 'decision' is required." });
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const resolved = await botManager.resolveBotApproval(botId, {
|
|
218
|
+
threadId,
|
|
219
|
+
approvalId,
|
|
220
|
+
decision,
|
|
221
|
+
});
|
|
222
|
+
res.json({ approval: resolved });
|
|
223
|
+
}));
|
|
224
|
+
app.get("/api/bots/:botId/capabilities", wrapAsync(async (req, res) => {
|
|
225
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
226
|
+
const result = await controlPlane.runSystemAction(CONTROL_ACTIONS.BOTS_CAPABILITIES_LIST, {
|
|
227
|
+
botId,
|
|
228
|
+
});
|
|
229
|
+
res.json(result);
|
|
230
|
+
}));
|
|
231
|
+
app.post("/api/bots/:botId/capabilities/reload", wrapAsync(async (req, res) => {
|
|
232
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
233
|
+
const result = await controlPlane.runSystemAction(CONTROL_ACTIONS.BOTS_CAPABILITIES_RELOAD, {
|
|
234
|
+
botId,
|
|
235
|
+
});
|
|
236
|
+
res.json(result);
|
|
237
|
+
}));
|
|
238
|
+
app.post("/api/bots/:botId/capabilities/scaffold", wrapAsync(async (req, res) => {
|
|
239
|
+
const botId = String(req.params.botId ?? "").trim();
|
|
240
|
+
const capabilityId = String(req.body?.capabilityId ?? "").trim();
|
|
241
|
+
const capabilityName = String(req.body?.capabilityName ?? "").trim();
|
|
242
|
+
if (!capabilityId) {
|
|
243
|
+
res.status(400).json({ error: "Field 'capabilityId' is required." });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const result = await controlPlane.runSystemAction(CONTROL_ACTIONS.BOTS_CAPABILITIES_SCAFFOLD, {
|
|
247
|
+
botId,
|
|
248
|
+
capabilityId,
|
|
249
|
+
capabilityName: capabilityName || undefined,
|
|
250
|
+
});
|
|
251
|
+
res.json(result);
|
|
252
|
+
}));
|
|
253
|
+
app.get("/api/projects", wrapAsync(async (req, res) => {
|
|
254
|
+
const projects = await controlPlane.runSystemAction(CONTROL_ACTIONS.PROJECTS_LIST, {});
|
|
255
|
+
res.json(projects);
|
|
256
|
+
}));
|
|
257
|
+
app.post("/api/projects/create", wrapAsync(async (req, res) => {
|
|
258
|
+
const name = String(req.body?.name ?? "").trim();
|
|
259
|
+
if (!name) {
|
|
260
|
+
res.status(400).json({ error: "Field 'name' is required." });
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const created = await controlPlane.runSystemAction(CONTROL_ACTIONS.PROJECTS_CREATE, { name });
|
|
264
|
+
res.json(created);
|
|
265
|
+
}));
|
|
266
|
+
app.use((error, req, res, _next) => {
|
|
267
|
+
const message = sanitizeError(error);
|
|
268
|
+
res.status(400).json({ error: message });
|
|
269
|
+
});
|
|
270
|
+
return app;
|
|
271
|
+
}
|
|
272
|
+
function registerSignals() {
|
|
273
|
+
process.on("SIGINT", () => {
|
|
274
|
+
void shutdown(0);
|
|
275
|
+
});
|
|
276
|
+
process.on("SIGTERM", () => {
|
|
277
|
+
void shutdown(0);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function wrapAsync(handler) {
|
|
281
|
+
return (req, res, next) => {
|
|
282
|
+
Promise.resolve(handler(req, res, next)).catch(next);
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function resolveRuntimeWebPublicBaseUrl({ explicit, configuredBaseUrl, host, port }) {
|
|
286
|
+
if (explicit) {
|
|
287
|
+
return configuredBaseUrl;
|
|
288
|
+
}
|
|
289
|
+
const exposedHost = host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
290
|
+
return `http://${exposedHost}:${port}`;
|
|
291
|
+
}
|
|
292
|
+
async function startWebServer({ app, host, basePort, autoIncrement, maxAttempts }) {
|
|
293
|
+
let port = basePort;
|
|
294
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
295
|
+
try {
|
|
296
|
+
const startedServer = await listenOnce({ app, host, port });
|
|
297
|
+
return { server: startedServer, port };
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
const occupied = error && typeof error === "object" && error.code === "EADDRINUSE";
|
|
301
|
+
if (!occupied || !autoIncrement || port >= 65535) {
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
port += 1;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
throw new Error(`Could not find a free web port after ${maxAttempts} attempts starting from ${basePort}.`);
|
|
308
|
+
}
|
|
309
|
+
function listenOnce({ app, host, port }) {
|
|
310
|
+
return new Promise((resolve, reject) => {
|
|
311
|
+
const candidate = app.listen(port, host);
|
|
312
|
+
candidate.once("listening", () => resolve(candidate));
|
|
313
|
+
candidate.once("error", (error) => reject(error));
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
async function shutdown(exitCode) {
|
|
317
|
+
if (shuttingDown) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
shuttingDown = true;
|
|
321
|
+
await cleanupBeforeExit();
|
|
322
|
+
process.exit(exitCode);
|
|
323
|
+
}
|
|
324
|
+
async function cleanupBeforeExit() {
|
|
325
|
+
if (botManager) {
|
|
326
|
+
await botManager.shutdownAll();
|
|
327
|
+
}
|
|
328
|
+
if (server) {
|
|
329
|
+
await new Promise((resolve) => {
|
|
330
|
+
server.close(() => resolve());
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
if (instanceLock) {
|
|
334
|
+
await instanceLock.release();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function sanitizeError(error) {
|
|
338
|
+
const raw = error instanceof Error ? error.message : String(error);
|
|
339
|
+
return raw.split(/\r?\n/).slice(0, 12).join("\n");
|
|
340
|
+
}
|
|
341
|
+
function parseDeleteModeFromRequest(body) {
|
|
342
|
+
const value = String(body?.deleteMode ?? "")
|
|
343
|
+
.trim()
|
|
344
|
+
.toLowerCase();
|
|
345
|
+
if (value === "soft" || value === "purge_data" || value === "purge_all") {
|
|
346
|
+
return value;
|
|
347
|
+
}
|
|
348
|
+
return "soft";
|
|
349
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
const BOT_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
3
|
+
export const DEFAULT_ADMIN_BOT_ID = "admin_agent";
|
|
4
|
+
export const DEFAULT_ADMIN_TOKEN_ENV = "TELEGRAM_TOKEN_ADMIN";
|
|
5
|
+
export const DEFAULT_ADMIN_CHANNEL_ID = "telegram_admin";
|
|
6
|
+
export function normalizeAdminBotId(value) {
|
|
7
|
+
const id = String(value ?? DEFAULT_ADMIN_BOT_ID).trim();
|
|
8
|
+
if (!BOT_ID_PATTERN.test(id)) {
|
|
9
|
+
throw new Error("ADMIN_BOT_ID has invalid format.");
|
|
10
|
+
}
|
|
11
|
+
return id;
|
|
12
|
+
}
|
|
13
|
+
export function normalizeAdminTokenEnv(value) {
|
|
14
|
+
const name = String(value ?? DEFAULT_ADMIN_TOKEN_ENV).trim();
|
|
15
|
+
if (!name) {
|
|
16
|
+
throw new Error("ADMIN_TELEGRAM_TOKEN_ENV cannot be empty.");
|
|
17
|
+
}
|
|
18
|
+
return name;
|
|
19
|
+
}
|
|
20
|
+
export function buildAdminAgentDefinition({ botId, tokenEnvName }) {
|
|
21
|
+
const normalizedBotId = normalizeAdminBotId(botId);
|
|
22
|
+
const normalizedTokenEnv = normalizeAdminTokenEnv(tokenEnvName);
|
|
23
|
+
return {
|
|
24
|
+
id: normalizedBotId,
|
|
25
|
+
name: "Admin Agent",
|
|
26
|
+
enabled: true,
|
|
27
|
+
autoStart: true,
|
|
28
|
+
dataDir: `./data/bots/${normalizedBotId}`,
|
|
29
|
+
threadMode: "single",
|
|
30
|
+
sharedThreadId: normalizedBotId === DEFAULT_ADMIN_BOT_ID
|
|
31
|
+
? "shared-admin"
|
|
32
|
+
: `shared-${normalizedBotId.replace(/_/g, "-")}`,
|
|
33
|
+
provider: {
|
|
34
|
+
kind: "codex",
|
|
35
|
+
options: {},
|
|
36
|
+
},
|
|
37
|
+
kernelAccess: {
|
|
38
|
+
enabled: true,
|
|
39
|
+
allowedActions: ["*"],
|
|
40
|
+
allowedChatIds: [],
|
|
41
|
+
},
|
|
42
|
+
channels: [
|
|
43
|
+
{
|
|
44
|
+
kind: "telegram",
|
|
45
|
+
id: DEFAULT_ADMIN_CHANNEL_ID,
|
|
46
|
+
tokenEnv: normalizedTokenEnv,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
capabilities: [],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { createProjectFingerprint } from "@copilot-hub/core/project-fingerprint";
|
|
4
|
+
test("createProjectFingerprint is stable and order-independent for channels", () => {
|
|
5
|
+
const a = createProjectFingerprint({
|
|
6
|
+
runtimeId: "control-plane",
|
|
7
|
+
workspaceRoot: "./workspace-admin",
|
|
8
|
+
providerKind: "CODEX",
|
|
9
|
+
channels: [
|
|
10
|
+
{ kind: "telegram", id: "123" },
|
|
11
|
+
{ kind: "whatsapp", id: "admin" },
|
|
12
|
+
],
|
|
13
|
+
});
|
|
14
|
+
const b = createProjectFingerprint({
|
|
15
|
+
runtimeId: "control-plane",
|
|
16
|
+
workspaceRoot: "./workspace-admin",
|
|
17
|
+
providerKind: "codex",
|
|
18
|
+
channels: [
|
|
19
|
+
{ kind: "whatsapp", id: "admin" },
|
|
20
|
+
{ kind: "telegram", id: "123" },
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
assert.equal(a, b);
|
|
24
|
+
assert.match(a, /^[a-f0-9]{24}$/);
|
|
25
|
+
});
|
|
26
|
+
test("createProjectFingerprint changes when stable inputs differ", () => {
|
|
27
|
+
const base = createProjectFingerprint({
|
|
28
|
+
runtimeId: "control-plane",
|
|
29
|
+
workspaceRoot: "./workspace-admin",
|
|
30
|
+
providerKind: "codex",
|
|
31
|
+
channels: [{ kind: "telegram", id: "123" }],
|
|
32
|
+
});
|
|
33
|
+
const changedWorkspace = createProjectFingerprint({
|
|
34
|
+
runtimeId: "control-plane",
|
|
35
|
+
workspaceRoot: "./workspace-other",
|
|
36
|
+
providerKind: "codex",
|
|
37
|
+
channels: [{ kind: "telegram", id: "123" }],
|
|
38
|
+
});
|
|
39
|
+
assert.notEqual(base, changedWorkspace);
|
|
40
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { normalizeThreadId } from "@copilot-hub/core/thread-id";
|
|
4
|
+
test("normalizeThreadId trims and accepts valid thread ids", () => {
|
|
5
|
+
assert.equal(normalizeThreadId(" shared-copilot-hub "), "shared-copilot-hub");
|
|
6
|
+
assert.equal(normalizeThreadId("chat:123_ABC-1"), "chat:123_ABC-1");
|
|
7
|
+
});
|
|
8
|
+
test("normalizeThreadId rejects empty and invalid values", () => {
|
|
9
|
+
assert.throws(() => normalizeThreadId(""), /threadId is required/);
|
|
10
|
+
assert.throws(() => normalizeThreadId("thread id with spaces"), /Invalid threadId/);
|
|
11
|
+
assert.throws(() => normalizeThreadId("chat/123"), /Invalid threadId/);
|
|
12
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@copilot-hub/control-plane",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Copilot Hub control plane",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p tsconfig.json",
|
|
9
|
+
"build:test": "tsc -p tsconfig.test.json",
|
|
10
|
+
"prestart": "node ../../scripts/ensure-shared-build.mjs && npm run build",
|
|
11
|
+
"start": "node dist/copilot-hub.js",
|
|
12
|
+
"predev": "node ../../scripts/ensure-shared-build.mjs && npm run build",
|
|
13
|
+
"dev": "node --watch dist/copilot-hub.js",
|
|
14
|
+
"pretest": "node ../../scripts/ensure-shared-build.mjs && npm run build && npm run build:test",
|
|
15
|
+
"test": "node ../../scripts/run-node-tests.mjs dist/test"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@copilot-hub/contracts": "0.1.0",
|
|
22
|
+
"@copilot-hub/core": "0.1.0",
|
|
23
|
+
"dotenv": "^16.4.7",
|
|
24
|
+
"express": "^4.21.2",
|
|
25
|
+
"grammy": "^1.38.3"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "copilot-hub",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Copilot Hub CLI and runtime bundle",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/openminedev/copilot-hub.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/openminedev/copilot-hub#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/openminedev/copilot-hub/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"copilot",
|
|
16
|
+
"telegram",
|
|
17
|
+
"agents",
|
|
18
|
+
"automation",
|
|
19
|
+
"cli"
|
|
20
|
+
],
|
|
21
|
+
"bin": {
|
|
22
|
+
"copilot-hub": "scripts/cli.mjs"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"scripts/",
|
|
28
|
+
"apps/agent-engine/.env.example",
|
|
29
|
+
"apps/agent-engine/bot-registry.example.json",
|
|
30
|
+
"apps/agent-engine/capabilities/",
|
|
31
|
+
"apps/agent-engine/dist/",
|
|
32
|
+
"apps/agent-engine/package.json",
|
|
33
|
+
"apps/control-plane/.env.example",
|
|
34
|
+
"apps/control-plane/bot-registry.example.json",
|
|
35
|
+
"apps/control-plane/capabilities/",
|
|
36
|
+
"apps/control-plane/dist/",
|
|
37
|
+
"apps/control-plane/package.json",
|
|
38
|
+
"packages/contracts/dist/",
|
|
39
|
+
"packages/contracts/package.json",
|
|
40
|
+
"packages/core/dist/",
|
|
41
|
+
"packages/core/package.json"
|
|
42
|
+
],
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"workspaces": [
|
|
47
|
+
"apps/*",
|
|
48
|
+
"packages/*"
|
|
49
|
+
],
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "npm run build --workspaces --if-present",
|
|
52
|
+
"prepare:shared": "node scripts/ensure-shared-build.mjs",
|
|
53
|
+
"start": "node scripts/cli.mjs start",
|
|
54
|
+
"stop": "node scripts/cli.mjs stop",
|
|
55
|
+
"restart": "node scripts/cli.mjs restart",
|
|
56
|
+
"status": "node scripts/cli.mjs status",
|
|
57
|
+
"logs": "node scripts/cli.mjs logs",
|
|
58
|
+
"configure": "node scripts/cli.mjs configure",
|
|
59
|
+
"test": "npm run test --workspaces --if-present",
|
|
60
|
+
"lint": "eslint .",
|
|
61
|
+
"format": "prettier --write \"{scripts,packages}/**/*.{js,mjs,ts,json}\" \"apps/*/src/**/*.{js,ts}\" \"apps/*/package.json\" \"apps/*/test/**/*.{js,ts}\" \"apps/*/tsconfig*.json\" \"{README.md,CONTRIBUTING.md,ARCHITECTURE.md}\" \"eslint.config.mjs\" \"package.json\" \"tsconfig.base.json\"",
|
|
62
|
+
"format:check": "prettier --check \"{scripts,packages}/**/*.{js,mjs,ts,json}\" \"apps/*/src/**/*.{js,ts}\" \"apps/*/package.json\" \"apps/*/test/**/*.{js,ts}\" \"apps/*/tsconfig*.json\" \"{README.md,CONTRIBUTING.md,ARCHITECTURE.md}\" \"eslint.config.mjs\" \"package.json\" \"tsconfig.base.json\"",
|
|
63
|
+
"start:control-plane": "npm --prefix apps/control-plane run start",
|
|
64
|
+
"start:agent-engine": "npm --prefix apps/agent-engine run start",
|
|
65
|
+
"setup:agent-engine": "npm --prefix apps/agent-engine run setup",
|
|
66
|
+
"check:agent-engine": "npm --prefix apps/agent-engine run build && node --check apps/agent-engine/dist/index.js",
|
|
67
|
+
"check:control-plane": "npm --prefix apps/control-plane run build && node --check apps/control-plane/dist/copilot-hub.js",
|
|
68
|
+
"check:apps": "npm run check:agent-engine && npm run check:control-plane",
|
|
69
|
+
"prepack": "npm run build"
|
|
70
|
+
},
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"@copilot-hub/contracts": "file:packages/contracts",
|
|
73
|
+
"@copilot-hub/core": "file:packages/core",
|
|
74
|
+
"dotenv": "^16.4.7",
|
|
75
|
+
"express": "^4.21.2",
|
|
76
|
+
"grammy": "^1.38.3"
|
|
77
|
+
},
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"@eslint/js": "^9.22.0",
|
|
80
|
+
"@types/node": "^22.13.10",
|
|
81
|
+
"eslint": "^9.22.0",
|
|
82
|
+
"globals": "^16.0.0",
|
|
83
|
+
"prettier": "^3.5.3",
|
|
84
|
+
"typescript": "^5.8.2"
|
|
85
|
+
},
|
|
86
|
+
"engines": {
|
|
87
|
+
"node": ">=20"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Contracts
|
|
2
|
+
|
|
3
|
+
Shared versioned contracts for control-plane actions across:
|
|
4
|
+
- `apps/agent-engine`
|
|
5
|
+
- `apps/control-plane`
|
|
6
|
+
|
|
7
|
+
Current contract:
|
|
8
|
+
- `control-plane.v1.json` (version `1.1.0`)
|
|
9
|
+
|
|
10
|
+
This package exports action constants and validators used by both planes.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const CONTROL_ACTIONS: Readonly<{
|
|
2
|
+
readonly BOTS_LIST: "bots:list";
|
|
3
|
+
readonly BOTS_STATUS: "bots:status";
|
|
4
|
+
readonly BOTS_START: "bots:start";
|
|
5
|
+
readonly BOTS_STOP: "bots:stop";
|
|
6
|
+
readonly BOTS_CREATE: "bots:create";
|
|
7
|
+
readonly BOTS_DELETE: "bots:delete";
|
|
8
|
+
readonly BOTS_SET_POLICY: "bots:set_policy";
|
|
9
|
+
readonly BOTS_SET_PROJECT: "bots:set_project";
|
|
10
|
+
readonly BOTS_CAPABILITIES_LIST: "bots:capabilities:list";
|
|
11
|
+
readonly BOTS_CAPABILITIES_RELOAD: "bots:capabilities:reload";
|
|
12
|
+
readonly BOTS_CAPABILITIES_SCAFFOLD: "bots:capabilities:scaffold";
|
|
13
|
+
readonly PROJECTS_LIST: "projects:list";
|
|
14
|
+
readonly PROJECTS_CREATE: "projects:create";
|
|
15
|
+
readonly SECRETS_LIST: "secrets:list";
|
|
16
|
+
readonly SECRETS_SET: "secrets:set";
|
|
17
|
+
readonly SECRETS_DELETE: "secrets:delete";
|
|
18
|
+
readonly EXTENSIONS_CONTRACT_GET: "extensions:contract:get";
|
|
19
|
+
}>;
|
|
20
|
+
export type ControlAction = (typeof CONTROL_ACTIONS)[keyof typeof CONTROL_ACTIONS];
|
|
21
|
+
export declare function normalizeControlAction(value: unknown): string;
|
|
22
|
+
export declare function isControlAction(value: unknown): value is ControlAction;
|
|
23
|
+
export declare function requireControlAction(value: unknown): ControlAction;
|
|
24
|
+
export declare const CONTROL_ACTION_LIST: readonly ControlAction[];
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const CONTROL_ACTIONS = Object.freeze({
|
|
2
|
+
BOTS_LIST: "bots:list",
|
|
3
|
+
BOTS_STATUS: "bots:status",
|
|
4
|
+
BOTS_START: "bots:start",
|
|
5
|
+
BOTS_STOP: "bots:stop",
|
|
6
|
+
BOTS_CREATE: "bots:create",
|
|
7
|
+
BOTS_DELETE: "bots:delete",
|
|
8
|
+
BOTS_SET_POLICY: "bots:set_policy",
|
|
9
|
+
BOTS_SET_PROJECT: "bots:set_project",
|
|
10
|
+
BOTS_CAPABILITIES_LIST: "bots:capabilities:list",
|
|
11
|
+
BOTS_CAPABILITIES_RELOAD: "bots:capabilities:reload",
|
|
12
|
+
BOTS_CAPABILITIES_SCAFFOLD: "bots:capabilities:scaffold",
|
|
13
|
+
PROJECTS_LIST: "projects:list",
|
|
14
|
+
PROJECTS_CREATE: "projects:create",
|
|
15
|
+
SECRETS_LIST: "secrets:list",
|
|
16
|
+
SECRETS_SET: "secrets:set",
|
|
17
|
+
SECRETS_DELETE: "secrets:delete",
|
|
18
|
+
EXTENSIONS_CONTRACT_GET: "extensions:contract:get",
|
|
19
|
+
});
|
|
20
|
+
const CONTROL_ACTION_SET = new Set(Object.values(CONTROL_ACTIONS));
|
|
21
|
+
export function normalizeControlAction(value) {
|
|
22
|
+
return String(value ?? "")
|
|
23
|
+
.trim()
|
|
24
|
+
.toLowerCase();
|
|
25
|
+
}
|
|
26
|
+
export function isControlAction(value) {
|
|
27
|
+
return CONTROL_ACTION_SET.has(normalizeControlAction(value));
|
|
28
|
+
}
|
|
29
|
+
export function requireControlAction(value) {
|
|
30
|
+
const action = normalizeControlAction(value);
|
|
31
|
+
if (!CONTROL_ACTION_SET.has(action)) {
|
|
32
|
+
throw new Error(`Unsupported control action '${action || "<empty>"}'.`);
|
|
33
|
+
}
|
|
34
|
+
return action;
|
|
35
|
+
}
|
|
36
|
+
export const CONTROL_ACTION_LIST = Object.freeze([...CONTROL_ACTION_SET]);
|
|
37
|
+
//# sourceMappingURL=control-plane.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-plane.js","sourceRoot":"","sources":["../src/control-plane.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,SAAS,EAAE,WAAW;IACtB,WAAW,EAAE,aAAa;IAC1B,UAAU,EAAE,YAAY;IACxB,SAAS,EAAE,WAAW;IACtB,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,aAAa;IAC1B,eAAe,EAAE,iBAAiB;IAClC,gBAAgB,EAAE,kBAAkB;IACpC,sBAAsB,EAAE,wBAAwB;IAChD,wBAAwB,EAAE,0BAA0B;IACpD,0BAA0B,EAAE,4BAA4B;IACxD,aAAa,EAAE,eAAe;IAC9B,eAAe,EAAE,iBAAiB;IAClC,YAAY,EAAE,cAAc;IAC5B,WAAW,EAAE,aAAa;IAC1B,cAAc,EAAE,gBAAgB;IAChC,uBAAuB,EAAE,yBAAyB;CAC1C,CAAC,CAAC;AAIZ,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAgB,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;AAElF,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,kBAAkB,CAAC,GAAG,CAAC,sBAAsB,CAAC,KAAK,CAAkB,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAuB,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,+BAA+B,MAAM,IAAI,SAAS,IAAI,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,MAAuB,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,kBAAkB,CAAoB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CONTROL_ACTIONS, CONTROL_ACTION_LIST, normalizeControlAction, isControlAction, requireControlAction, } from "./control-plane.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,oBAAoB,GACrB,MAAM,oBAAoB,CAAC"}
|