@dobby.ai/dobby 0.1.1 → 0.1.2

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 (136) hide show
  1. package/README.md +20 -7
  2. package/dist/src/agent/event-forwarder.js +185 -16
  3. package/dist/src/cli/commands/cron.js +39 -35
  4. package/dist/src/cli/program.js +0 -6
  5. package/dist/src/core/types.js +2 -0
  6. package/dist/src/cron/config.js +2 -2
  7. package/dist/src/cron/service.js +87 -23
  8. package/dist/src/cron/store.js +1 -1
  9. package/package.json +9 -3
  10. package/.env.example +0 -8
  11. package/AGENTS.md +0 -267
  12. package/ROADMAP.md +0 -34
  13. package/config/cron.example.json +0 -9
  14. package/config/gateway.example.json +0 -132
  15. package/dist/plugins/connector-discord/src/mapper.js +0 -75
  16. package/dist/src/cli/tests/config-command.test.js +0 -42
  17. package/dist/src/cli/tests/config-io.test.js +0 -64
  18. package/dist/src/cli/tests/config-mutators.test.js +0 -47
  19. package/dist/src/cli/tests/discord-mapper.test.js +0 -90
  20. package/dist/src/cli/tests/doctor.test.js +0 -252
  21. package/dist/src/cli/tests/init-catalog.test.js +0 -134
  22. package/dist/src/cli/tests/program-options.test.js +0 -78
  23. package/dist/src/cli/tests/routing-config.test.js +0 -254
  24. package/dist/src/core/tests/control-command.test.js +0 -17
  25. package/dist/src/core/tests/runtime-registry.test.js +0 -116
  26. package/dist/src/core/tests/typing-controller.test.js +0 -103
  27. package/docs/BOXLITE_SANDBOX_FEASIBILITY.md +0 -175
  28. package/docs/CRON_SCHEDULER_DESIGN.md +0 -374
  29. package/docs/DOCKER_SANDBOX_vs_BOXLITE.md +0 -77
  30. package/docs/EXTENSION_SYSTEM_ARCHITECTURE.md +0 -119
  31. package/docs/MVP.md +0 -135
  32. package/docs/RUNBOOK.md +0 -243
  33. package/docs/TEAMWORK_HANDOFF_DESIGN.md +0 -440
  34. package/plugins/connector-discord/dobby.manifest.json +0 -18
  35. package/plugins/connector-discord/index.js +0 -1
  36. package/plugins/connector-discord/package-lock.json +0 -360
  37. package/plugins/connector-discord/package.json +0 -38
  38. package/plugins/connector-discord/src/connector.ts +0 -345
  39. package/plugins/connector-discord/src/contribution.ts +0 -21
  40. package/plugins/connector-discord/src/mapper.ts +0 -101
  41. package/plugins/connector-discord/tsconfig.json +0 -19
  42. package/plugins/connector-feishu/dobby.manifest.json +0 -18
  43. package/plugins/connector-feishu/index.js +0 -1
  44. package/plugins/connector-feishu/package-lock.json +0 -618
  45. package/plugins/connector-feishu/package.json +0 -38
  46. package/plugins/connector-feishu/src/connector.ts +0 -343
  47. package/plugins/connector-feishu/src/contribution.ts +0 -26
  48. package/plugins/connector-feishu/src/mapper.ts +0 -401
  49. package/plugins/connector-feishu/tsconfig.json +0 -19
  50. package/plugins/plugin-sdk/index.d.ts +0 -261
  51. package/plugins/plugin-sdk/index.js +0 -1
  52. package/plugins/plugin-sdk/package-lock.json +0 -12
  53. package/plugins/plugin-sdk/package.json +0 -22
  54. package/plugins/provider-claude/dobby.manifest.json +0 -17
  55. package/plugins/provider-claude/index.js +0 -1
  56. package/plugins/provider-claude/package-lock.json +0 -3398
  57. package/plugins/provider-claude/package.json +0 -39
  58. package/plugins/provider-claude/src/contribution.ts +0 -1018
  59. package/plugins/provider-claude/tsconfig.json +0 -19
  60. package/plugins/provider-claude-cli/dobby.manifest.json +0 -17
  61. package/plugins/provider-claude-cli/index.js +0 -1
  62. package/plugins/provider-claude-cli/package-lock.json +0 -2898
  63. package/plugins/provider-claude-cli/package.json +0 -38
  64. package/plugins/provider-claude-cli/src/contribution.ts +0 -1673
  65. package/plugins/provider-claude-cli/tsconfig.json +0 -19
  66. package/plugins/provider-pi/dobby.manifest.json +0 -17
  67. package/plugins/provider-pi/index.js +0 -1
  68. package/plugins/provider-pi/package-lock.json +0 -3877
  69. package/plugins/provider-pi/package.json +0 -40
  70. package/plugins/provider-pi/src/contribution.ts +0 -606
  71. package/plugins/provider-pi/tsconfig.json +0 -19
  72. package/plugins/sandbox-core/boxlite.js +0 -1
  73. package/plugins/sandbox-core/dobby.manifest.json +0 -17
  74. package/plugins/sandbox-core/docker.js +0 -1
  75. package/plugins/sandbox-core/package-lock.json +0 -136
  76. package/plugins/sandbox-core/package.json +0 -39
  77. package/plugins/sandbox-core/src/boxlite-context.ts +0 -2
  78. package/plugins/sandbox-core/src/boxlite-contribution.ts +0 -53
  79. package/plugins/sandbox-core/src/boxlite-executor.ts +0 -911
  80. package/plugins/sandbox-core/src/docker-contribution.ts +0 -43
  81. package/plugins/sandbox-core/src/docker-executor.ts +0 -217
  82. package/plugins/sandbox-core/tsconfig.json +0 -19
  83. package/scripts/local-extensions.mjs +0 -168
  84. package/src/agent/event-forwarder.ts +0 -414
  85. package/src/cli/commands/config.ts +0 -328
  86. package/src/cli/commands/configure.ts +0 -92
  87. package/src/cli/commands/cron.ts +0 -410
  88. package/src/cli/commands/doctor.ts +0 -331
  89. package/src/cli/commands/extension.ts +0 -207
  90. package/src/cli/commands/init.ts +0 -211
  91. package/src/cli/commands/start.ts +0 -223
  92. package/src/cli/commands/topology.ts +0 -415
  93. package/src/cli/index.ts +0 -9
  94. package/src/cli/program.ts +0 -314
  95. package/src/cli/shared/config-io.ts +0 -245
  96. package/src/cli/shared/config-mutators.ts +0 -470
  97. package/src/cli/shared/config-schema.ts +0 -228
  98. package/src/cli/shared/config-types.ts +0 -129
  99. package/src/cli/shared/configure-sections.ts +0 -595
  100. package/src/cli/shared/discord-config.ts +0 -14
  101. package/src/cli/shared/init-catalog.ts +0 -249
  102. package/src/cli/shared/local-extension-specs.ts +0 -108
  103. package/src/cli/shared/runtime.ts +0 -33
  104. package/src/cli/shared/schema-prompts.ts +0 -443
  105. package/src/cli/tests/config-command.test.ts +0 -56
  106. package/src/cli/tests/config-io.test.ts +0 -92
  107. package/src/cli/tests/config-mutators.test.ts +0 -59
  108. package/src/cli/tests/discord-mapper.test.ts +0 -128
  109. package/src/cli/tests/doctor.test.ts +0 -269
  110. package/src/cli/tests/init-catalog.test.ts +0 -144
  111. package/src/cli/tests/program-options.test.ts +0 -95
  112. package/src/cli/tests/routing-config.test.ts +0 -281
  113. package/src/core/control-command.ts +0 -12
  114. package/src/core/dedup-store.ts +0 -103
  115. package/src/core/gateway.ts +0 -609
  116. package/src/core/routing.ts +0 -404
  117. package/src/core/runtime-registry.ts +0 -141
  118. package/src/core/tests/control-command.test.ts +0 -20
  119. package/src/core/tests/runtime-registry.test.ts +0 -140
  120. package/src/core/tests/typing-controller.test.ts +0 -129
  121. package/src/core/types.ts +0 -324
  122. package/src/core/typing-controller.ts +0 -119
  123. package/src/cron/config.ts +0 -154
  124. package/src/cron/schedule.ts +0 -61
  125. package/src/cron/service.ts +0 -249
  126. package/src/cron/store.ts +0 -155
  127. package/src/cron/types.ts +0 -60
  128. package/src/extension/loader.ts +0 -145
  129. package/src/extension/manager.ts +0 -355
  130. package/src/extension/manifest.ts +0 -26
  131. package/src/extension/registry.ts +0 -229
  132. package/src/main.ts +0 -8
  133. package/src/sandbox/executor.ts +0 -44
  134. package/src/sandbox/host-executor.ts +0 -118
  135. package/src/shared/dobby-repo.ts +0 -48
  136. package/tsconfig.json +0 -18
