@lobu/worker 3.0.9 → 3.0.13

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 (49) hide show
  1. package/dist/openclaw/session-context.d.ts.map +1 -1
  2. package/dist/openclaw/session-context.js +1 -1
  3. package/dist/openclaw/session-context.js.map +1 -1
  4. package/package.json +10 -9
  5. package/USAGE.md +0 -120
  6. package/docs/custom-base-image.md +0 -88
  7. package/scripts/worker-entrypoint.sh +0 -184
  8. package/src/__tests__/audio-provider-suggestions.test.ts +0 -198
  9. package/src/__tests__/embedded-just-bash-bootstrap.test.ts +0 -39
  10. package/src/__tests__/embedded-tools.test.ts +0 -558
  11. package/src/__tests__/instructions.test.ts +0 -59
  12. package/src/__tests__/memory-flush-runtime.test.ts +0 -138
  13. package/src/__tests__/memory-flush.test.ts +0 -64
  14. package/src/__tests__/model-resolver.test.ts +0 -156
  15. package/src/__tests__/processor.test.ts +0 -225
  16. package/src/__tests__/setup.ts +0 -109
  17. package/src/__tests__/sse-client.test.ts +0 -48
  18. package/src/__tests__/tool-policy.test.ts +0 -269
  19. package/src/__tests__/worker.test.ts +0 -89
  20. package/src/core/error-handler.ts +0 -70
  21. package/src/core/project-scanner.ts +0 -65
  22. package/src/core/types.ts +0 -125
  23. package/src/core/url-utils.ts +0 -9
  24. package/src/core/workspace.ts +0 -138
  25. package/src/embedded/just-bash-bootstrap.ts +0 -228
  26. package/src/gateway/gateway-integration.ts +0 -287
  27. package/src/gateway/message-batcher.ts +0 -128
  28. package/src/gateway/sse-client.ts +0 -955
  29. package/src/gateway/types.ts +0 -68
  30. package/src/index.ts +0 -144
  31. package/src/instructions/builder.ts +0 -80
  32. package/src/instructions/providers.ts +0 -27
  33. package/src/modules/lifecycle.ts +0 -92
  34. package/src/openclaw/custom-tools.ts +0 -290
  35. package/src/openclaw/instructions.ts +0 -38
  36. package/src/openclaw/model-resolver.ts +0 -150
  37. package/src/openclaw/plugin-loader.ts +0 -427
  38. package/src/openclaw/processor.ts +0 -216
  39. package/src/openclaw/session-context.ts +0 -277
  40. package/src/openclaw/tool-policy.ts +0 -212
  41. package/src/openclaw/tools.ts +0 -208
  42. package/src/openclaw/worker.ts +0 -1792
  43. package/src/server.ts +0 -329
  44. package/src/shared/audio-provider-suggestions.ts +0 -132
  45. package/src/shared/processor-utils.ts +0 -33
  46. package/src/shared/provider-auth-hints.ts +0 -64
  47. package/src/shared/tool-display-config.ts +0 -75
  48. package/src/shared/tool-implementations.ts +0 -768
  49. package/tsconfig.json +0 -21
