@tangle-network/agent-app 0.18.0 → 0.19.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.
@@ -0,0 +1,146 @@
1
+ import { AgentProfileFileMount, AgentProfileMcpServer, AgentProfile, ScopedTokenScope, SandboxInstance, Sandbox } from '@tangle-network/sandbox';
2
+ import { a as AppToolName, c as ToolHeaderNames } from '../auth-BlS9GWfL.js';
3
+ import { b as AppToolContext } from '../types-2rOJo8Hc.js';
4
+ import { Harness } from '../harness/index.js';
5
+
6
+ type Outcome<T> = {
7
+ succeeded: true;
8
+ value: T;
9
+ } | {
10
+ succeeded: false;
11
+ error: Error;
12
+ };
13
+ interface SandboxClientCredentials {
14
+ apiKey: string;
15
+ baseUrl: string;
16
+ }
17
+ interface SandboxResourceConfig {
18
+ image: string;
19
+ cpuCores: number;
20
+ memoryMB: number;
21
+ diskGB: number;
22
+ maxLifetimeSeconds: number;
23
+ idleTimeoutSeconds: number;
24
+ }
25
+ interface ProviderResolutionConfig {
26
+ routerBaseUrl?: string;
27
+ apiKey?: string;
28
+ providerName?: string;
29
+ modelName?: string;
30
+ defaultModel?: string;
31
+ openaiApiKey?: string;
32
+ }
33
+ interface SandboxBuildContext {
34
+ workspaceId: string;
35
+ connectedIntegrationIds: string[];
36
+ }
37
+ interface ProfileComposeOptions {
38
+ systemPrompt?: string;
39
+ extraFiles?: AgentProfileFileMount[];
40
+ extraMcp?: Record<string, AgentProfileMcpServer>;
41
+ name?: string;
42
+ }
43
+ interface SandboxRuntimeConfig {
44
+ credentials: () => SandboxClientCredentials | null;
45
+ name: (workspaceId: string) => string;
46
+ metadata: (harness: Harness) => Record<string, unknown>;
47
+ connectedIntegrationIds: (workspaceId: string) => Promise<string[]>;
48
+ env: (ctx: SandboxBuildContext) => Promise<Record<string, string>>;
49
+ files: (ctx: SandboxBuildContext) => Promise<AgentProfileFileMount[]>;
50
+ secrets: (workspaceId: string) => Promise<string[]>;
51
+ profile: (options: ProfileComposeOptions) => AgentProfile;
52
+ permissionRole?: (workspaceRole: string) => SandboxPermissionLevel;
53
+ resources?: SandboxResourceConfig;
54
+ provider?: ProviderResolutionConfig;
55
+ }
56
+ declare const DEFAULT_SANDBOX_RESOURCES: SandboxResourceConfig;
57
+ declare function getClient(shell: SandboxRuntimeConfig): Sandbox;
58
+ declare function resetClientCache(): void;
59
+ interface AppToolDescriptor {
60
+ tool: AppToolName;
61
+ key: string;
62
+ description: string;
63
+ }
64
+ interface BuildAppToolMcpServersOptions {
65
+ tools: AppToolDescriptor[];
66
+ baseUrl: string;
67
+ token: string;
68
+ ctx: AppToolContext;
69
+ headerNames?: ToolHeaderNames;
70
+ }
71
+ declare function buildAppToolMcpServers(options: BuildAppToolMcpServersOptions): Record<string, AgentProfileMcpServer>;
72
+ interface EnsureWorkspaceSandboxOptions {
73
+ workspaceId: string;
74
+ userId?: string;
75
+ harness: Harness;
76
+ }
77
+ declare function ensureWorkspaceSandbox(shell: SandboxRuntimeConfig, options: EnsureWorkspaceSandboxOptions): Promise<SandboxInstance>;
78
+ interface ResolvedModel {
79
+ model: string;
80
+ provider: string;
81
+ apiKey: string;
82
+ baseUrl?: string;
83
+ }
84
+ declare function resolveModel(config: ProviderResolutionConfig | undefined, override?: {
85
+ model?: string;
86
+ modelApiKey?: string;
87
+ }): ResolvedModel | undefined;
88
+ declare function flattenHistory(message: string, history?: Array<{
89
+ role: 'user' | 'assistant';
90
+ content: string;
91
+ }>): string;
92
+ declare function mergeExtraMcp(appToolMcp: Record<string, AgentProfileMcpServer>, baseProfileMcp: Record<string, AgentProfileMcpServer>, extra: Record<string, AgentProfileMcpServer> | undefined): Record<string, AgentProfileMcpServer>;
93
+ declare function attachReasoningEffort(profile: AgentProfile, harness: Harness, effort: 'auto' | 'low' | 'medium' | 'high' | undefined): AgentProfile;
94
+ interface StreamSandboxPromptOptions {
95
+ sessionId?: string;
96
+ executionId?: string;
97
+ lastEventId?: string;
98
+ systemPrompt?: string;
99
+ model?: string;
100
+ modelApiKey?: string;
101
+ history?: Array<{
102
+ role: 'user' | 'assistant';
103
+ content: string;
104
+ }>;
105
+ harness?: Harness;
106
+ effort?: 'auto' | 'low' | 'medium' | 'high';
107
+ appToolMcp?: Record<string, AgentProfileMcpServer>;
108
+ baseProfileMcp?: Record<string, AgentProfileMcpServer>;
109
+ extraMcp?: Record<string, AgentProfileMcpServer>;
110
+ }
111
+ declare function streamSandboxPrompt(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options?: StreamSandboxPromptOptions): AsyncGenerator<unknown>;
112
+ declare function runSandboxPrompt(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options?: StreamSandboxPromptOptions): Promise<string>;
113
+ type SandboxPermissionLevel = 'owner' | 'admin' | 'developer' | 'viewer';
114
+ interface MemberSyncSeam {
115
+ roleToSandboxRole: (workspaceRole: string) => SandboxPermissionLevel;
116
+ }
117
+ declare function syncSandboxMemberAdd(box: SandboxInstance, seam: MemberSyncSeam, userId: string, role: string): Promise<Outcome<void>>;
118
+ declare function syncSandboxMemberRemove(box: SandboxInstance, userId: string): Promise<Outcome<void>>;
119
+ declare function syncSandboxMemberRole(box: SandboxInstance, seam: MemberSyncSeam, userId: string, role: string): Promise<Outcome<void>>;
120
+ interface SecretStore {
121
+ create: (name: string, value: string) => Promise<void>;
122
+ update: (name: string, value: string) => Promise<void>;
123
+ get: (name: string) => Promise<string>;
124
+ delete: (name: string) => Promise<void>;
125
+ }
126
+ declare function secretStoreFromClient(shell: SandboxRuntimeConfig): SecretStore;
127
+ declare function storeSecret(store: SecretStore, name: string, value: string): Promise<Outcome<void>>;
128
+ declare function readSecret(store: SecretStore, name: string): Promise<Outcome<string>>;
129
+ declare function deleteSecret(store: SecretStore, name: string): Promise<Outcome<void>>;
130
+ interface ScopedTokenResult {
131
+ token: string;
132
+ expiresAt: Date;
133
+ scope: ScopedTokenScope;
134
+ }
135
+ /**
136
+ * Mint a scoped token for an already-provisioned box (e.g. to hand a terminal
137
+ * proxy a narrowed credential). Uses the SDK's native `box.mintScopedToken`,
138
+ * which normalizes `expiresAt` to a Date — no hand-rolled wire call.
139
+ */
140
+ declare function mintSandboxScopedToken(box: SandboxInstance, options: {
141
+ scope: ScopedTokenScope;
142
+ sessionId?: string;
143
+ ttlMinutes?: number;
144
+ }): Promise<Outcome<ScopedTokenResult>>;
145
+
146
+ export { type AppToolDescriptor, type BuildAppToolMcpServersOptions, DEFAULT_SANDBOX_RESOURCES, type EnsureWorkspaceSandboxOptions, type MemberSyncSeam, type Outcome, type ProfileComposeOptions, type ProviderResolutionConfig, type ResolvedModel, type SandboxBuildContext, type SandboxClientCredentials, type SandboxPermissionLevel, type SandboxResourceConfig, type SandboxRuntimeConfig, type ScopedTokenResult, type SecretStore, type StreamSandboxPromptOptions, attachReasoningEffort, buildAppToolMcpServers, deleteSecret, ensureWorkspaceSandbox, flattenHistory, getClient, mergeExtraMcp, mintSandboxScopedToken, readSecret, resetClientCache, resolveModel, runSandboxPrompt, secretStoreFromClient, storeSecret, streamSandboxPrompt, syncSandboxMemberAdd, syncSandboxMemberRemove, syncSandboxMemberRole };
@@ -0,0 +1,304 @@
1
+ import "../chunk-MH6AVXQ7.js";
2
+ import {
3
+ buildAppToolMcpServer
4
+ } from "../chunk-A76ZHWNF.js";
5
+ import "../chunk-JZZ6AWF4.js";
6
+
7
+ // src/sandbox/index.ts
8
+ import {
9
+ Sandbox
10
+ } from "@tangle-network/sandbox";
11
+ var ok = (value) => ({ succeeded: true, value });
12
+ var fail = (error) => ({
13
+ succeeded: false,
14
+ error: error instanceof Error ? error : new Error(String(error))
15
+ });
16
+ var DEFAULT_SANDBOX_RESOURCES = {
17
+ image: "universal",
18
+ cpuCores: 2,
19
+ memoryMB: 4096,
20
+ diskGB: 10,
21
+ maxLifetimeSeconds: 86400,
22
+ idleTimeoutSeconds: 3600
23
+ };
24
+ var _cached = null;
25
+ function getClient(shell) {
26
+ const creds = shell.credentials();
27
+ if (!creds) throw new Error("sandbox credentials are required (apiKey/baseUrl)");
28
+ const fingerprint = `${creds.apiKey} ${creds.baseUrl}`;
29
+ if (_cached && _cached.fingerprint === fingerprint) return _cached.client;
30
+ const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl });
31
+ _cached = { client, fingerprint };
32
+ return client;
33
+ }
34
+ function resetClientCache() {
35
+ _cached = null;
36
+ }
37
+ function buildAppToolMcpServers(options) {
38
+ const entries = {};
39
+ for (const { tool, key, description } of options.tools) {
40
+ entries[key] = buildAppToolMcpServer({
41
+ tool,
42
+ baseUrl: options.baseUrl,
43
+ token: options.token,
44
+ ctx: options.ctx,
45
+ description,
46
+ headerNames: options.headerNames
47
+ });
48
+ }
49
+ return entries;
50
+ }
51
+ async function listRunning(client, name) {
52
+ try {
53
+ const running = await client.list({ status: "running" });
54
+ return ok(running.find((s) => s.name === name) ?? null);
55
+ } catch (err) {
56
+ return fail(err);
57
+ }
58
+ }
59
+ async function deleteBox(box) {
60
+ try {
61
+ await box.delete();
62
+ return ok(void 0);
63
+ } catch (err) {
64
+ return fail(err);
65
+ }
66
+ }
67
+ async function ensureWorkspaceSandbox(shell, options) {
68
+ const { workspaceId, userId, harness } = options;
69
+ const client = getClient(shell);
70
+ const name = shell.name(workspaceId);
71
+ const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES;
72
+ const existing = await listRunning(client, name);
73
+ if (existing.succeeded && existing.value) {
74
+ const found = existing.value;
75
+ if (found.metadata?.harness === harness) return found;
76
+ const dropped = await deleteBox(found);
77
+ if (!dropped.succeeded) {
78
+ throw new Error(
79
+ `harness-mismatched sandbox ${name} (was ${String(found.metadata?.harness ?? "unknown")}, want ${harness}) could not be deleted`,
80
+ { cause: dropped.error }
81
+ );
82
+ }
83
+ }
84
+ const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId);
85
+ const buildCtx = { workspaceId, connectedIntegrationIds };
86
+ const [secrets, env, files] = await Promise.all([
87
+ shell.secrets(workspaceId),
88
+ shell.env(buildCtx),
89
+ shell.files(buildCtx)
90
+ ]);
91
+ const profile = shell.profile({ extraFiles: files });
92
+ const role = userId && shell.permissionRole ? shell.permissionRole("developer") : void 0;
93
+ const payload = {
94
+ name,
95
+ image: resources.image,
96
+ metadata: shell.metadata(harness),
97
+ ...userId ? { permissions: { initialUsers: [{ userId, role }] } } : {},
98
+ env,
99
+ secrets,
100
+ backend: { type: harness, profile },
101
+ maxLifetimeSeconds: resources.maxLifetimeSeconds,
102
+ idleTimeoutSeconds: resources.idleTimeoutSeconds,
103
+ resources: {
104
+ cpuCores: resources.cpuCores,
105
+ memoryMB: resources.memoryMB,
106
+ diskGB: resources.diskGB
107
+ }
108
+ };
109
+ const box = await client.create(payload);
110
+ await box.waitFor("running", { timeoutMs: 12e4 });
111
+ if (!box.connection?.runtimeUrl) await box.refresh();
112
+ return box;
113
+ }
114
+ function resolveModel(config, override) {
115
+ const c = config ?? {};
116
+ const explicitBaseUrl = c.routerBaseUrl;
117
+ const explicitApiKey = override?.modelApiKey ?? c.apiKey;
118
+ const provider = c.providerName ?? (explicitApiKey ? "openai-compat" : c.openaiApiKey ? "openai" : void 0);
119
+ const modelName = override?.model ?? c.modelName ?? (provider === "openai" || provider === "openai-compat" ? c.defaultModel : void 0);
120
+ const apiKey = explicitApiKey ?? (provider === "openai" ? c.openaiApiKey : void 0);
121
+ if (!provider || !modelName || !apiKey) return void 0;
122
+ return {
123
+ model: modelName,
124
+ provider,
125
+ apiKey,
126
+ ...explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}
127
+ };
128
+ }
129
+ function flattenHistory(message, history) {
130
+ if (!history?.length) return message;
131
+ const transcript = history.map((entry) => `${entry.role === "assistant" ? "Assistant" : "User"}: ${entry.content}`).join("\n\n");
132
+ return `${transcript}
133
+
134
+ User: ${message}`;
135
+ }
136
+ function mergeExtraMcp(appToolMcp, baseProfileMcp, extra) {
137
+ for (const key of Object.keys(extra ?? {})) {
138
+ if (key in appToolMcp || key in baseProfileMcp) {
139
+ throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`);
140
+ }
141
+ }
142
+ return { ...appToolMcp, ...extra ?? {} };
143
+ }
144
+ function attachReasoningEffort(profile, harness, effort) {
145
+ if (!effort || effort === "auto") return profile;
146
+ return {
147
+ ...profile,
148
+ extensions: {
149
+ ...profile.extensions ?? {},
150
+ [harness]: {
151
+ ...profile.extensions?.[harness] ?? {},
152
+ reasoningEffort: effort
153
+ }
154
+ }
155
+ };
156
+ }
157
+ async function* streamSandboxPrompt(shell, box, message, options) {
158
+ const harness = options?.harness ?? "opencode";
159
+ const model = resolveModel(shell.provider, {
160
+ model: options?.model,
161
+ modelApiKey: options?.modelApiKey
162
+ });
163
+ const prompt = flattenHistory(message, options?.history);
164
+ const appToolMcp = options?.appToolMcp ?? {};
165
+ const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp);
166
+ const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp });
167
+ const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort);
168
+ const stream = box.streamPrompt(prompt, {
169
+ sessionId: options?.sessionId,
170
+ executionId: options?.executionId,
171
+ lastEventId: options?.lastEventId,
172
+ backend: {
173
+ type: harness,
174
+ profile: profileWithEffort,
175
+ ...model ? { model } : {}
176
+ }
177
+ });
178
+ for await (const event of stream) yield event;
179
+ }
180
+ async function runSandboxPrompt(shell, box, message, options) {
181
+ let fullText = "";
182
+ let firstTextSeen = false;
183
+ for await (const rawEvent of streamSandboxPrompt(shell, box, message, options)) {
184
+ const event = rawEvent;
185
+ if (!event.type) continue;
186
+ if (event.type === "message.part.updated") {
187
+ const part = event.data?.part;
188
+ const delta = typeof event.data?.delta === "string" ? event.data.delta : null;
189
+ if (String(part?.type ?? "") === "text") {
190
+ if (!firstTextSeen) {
191
+ firstTextSeen = true;
192
+ continue;
193
+ }
194
+ if (delta) fullText += delta;
195
+ else if (typeof part?.text === "string") fullText = part.text;
196
+ }
197
+ } else if (event.type === "result") {
198
+ const finalText = typeof event.data?.finalText === "string" ? event.data.finalText : null;
199
+ if (finalText) fullText = finalText;
200
+ }
201
+ }
202
+ return fullText;
203
+ }
204
+ async function syncSandboxMemberAdd(box, seam, userId, role) {
205
+ try {
206
+ await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) });
207
+ return ok(void 0);
208
+ } catch (err) {
209
+ return fail(err);
210
+ }
211
+ }
212
+ async function syncSandboxMemberRemove(box, userId) {
213
+ try {
214
+ await box.permissions.remove(userId, { preserveHomeDir: true });
215
+ return ok(void 0);
216
+ } catch (err) {
217
+ return fail(err);
218
+ }
219
+ }
220
+ async function syncSandboxMemberRole(box, seam, userId, role) {
221
+ try {
222
+ await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) });
223
+ return ok(void 0);
224
+ } catch (err) {
225
+ return fail(err);
226
+ }
227
+ }
228
+ function secretStoreFromClient(shell) {
229
+ const client = getClient(shell);
230
+ return {
231
+ create: async (name, value) => {
232
+ await client.secrets.create(name, value);
233
+ },
234
+ update: async (name, value) => {
235
+ await client.secrets.update(name, value);
236
+ },
237
+ get: (name) => client.secrets.get(name),
238
+ delete: async (name) => {
239
+ await client.secrets.delete(name);
240
+ }
241
+ };
242
+ }
243
+ async function storeSecret(store, name, value) {
244
+ try {
245
+ await store.create(name, value);
246
+ return ok(void 0);
247
+ } catch {
248
+ try {
249
+ await store.update(name, value);
250
+ return ok(void 0);
251
+ } catch (err) {
252
+ return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }));
253
+ }
254
+ }
255
+ }
256
+ async function readSecret(store, name) {
257
+ try {
258
+ return ok(await store.get(name));
259
+ } catch (err) {
260
+ return fail(err);
261
+ }
262
+ }
263
+ async function deleteSecret(store, name) {
264
+ try {
265
+ await store.delete(name);
266
+ return ok(void 0);
267
+ } catch (err) {
268
+ return fail(err);
269
+ }
270
+ }
271
+ async function mintSandboxScopedToken(box, options) {
272
+ try {
273
+ const token = await box.mintScopedToken({
274
+ scope: options.scope,
275
+ ...options.sessionId ? { sessionId: options.sessionId } : {},
276
+ ...options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}
277
+ });
278
+ return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope });
279
+ } catch (err) {
280
+ return fail(err);
281
+ }
282
+ }
283
+ export {
284
+ DEFAULT_SANDBOX_RESOURCES,
285
+ attachReasoningEffort,
286
+ buildAppToolMcpServers,
287
+ deleteSecret,
288
+ ensureWorkspaceSandbox,
289
+ flattenHistory,
290
+ getClient,
291
+ mergeExtraMcp,
292
+ mintSandboxScopedToken,
293
+ readSecret,
294
+ resetClientCache,
295
+ resolveModel,
296
+ runSandboxPrompt,
297
+ secretStoreFromClient,
298
+ storeSecret,
299
+ streamSandboxPrompt,
300
+ syncSandboxMemberAdd,
301
+ syncSandboxMemberRemove,
302
+ syncSandboxMemberRole
303
+ };
304
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/sandbox/index.ts"],"sourcesContent":["import {\n Sandbox,\n type AgentProfile,\n type AgentProfileFileMount,\n type AgentProfileMcpServer,\n type SandboxInstance,\n type ScopedTokenScope,\n} from '@tangle-network/sandbox'\nimport {\n buildAppToolMcpServer,\n type AppToolName,\n type AppToolContext,\n type ToolHeaderNames,\n} from '../tools/index'\nimport type { Harness } from '../harness/index'\n\nexport type Outcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: Error }\n\nconst ok = <T>(value: T): Outcome<T> => ({ succeeded: true, value })\nconst fail = (error: unknown): Outcome<never> => ({\n succeeded: false,\n error: error instanceof Error ? error : new Error(String(error)),\n})\n\nexport interface SandboxClientCredentials {\n apiKey: string\n baseUrl: string\n}\n\nexport interface SandboxResourceConfig {\n image: string\n cpuCores: number\n memoryMB: number\n diskGB: number\n maxLifetimeSeconds: number\n idleTimeoutSeconds: number\n}\n\nexport interface ProviderResolutionConfig {\n routerBaseUrl?: string\n apiKey?: string\n providerName?: string\n modelName?: string\n defaultModel?: string\n openaiApiKey?: string\n}\n\nexport interface SandboxBuildContext {\n workspaceId: string\n connectedIntegrationIds: string[]\n}\n\nexport interface ProfileComposeOptions {\n systemPrompt?: string\n extraFiles?: AgentProfileFileMount[]\n extraMcp?: Record<string, AgentProfileMcpServer>\n name?: string\n}\n\nexport interface SandboxRuntimeConfig {\n credentials: () => SandboxClientCredentials | null\n name: (workspaceId: string) => string\n metadata: (harness: Harness) => Record<string, unknown>\n connectedIntegrationIds: (workspaceId: string) => Promise<string[]>\n env: (ctx: SandboxBuildContext) => Promise<Record<string, string>>\n files: (ctx: SandboxBuildContext) => Promise<AgentProfileFileMount[]>\n secrets: (workspaceId: string) => Promise<string[]>\n profile: (options: ProfileComposeOptions) => AgentProfile\n permissionRole?: (workspaceRole: string) => SandboxPermissionLevel\n resources?: SandboxResourceConfig\n provider?: ProviderResolutionConfig\n}\n\nexport const DEFAULT_SANDBOX_RESOURCES: SandboxResourceConfig = {\n image: 'universal',\n cpuCores: 2,\n memoryMB: 4096,\n diskGB: 10,\n maxLifetimeSeconds: 86400,\n idleTimeoutSeconds: 3600,\n}\n\ninterface ClientCacheEntry {\n client: Sandbox\n fingerprint: string\n}\n\nlet _cached: ClientCacheEntry | null = null\n\nexport function getClient(shell: SandboxRuntimeConfig): Sandbox {\n const creds = shell.credentials()\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n\n const fingerprint = `${creds.apiKey} ${creds.baseUrl}`\n if (_cached && _cached.fingerprint === fingerprint) return _cached.client\n\n const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl })\n _cached = { client, fingerprint }\n return client\n}\n\nexport function resetClientCache(): void {\n _cached = null\n}\n\nexport interface AppToolDescriptor {\n tool: AppToolName\n key: string\n description: string\n}\n\nexport interface BuildAppToolMcpServersOptions {\n tools: AppToolDescriptor[]\n baseUrl: string\n token: string\n ctx: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\nexport function buildAppToolMcpServers(\n options: BuildAppToolMcpServersOptions,\n): Record<string, AgentProfileMcpServer> {\n const entries: Record<string, AgentProfileMcpServer> = {}\n for (const { tool, key, description } of options.tools) {\n entries[key] = buildAppToolMcpServer({\n tool,\n baseUrl: options.baseUrl,\n token: options.token,\n ctx: options.ctx,\n description,\n headerNames: options.headerNames,\n }) as AgentProfileMcpServer\n }\n return entries\n}\n\nexport interface EnsureWorkspaceSandboxOptions {\n workspaceId: string\n userId?: string\n harness: Harness\n}\n\nasync function listRunning(\n client: Sandbox,\n name: string,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const running = await client.list({ status: 'running' })\n return ok(running.find((s) => s.name === name) ?? null)\n } catch (err) {\n return fail(err)\n }\n}\n\nasync function deleteBox(box: SandboxInstance): Promise<Outcome<void>> {\n try {\n await box.delete()\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\n// The SDK narrows `backend.type` to its own BackendType union and\n// `initialUsers[].role` to PermissionLevel — neither symbol is exported. The\n// create payload is assembled with the product's Harness/role strings, which\n// are a superset surface; the localized cast at the boundary is the only place\n// this widening is allowed, and the runtime contract (the sidecar boots the\n// named harness) is what enforces correctness.\ntype CreatePayload = Parameters<Sandbox['create']>[0]\n\nexport async function ensureWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n): Promise<SandboxInstance> {\n const { workspaceId, userId, harness } = options\n const client = getClient(shell)\n const name = shell.name(workspaceId)\n const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES\n\n const existing = await listRunning(client, name)\n if (existing.succeeded && existing.value) {\n const found = existing.value\n if (found.metadata?.harness === harness) return found\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(\n `harness-mismatched sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}) could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = { workspaceId, connectedIntegrationIds }\n const [secrets, env, files] = await Promise.all([\n shell.secrets(workspaceId),\n shell.env(buildCtx),\n shell.files(buildCtx),\n ])\n const profile = shell.profile({ extraFiles: files })\n\n const role = userId && shell.permissionRole ? shell.permissionRole('developer') : undefined\n\n const payload = {\n name,\n image: resources.image,\n metadata: shell.metadata(harness),\n ...(userId ? { permissions: { initialUsers: [{ userId, role }] } } : {}),\n env,\n secrets,\n backend: { type: harness, profile },\n maxLifetimeSeconds: resources.maxLifetimeSeconds,\n idleTimeoutSeconds: resources.idleTimeoutSeconds,\n resources: {\n cpuCores: resources.cpuCores,\n memoryMB: resources.memoryMB,\n diskGB: resources.diskGB,\n },\n } as CreatePayload\n\n const box = await client.create(payload)\n\n await box.waitFor('running', { timeoutMs: 120_000 })\n if (!box.connection?.runtimeUrl) await box.refresh()\n return box\n}\n\nexport interface ResolvedModel {\n model: string\n provider: string\n apiKey: string\n baseUrl?: string\n}\n\nexport function resolveModel(\n config: ProviderResolutionConfig | undefined,\n override?: { model?: string; modelApiKey?: string },\n): ResolvedModel | undefined {\n const c = config ?? {}\n const explicitBaseUrl = c.routerBaseUrl\n const explicitApiKey = override?.modelApiKey ?? c.apiKey\n const provider =\n c.providerName ?? (explicitApiKey ? 'openai-compat' : c.openaiApiKey ? 'openai' : undefined)\n const modelName =\n override?.model ??\n c.modelName ??\n (provider === 'openai' || provider === 'openai-compat' ? c.defaultModel : undefined)\n const apiKey = explicitApiKey ?? (provider === 'openai' ? c.openaiApiKey : undefined)\n if (!provider || !modelName || !apiKey) return undefined\n return {\n model: modelName,\n provider,\n apiKey,\n ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}),\n }\n}\n\nexport function flattenHistory(\n message: string,\n history?: Array<{ role: 'user' | 'assistant'; content: string }>,\n): string {\n if (!history?.length) return message\n const transcript = history\n .map((entry) => `${entry.role === 'assistant' ? 'Assistant' : 'User'}: ${entry.content}`)\n .join('\\n\\n')\n return `${transcript}\\n\\nUser: ${message}`\n}\n\nexport function mergeExtraMcp(\n appToolMcp: Record<string, AgentProfileMcpServer>,\n baseProfileMcp: Record<string, AgentProfileMcpServer>,\n extra: Record<string, AgentProfileMcpServer> | undefined,\n): Record<string, AgentProfileMcpServer> {\n for (const key of Object.keys(extra ?? {})) {\n if (key in appToolMcp || key in baseProfileMcp) {\n throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`)\n }\n }\n return { ...appToolMcp, ...(extra ?? {}) }\n}\n\nexport function attachReasoningEffort(\n profile: AgentProfile,\n harness: Harness,\n effort: 'auto' | 'low' | 'medium' | 'high' | undefined,\n): AgentProfile {\n if (!effort || effort === 'auto') return profile\n return {\n ...profile,\n extensions: {\n ...(profile.extensions ?? {}),\n [harness]: {\n ...(profile.extensions?.[harness] ?? {}),\n reasoningEffort: effort,\n },\n },\n }\n}\n\nexport interface StreamSandboxPromptOptions {\n sessionId?: string\n executionId?: string\n lastEventId?: string\n systemPrompt?: string\n model?: string\n modelApiKey?: string\n history?: Array<{ role: 'user' | 'assistant'; content: string }>\n harness?: Harness\n effort?: 'auto' | 'low' | 'medium' | 'high'\n appToolMcp?: Record<string, AgentProfileMcpServer>\n baseProfileMcp?: Record<string, AgentProfileMcpServer>\n extraMcp?: Record<string, AgentProfileMcpServer>\n}\n\ntype StreamPromptOptions = Parameters<SandboxInstance['streamPrompt']>[1]\n\nexport async function* streamSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options?: StreamSandboxPromptOptions,\n): AsyncGenerator<unknown> {\n const harness = options?.harness ?? 'opencode'\n const model = resolveModel(shell.provider, {\n model: options?.model,\n modelApiKey: options?.modelApiKey,\n })\n\n const prompt = flattenHistory(message, options?.history)\n\n const appToolMcp = options?.appToolMcp ?? {}\n const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp)\n\n const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp })\n const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort)\n\n const stream = box.streamPrompt(prompt, {\n sessionId: options?.sessionId,\n executionId: options?.executionId,\n lastEventId: options?.lastEventId,\n backend: {\n type: harness,\n profile: profileWithEffort,\n ...(model ? { model } : {}),\n },\n } as StreamPromptOptions)\n\n for await (const event of stream) yield event\n}\n\nexport async function runSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options?: StreamSandboxPromptOptions,\n): Promise<string> {\n let fullText = ''\n let firstTextSeen = false\n\n for await (const rawEvent of streamSandboxPrompt(shell, box, message, options)) {\n const event = rawEvent as { type?: string; data?: Record<string, unknown> }\n if (!event.type) continue\n\n if (event.type === 'message.part.updated') {\n const part = event.data?.part as Record<string, unknown> | undefined\n const delta = typeof event.data?.delta === 'string' ? event.data.delta : null\n if (String(part?.type ?? '') === 'text') {\n if (!firstTextSeen) {\n firstTextSeen = true\n continue\n }\n if (delta) fullText += delta\n else if (typeof part?.text === 'string') fullText = part.text\n }\n } else if (event.type === 'result') {\n const finalText = typeof event.data?.finalText === 'string' ? event.data.finalText : null\n if (finalText) fullText = finalText\n }\n }\n\n return fullText\n}\n\n// Mirrors the SDK's PermissionLevel union (not re-exported by\n// @tangle-network/sandbox). The product's role-mapping seam must produce one of\n// these; binding the seam's return type to the union makes a wrong mapping a\n// compile error rather than a runtime 400 from the orchestrator.\nexport type SandboxPermissionLevel = 'owner' | 'admin' | 'developer' | 'viewer'\n\nexport interface MemberSyncSeam {\n roleToSandboxRole: (workspaceRole: string) => SandboxPermissionLevel\n}\n\nexport async function syncSandboxMemberAdd(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRemove(\n box: SandboxInstance,\n userId: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.remove(userId, { preserveHomeDir: true })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRole(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface SecretStore {\n create: (name: string, value: string) => Promise<void>\n update: (name: string, value: string) => Promise<void>\n get: (name: string) => Promise<string>\n delete: (name: string) => Promise<void>\n}\n\nexport function secretStoreFromClient(shell: SandboxRuntimeConfig): SecretStore {\n const client = getClient(shell)\n return {\n create: async (name, value) => {\n await client.secrets.create(name, value)\n },\n update: async (name, value) => {\n await client.secrets.update(name, value)\n },\n get: (name) => client.secrets.get(name),\n delete: async (name) => {\n await client.secrets.delete(name)\n },\n }\n}\n\nexport async function storeSecret(\n store: SecretStore,\n name: string,\n value: string,\n): Promise<Outcome<void>> {\n try {\n await store.create(name, value)\n return ok(undefined)\n } catch {\n try {\n await store.update(name, value)\n return ok(undefined)\n } catch (err) {\n return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }))\n }\n }\n}\n\nexport async function readSecret(store: SecretStore, name: string): Promise<Outcome<string>> {\n try {\n return ok(await store.get(name))\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function deleteSecret(store: SecretStore, name: string): Promise<Outcome<void>> {\n try {\n await store.delete(name)\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface ScopedTokenResult {\n token: string\n expiresAt: Date\n scope: ScopedTokenScope\n}\n\n/**\n * Mint a scoped token for an already-provisioned box (e.g. to hand a terminal\n * proxy a narrowed credential). Uses the SDK's native `box.mintScopedToken`,\n * which normalizes `expiresAt` to a Date — no hand-rolled wire call.\n */\nexport async function mintSandboxScopedToken(\n box: SandboxInstance,\n options: { scope: ScopedTokenScope; sessionId?: string; ttlMinutes?: number },\n): Promise<Outcome<ScopedTokenResult>> {\n try {\n const token = await box.mintScopedToken({\n scope: options.scope,\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...(options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}),\n })\n return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope })\n } catch (err) {\n return fail(err)\n }\n}"],"mappings":";;;;;;;AAAA;AAAA,EACE;AAAA,OAMK;AAaP,IAAM,KAAK,CAAI,WAA0B,EAAE,WAAW,MAAM,MAAM;AAClE,IAAM,OAAO,CAAC,WAAoC;AAAA,EAChD,WAAW;AAAA,EACX,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACjE;AAmDO,IAAM,4BAAmD;AAAA,EAC9D,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,oBAAoB;AAAA,EACpB,oBAAoB;AACtB;AAOA,IAAI,UAAmC;AAEhC,SAAS,UAAU,OAAsC;AAC9D,QAAM,QAAQ,MAAM,YAAY;AAChC,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,mDAAmD;AAE/E,QAAM,cAAc,GAAG,MAAM,MAAM,IAAI,MAAM,OAAO;AACpD,MAAI,WAAW,QAAQ,gBAAgB,YAAa,QAAO,QAAQ;AAEnE,QAAM,SAAS,IAAI,QAAQ,EAAE,QAAQ,MAAM,QAAQ,SAAS,MAAM,QAAQ,CAAC;AAC3E,YAAU,EAAE,QAAQ,YAAY;AAChC,SAAO;AACT;AAEO,SAAS,mBAAyB;AACvC,YAAU;AACZ;AAgBO,SAAS,uBACd,SACuC;AACvC,QAAM,UAAiD,CAAC;AACxD,aAAW,EAAE,MAAM,KAAK,YAAY,KAAK,QAAQ,OAAO;AACtD,YAAQ,GAAG,IAAI,sBAAsB;AAAA,MACnC;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,KAAK,QAAQ;AAAA,MACb;AAAA,MACA,aAAa,QAAQ;AAAA,IACvB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAQA,eAAe,YACb,QACA,MAC0C;AAC1C,MAAI;AACF,UAAM,UAAU,MAAM,OAAO,KAAK,EAAE,QAAQ,UAAU,CAAC;AACvD,WAAO,GAAG,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK,IAAI;AAAA,EACxD,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAe,UAAU,KAA8C;AACrE,MAAI;AACF,UAAM,IAAI,OAAO;AACjB,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAUA,eAAsB,uBACpB,OACA,SAC0B;AAC1B,QAAM,EAAE,aAAa,QAAQ,QAAQ,IAAI;AACzC,QAAM,SAAS,UAAU,KAAK;AAC9B,QAAM,OAAO,MAAM,KAAK,WAAW;AACnC,QAAM,YAAY,MAAM,aAAa;AAErC,QAAM,WAAW,MAAM,YAAY,QAAQ,IAAI;AAC/C,MAAI,SAAS,aAAa,SAAS,OAAO;AACxC,UAAM,QAAQ,SAAS;AACvB,QAAI,MAAM,UAAU,YAAY,QAAS,QAAO;AAChD,UAAM,UAAU,MAAM,UAAU,KAAK;AACrC,QAAI,CAAC,QAAQ,WAAW;AACtB,YAAM,IAAI;AAAA,QACR,8BAA8B,IAAI,SACxB,OAAO,MAAM,UAAU,WAAW,SAAS,CAAC,UAAU,OAAO;AAAA,QACvE,EAAE,OAAO,QAAQ,MAAM;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,0BAA0B,MAAM,MAAM,wBAAwB,WAAW;AAC/E,QAAM,WAAgC,EAAE,aAAa,wBAAwB;AAC7E,QAAM,CAAC,SAAS,KAAK,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC9C,MAAM,QAAQ,WAAW;AAAA,IACzB,MAAM,IAAI,QAAQ;AAAA,IAClB,MAAM,MAAM,QAAQ;AAAA,EACtB,CAAC;AACD,QAAM,UAAU,MAAM,QAAQ,EAAE,YAAY,MAAM,CAAC;AAEnD,QAAM,OAAO,UAAU,MAAM,iBAAiB,MAAM,eAAe,WAAW,IAAI;AAElF,QAAM,UAAU;AAAA,IACd;AAAA,IACA,OAAO,UAAU;AAAA,IACjB,UAAU,MAAM,SAAS,OAAO;AAAA,IAChC,GAAI,SAAS,EAAE,aAAa,EAAE,cAAc,CAAC,EAAE,QAAQ,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC;AAAA,IACtE;AAAA,IACA;AAAA,IACA,SAAS,EAAE,MAAM,SAAS,QAAQ;AAAA,IAClC,oBAAoB,UAAU;AAAA,IAC9B,oBAAoB,UAAU;AAAA,IAC9B,WAAW;AAAA,MACT,UAAU,UAAU;AAAA,MACpB,UAAU,UAAU;AAAA,MACpB,QAAQ,UAAU;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,OAAO,OAAO,OAAO;AAEvC,QAAM,IAAI,QAAQ,WAAW,EAAE,WAAW,KAAQ,CAAC;AACnD,MAAI,CAAC,IAAI,YAAY,WAAY,OAAM,IAAI,QAAQ;AACnD,SAAO;AACT;AASO,SAAS,aACd,QACA,UAC2B;AAC3B,QAAM,IAAI,UAAU,CAAC;AACrB,QAAM,kBAAkB,EAAE;AAC1B,QAAM,iBAAiB,UAAU,eAAe,EAAE;AAClD,QAAM,WACJ,EAAE,iBAAiB,iBAAiB,kBAAkB,EAAE,eAAe,WAAW;AACpF,QAAM,YACJ,UAAU,SACV,EAAE,cACD,aAAa,YAAY,aAAa,kBAAkB,EAAE,eAAe;AAC5E,QAAM,SAAS,mBAAmB,aAAa,WAAW,EAAE,eAAe;AAC3E,MAAI,CAAC,YAAY,CAAC,aAAa,CAAC,OAAQ,QAAO;AAC/C,SAAO;AAAA,IACL,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,GAAI,kBAAkB,EAAE,SAAS,gBAAgB,IAAI,CAAC;AAAA,EACxD;AACF;AAEO,SAAS,eACd,SACA,SACQ;AACR,MAAI,CAAC,SAAS,OAAQ,QAAO;AAC7B,QAAM,aAAa,QAChB,IAAI,CAAC,UAAU,GAAG,MAAM,SAAS,cAAc,cAAc,MAAM,KAAK,MAAM,OAAO,EAAE,EACvF,KAAK,MAAM;AACd,SAAO,GAAG,UAAU;AAAA;AAAA,QAAa,OAAO;AAC1C;AAEO,SAAS,cACd,YACA,gBACA,OACuC;AACvC,aAAW,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,GAAG;AAC1C,QAAI,OAAO,cAAc,OAAO,gBAAgB;AAC9C,YAAM,IAAI,MAAM,iBAAiB,GAAG,gDAAgD;AAAA,IACtF;AAAA,EACF;AACA,SAAO,EAAE,GAAG,YAAY,GAAI,SAAS,CAAC,EAAG;AAC3C;AAEO,SAAS,sBACd,SACA,SACA,QACc;AACd,MAAI,CAAC,UAAU,WAAW,OAAQ,QAAO;AACzC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY;AAAA,MACV,GAAI,QAAQ,cAAc,CAAC;AAAA,MAC3B,CAAC,OAAO,GAAG;AAAA,QACT,GAAI,QAAQ,aAAa,OAAO,KAAK,CAAC;AAAA,QACtC,iBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAmBA,gBAAuB,oBACrB,OACA,KACA,SACA,SACyB;AACzB,QAAM,UAAU,SAAS,WAAW;AACpC,QAAM,QAAQ,aAAa,MAAM,UAAU;AAAA,IACzC,OAAO,SAAS;AAAA,IAChB,aAAa,SAAS;AAAA,EACxB,CAAC;AAED,QAAM,SAAS,eAAe,SAAS,SAAS,OAAO;AAEvD,QAAM,aAAa,SAAS,cAAc,CAAC;AAC3C,QAAM,WAAW,cAAc,YAAY,SAAS,kBAAkB,CAAC,GAAG,SAAS,QAAQ;AAE3F,QAAM,UAAU,MAAM,QAAQ,EAAE,cAAc,SAAS,cAAc,SAAS,CAAC;AAC/E,QAAM,oBAAoB,sBAAsB,SAAS,SAAS,SAAS,MAAM;AAEjF,QAAM,SAAS,IAAI,aAAa,QAAQ;AAAA,IACtC,WAAW,SAAS;AAAA,IACpB,aAAa,SAAS;AAAA,IACtB,aAAa,SAAS;AAAA,IACtB,SAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IAC3B;AAAA,EACF,CAAwB;AAExB,mBAAiB,SAAS,OAAQ,OAAM;AAC1C;AAEA,eAAsB,iBACpB,OACA,KACA,SACA,SACiB;AACjB,MAAI,WAAW;AACf,MAAI,gBAAgB;AAEpB,mBAAiB,YAAY,oBAAoB,OAAO,KAAK,SAAS,OAAO,GAAG;AAC9E,UAAM,QAAQ;AACd,QAAI,CAAC,MAAM,KAAM;AAEjB,QAAI,MAAM,SAAS,wBAAwB;AACzC,YAAM,OAAO,MAAM,MAAM;AACzB,YAAM,QAAQ,OAAO,MAAM,MAAM,UAAU,WAAW,MAAM,KAAK,QAAQ;AACzE,UAAI,OAAO,MAAM,QAAQ,EAAE,MAAM,QAAQ;AACvC,YAAI,CAAC,eAAe;AAClB,0BAAgB;AAChB;AAAA,QACF;AACA,YAAI,MAAO,aAAY;AAAA,iBACd,OAAO,MAAM,SAAS,SAAU,YAAW,KAAK;AAAA,MAC3D;AAAA,IACF,WAAW,MAAM,SAAS,UAAU;AAClC,YAAM,YAAY,OAAO,MAAM,MAAM,cAAc,WAAW,MAAM,KAAK,YAAY;AACrF,UAAI,UAAW,YAAW;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;AAYA,eAAsB,qBACpB,KACA,MACA,QACA,MACwB;AACxB,MAAI;AACF,UAAM,IAAI,YAAY,IAAI,EAAE,QAAQ,MAAM,KAAK,kBAAkB,IAAI,EAAE,CAAC;AACxE,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAsB,wBACpB,KACA,QACwB;AACxB,MAAI;AACF,UAAM,IAAI,YAAY,OAAO,QAAQ,EAAE,iBAAiB,KAAK,CAAC;AAC9D,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAsB,sBACpB,KACA,MACA,QACA,MACwB;AACxB,MAAI;AACF,UAAM,IAAI,YAAY,OAAO,QAAQ,EAAE,MAAM,KAAK,kBAAkB,IAAI,EAAE,CAAC;AAC3E,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AASO,SAAS,sBAAsB,OAA0C;AAC9E,QAAM,SAAS,UAAU,KAAK;AAC9B,SAAO;AAAA,IACL,QAAQ,OAAO,MAAM,UAAU;AAC7B,YAAM,OAAO,QAAQ,OAAO,MAAM,KAAK;AAAA,IACzC;AAAA,IACA,QAAQ,OAAO,MAAM,UAAU;AAC7B,YAAM,OAAO,QAAQ,OAAO,MAAM,KAAK;AAAA,IACzC;AAAA,IACA,KAAK,CAAC,SAAS,OAAO,QAAQ,IAAI,IAAI;AAAA,IACtC,QAAQ,OAAO,SAAS;AACtB,YAAM,OAAO,QAAQ,OAAO,IAAI;AAAA,IAClC;AAAA,EACF;AACF;AAEA,eAAsB,YACpB,OACA,MACA,OACwB;AACxB,MAAI;AACF,UAAM,MAAM,OAAO,MAAM,KAAK;AAC9B,WAAO,GAAG,MAAS;AAAA,EACrB,QAAQ;AACN,QAAI;AACF,YAAM,MAAM,OAAO,MAAM,KAAK;AAC9B,aAAO,GAAG,MAAS;AAAA,IACrB,SAAS,KAAK;AACZ,aAAO,KAAK,IAAI,MAAM,kCAAkC,IAAI,IAAI,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,IACjF;AAAA,EACF;AACF;AAEA,eAAsB,WAAW,OAAoB,MAAwC;AAC3F,MAAI;AACF,WAAO,GAAG,MAAM,MAAM,IAAI,IAAI,CAAC;AAAA,EACjC,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAsB,aAAa,OAAoB,MAAsC;AAC3F,MAAI;AACF,UAAM,MAAM,OAAO,IAAI;AACvB,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAaA,eAAsB,uBACpB,KACA,SACqC;AACrC,MAAI;AACF,UAAM,QAAQ,MAAM,IAAI,gBAAgB;AAAA,MACtC,OAAO,QAAQ;AAAA,MACf,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC5D,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,IACjE,CAAC;AACD,WAAO,GAAG,EAAE,OAAO,MAAM,OAAO,WAAW,MAAM,WAAW,OAAO,MAAM,MAAM,CAAC;AAAA,EAClF,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;","names":[]}
@@ -1,7 +1,8 @@
1
1
  import { j as SequenceMediaKind, o as SequenceTimeline, r as TimelineInterval, m as SequenceStore } from '../store-gckrNq-g.js';
2
2
  export { M as MIN_SEQUENCE_CLIP_FRAMES, N as NewSequenceClip, a as NewSequenceDecision, b as NewSequenceTrack, S as SequenceClip, c as SequenceClipMedia, d as SequenceClipPatch, e as SequenceDecision, f as SequenceExportFormat, g as SequenceExportRecord, h as SequenceExportStatus, i as SequenceFrameSnapshot, k as SequenceMeta, l as SequenceStatus, n as SequenceStoreScope, p as SequenceTrack, q as SequenceTrackKind, T as TimelineClipBounds, s as assertClipFitsSequence, t as chooseCaptionPlacement, u as clampClipDuration, v as clampClipStart, w as formatSeconds, x as formatTimecode, y as framesToSeconds, z as secondsToFrames, A as snapshotFrame, B as trackIntervals } from '../store-gckrNq-g.js';
3
3
  export { A as AddCaptionOperation, C as CaptionTargetResolution, a as CreateTrackOperation, D as DeleteClipOperation, E as ExtendSequenceOperation, M as MoveClipOperation, P as PlaceClipOperation, Q as QueueExportOperation, S as SEQUENCE_OPERATION_TYPES, b as SequenceApplyResult, c as SequenceOperation, d as SequenceOperationContext, e as SequenceOperationType, f as SequencePlan, g as SetClipDisabledOperation, h as SetClipTextOperation, i as SplitClipOperation, T as TrimClipOperation, j as applySequenceOperation, k as applySequenceOperations, l as assertSequenceMediaUrl, m as captionTrackNameForLanguage, n as lastClipEndFrame, p as parseSequenceOperations, r as resolveCaptionPlacement, o as resolveCaptionTarget, q as resolvePlaceClipTrack, v as validateAddCaption, s as validateCreateTrack, t as validateDeleteClip, u as validateExtendSequence, w as validateMoveClip, x as validatePlaceClip, y as validateQueueExport, z as validateSequenceOperation, B as validateSequenceOperations, F as validateSetClipDisabled, G as validateSetClipText, H as validateSplitClip, I as validateTrimClip } from '../apply-Cp8c3K9D.js';
4
- import { f as ToolHeaderNames, a as AppToolMcpServer } from '../mcp-eZCmkgCF.js';
4
+ import { c as ToolHeaderNames } from '../auth-BlS9GWfL.js';
5
+ import { A as AppToolMcpServer } from '../mcp-BShTlESm.js';
5
6
  import { b as AppToolContext } from '../types-2rOJo8Hc.js';
6
7
 
7
8
  /**
@@ -1,126 +1,10 @@
1
- // src/skills/index.ts
2
- function inlineResource(name, content) {
3
- return { kind: "inline", name, content };
4
- }
5
- function skillMountPath(id) {
6
- return `~/.claude/skills/${id}/SKILL.md`;
7
- }
8
- function normalizeKey(key, anchor) {
9
- const marker = `${anchor}/`;
10
- const at = key.lastIndexOf(marker);
11
- if (at >= 0) return key.slice(at);
12
- return key.startsWith("./") ? key.slice(2) : key;
13
- }
14
- function toCorpusId(normalizedKey, anchor) {
15
- const nested = normalizedKey.match(new RegExp(`${anchor}/([^/]+)/SKILL\\.md$`));
16
- if (nested) return nested[1];
17
- const flat = normalizedKey.match(new RegExp(`${anchor}/(.+)\\.md$`));
18
- if (flat) return flat[1];
19
- return normalizedKey;
20
- }
21
- function nodeBuiltins() {
22
- const getBuiltin = globalThis.process?.getBuiltinModule;
23
- if (typeof getBuiltin !== "function") return void 0;
24
- return {
25
- fs: getBuiltin("node:fs"),
26
- path: getBuiltin("node:path"),
27
- url: getBuiltin("node:url")
28
- };
29
- }
30
- function fsWalkFlat(builtins, root) {
31
- const { fs, path } = builtins;
32
- const out = {};
33
- if (!fs.existsSync(root)) return out;
34
- const walk = (dir) => {
35
- let entries;
36
- try {
37
- entries = fs.readdirSync(dir, { withFileTypes: true });
38
- } catch {
39
- return;
40
- }
41
- for (const entry of entries) {
42
- if (entry.name.startsWith(".")) continue;
43
- const full = path.join(dir, entry.name);
44
- if (entry.isDirectory()) walk(full);
45
- else if (entry.isFile() && entry.name.endsWith(".md")) out[full] = fs.readFileSync(full, "utf8");
46
- }
47
- };
48
- walk(root);
49
- return out;
50
- }
51
- function fsWalkNested(builtins, root) {
52
- const { fs, path } = builtins;
53
- const out = {};
54
- if (!fs.existsSync(root)) return out;
55
- let entries;
56
- try {
57
- entries = fs.readdirSync(root, { withFileTypes: true });
58
- } catch {
59
- return out;
60
- }
61
- for (const entry of entries) {
62
- if (!entry.isDirectory()) continue;
63
- const skillFile = path.join(root, entry.name, "SKILL.md");
64
- if (!fs.existsSync(skillFile)) continue;
65
- out[skillFile] = fs.readFileSync(skillFile, "utf8");
66
- }
67
- return out;
68
- }
69
- function resolveFsBase(builtins, fsBaseDir, importMetaUrl) {
70
- const { path, url } = builtins;
71
- if (path.isAbsolute(fsBaseDir)) return fsBaseDir;
72
- const here = importMetaUrl ? path.dirname(url.fileURLToPath(importMetaUrl)) : process.cwd();
73
- return path.join(here, fsBaseDir);
74
- }
75
- function loadMarkdownCorpus(options, importMetaUrl) {
76
- const { anchor, globModules, fsBaseDir, fsLayout = "flat", skip } = options;
77
- let modules;
78
- let source;
79
- if (globModules && Object.keys(globModules).length > 0) {
80
- modules = globModules;
81
- source = "vite";
82
- } else {
83
- const builtins = nodeBuiltins();
84
- if (builtins && fsBaseDir) {
85
- const root = resolveFsBase(builtins, fsBaseDir, importMetaUrl);
86
- modules = fsLayout === "nested" ? fsWalkNested(builtins, root) : fsWalkFlat(builtins, root);
87
- source = Object.keys(modules).length > 0 ? "fs" : "empty";
88
- } else {
89
- modules = {};
90
- source = "empty";
91
- }
92
- }
93
- const entries = [];
94
- for (const [rawKey, content] of Object.entries(modules)) {
95
- if (typeof content !== "string") continue;
96
- const key = normalizeKey(rawKey, anchor);
97
- if (skip && skip(key)) continue;
98
- entries.push({ id: toCorpusId(key, anchor), key, content });
99
- }
100
- entries.sort((a, b) => a.id.localeCompare(b.id));
101
- return { source, entries };
102
- }
103
- function corpusSkills(corpus, anchor) {
104
- return corpus.map(
105
- (entry) => ({
106
- path: `${anchor}/${entry.id}.md`,
107
- resource: inlineResource(`${anchor}-${entry.id}`, entry.content)
108
- })
109
- ).sort((a, b) => a.path.localeCompare(b.path));
110
- }
111
- function registrySkills(registry, tier = "free") {
112
- return registry.filter((s) => s.tier === tier).map(
113
- (s) => ({
114
- path: skillMountPath(s.id),
115
- resource: inlineResource(s.id, s.skillMd)
116
- })
117
- ).sort((a, b) => a.path.localeCompare(b.path));
118
- }
119
- function composeShellResources(input) {
120
- const { skills = [], knowledge = [], evolvable = [], registry = [], predicate } = input;
121
- const composed = [...skills, ...knowledge, ...evolvable, ...registry];
122
- return predicate ? composed.filter(predicate) : composed;
123
- }
1
+ import {
2
+ composeShellResources,
3
+ corpusSkills,
4
+ loadMarkdownCorpus,
5
+ registrySkills,
6
+ skillMountPath
7
+ } from "../chunk-KOG473C4.js";
124
8
  export {
125
9
  composeShellResources,
126
10
  corpusSkills,