@@ -1,355 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { access, mkdir, readFile, writeFile } from "node:fs/promises";
3
- import { createRequire } from "node:module";
4
- import { dirname, join, resolve } from "node:path";
5
- import type { ExtensionManifest, GatewayLogger } from "../core/types.js";
6
- import { readExtensionManifest } from "./manifest.js";
7
-
8
- const STORE_PACKAGE_NAME = "dobby-extension-store";
9
-
10
- interface StorePackageJson {
11
- name: string;
12
- private: boolean;
13
- description?: string;
14
- dependencies?: Record<string, string>;
15
- }
16
-
17
- export interface InstalledExtensionInfo {
18
- packageName: string;
19
- version: string;
20
- manifest: ExtensionManifest;
21
- }
22
-
23
- export interface ListedExtensionInfo {
24
- packageName: string;
25
- version: string;
26
- manifest?: ExtensionManifest;
27
- error?: string;
28
- }
29
-
30
- function isJavaScriptEntry(entry: string): boolean {
31
- return entry.endsWith(".js") || entry.endsWith(".mjs") || entry.endsWith(".cjs");
32
- }
33
-
34
- function assertWithinRoot(pathToCheck: string, rootDir: string): void {
35
- const normalizedRoot = resolve(rootDir);
36
- const normalizedPath = resolve(pathToCheck);
37
- if (normalizedPath === normalizedRoot) {
38
- return;
39
- }
40
-
41
- const rootPrefix = normalizedRoot.endsWith("/") || normalizedRoot.endsWith("\\")
42
- ? normalizedRoot
43
- : `${normalizedRoot}${process.platform === "win32" ? "\\" : "/"}`;
44
- if (!normalizedPath.startsWith(rootPrefix)) {
45
- throw new Error(`Path '${normalizedPath}' escapes package root '${normalizedRoot}'`);
46
- }
47
- }
48
-
49
- function parsePackageNameFromSpec(packageSpec: string): string | null {
50
- const trimmed = packageSpec.trim();
51
- if (!trimmed) return null;
52
-
53
- const scopedMatch = /^(@[^/]+\/[^@]+)(?:@.+)?$/.exec(trimmed);
54
- if (scopedMatch?.[1]) {
55
- return scopedMatch[1];
56
- }
57
-
58
- if (
59
- trimmed.startsWith("file:")
60
- || trimmed.startsWith("git+")
61
- || trimmed.startsWith("http://")
62
- || trimmed.startsWith("https://")
63
- || trimmed.startsWith("./")
64
- || trimmed.startsWith("../")
65
- || trimmed.startsWith("/")
66
- || trimmed.includes("/")
67
- ) {
68
- return null;
69
- }
70
-
71
- const unscopedMatch = /^([^@]+)(?:@.+)?$/.exec(trimmed);
72
- return unscopedMatch?.[1] ?? null;
73
- }
74
-
75
- async function parsePackageNameFromLocalSpec(packageSpec: string): Promise<string | null> {
76
- const trimmed = packageSpec.trim();
77
- if (!trimmed) return null;
78
-
79
- let localPath: string | null = null;
80
- if (trimmed.startsWith("file:")) {
81
- localPath = trimmed.slice("file:".length);
82
- } else if (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith("/")) {
83
- localPath = trimmed;
84
- }
85
-
86
- if (!localPath) {
87
- return null;
88
- }
89
-
90
- const packageJsonPath = resolve(process.cwd(), localPath, "package.json");
91
- try {
92
- const raw = await readFile(packageJsonPath, "utf-8");
93
- const parsed = JSON.parse(raw) as { name?: unknown };
94
- return typeof parsed.name === "string" && parsed.name.length > 0 ? parsed.name : null;
95
- } catch {
96
- return null;
97
- }
98
- }
99
-
100
- async function pickInstalledPackageName(
101
- packageSpec: string,
102
- beforeDeps: Record<string, string>,
103
- afterDeps: Record<string, string>,
104
- ): Promise<string> {
105
- const changedPackages = Object.entries(afterDeps)
106
- .filter(([name, version]) => beforeDeps[name] !== version)
107
- .map(([name]) => name);
108
-
109
- if (changedPackages.length === 1) {
110
- return changedPackages[0]!;
111
- }
112
-
113
- const inferred = parsePackageNameFromSpec(packageSpec);
114
- if (inferred && afterDeps[inferred]) {
115
- return inferred;
116
- }
117
-
118
- const localInferred = await parsePackageNameFromLocalSpec(packageSpec);
119
- if (localInferred && afterDeps[localInferred]) {
120
- return localInferred;
121
- }
122
-
123
- if (changedPackages.length > 0) {
124
- return changedPackages[0]!;
125
- }
126
-
127
- throw new Error(
128
- `Could not determine installed package from spec '${packageSpec}'. Run 'extension list' to inspect extension store state.`,
129
- );
130
- }
131
-
132
- export class ExtensionStoreManager {
133
- constructor(
134
- private readonly logger: GatewayLogger,
135
- private readonly extensionsDir: string,
136
- ) { }
137
-
138
- async ensureStoreInitialized(): Promise<void> {
139
- await mkdir(this.extensionsDir, { recursive: true });
140
- const storePackageJsonPath = this.storePackageJsonPath();
141
- try {
142
- await access(storePackageJsonPath);
143
- return;
144
- } catch {
145
- const payload: StorePackageJson = {
146
- name: STORE_PACKAGE_NAME,
147
- private: true,
148
- description: "Managed extension store for dobby",
149
- };
150
- await writeFile(storePackageJsonPath, `${JSON.stringify(payload, null, 2)}\n`, "utf-8");
151
- }
152
- }
153
-
154
- async install(packageSpec: string): Promise<InstalledExtensionInfo> {
155
- const installed = await this.installMany([packageSpec]);
156
- if (installed.length === 0) {
157
- throw new Error(`Failed to install package from spec '${packageSpec}'`);
158
- }
159
-
160
- return installed[0]!;
161
- }
162
-
163
- async installMany(packageSpecs: string[]): Promise<InstalledExtensionInfo[]> {
164
- const normalizedSpecs = packageSpecs
165
- .map((item) => item.trim())
166
- .filter((item) => item.length > 0);
167
-
168
- if (normalizedSpecs.length === 0) {
169
- return [];
170
- }
171
-
172
- await this.ensureStoreInitialized();
173
- const beforeDeps = await this.readDependencies();
174
-
175
- await this.runNpm(["install", "--prefix", this.extensionsDir, "--save-exact", ...normalizedSpecs]);
176
-
177
- const afterDeps = await this.readDependencies();
178
- const seenPackages = new Set<string>();
179
- const installedPackages: InstalledExtensionInfo[] = [];
180
-
181
- for (const spec of normalizedSpecs) {
182
- const packageName = await this.resolveInstalledPackageName(spec, beforeDeps, afterDeps, normalizedSpecs.length > 1);
183
- if (seenPackages.has(packageName)) {
184
- continue;
185
- }
186
- seenPackages.add(packageName);
187
-
188
- const version = afterDeps[packageName];
189
- if (!version) {
190
- throw new Error(`Package '${packageName}' is not present in extension store after installation`);
191
- }
192
-
193
- const installed = await this.readInstalledExtension(packageName, version);
194
- this.logger.info(
195
- {
196
- package: installed.packageName,
197
- version: installed.version,
198
- contributions: installed.manifest.contributions.map((item) => `${item.kind}:${item.id}`),
199
- },
200
- "Extension installed",
201
- );
202
- installedPackages.push(installed);
203
- }
204
-
205
- return installedPackages;
206
- }
207
-
208
- async uninstall(packageName: string): Promise<void> {
209
- await this.ensureStoreInitialized();
210
- await this.runNpm(["uninstall", "--prefix", this.extensionsDir, packageName]);
211
- this.logger.info({ package: packageName }, "Extension uninstalled");
212
- }
213
-
214
- async listInstalled(): Promise<ListedExtensionInfo[]> {
215
- await this.ensureStoreInitialized();
216
- const dependencies = await this.readDependencies();
217
-
218
- const listed: ListedExtensionInfo[] = [];
219
- const names = Object.keys(dependencies).sort((a, b) => a.localeCompare(b));
220
- for (const packageName of names) {
221
- const version = dependencies[packageName]!;
222
- try {
223
- const installed = await this.readInstalledExtension(packageName, version);
224
- listed.push({
225
- packageName,
226
- version,
227
- manifest: installed.manifest,
228
- });
229
- } catch (error) {
230
- listed.push({
231
- packageName,
232
- version,
233
- error: error instanceof Error ? error.message : String(error),
234
- });
235
- }
236
- }
237
-
238
- return listed;
239
- }
240
-
241
- private storePackageJsonPath(): string {
242
- return join(this.extensionsDir, "package.json");
243
- }
244
-
245
- private createStoreRequire(): NodeRequire {
246
- return createRequire(this.storePackageJsonPath());
247
- }
248
-
249
- private async readDependencies(): Promise<Record<string, string>> {
250
- const path = this.storePackageJsonPath();
251
- try {
252
- const raw = await readFile(path, "utf-8");
253
- const parsed = JSON.parse(raw) as StorePackageJson;
254
- return parsed.dependencies ?? {};
255
- } catch {
256
- return {};
257
- }
258
- }
259
-
260
- private async readInstalledExtension(packageName: string, version: string): Promise<InstalledExtensionInfo> {
261
- const storeRequire = this.createStoreRequire();
262
-
263
- let packageJsonPath: string;
264
- try {
265
- packageJsonPath = storeRequire.resolve(`${packageName}/package.json`);
266
- } catch (error) {
267
- throw new Error(
268
- `Package '${packageName}' is declared in extension store but cannot be resolved: ${error instanceof Error ? error.message : String(error)}`,
269
- );
270
- }
271
-
272
- const packageRoot = dirname(packageJsonPath);
273
- const manifestPath = resolve(packageRoot, "dobby.manifest.json");
274
- const manifest = await readExtensionManifest(manifestPath);
275
-
276
- for (const contribution of manifest.contributions) {
277
- if (!isJavaScriptEntry(contribution.entry)) {
278
- throw new Error(
279
- `Contribution '${contribution.id}' in package '${packageName}' must use a built JavaScript entry, got '${contribution.entry}'`,
280
- );
281
- }
282
-
283
- const entryPath = resolve(packageRoot, contribution.entry);
284
- assertWithinRoot(entryPath, packageRoot);
285
- try {
286
- await access(entryPath);
287
- } catch {
288
- throw new Error(
289
- `Contribution '${contribution.id}' in package '${packageName}' points to missing entry '${contribution.entry}'`,
290
- );
291
- }
292
- }
293
-
294
- return {
295
- packageName,
296
- version,
297
- manifest,
298
- };
299
- }
300
-
301
- private async resolveInstalledPackageName(
302
- packageSpec: string,
303
- beforeDeps: Record<string, string>,
304
- afterDeps: Record<string, string>,
305
- isBatchInstall: boolean,
306
- ): Promise<string> {
307
- const inferred = parsePackageNameFromSpec(packageSpec);
308
- if (inferred && afterDeps[inferred]) {
309
- return inferred;
310
- }
311
-
312
- const inferredLocal = await parsePackageNameFromLocalSpec(packageSpec);
313
- if (inferredLocal && afterDeps[inferredLocal]) {
314
- return inferredLocal;
315
- }
316
-
317
- if (!isBatchInstall) {
318
- return pickInstalledPackageName(packageSpec, beforeDeps, afterDeps);
319
- }
320
-
321
- const changedPackages = Object.entries(afterDeps)
322
- .filter(([name, version]) => beforeDeps[name] !== version)
323
- .map(([name]) => name);
324
- if (changedPackages.length === 1) {
325
- return changedPackages[0]!;
326
- }
327
-
328
- throw new Error(
329
- `Could not determine installed package from spec '${packageSpec}' in batch install mode. ` +
330
- "Use explicit npm package names for init/installMany.",
331
- );
332
- }
333
-
334
- private async runNpm(args: string[]): Promise<void> {
335
- await new Promise<void>((resolvePromise, rejectPromise) => {
336
- const command = process.platform === "win32" ? "npm.cmd" : "npm";
337
- const child = spawn(command, args, {
338
- stdio: "inherit",
339
- env: process.env,
340
- });
341
-
342
- child.once("error", (error) => {
343
- rejectPromise(error);
344
- });
345
-
346
- child.once("exit", (code) => {
347
- if (code === 0) {
348
- resolvePromise();
349
- return;
350
- }
351
- rejectPromise(new Error(`npm ${args.join(" ")} failed with exit code ${code ?? "unknown"}`));
352
- });
353
- });
354
- }
355
- }
@@ -1,26 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { z } from "zod";
3
- import type { ExtensionManifest } from "../core/types.js";
4
-
5
- const contributionManifestSchema = z.object({
6
- id: z.string().min(1),
7
- kind: z.enum(["provider", "connector", "sandbox"]),
8
- entry: z.string().min(1),
9
- capabilities: z.record(z.string(), z.unknown()).optional(),
10
- });
11
-
12
- const manifestSchema = z.object({
13
- apiVersion: z.string().min(1),
14
- name: z.string().min(1),
15
- version: z.string().min(1),
16
- contributions: z.array(contributionManifestSchema).min(1),
17
- });
18
-
19
- export function parseExtensionManifest(value: unknown): ExtensionManifest {
20
- return manifestSchema.parse(value) as ExtensionManifest;
21
- }
22
-
23
- export async function readExtensionManifest(manifestPath: string): Promise<ExtensionManifest> {
24
- const raw = await readFile(manifestPath, "utf-8");
25
- return parseExtensionManifest(JSON.parse(raw));
26
- }
@@ -1,229 +0,0 @@
1
- import { join } from "node:path";
2
- import type {
3
- ConnectorContributionModule,
4
- ConnectorPlugin,
5
- ConnectorsConfig,
6
- DataConfig,
7
- ExtensionHostContext,
8
- ProviderContributionModule,
9
- ProvidersConfig,
10
- ProviderInstance,
11
- SandboxContributionModule,
12
- SandboxesConfig,
13
- SandboxInstance,
14
- } from "../core/types.js";
15
- import type { LoadedExtensionPackage } from "./loader.js";
16
-
17
- interface ProviderContributionRegistration {
18
- contributionId: string;
19
- packageName: string;
20
- createInstance: (options: {
21
- instanceId: string;
22
- config: Record<string, unknown>;
23
- host: ExtensionHostContext;
24
- data: DataConfig;
25
- }) => Promise<ProviderInstance> | ProviderInstance;
26
- }
27
-
28
- interface ConnectorContributionRegistration {
29
- contributionId: string;
30
- packageName: string;
31
- createInstance: (options: {
32
- instanceId: string;
33
- config: Record<string, unknown>;
34
- host: ExtensionHostContext;
35
- attachmentsRoot: string;
36
- }) => Promise<ConnectorPlugin> | ConnectorPlugin;
37
- }
38
-
39
- interface SandboxContributionRegistration {
40
- contributionId: string;
41
- packageName: string;
42
- createInstance: (options: {
43
- instanceId: string;
44
- config: Record<string, unknown>;
45
- host: ExtensionHostContext;
46
- }) => Promise<SandboxInstance> | SandboxInstance;
47
- }
48
-
49
- export interface RegisteredContributionSchemaInfo {
50
- contributionId: string;
51
- packageName: string;
52
- kind: "provider" | "connector" | "sandbox";
53
- configSchema?: Record<string, unknown>;
54
- }
55
-
56
- function isRecord(value: unknown): value is Record<string, unknown> {
57
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
58
- }
59
-
60
- function normalizeContributionSchema(value: unknown): Record<string, unknown> | undefined {
61
- if (!isRecord(value)) {
62
- return undefined;
63
- }
64
- return value;
65
- }
66
-
67
- export class ExtensionRegistry {
68
- private readonly providers = new Map<string, ProviderContributionRegistration>();
69
- private readonly connectors = new Map<string, ConnectorContributionRegistration>();
70
- private readonly sandboxes = new Map<string, SandboxContributionRegistration>();
71
- private readonly contributionSchemas = new Map<string, RegisteredContributionSchemaInfo>();
72
-
73
- registerPackages(loadedPackages: LoadedExtensionPackage[]): void {
74
- for (const extensionPackage of loadedPackages) {
75
- for (const contribution of extensionPackage.contributions) {
76
- if (this.contributionSchemas.has(contribution.manifest.id)) {
77
- throw new Error(`Duplicate contribution id '${contribution.manifest.id}'`);
78
- }
79
-
80
- const normalizedSchema = normalizeContributionSchema(
81
- (contribution.module as { configSchema?: unknown }).configSchema,
82
- );
83
- this.contributionSchemas.set(contribution.manifest.id, {
84
- contributionId: contribution.manifest.id,
85
- packageName: extensionPackage.packageName,
86
- kind: contribution.manifest.kind,
87
- ...(normalizedSchema ? { configSchema: normalizedSchema } : {}),
88
- });
89
-
90
- if (contribution.manifest.kind === "provider") {
91
- const module = contribution.module as ProviderContributionModule;
92
- if (this.providers.has(contribution.manifest.id)) {
93
- throw new Error(`Duplicate provider contribution id '${contribution.manifest.id}'`);
94
- }
95
- this.providers.set(contribution.manifest.id, {
96
- contributionId: contribution.manifest.id,
97
- packageName: extensionPackage.packageName,
98
- createInstance: module.createInstance,
99
- });
100
- continue;
101
- }
102
-
103
- if (contribution.manifest.kind === "connector") {
104
- const module = contribution.module as ConnectorContributionModule;
105
- if (this.connectors.has(contribution.manifest.id)) {
106
- throw new Error(`Duplicate connector contribution id '${contribution.manifest.id}'`);
107
- }
108
- this.connectors.set(contribution.manifest.id, {
109
- contributionId: contribution.manifest.id,
110
- packageName: extensionPackage.packageName,
111
- createInstance: module.createInstance,
112
- });
113
- continue;
114
- }
115
-
116
- const module = contribution.module as SandboxContributionModule;
117
- if (this.sandboxes.has(contribution.manifest.id)) {
118
- throw new Error(`Duplicate sandbox contribution id '${contribution.manifest.id}'`);
119
- }
120
- this.sandboxes.set(contribution.manifest.id, {
121
- contributionId: contribution.manifest.id,
122
- packageName: extensionPackage.packageName,
123
- createInstance: module.createInstance,
124
- });
125
- }
126
- }
127
- }
128
-
129
- listContributionSchemas(): RegisteredContributionSchemaInfo[] {
130
- return [...this.contributionSchemas.values()]
131
- .sort((a, b) => a.contributionId.localeCompare(b.contributionId))
132
- .map((item) => ({
133
- contributionId: item.contributionId,
134
- packageName: item.packageName,
135
- kind: item.kind,
136
- ...(item.configSchema ? { configSchema: item.configSchema } : {}),
137
- }));
138
- }
139
-
140
- getContributionSchema(contributionId: string): RegisteredContributionSchemaInfo | null {
141
- const found = this.contributionSchemas.get(contributionId);
142
- if (!found) {
143
- return null;
144
- }
145
-
146
- return {
147
- contributionId: found.contributionId,
148
- packageName: found.packageName,
149
- kind: found.kind,
150
- ...(found.configSchema ? { configSchema: found.configSchema } : {}),
151
- };
152
- }
153
-
154
- async createProviderInstances(
155
- config: ProvidersConfig,
156
- context: ExtensionHostContext,
157
- data: DataConfig,
158
- ): Promise<Map<string, ProviderInstance>> {
159
- const instances = new Map<string, ProviderInstance>();
160
-
161
- for (const [instanceId, instanceConfig] of Object.entries(config.items)) {
162
- const contribution = this.providers.get(instanceConfig.type);
163
- if (!contribution) {
164
- throw new Error(
165
- `Provider instance '${instanceId}' references unknown contribution '${instanceConfig.type}'`,
166
- );
167
- }
168
- const instance = await contribution.createInstance({
169
- instanceId,
170
- config: instanceConfig.config,
171
- host: context,
172
- data,
173
- });
174
- instances.set(instanceId, instance);
175
- }
176
-
177
- return instances;
178
- }
179
-
180
- async createConnectorInstances(
181
- config: ConnectorsConfig,
182
- context: ExtensionHostContext,
183
- attachmentsBaseDir: string,
184
- ): Promise<ConnectorPlugin[]> {
185
- const instances: ConnectorPlugin[] = [];
186
-
187
- for (const [instanceId, instanceConfig] of Object.entries(config.items)) {
188
- const contribution = this.connectors.get(instanceConfig.type);
189
- if (!contribution) {
190
- throw new Error(
191
- `Connector instance '${instanceId}' references unknown contribution '${instanceConfig.type}'`,
192
- );
193
- }
194
- const connector = await contribution.createInstance({
195
- instanceId,
196
- config: instanceConfig.config,
197
- host: context,
198
- attachmentsRoot: join(attachmentsBaseDir, instanceId),
199
- });
200
- instances.push(connector);
201
- }
202
-
203
- return instances;
204
- }
205
-
206
- async createSandboxInstances(
207
- config: SandboxesConfig,
208
- context: ExtensionHostContext,
209
- ): Promise<Map<string, SandboxInstance>> {
210
- const instances = new Map<string, SandboxInstance>();
211
-
212
- for (const [instanceId, instanceConfig] of Object.entries(config.items)) {
213
- const contribution = this.sandboxes.get(instanceConfig.type);
214
- if (!contribution) {
215
- throw new Error(
216
- `Sandbox instance '${instanceId}' references unknown contribution '${instanceConfig.type}'`,
217
- );
218
- }
219
- const sandbox = await contribution.createInstance({
220
- instanceId,
221
- config: instanceConfig.config,
222
- host: context,
223
- });
224
- instances.set(instanceId, sandbox);
225
- }
226
-
227
- return instances;
228
- }
229
- }
package/src/main.ts DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { runCli } from "./cli/index.js";
4
-
5
- void runCli().catch((error) => {
6
- console.error(error instanceof Error ? error.message : String(error));
7
- process.exit(1);
8
- });
@@ -1,44 +0,0 @@
1
- import type { GatewayLogger } from "../core/types.js";
2
-
3
- export interface ExecOptions {
4
- timeoutSeconds?: number;
5
- signal?: AbortSignal;
6
- env?: NodeJS.ProcessEnv;
7
- }
8
-
9
- export interface ExecResult {
10
- stdout: string;
11
- stderr: string;
12
- code: number;
13
- killed: boolean;
14
- }
15
-
16
- export interface SpawnOptions {
17
- command: string;
18
- args: string[];
19
- cwd?: string;
20
- env?: NodeJS.ProcessEnv;
21
- signal?: AbortSignal;
22
- tty?: boolean;
23
- }
24
-
25
- export interface SpawnedProcess {
26
- stdin: NodeJS.WritableStream;
27
- stdout: NodeJS.ReadableStream;
28
- stderr: NodeJS.ReadableStream;
29
- readonly killed: boolean;
30
- readonly exitCode: number | null;
31
- kill(signal?: NodeJS.Signals): boolean;
32
- on(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): void;
33
- on(event: "error", listener: (error: Error) => void): void;
34
- once(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): void;
35
- once(event: "error", listener: (error: Error) => void): void;
36
- off(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): void;
37
- off(event: "error", listener: (error: Error) => void): void;
38
- }
39
-
40
- export interface Executor {
41
- exec(command: string, cwd: string, options?: ExecOptions): Promise<ExecResult>;
42
- spawn(options: SpawnOptions): SpawnedProcess;
43
- close(): Promise<void>;
44
- }