@dobby.ai/dobby 0.1.0 → 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 (156) hide show
  1. package/README.md +84 -39
  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/commands/doctor.js +81 -2
  5. package/dist/src/cli/commands/extension.js +3 -1
  6. package/dist/src/cli/commands/init.js +43 -173
  7. package/dist/src/cli/commands/topology.js +38 -14
  8. package/dist/src/cli/program.js +15 -137
  9. package/dist/src/cli/shared/config-io.js +3 -31
  10. package/dist/src/cli/shared/config-mutators.js +33 -9
  11. package/dist/src/cli/shared/configure-sections.js +52 -12
  12. package/dist/src/cli/shared/init-catalog.js +89 -46
  13. package/dist/src/cli/shared/local-extension-specs.js +85 -0
  14. package/dist/src/cli/shared/schema-prompts.js +26 -2
  15. package/dist/src/core/gateway.js +3 -1
  16. package/dist/src/core/routing.js +53 -38
  17. package/dist/src/core/types.js +2 -0
  18. package/dist/src/cron/config.js +2 -2
  19. package/dist/src/cron/service.js +87 -23
  20. package/dist/src/cron/store.js +1 -1
  21. package/dist/src/main.js +0 -0
  22. package/dist/src/shared/dobby-repo.js +40 -0
  23. package/package.json +11 -4
  24. package/.env.example +0 -9
  25. package/AGENTS.md +0 -267
  26. package/ROADMAP.md +0 -34
  27. package/config/cron.example.json +0 -9
  28. package/config/gateway.example.json +0 -128
  29. package/config/models.custom.example.json +0 -27
  30. package/dist/src/agent/tests/event-forwarder.test.js +0 -113
  31. package/dist/src/cli/shared/config-path.js +0 -207
  32. package/dist/src/cli/shared/init-models-file.js +0 -65
  33. package/dist/src/cli/shared/presets.js +0 -86
  34. package/dist/src/cli/tests/config-command.test.js +0 -42
  35. package/dist/src/cli/tests/config-io.test.js +0 -64
  36. package/dist/src/cli/tests/config-mutators.test.js +0 -47
  37. package/dist/src/cli/tests/config-path.test.js +0 -21
  38. package/dist/src/cli/tests/discord-config.test.js +0 -23
  39. package/dist/src/cli/tests/doctor.test.js +0 -107
  40. package/dist/src/cli/tests/init-catalog.test.js +0 -87
  41. package/dist/src/cli/tests/presets.test.js +0 -41
  42. package/dist/src/cli/tests/program-options.test.js +0 -92
  43. package/dist/src/cli/tests/routing-config.test.js +0 -199
  44. package/dist/src/cli/tests/routing-legacy.test.js +0 -191
  45. package/dist/src/core/tests/control-command.test.js +0 -17
  46. package/dist/src/core/tests/gateway-update-strategy.test.js +0 -167
  47. package/dist/src/core/tests/runtime-registry.test.js +0 -116
  48. package/dist/src/core/tests/typing-controller.test.js +0 -103
  49. package/docs/BOXLITE_SANDBOX_FEASIBILITY.md +0 -175
  50. package/docs/CRON_SCHEDULER_DESIGN.md +0 -374
  51. package/docs/DOCKER_SANDBOX_vs_BOXLITE.md +0 -77
  52. package/docs/EXTENSION_SYSTEM_ARCHITECTURE.md +0 -119
  53. package/docs/MVP.md +0 -135
  54. package/docs/RUNBOOK.md +0 -242
  55. package/docs/TEAMWORK_HANDOFF_DESIGN.md +0 -440
  56. package/plugins/connector-discord/dobby.manifest.json +0 -18
  57. package/plugins/connector-discord/index.js +0 -1
  58. package/plugins/connector-discord/package-lock.json +0 -360
  59. package/plugins/connector-discord/package.json +0 -38
  60. package/plugins/connector-discord/src/connector.ts +0 -350
  61. package/plugins/connector-discord/src/contribution.ts +0 -21
  62. package/plugins/connector-discord/src/mapper.ts +0 -102
  63. package/plugins/connector-discord/tsconfig.json +0 -19
  64. package/plugins/connector-feishu/dobby.manifest.json +0 -18
  65. package/plugins/connector-feishu/index.js +0 -1
  66. package/plugins/connector-feishu/package-lock.json +0 -618
  67. package/plugins/connector-feishu/package.json +0 -38
  68. package/plugins/connector-feishu/src/connector.ts +0 -343
  69. package/plugins/connector-feishu/src/contribution.ts +0 -26
  70. package/plugins/connector-feishu/src/mapper.ts +0 -401
  71. package/plugins/connector-feishu/tsconfig.json +0 -19
  72. package/plugins/plugin-sdk/index.d.ts +0 -261
  73. package/plugins/plugin-sdk/index.js +0 -1
  74. package/plugins/plugin-sdk/package-lock.json +0 -12
  75. package/plugins/plugin-sdk/package.json +0 -22
  76. package/plugins/provider-claude/dobby.manifest.json +0 -17
  77. package/plugins/provider-claude/index.js +0 -1
  78. package/plugins/provider-claude/package-lock.json +0 -3398
  79. package/plugins/provider-claude/package.json +0 -39
  80. package/plugins/provider-claude/src/contribution.ts +0 -1018
  81. package/plugins/provider-claude/tsconfig.json +0 -19
  82. package/plugins/provider-claude-cli/dobby.manifest.json +0 -17
  83. package/plugins/provider-claude-cli/index.js +0 -1
  84. package/plugins/provider-claude-cli/package-lock.json +0 -2898
  85. package/plugins/provider-claude-cli/package.json +0 -38
  86. package/plugins/provider-claude-cli/src/contribution.ts +0 -1673
  87. package/plugins/provider-claude-cli/tsconfig.json +0 -19
  88. package/plugins/provider-pi/dobby.manifest.json +0 -17
  89. package/plugins/provider-pi/index.js +0 -1
  90. package/plugins/provider-pi/package-lock.json +0 -3877
  91. package/plugins/provider-pi/package.json +0 -40
  92. package/plugins/provider-pi/src/contribution.ts +0 -476
  93. package/plugins/provider-pi/tsconfig.json +0 -19
  94. package/plugins/sandbox-core/boxlite.js +0 -1
  95. package/plugins/sandbox-core/dobby.manifest.json +0 -17
  96. package/plugins/sandbox-core/docker.js +0 -1
  97. package/plugins/sandbox-core/package-lock.json +0 -136
  98. package/plugins/sandbox-core/package.json +0 -39
  99. package/plugins/sandbox-core/src/boxlite-context.ts +0 -2
  100. package/plugins/sandbox-core/src/boxlite-contribution.ts +0 -53
  101. package/plugins/sandbox-core/src/boxlite-executor.ts +0 -911
  102. package/plugins/sandbox-core/src/docker-contribution.ts +0 -43
  103. package/plugins/sandbox-core/src/docker-executor.ts +0 -217
  104. package/plugins/sandbox-core/tsconfig.json +0 -19
  105. package/scripts/local-extensions.mjs +0 -168
  106. package/src/agent/event-forwarder.ts +0 -414
  107. package/src/cli/commands/config.ts +0 -328
  108. package/src/cli/commands/configure.ts +0 -92
  109. package/src/cli/commands/cron.ts +0 -410
  110. package/src/cli/commands/doctor.ts +0 -230
  111. package/src/cli/commands/extension.ts +0 -205
  112. package/src/cli/commands/init.ts +0 -396
  113. package/src/cli/commands/start.ts +0 -223
  114. package/src/cli/commands/topology.ts +0 -383
  115. package/src/cli/index.ts +0 -9
  116. package/src/cli/program.ts +0 -465
  117. package/src/cli/shared/config-io.ts +0 -277
  118. package/src/cli/shared/config-mutators.ts +0 -440
  119. package/src/cli/shared/config-schema.ts +0 -228
  120. package/src/cli/shared/config-types.ts +0 -121
  121. package/src/cli/shared/configure-sections.ts +0 -551
  122. package/src/cli/shared/discord-config.ts +0 -14
  123. package/src/cli/shared/init-catalog.ts +0 -189
  124. package/src/cli/shared/init-models-file.ts +0 -77
  125. package/src/cli/shared/runtime.ts +0 -33
  126. package/src/cli/shared/schema-prompts.ts +0 -414
  127. package/src/cli/tests/config-command.test.ts +0 -56
  128. package/src/cli/tests/config-io.test.ts +0 -92
  129. package/src/cli/tests/config-mutators.test.ts +0 -59
  130. package/src/cli/tests/doctor.test.ts +0 -120
  131. package/src/cli/tests/init-catalog.test.ts +0 -96
  132. package/src/cli/tests/program-options.test.ts +0 -113
  133. package/src/cli/tests/routing-config.test.ts +0 -209
  134. package/src/core/control-command.ts +0 -12
  135. package/src/core/dedup-store.ts +0 -103
  136. package/src/core/gateway.ts +0 -607
  137. package/src/core/routing.ts +0 -379
  138. package/src/core/runtime-registry.ts +0 -141
  139. package/src/core/tests/control-command.test.ts +0 -20
  140. package/src/core/tests/runtime-registry.test.ts +0 -140
  141. package/src/core/tests/typing-controller.test.ts +0 -129
  142. package/src/core/types.ts +0 -318
  143. package/src/core/typing-controller.ts +0 -119
  144. package/src/cron/config.ts +0 -154
  145. package/src/cron/schedule.ts +0 -61
  146. package/src/cron/service.ts +0 -249
  147. package/src/cron/store.ts +0 -155
  148. package/src/cron/types.ts +0 -60
  149. package/src/extension/loader.ts +0 -145
  150. package/src/extension/manager.ts +0 -355
  151. package/src/extension/manifest.ts +0 -26
  152. package/src/extension/registry.ts +0 -229
  153. package/src/main.ts +0 -8
  154. package/src/sandbox/executor.ts +0 -44
  155. package/src/sandbox/host-executor.ts +0 -118
  156. package/tsconfig.json +0 -18