@@ -1,48 +0,0 @@
1
- import { afterEach, describe, expect, mock, test } from "bun:test";
2
- import { GatewayClient } from "../gateway/sse-client";
3
-
4
- describe("GatewayClient heartbeat ACKs", () => {
5
- const originalFetch = globalThis.fetch;
6
-
7
- afterEach(() => {
8
- globalThis.fetch = originalFetch;
9
- });
10
-
11
- test("ACKs heartbeat pings over the worker response endpoint", async () => {
12
- const fetchMock = mock(
13
- async (_url: string | URL | Request, _options?: RequestInit) =>
14
- new Response(JSON.stringify({ success: true }), {
15
- status: 200,
16
- headers: { "Content-Type": "application/json" },
17
- })
18
- );
19
- globalThis.fetch = fetchMock as unknown as typeof fetch;
20
-
21
- const client = new GatewayClient(
22
- "https://gateway.example.com",
23
- "worker-token",
24
- "user-1",
25
- "worker-1"
26
- );
27
-
28
- await (client as any).handleEvent(
29
- "ping",
30
- JSON.stringify({ timestamp: Date.now() })
31
- );
32
-
33
- expect(fetchMock).toHaveBeenCalledTimes(1);
34
- expect(fetchMock.mock.calls[0]?.[0]).toBe(
35
- "https://gateway.example.com/worker/response"
36
- );
37
- expect(fetchMock.mock.calls[0]?.[1]).toMatchObject({
38
- method: "POST",
39
- headers: {
40
- "Content-Type": "application/json",
41
- Authorization: "Bearer worker-token",
42
- },
43
- });
44
- expect(fetchMock.mock.calls[0]?.[1]?.body).toBe(
45
- JSON.stringify({ received: true, heartbeat: true })
46
- );
47
- });
48
- });
@@ -1,269 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import {
3
- type BashCommandPolicy,
4
- buildToolPolicy,
5
- enforceBashCommandPolicy,
6
- isToolAllowedByPolicy,
7
- normalizeToolList,
8
- } from "../openclaw/tool-policy";
9
-
10
- describe("normalizeToolList", () => {
11
- test("returns empty array for undefined", () => {
12
- expect(normalizeToolList(undefined)).toEqual([]);
13
- });
14
-
15
- test("returns empty array for empty string", () => {
16
- expect(normalizeToolList("")).toEqual([]);
17
- });
18
-
19
- test("splits comma-separated string", () => {
20
- expect(normalizeToolList("read,write,edit")).toEqual([
21
- "read",
22
- "write",
23
- "edit",
24
- ]);
25
- });
26
-
27
- test("splits newline-separated string", () => {
28
- expect(normalizeToolList("read\nwrite\nedit")).toEqual([
29
- "read",
30
- "write",
31
- "edit",
32
- ]);
33
- });
34
-
35
- test("trims whitespace from entries", () => {
36
- expect(normalizeToolList(" read , write , edit ")).toEqual([
37
- "read",
38
- "write",
39
- "edit",
40
- ]);
41
- });
42
-
43
- test("filters empty entries", () => {
44
- expect(normalizeToolList("read,,write,,")).toEqual(["read", "write"]);
45
- });
46
-
47
- test("passes through arrays", () => {
48
- expect(normalizeToolList(["read", "write"])).toEqual(["read", "write"]);
49
- });
50
- });
51
-
52
- describe("buildToolPolicy", () => {
53
- test("returns default policy with no inputs", () => {
54
- const policy = buildToolPolicy({});
55
- expect(policy.allowedPatterns).toEqual([]);
56
- expect(policy.deniedPatterns).toEqual([]);
57
- expect(policy.strictMode).toBe(false);
58
- expect(policy.bashPolicy.allowAll).toBe(false);
59
- expect(policy.bashPolicy.allowPrefixes).toEqual([]);
60
- expect(policy.bashPolicy.denyPrefixes).toContain("apt-get ");
61
- expect(policy.bashPolicy.denyPrefixes).toContain("nix-shell ");
62
- });
63
-
64
- test("merges toolsConfig with params", () => {
65
- const policy = buildToolPolicy({
66
- toolsConfig: { allowedTools: ["Read"], deniedTools: ["Write"] },
67
- allowedTools: "Edit",
68
- disallowedTools: "Bash",
69
- });
70
- expect(policy.allowedPatterns).toEqual(["Read", "Edit"]);
71
- expect(policy.deniedPatterns).toEqual(["Write", "Bash"]);
72
- });
73
-
74
- test("sets strictMode from toolsConfig", () => {
75
- const policy = buildToolPolicy({
76
- toolsConfig: { strictMode: true },
77
- });
78
- expect(policy.strictMode).toBe(true);
79
- });
80
-
81
- test("extracts Bash allow prefixes", () => {
82
- const policy = buildToolPolicy({
83
- allowedTools: ["Bash(npm:*)", "Bash(git:*)"],
84
- });
85
- expect(policy.bashPolicy.allowPrefixes).toEqual(["npm", "git"]);
86
- });
87
-
88
- test("extracts Bash deny prefixes", () => {
89
- const policy = buildToolPolicy({
90
- disallowedTools: ["Bash(rm:*)"],
91
- });
92
- expect(policy.bashPolicy.denyPrefixes).toContain("rm");
93
- expect(policy.bashPolicy.denyPrefixes).toContain("apt ");
94
- });
95
-
96
- test("detects bash allowAll when Bash is in allowed patterns", () => {
97
- const policy = buildToolPolicy({ allowedTools: ["Bash", "Read"] });
98
- expect(policy.bashPolicy.allowAll).toBe(true);
99
- });
100
-
101
- test("wildcard * enables bash allowAll", () => {
102
- const policy = buildToolPolicy({ allowedTools: ["*"] });
103
- expect(policy.bashPolicy.allowAll).toBe(true);
104
- });
105
- });
106
-
107
- describe("isToolAllowedByPolicy", () => {
108
- test("allows all tools in non-strict mode", () => {
109
- const policy = buildToolPolicy({});
110
- expect(isToolAllowedByPolicy("Read", policy)).toBe(true);
111
- expect(isToolAllowedByPolicy("Write", policy)).toBe(true);
112
- expect(isToolAllowedByPolicy("CustomTool", policy)).toBe(true);
113
- });
114
-
115
- test("denies explicitly denied tools", () => {
116
- const policy = buildToolPolicy({ disallowedTools: ["Write"] });
117
- expect(isToolAllowedByPolicy("Write", policy)).toBe(false);
118
- expect(isToolAllowedByPolicy("Read", policy)).toBe(true);
119
- });
120
-
121
- test("allows bash in non-strict mode even without explicit allow", () => {
122
- const policy = buildToolPolicy({});
123
- expect(isToolAllowedByPolicy("Bash", policy)).toBe(true);
124
- });
125
-
126
- test("blocks bash in strict mode without explicit allow", () => {
127
- const policy = buildToolPolicy({
128
- toolsConfig: { strictMode: true },
129
- });
130
- expect(isToolAllowedByPolicy("Bash", policy)).toBe(false);
131
- });
132
-
133
- test("allows bash in strict mode with explicit allow", () => {
134
- const policy = buildToolPolicy({
135
- toolsConfig: { strictMode: true, allowedTools: ["Bash"] },
136
- });
137
- expect(isToolAllowedByPolicy("Bash", policy)).toBe(true);
138
- });
139
-
140
- test("allows bash in strict mode with command allowlist", () => {
141
- const policy = buildToolPolicy({
142
- toolsConfig: { strictMode: true },
143
- allowedTools: ["Bash(npm:*)"],
144
- });
145
- expect(isToolAllowedByPolicy("Bash", policy)).toBe(true);
146
- });
147
-
148
- test("blocks non-allowed tools in strict mode", () => {
149
- const policy = buildToolPolicy({
150
- toolsConfig: { strictMode: true, allowedTools: ["Read"] },
151
- });
152
- expect(isToolAllowedByPolicy("Read", policy)).toBe(true);
153
- expect(isToolAllowedByPolicy("Write", policy)).toBe(false);
154
- });
155
-
156
- test("wildcard in allowed patterns allows all tools", () => {
157
- const policy = buildToolPolicy({
158
- toolsConfig: { strictMode: true, allowedTools: ["*"] },
159
- });
160
- expect(isToolAllowedByPolicy("AnythingGoes", policy)).toBe(true);
161
- });
162
-
163
- test("case-insensitive tool matching", () => {
164
- const policy = buildToolPolicy({ disallowedTools: ["write"] });
165
- expect(isToolAllowedByPolicy("Write", policy)).toBe(false);
166
- expect(isToolAllowedByPolicy("WRITE", policy)).toBe(false);
167
- });
168
-
169
- test("Bash filters in deny list do not block non-Bash tool matching", () => {
170
- // Bash(rm:*) should only affect bash command filtering, not block the Bash tool itself
171
- const policy = buildToolPolicy({ disallowedTools: ["Bash(rm:*)"] });
172
- expect(isToolAllowedByPolicy("Bash", policy)).toBe(true);
173
- });
174
- });
175
-
176
- describe("enforceBashCommandPolicy", () => {
177
- test("allows empty command", () => {
178
- const policy: BashCommandPolicy = {
179
- allowAll: false,
180
- allowPrefixes: [],
181
- denyPrefixes: [],
182
- };
183
- expect(() => enforceBashCommandPolicy("", policy)).not.toThrow();
184
- expect(() => enforceBashCommandPolicy(" ", policy)).not.toThrow();
185
- });
186
-
187
- test("throws on denied prefix match", () => {
188
- const policy: BashCommandPolicy = {
189
- allowAll: true,
190
- allowPrefixes: [],
191
- denyPrefixes: ["rm"],
192
- };
193
- expect(() => enforceBashCommandPolicy("rm -rf /", policy)).toThrow(
194
- "Bash command denied by policy"
195
- );
196
- });
197
-
198
- test("deny check is case-insensitive", () => {
199
- const policy: BashCommandPolicy = {
200
- allowAll: true,
201
- allowPrefixes: [],
202
- denyPrefixes: ["rm"],
203
- };
204
- expect(() => enforceBashCommandPolicy("RM -rf /", policy)).toThrow(
205
- "Bash command denied by policy"
206
- );
207
- });
208
-
209
- test("package manager commands are blocked", () => {
210
- const policy = buildToolPolicy({});
211
- expect(() =>
212
- enforceBashCommandPolicy("apt-get install -y ffmpeg", policy.bashPolicy)
213
- ).toThrow("Bash command denied by policy");
214
- });
215
-
216
- test("allows all when allowAll is true", () => {
217
- const policy: BashCommandPolicy = {
218
- allowAll: true,
219
- allowPrefixes: [],
220
- denyPrefixes: [],
221
- };
222
- expect(() =>
223
- enforceBashCommandPolicy("any command here", policy)
224
- ).not.toThrow();
225
- });
226
-
227
- test("allows when no allow prefixes (no filter)", () => {
228
- const policy: BashCommandPolicy = {
229
- allowAll: false,
230
- allowPrefixes: [],
231
- denyPrefixes: [],
232
- };
233
- expect(() =>
234
- enforceBashCommandPolicy("some command", policy)
235
- ).not.toThrow();
236
- });
237
-
238
- test("allows commands matching allow prefixes", () => {
239
- const policy: BashCommandPolicy = {
240
- allowAll: false,
241
- allowPrefixes: ["npm", "git"],
242
- denyPrefixes: [],
243
- };
244
- expect(() => enforceBashCommandPolicy("npm install", policy)).not.toThrow();
245
- expect(() => enforceBashCommandPolicy("git status", policy)).not.toThrow();
246
- });
247
-
248
- test("rejects commands not matching allow prefixes", () => {
249
- const policy: BashCommandPolicy = {
250
- allowAll: false,
251
- allowPrefixes: ["npm", "git"],
252
- denyPrefixes: [],
253
- };
254
- expect(() =>
255
- enforceBashCommandPolicy("curl http://example.com", policy)
256
- ).toThrow("Bash command not allowed by policy");
257
- });
258
-
259
- test("deny takes priority over allow", () => {
260
- const policy: BashCommandPolicy = {
261
- allowAll: false,
262
- allowPrefixes: ["rm"],
263
- denyPrefixes: ["rm"],
264
- };
265
- expect(() => enforceBashCommandPolicy("rm file.txt", policy)).toThrow(
266
- "Bash command denied by policy"
267
- );
268
- });
269
- });
@@ -1,89 +0,0 @@
1
- /**
2
- * Tests for OpenClawWorker constructor validation and basic setup.
3
- * Full execution tests require the OpenClaw runtime and are covered
4
- * by integration tests via test-bot.sh.
5
- */
6
-
7
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
8
- import { OpenClawWorker } from "../openclaw/worker";
9
- import { mockWorkerConfig, TestHelpers } from "./setup";
10
-
11
- describe("OpenClawWorker", () => {
12
- let restoreFetch: () => void;
13
- let originalDispatcherUrl: string | undefined;
14
- let originalWorkerToken: string | undefined;
15
-
16
- beforeEach(() => {
17
- originalDispatcherUrl = process.env.DISPATCHER_URL;
18
- originalWorkerToken = process.env.WORKER_TOKEN;
19
- process.env.DISPATCHER_URL = "https://test-dispatcher.example.com";
20
- process.env.WORKER_TOKEN = "test-worker-token";
21
- restoreFetch = TestHelpers.mockFetch();
22
- });
23
-
24
- afterEach(() => {
25
- restoreFetch();
26
- if (originalDispatcherUrl) {
27
- process.env.DISPATCHER_URL = originalDispatcherUrl;
28
- } else {
29
- delete process.env.DISPATCHER_URL;
30
- }
31
- if (originalWorkerToken) {
32
- process.env.WORKER_TOKEN = originalWorkerToken;
33
- } else {
34
- delete process.env.WORKER_TOKEN;
35
- }
36
- });
37
-
38
- test("constructor requires DISPATCHER_URL", () => {
39
- const original = process.env.DISPATCHER_URL;
40
- delete process.env.DISPATCHER_URL;
41
-
42
- expect(
43
- () => new OpenClawWorker({ ...mockWorkerConfig, sessionKey: "missing" })
44
- ).toThrow(
45
- "DISPATCHER_URL and WORKER_TOKEN environment variables are required"
46
- );
47
-
48
- process.env.DISPATCHER_URL = original;
49
- });
50
-
51
- test("constructor requires WORKER_TOKEN", () => {
52
- const original = process.env.WORKER_TOKEN;
53
- delete process.env.WORKER_TOKEN;
54
-
55
- expect(
56
- () => new OpenClawWorker({ ...mockWorkerConfig, sessionKey: "missing" })
57
- ).toThrow(
58
- "DISPATCHER_URL and WORKER_TOKEN environment variables are required"
59
- );
60
-
61
- process.env.WORKER_TOKEN = original;
62
- });
63
-
64
- test("constructor requires teamId", () => {
65
- expect(
66
- () => new OpenClawWorker({ ...mockWorkerConfig, teamId: undefined })
67
- ).toThrow("teamId is required for worker initialization");
68
- });
69
-
70
- test("constructor requires conversationId", () => {
71
- expect(
72
- () =>
73
- new OpenClawWorker({
74
- ...mockWorkerConfig,
75
- conversationId: undefined as any,
76
- })
77
- ).toThrow("conversationId is required for worker initialization");
78
- });
79
-
80
- test("getWorkerTransport returns transport after construction", () => {
81
- const worker = new OpenClawWorker(mockWorkerConfig);
82
- expect(worker.getWorkerTransport()).not.toBeNull();
83
- });
84
-
85
- test("cleanup completes without error", async () => {
86
- const worker = new OpenClawWorker(mockWorkerConfig);
87
- await expect(worker.cleanup()).resolves.toBeUndefined();
88
- });
89
- });
@@ -1,70 +0,0 @@
1
- import { createLogger, type WorkerTransport } from "@lobu/core";
2
-
3
- const logger = createLogger("worker");
4
-
5
- /**
6
- * Format error message for display
7
- * Generic error formatter that works for any AI agent
8
- */
9
- function formatErrorMessage(error: unknown): string {
10
- let errorMsg = `💥 Worker crashed`;
11
-
12
- if (error instanceof Error) {
13
- errorMsg += `: ${error.message}`;
14
- // Add error type if it's not generic
15
- if (
16
- error.constructor.name !== "Error" &&
17
- error.constructor.name !== "WorkspaceError"
18
- ) {
19
- errorMsg = `💥 Worker crashed (${error.constructor.name}): ${error.message}`;
20
- }
21
- } else {
22
- errorMsg += ": Unknown error";
23
- }
24
-
25
- return errorMsg;
26
- }
27
-
28
- function classifyError(error: unknown): string | undefined {
29
- if (!(error instanceof Error)) return undefined;
30
- if (
31
- error.message.includes("No model configured") ||
32
- error.message.includes("No provider specified")
33
- )
34
- return "NO_MODEL_CONFIGURED";
35
- return undefined;
36
- }
37
-
38
- /**
39
- * Handle execution error - decides between authentication and generic errors
40
- * Generic error handler that works for any AI agent
41
- */
42
- export async function handleExecutionError(
43
- error: unknown,
44
- transport: WorkerTransport
45
- ): Promise<void> {
46
- logger.error("Worker execution failed:", error);
47
-
48
- const code = classifyError(error);
49
-
50
- try {
51
- if (code) {
52
- // Known error — clean message, no "Worker crashed" text
53
- await transport.signalError(
54
- error instanceof Error ? error : new Error(String(error)),
55
- code
56
- );
57
- } else {
58
- // Unknown error — existing behavior
59
- const errorMsg = formatErrorMessage(error);
60
- await transport.sendStreamDelta(errorMsg, true, true);
61
- await transport.signalError(
62
- error instanceof Error ? error : new Error(String(error))
63
- );
64
- }
65
- } catch (gatewayError) {
66
- logger.error("Failed to send error via gateway:", gatewayError);
67
- // Re-throw the original error
68
- throw error;
69
- }
70
- }
@@ -1,65 +0,0 @@
1
- import fs from "node:fs";
2
-
3
- /**
4
- * Scan a directory tree and find all project directories
5
- * A project directory is one that contains a build config file
6
- * (Makefile, package.json, pyproject.toml, etc.)
7
- *
8
- * Generic utility that works for any AI agent
9
- */
10
- export function listAppDirectories(rootDirectory: string): string[] {
11
- const foundDirectories: string[] = [];
12
- const ignored = new Set([
13
- "node_modules",
14
- ".git",
15
- ".next",
16
- "dist",
17
- "build",
18
- "vendor",
19
- "target",
20
- ".venv",
21
- "venv",
22
- ]);
23
-
24
- const buildConfigFiles = new Set([
25
- "Makefile",
26
- "makefile",
27
- "package.json",
28
- "pyproject.toml",
29
- "Cargo.toml",
30
- "pom.xml",
31
- "build.gradle",
32
- "build.gradle.kts",
33
- "CMakeLists.txt",
34
- "go.mod",
35
- ]);
36
-
37
- const walk = (dir: string): void => {
38
- let entries: fs.Dirent[] = [];
39
- try {
40
- entries = fs.readdirSync(dir, { withFileTypes: true });
41
- } catch {
42
- return;
43
- }
44
-
45
- // Check if current directory has any build config files
46
- const hasConfigFile = entries.some(
47
- (entry) => entry.isFile() && buildConfigFiles.has(entry.name)
48
- );
49
-
50
- if (hasConfigFile) {
51
- foundDirectories.push(dir);
52
- }
53
-
54
- // Recursively walk subdirectories
55
- for (const entry of entries) {
56
- const p = `${dir}/${entry.name}`;
57
- if (entry.isDirectory() && !ignored.has(entry.name)) {
58
- walk(p);
59
- }
60
- }
61
- };
62
-
63
- walk(rootDirectory);
64
- return foundDirectories;
65
- }
package/src/core/types.ts DELETED
@@ -1,125 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- /**
4
- * Consolidated types for worker package
5
- * Merged from: base/types.ts, types.ts, interfaces.ts
6
- */
7
-
8
- import type { WorkerTransport } from "@lobu/core";
9
-
10
- // ============================================================================
11
- // WORKER INTERFACES
12
- // ============================================================================
13
-
14
- /**
15
- * Interface for worker executors
16
- * Allows different agent implementations
17
- */
18
- export interface WorkerExecutor {
19
- /**
20
- * Execute the worker job
21
- */
22
- execute(): Promise<void>;
23
-
24
- /**
25
- * Cleanup worker resources
26
- */
27
- cleanup(): Promise<void>;
28
-
29
- /**
30
- * Get the worker transport for sending updates to gateway
31
- */
32
- getWorkerTransport(): WorkerTransport | null;
33
- }
34
-
35
- // ============================================================================
36
- // WORKER CONFIG & WORKSPACE
37
- // ============================================================================
38
-
39
- export interface WorkerConfig {
40
- sessionKey: string;
41
- userId: string;
42
- agentId: string; // Space identifier for multi-tenant isolation
43
- channelId: string;
44
- conversationId: string;
45
- userPrompt: string; // Base64 encoded
46
- responseChannel: string; // Platform-agnostic response channel
47
- responseId: string; // Platform-agnostic response message ID
48
- botResponseId?: string; // Bot's response message ID for updates
49
- agentOptions: string; // JSON string
50
- teamId?: string; // Platform team/workspace ID (e.g., Slack team ID)
51
- platform: string; // Platform identifier (e.g., "slack", "discord")
52
- platformMetadata?: any; // Platform-specific metadata (e.g., files, user info)
53
- workspace: {
54
- baseDirectory: string;
55
- };
56
- }
57
-
58
- export interface WorkspaceSetupConfig {
59
- baseDirectory: string;
60
- }
61
-
62
- export interface WorkspaceInfo {
63
- baseDirectory: string;
64
- userDirectory: string;
65
- }
66
-
67
- // ============================================================================
68
- // PROGRESS & EXECUTION TYPES
69
- // ============================================================================
70
-
71
- /**
72
- * Progress update from AI agent execution
73
- */
74
- export type ProgressUpdate =
75
- | {
76
- type: "output";
77
- data: unknown; // Agent-specific message format
78
- timestamp: number;
79
- }
80
- | {
81
- type: "completion";
82
- data: {
83
- exitCode?: number;
84
- message?: string;
85
- success?: boolean;
86
- sessionId?: string;
87
- };
88
- timestamp: number;
89
- }
90
- | {
91
- type: "error";
92
- data: Error | { message?: string; stack?: string; error?: string };
93
- timestamp: number;
94
- }
95
- | {
96
- type: "status_update";
97
- data: {
98
- elapsedSeconds: number;
99
- state: string;
100
- };
101
- timestamp: number;
102
- };
103
-
104
- /**
105
- * Callback for receiving progress updates during AI execution
106
- */
107
- export type ProgressCallback = (update: ProgressUpdate) => Promise<void>;
108
-
109
- /**
110
- * Session context for AI execution
111
- * Contains information about the current session (platform, user, workspace)
112
- */
113
-
114
- /**
115
- * Result from session execution (includes session metadata)
116
- */
117
- export interface SessionExecutionResult {
118
- success: boolean;
119
- exitCode: number;
120
- output: string;
121
- error?: string;
122
- sessionKey: string;
123
- persisted?: boolean;
124
- storagePath?: string;
125
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Ensure URL has http:// or https:// prefix
3
- */
4
- export function ensureBaseUrl(url: string): string {
5
- if (!url.startsWith("http://") && !url.startsWith("https://")) {
6
- return `http://${url}`;
7
- }
8
- return url;
9
- }