@@ -1,40 +0,0 @@
1
- {
2
- "name": "@dobby.ai/provider-pi",
3
- "version": "0.1.2",
4
- "private": false,
5
- "type": "module",
6
- "description": "Built-in pi provider extension package",
7
- "main": "./index.js",
8
- "scripts": {
9
- "build": "tsc -p tsconfig.json",
10
- "check": "tsc -p tsconfig.json --noEmit",
11
- "prepack": "npm run build"
12
- },
13
- "dependencies": {
14
- "@mariozechner/pi-agent-core": "^0.53.0",
15
- "@mariozechner/pi-ai": "^0.53.0",
16
- "@mariozechner/pi-coding-agent": "^0.53.0",
17
- "zod": "^4.3.6"
18
- },
19
- "peerDependencies": {
20
- "@dobby.ai/plugin-sdk": "^0.1.0"
21
- },
22
- "peerDependenciesMeta": {
23
- "@dobby.ai/plugin-sdk": {
24
- "optional": true
25
- }
26
- },
27
- "devDependencies": {
28
- "@dobby.ai/plugin-sdk": "file:../plugin-sdk",
29
- "@types/node": "^22.10.5",
30
- "typescript": "^5.9.2"
31
- },
32
- "files": [
33
- "index.js",
34
- "dist/",
35
- "dobby.manifest.json"
36
- ],
37
- "publishConfig": {
38
- "access": "public"
39
- }
40
- }
@@ -1,476 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
- import { dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
- import type { AgentMessage, ThinkingLevel } from "@mariozechner/pi-agent-core";
5
- import {
6
- AuthStorage,
7
- type CreateAgentSessionOptions,
8
- type ToolDefinition,
9
- createAgentSession,
10
- createBashTool,
11
- createEditTool,
12
- createFindTool,
13
- createGrepTool,
14
- createLsTool,
15
- createReadTool,
16
- createWriteTool,
17
- ModelRegistry,
18
- SessionManager,
19
- type AgentSession,
20
- type BashOperations,
21
- type EditOperations,
22
- type ReadOperations,
23
- type WriteOperations,
24
- } from "@mariozechner/pi-coding-agent";
25
- import type { Api, ImageContent, Model } from "@mariozechner/pi-ai";
26
- import { z } from "zod";
27
- import type {
28
- GatewayAgentEvent,
29
- GatewayAgentRuntime,
30
- ProviderContributionModule,
31
- ProviderInstance,
32
- ProviderInstanceCreateOptions,
33
- ProviderSessionArchiveOptions,
34
- ProviderRuntimeCreateOptions,
35
- } from "@dobby.ai/plugin-sdk";
36
-
37
- const BOXLITE_CONTEXT_CONVERSATION_KEY_ENV = "__IM_AGENT_BOXLITE_CONVERSATION_KEY";
38
- const BOXLITE_CONTEXT_PROJECT_ROOT_ENV = "__IM_AGENT_BOXLITE_PROJECT_ROOT";
39
-
40
- type RuntimeTool = NonNullable<CreateAgentSessionOptions["tools"]>[number];
41
-
42
- interface PiProviderConfig {
43
- provider: string;
44
- model: string;
45
- thinkingLevel: ThinkingLevel;
46
- agentDir?: string;
47
- authFile?: string;
48
- modelsFile?: string;
49
- }
50
-
51
- interface BuiltTools {
52
- activeTools: RuntimeTool[];
53
- customTools: ToolDefinition[];
54
- }
55
-
56
- const piProviderConfigSchema = z.object({
57
- provider: z.string().min(1),
58
- model: z.string().min(1),
59
- thinkingLevel: z.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).default("off"),
60
- agentDir: z.string().optional(),
61
- authFile: z.string().optional(),
62
- modelsFile: z.string().default("./models.custom.json"),
63
- });
64
-
65
- const IMAGE_MIME_TYPES: Record<string, string> = {
66
- ".jpg": "image/jpeg",
67
- ".jpeg": "image/jpeg",
68
- ".png": "image/png",
69
- ".gif": "image/gif",
70
- ".webp": "image/webp",
71
- };
72
-
73
- function assertWithinRoot(absolutePath: string, rootDir: string): void {
74
- const normalizedRoot = resolve(rootDir);
75
- const normalizedPath = resolve(absolutePath);
76
- const rootPrefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;
77
-
78
- if (normalizedPath !== normalizedRoot && !normalizedPath.startsWith(rootPrefix)) {
79
- throw new Error(`Path '${normalizedPath}' is outside allowed project root '${normalizedRoot}'`);
80
- }
81
- }
82
-
83
- function safeSegment(value: string): string {
84
- return value.replaceAll(/[^a-zA-Z0-9._-]/g, "_");
85
- }
86
-
87
- function extractAssistantText(message: AgentMessage): string {
88
- if (message.role !== "assistant") return "";
89
- const blocks = message.content.filter((block): block is { type: "text"; text: string } => block.type === "text");
90
- return blocks.map((block) => block.text).join("\n");
91
- }
92
-
93
- function extractToolResultText(result: unknown): string {
94
- if (!result || typeof result !== "object") return "(no output)";
95
- const content = (result as { content?: unknown }).content;
96
- if (!Array.isArray(content)) return "(no output)";
97
-
98
- const textBlocks = content.filter(
99
- (block): block is { type: "text"; text: string } =>
100
- typeof block === "object" &&
101
- block !== null &&
102
- "type" in block &&
103
- (block as { type: string }).type === "text" &&
104
- "text" in block,
105
- );
106
-
107
- const text = textBlocks.map((block) => block.text).join("\n").trim();
108
- return text.length > 0 ? text : "(no output)";
109
- }
110
-
111
- function normalizeMaybePath(configBaseDir: string, value: string | undefined): string | undefined {
112
- if (!value) return undefined;
113
- const trimmed = value.trim();
114
- if (trimmed.length === 0) return undefined;
115
- if (trimmed === "~") return resolve(process.env.HOME ?? "", ".");
116
- if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
117
- return resolve(process.env.HOME ?? "", trimmed.slice(2));
118
- }
119
- return resolve(configBaseDir, trimmed);
120
- }
121
-
122
- function formatArchiveStamp(timestampMs: number): string {
123
- return new Date(timestampMs).toISOString().replaceAll(":", "-").replaceAll(".", "-");
124
- }
125
-
126
- async function archiveSessionPath(
127
- sessionsDir: string,
128
- sourcePath: string,
129
- archivedAtMs: number,
130
- ): Promise<string | undefined> {
131
- const relativePath = relative(sessionsDir, sourcePath);
132
- if (relativePath.startsWith("..") || isAbsolute(relativePath)) {
133
- throw new Error(`Session path '${sourcePath}' is outside sessions dir '${sessionsDir}'`);
134
- }
135
-
136
- const archiveRoot = join(sessionsDir, "_archived", `${formatArchiveStamp(archivedAtMs)}-${randomUUID().slice(0, 8)}`);
137
- const archivePath = join(archiveRoot, relativePath);
138
- await mkdir(dirname(archivePath), { recursive: true });
139
-
140
- try {
141
- await rename(sourcePath, archivePath);
142
- return archivePath;
143
- } catch (error) {
144
- const asErr = error as NodeJS.ErrnoException;
145
- if (asErr.code === "ENOENT") {
146
- return undefined;
147
- }
148
- throw error;
149
- }
150
- }
151
-
152
- class PiGatewayRuntime implements GatewayAgentRuntime {
153
- constructor(private readonly session: AgentSession) {}
154
-
155
- async prompt(text: string, options?: { images?: ImageContent[] }): Promise<void> {
156
- if (options?.images && options.images.length > 0) {
157
- await this.session.prompt(text, { images: options.images });
158
- return;
159
- }
160
- await this.session.prompt(text);
161
- }
162
-
163
- subscribe(listener: (event: GatewayAgentEvent) => void): () => void {
164
- return this.session.subscribe((event) => {
165
- if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
166
- listener({ type: "message_delta", delta: event.assistantMessageEvent.delta });
167
- return;
168
- }
169
-
170
- if (event.type === "message_end" && event.message.role === "assistant") {
171
- const finalText = extractAssistantText(event.message);
172
- if (finalText.trim().length > 0) {
173
- listener({ type: "message_complete", text: finalText });
174
- }
175
- return;
176
- }
177
-
178
- if (event.type === "tool_execution_start") {
179
- listener({ type: "tool_start", toolName: event.toolName });
180
- return;
181
- }
182
-
183
- if (event.type === "tool_execution_end") {
184
- listener({
185
- type: "tool_end",
186
- toolName: event.toolName,
187
- isError: event.isError,
188
- output: extractToolResultText(event.result),
189
- });
190
- return;
191
- }
192
-
193
- if (event.type === "auto_compaction_start") {
194
- listener({ type: "status", message: `Compacting context (${event.reason})...` });
195
- return;
196
- }
197
-
198
- if (event.type === "auto_retry_start") {
199
- listener({ type: "status", message: `Retrying (${event.attempt}/${event.maxAttempts})...` });
200
- }
201
- });
202
- }
203
-
204
- async abort(): Promise<void> {
205
- await this.session.abort();
206
- }
207
-
208
- dispose(): void {
209
- this.session.dispose();
210
- }
211
- }
212
-
213
- class PiProviderInstanceImpl implements ProviderInstance {
214
- private readonly authStorage: AuthStorage;
215
- private readonly modelRegistry: ModelRegistry;
216
- private readonly model: Model<Api>;
217
-
218
- constructor(
219
- readonly id: string,
220
- private readonly providerConfig: PiProviderConfig,
221
- private readonly dataConfig: ProviderInstanceCreateOptions["data"],
222
- private readonly logger: ProviderInstanceCreateOptions["host"]["logger"],
223
- ) {
224
- this.authStorage = AuthStorage.create(providerConfig.authFile);
225
- this.modelRegistry = new ModelRegistry(this.authStorage, providerConfig.modelsFile);
226
-
227
- const model = this.modelRegistry.find(providerConfig.provider, providerConfig.model);
228
- if (!model) {
229
- throw new Error(`Configured model '${providerConfig.provider}/${providerConfig.model}' not found`);
230
- }
231
- this.model = model;
232
- }
233
-
234
- async createRuntime(options: ProviderRuntimeCreateOptions): Promise<GatewayAgentRuntime> {
235
- const sessionFile = options.sessionPolicy === "ephemeral"
236
- ? this.getEphemeralSessionFilePath(options.conversationKey)
237
- : this.getSessionFilePath(options.inbound);
238
- const sessionDir = dirname(sessionFile);
239
-
240
- await mkdir(this.dataConfig.sessionsDir, { recursive: true });
241
- await mkdir(this.dataConfig.logsDir, { recursive: true });
242
- await mkdir(this.dataConfig.stateDir, { recursive: true });
243
- await mkdir(this.dataConfig.attachmentsDir, { recursive: true });
244
- await mkdir(sessionDir, { recursive: true });
245
-
246
- const builtTools = this.buildTools(
247
- options.conversationKey,
248
- options.route.profile.projectRoot,
249
- options.route.profile.tools,
250
- options,
251
- );
252
-
253
- const sessionOptions = {
254
- cwd: options.route.profile.projectRoot,
255
- authStorage: this.authStorage,
256
- modelRegistry: this.modelRegistry,
257
- sessionManager: SessionManager.open(sessionFile, sessionDir),
258
- model: this.model,
259
- thinkingLevel: this.providerConfig.thinkingLevel,
260
- tools: builtTools.activeTools,
261
- customTools: builtTools.customTools,
262
- ...(this.providerConfig.agentDir ? { agentDir: this.providerConfig.agentDir } : {}),
263
- };
264
-
265
- const { session } = await createAgentSession(sessionOptions);
266
-
267
- this.logger.info(
268
- {
269
- providerInstance: this.id,
270
- activeTools: builtTools.activeTools.map((tool) => tool.name),
271
- },
272
- "Provider runtime initialized",
273
- );
274
-
275
- if (options.route.profile.systemPromptFile) {
276
- try {
277
- const prompt = await readFile(options.route.profile.systemPromptFile, "utf-8");
278
- session.agent.setSystemPrompt(prompt);
279
- } catch (error) {
280
- this.logger.warn(
281
- { err: error, routeId: options.route.routeId, file: options.route.profile.systemPromptFile },
282
- "Failed to load route system prompt; continuing with default",
283
- );
284
- }
285
- }
286
-
287
- return new PiGatewayRuntime(session);
288
- }
289
-
290
- async archiveSession(options: ProviderSessionArchiveOptions): Promise<{ archived: boolean; archivePath?: string }> {
291
- const sessionFile = options.sessionPolicy === "ephemeral"
292
- ? this.getEphemeralSessionFilePath(options.conversationKey)
293
- : this.getSessionFilePath(options.inbound);
294
- const archivePath = await archiveSessionPath(
295
- this.dataConfig.sessionsDir,
296
- sessionFile,
297
- options.archivedAtMs ?? Date.now(),
298
- );
299
- return archivePath ? { archived: true, archivePath } : { archived: false };
300
- }
301
-
302
- private buildTools(
303
- conversationKey: string,
304
- projectRoot: string,
305
- profile: "full" | "readonly",
306
- options: ProviderRuntimeCreateOptions,
307
- ): BuiltTools {
308
- const readOps: ReadOperations = {
309
- access: async (absolutePath) => {
310
- assertWithinRoot(absolutePath, projectRoot);
311
- },
312
- readFile: async (absolutePath) => {
313
- assertWithinRoot(absolutePath, projectRoot);
314
- return readFile(absolutePath);
315
- },
316
- detectImageMimeType: async (absolutePath) => {
317
- const ext = extname(absolutePath).toLowerCase();
318
- return IMAGE_MIME_TYPES[ext] ?? null;
319
- },
320
- };
321
-
322
- const writeOps: WriteOperations = {
323
- mkdir: async (dir) => {
324
- assertWithinRoot(dir, projectRoot);
325
- await mkdir(dir, { recursive: true });
326
- },
327
- writeFile: async (absolutePath, content) => {
328
- assertWithinRoot(absolutePath, projectRoot);
329
- await writeFile(absolutePath, content, "utf-8");
330
- },
331
- };
332
-
333
- const editOps: EditOperations = {
334
- access: async (absolutePath) => {
335
- assertWithinRoot(absolutePath, projectRoot);
336
- },
337
- readFile: async (absolutePath) => {
338
- assertWithinRoot(absolutePath, projectRoot);
339
- return readFile(absolutePath);
340
- },
341
- writeFile: async (absolutePath, content) => {
342
- assertWithinRoot(absolutePath, projectRoot);
343
- await writeFile(absolutePath, content, "utf-8");
344
- },
345
- };
346
-
347
- const bashOps: BashOperations = {
348
- exec: async (command, cwd, execOptionsFromTool) => {
349
- const env: NodeJS.ProcessEnv = {
350
- ...(execOptionsFromTool.env ?? {}),
351
- [BOXLITE_CONTEXT_CONVERSATION_KEY_ENV]: conversationKey,
352
- [BOXLITE_CONTEXT_PROJECT_ROOT_ENV]: projectRoot,
353
- };
354
-
355
- const execOptions = {
356
- ...(execOptionsFromTool.signal ? { signal: execOptionsFromTool.signal } : {}),
357
- ...(execOptionsFromTool.timeout !== undefined ? { timeoutSeconds: execOptionsFromTool.timeout } : {}),
358
- env,
359
- };
360
-
361
- this.logger.info(
362
- {
363
- providerInstance: this.id,
364
- sandboxExecutorType: options.executor.constructor?.name ?? "unknown",
365
- cwd,
366
- timeoutSeconds: execOptions.timeoutSeconds,
367
- },
368
- "Dispatching bash command to sandbox executor",
369
- );
370
-
371
- const result = await options.executor.exec(command, cwd, execOptions);
372
- const combined = `${result.stdout}${result.stderr}`;
373
- if (combined.length > 0) {
374
- execOptionsFromTool.onData(Buffer.from(combined, "utf-8"));
375
- }
376
-
377
- this.logger.info(
378
- {
379
- providerInstance: this.id,
380
- sandboxExecutorType: options.executor.constructor?.name ?? "unknown",
381
- code: result.code,
382
- killed: result.killed,
383
- stdoutBytes: Buffer.byteLength(result.stdout, "utf-8"),
384
- stderrBytes: Buffer.byteLength(result.stderr, "utf-8"),
385
- },
386
- "Sandbox executor completed bash command",
387
- );
388
-
389
- return { exitCode: result.killed ? null : result.code };
390
- },
391
- };
392
-
393
- const readTool = createReadTool(projectRoot, { operations: readOps }) as RuntimeTool;
394
- const bashTool = createBashTool(projectRoot, { operations: bashOps }) as RuntimeTool;
395
- const editTool = createEditTool(projectRoot, { operations: editOps }) as RuntimeTool;
396
- const writeTool = createWriteTool(projectRoot, { operations: writeOps }) as RuntimeTool;
397
- const grepTool = createGrepTool(projectRoot) as RuntimeTool;
398
- const findTool = createFindTool(projectRoot) as RuntimeTool;
399
- const lsTool = createLsTool(projectRoot) as RuntimeTool;
400
-
401
- if (profile === "readonly") {
402
- const activeTools = [readTool, grepTool, findTool, lsTool];
403
- return {
404
- activeTools,
405
- customTools: activeTools.map((tool) => this.toCustomToolDefinition(tool)),
406
- };
407
- }
408
-
409
- const activeTools = [readTool, bashTool, editTool, writeTool];
410
- return {
411
- activeTools,
412
- customTools: activeTools.map((tool) => this.toCustomToolDefinition(tool)),
413
- };
414
- }
415
-
416
- private toCustomToolDefinition(tool: RuntimeTool): ToolDefinition {
417
- return {
418
- name: tool.name,
419
- label: tool.label,
420
- description: tool.description,
421
- parameters: tool.parameters,
422
- execute: (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, signal, onUpdate),
423
- };
424
- }
425
-
426
- private getSessionFilePath(inbound: ProviderRuntimeCreateOptions["inbound"]): string {
427
- const guildSegment = safeSegment(inbound.guildId ?? "dm");
428
- const connectorSegment = safeSegment(inbound.connectorId);
429
- const sourceSegment = safeSegment(inbound.source.id);
430
- const threadSegment = safeSegment(inbound.threadId ?? "root");
431
- const chatSegment = safeSegment(inbound.chatId);
432
-
433
- return join(
434
- this.dataConfig.sessionsDir,
435
- connectorSegment,
436
- inbound.platform,
437
- safeSegment(inbound.accountId),
438
- guildSegment,
439
- sourceSegment,
440
- threadSegment,
441
- `${chatSegment}.jsonl`,
442
- );
443
- }
444
-
445
- private getEphemeralSessionFilePath(conversationKey: string): string {
446
- return join(
447
- this.dataConfig.sessionsDir,
448
- "_cron-ephemeral",
449
- `${safeSegment(conversationKey)}.jsonl`,
450
- );
451
- }
452
- }
453
-
454
- export const providerPiContribution: ProviderContributionModule = {
455
- kind: "provider",
456
- configSchema: z.toJSONSchema(piProviderConfigSchema),
457
- createInstance(options) {
458
- const parsed = piProviderConfigSchema.parse(options.config);
459
- const agentDir = normalizeMaybePath(options.host.configBaseDir, parsed.agentDir);
460
- const authFile = normalizeMaybePath(options.host.configBaseDir, parsed.authFile);
461
- const modelsFile = normalizeMaybePath(options.host.configBaseDir, parsed.modelsFile);
462
-
463
- const normalizedConfig: PiProviderConfig = {
464
- provider: parsed.provider,
465
- model: parsed.model,
466
- thinkingLevel: parsed.thinkingLevel,
467
- ...(agentDir ? { agentDir } : {}),
468
- ...(authFile ? { authFile } : {}),
469
- ...(modelsFile ? { modelsFile } : {}),
470
- };
471
-
472
- return new PiProviderInstanceImpl(options.instanceId, normalizedConfig, options.data, options.host.logger);
473
- },
474
- };
475
-
476
- export default providerPiContribution;
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "types": ["node"],
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "skipLibCheck": true,
13
- "noUncheckedIndexedAccess": true,
14
- "exactOptionalPropertyTypes": true,
15
- "resolveJsonModule": true
16
- },
17
- "include": ["src/**/*.ts"],
18
- "exclude": ["dist", "node_modules"]
19
- }
@@ -1 +0,0 @@
1
- export { sandboxBoxliteContribution as contribution, sandboxBoxliteContribution as default } from "./dist/boxlite-contribution.js";
@@ -1,17 +0,0 @@
1
- {
2
- "apiVersion": "1.0",
3
- "name": "@dobby.ai/sandbox-core",
4
- "version": "0.1.0",
5
- "contributions": [
6
- {
7
- "id": "sandbox.docker",
8
- "kind": "sandbox",
9
- "entry": "./dist/docker-contribution.js"
10
- },
11
- {
12
- "id": "sandbox.boxlite",
13
- "kind": "sandbox",
14
- "entry": "./dist/boxlite-contribution.js"
15
- }
16
- ]
17
- }
@@ -1 +0,0 @@
1
- export { sandboxDockerContribution as contribution, sandboxDockerContribution as default } from "./dist/docker-contribution.js";
@@ -1,136 +0,0 @@
1
- {
2
- "name": "@dobby.ai/sandbox-core",
3
- "version": "0.1.1",
4
- "lockfileVersion": 3,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "@dobby.ai/sandbox-core",
9
- "version": "0.1.1",
10
- "dependencies": {
11
- "@boxlite-ai/boxlite": "^0.2.11",
12
- "zod": "^4.3.6"
13
- },
14
- "devDependencies": {
15
- "@dobby.ai/plugin-sdk": "file:../plugin-sdk",
16
- "@types/node": "^22.10.5",
17
- "typescript": "^5.9.2"
18
- },
19
- "peerDependencies": {
20
- "@dobby.ai/plugin-sdk": "^0.1.0"
21
- },
22
- "peerDependenciesMeta": {
23
- "@dobby.ai/plugin-sdk": {
24
- "optional": true
25
- }
26
- }
27
- },
28
- "../plugin-sdk": {
29
- "name": "@dobby.ai/plugin-sdk",
30
- "version": "0.1.2",
31
- "dev": true
32
- },
33
- "node_modules/@boxlite-ai/boxlite": {
34
- "version": "0.2.11",
35
- "resolved": "https://registry.npmmirror.com/@boxlite-ai/boxlite/-/boxlite-0.2.11.tgz",
36
- "integrity": "sha512-IJ+jyYdsc1hmZknDtqGpRyMAMxoQfF1VFDVuPhiO59fBmoDEI5u69DzoMtyax4gzL3Q46tjYkVBvJhNtSDaxBw==",
37
- "license": "Apache-2.0",
38
- "workspaces": [
39
- "npm/*"
40
- ],
41
- "engines": {
42
- "node": ">=18.0.0"
43
- },
44
- "optionalDependencies": {
45
- "@boxlite-ai/boxlite-darwin-arm64": "0.2.11",
46
- "@boxlite-ai/boxlite-darwin-x64": "0.2.11",
47
- "@boxlite-ai/boxlite-linux-arm64-gnu": "0.2.11",
48
- "@boxlite-ai/boxlite-linux-x64-gnu": "0.2.11"
49
- },
50
- "peerDependencies": {
51
- "playwright-core": ">=1.58.0"
52
- },
53
- "peerDependenciesMeta": {
54
- "playwright-core": {
55
- "optional": true
56
- }
57
- }
58
- },
59
- "node_modules/@boxlite-ai/boxlite-darwin-arm64": {
60
- "version": "0.2.11",
61
- "resolved": "https://registry.npmmirror.com/@boxlite-ai/boxlite-darwin-arm64/-/boxlite-darwin-arm64-0.2.11.tgz",
62
- "integrity": "sha512-JjNf6S/+XqooWvFX2Zn9XjmeML/e6Errk0jzG77v8YV0k2nNmt8P1nMANb2kMPbsQn93ap9v74VnYesYdKRoNg==",
63
- "cpu": [
64
- "arm64"
65
- ],
66
- "license": "Apache-2.0",
67
- "optional": true,
68
- "os": [
69
- "darwin"
70
- ],
71
- "engines": {
72
- "node": ">=18.0.0"
73
- }
74
- },
75
- "node_modules/@boxlite-ai/boxlite-linux-x64-gnu": {
76
- "version": "0.2.11",
77
- "resolved": "https://registry.npmmirror.com/@boxlite-ai/boxlite-linux-x64-gnu/-/boxlite-linux-x64-gnu-0.2.11.tgz",
78
- "integrity": "sha512-H3a8FMc6X4KVsmlQKs2xTIlSh4KhiI52MnXV16OwcC6OWQBBadR1N6GCCKojfwpqn6yIsZc2dxoyy25YTYYf9g==",
79
- "cpu": [
80
- "x64"
81
- ],
82
- "license": "Apache-2.0",
83
- "optional": true,
84
- "os": [
85
- "linux"
86
- ],
87
- "engines": {
88
- "node": ">=18.0.0"
89
- }
90
- },
91
- "node_modules/@dobby.ai/plugin-sdk": {
92
- "resolved": "../plugin-sdk",
93
- "link": true
94
- },
95
- "node_modules/@types/node": {
96
- "version": "22.19.11",
97
- "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.19.11.tgz",
98
- "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==",
99
- "dev": true,
100
- "license": "MIT",
101
- "dependencies": {
102
- "undici-types": "~6.21.0"
103
- }
104
- },
105
- "node_modules/typescript": {
106
- "version": "5.9.3",
107
- "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
108
- "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
109
- "dev": true,
110
- "license": "Apache-2.0",
111
- "bin": {
112
- "tsc": "bin/tsc",
113
- "tsserver": "bin/tsserver"
114
- },
115
- "engines": {
116
- "node": ">=14.17"
117
- }
118
- },
119
- "node_modules/undici-types": {
120
- "version": "6.21.0",
121
- "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz",
122
- "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
123
- "dev": true,
124
- "license": "MIT"
125
- },
126
- "node_modules/zod": {
127
- "version": "4.3.6",
128
- "resolved": "https://registry.npmmirror.com/zod/-/zod-4.3.6.tgz",
129
- "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
130
- "license": "MIT",
131
- "funding": {
132
- "url": "https://github.com/sponsors/colinhacks"
133
- }
134
- }
135
- }
136
- }