@larkup/sandbox 0.1.3 → 0.1.5

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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @larkup/sandbox@0.1.3 build /home/runner/work/larkup/larkup/packages/sandbox
2
+ > @larkup/sandbox@0.1.5 build /Users/abdelrahmanabounida/Desktop/my-ai-startup/larkup/larkup/packages/sandbox
3
3
  > tsc -p tsconfig.build.json --outDir dist
4
4
 
@@ -0,0 +1,18 @@
1
+
2
+ > @larkup/sandbox@0.1.5 test /Users/abdelrahmanabounida/Desktop/my-ai-startup/larkup/larkup/packages/sandbox
3
+ > vitest run
4
+
5
+
6
+  RUN  v4.1.11 /Users/abdelrahmanabounida/Desktop/my-ai-startup/larkup/larkup/packages/sandbox
7
+
8
+ ✓ src/remote-exec.test.ts (14 tests) 116ms
9
+ ✓ src/providers/flyio.test.ts (6 tests) 9ms
10
+ ✓ src/providers/modal.test.ts (4 tests) 10ms
11
+ ✓ src/providers/daytona.test.ts (5 tests) 4ms
12
+ ✓ src/providers/vercel.test.ts (6 tests) 36ms
13
+ ✓ src/providers/e2b.test.ts (9 tests) 45ms
14
+ ✓ src/providers/northflank.test.ts (7 tests) 39ms
15
+ ✓ src/local-runner.test.ts (2 tests) 505ms
16
+ ✓ runs JavaScript without Docker and returns output artifacts  359ms
17
+ ✓ src/providers/cloudflare.test.ts (6 tests) 14ms
18
+  ELIFECYCLE  Test failed. See above for more details.
@@ -0,0 +1,4 @@
1
+
2
+ > @larkup/sandbox@0.1.5 type-check /Users/abdelrahmanabounida/Desktop/my-ai-startup/larkup/larkup/packages/sandbox
3
+ > tsc --noEmit
4
+
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @larkup/sandbox
2
2
 
3
+ ## 0.1.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 848cc4c: Route spreadsheet questions through structured table queries before optional code analysis, validate local Python analysis dependencies before exposing code tools, and index every non-empty Excel worksheet as a separate dataset.
8
+
9
+ ## 0.1.4
10
+
11
+ ### Patch Changes
12
+
13
+ - 847b502: Keep global installs and updates quiet and compatible by aligning Apache Arrow with LanceDB's
14
+ supported peer range, shipping the marketplace TypeScript runtime loader, and using the renamed
15
+ Daytona SDK package. Public tarballs also scrub local project state from all traced workspaces.
16
+
3
17
  ## 0.1.3
4
18
 
5
19
  ### Patch Changes
@@ -5,6 +5,10 @@ import path from 'node:path';
5
5
  import { spawn } from 'node:child_process';
6
6
  import { getMimeType } from './mime.js';
7
7
  let pythonCommand;
8
+ // Keep this list in sync with the capabilities advertised by executeAnalysis
9
+ // and analyzeCorpusWithCode. A bare Python installation is not an analysis
10
+ // runtime, so it must not make those tools appear available.
11
+ const ANALYSIS_PYTHON_MODULES = ['numpy', 'pandas', 'matplotlib', 'scipy', 'sklearn', 'seaborn'];
8
12
  function run(command, args, cwd, timeoutMs = 10_000) {
9
13
  return new Promise((resolve, reject) => {
10
14
  const child = spawn(command.executable, [...command.args, ...args], {
@@ -38,7 +42,7 @@ function run(command, args, cwd, timeoutMs = 10_000) {
38
42
  resolve({
39
43
  stdout,
40
44
  stderr: timedOut ? `${stderr}\nExecution timed out.`.trim() : stderr,
41
- exitCode: timedOut ? 124 : code ?? 1,
45
+ exitCode: timedOut ? 124 : (code ?? 1),
42
46
  });
43
47
  });
44
48
  });
@@ -115,6 +119,28 @@ export async function checkLocalRuntime() {
115
119
  error: 'Local code execution needs Python 3. Install Python or choose Docker or a remote sandbox provider.',
116
120
  };
117
121
  }
122
+ try {
123
+ const dependencyCheck = await run(python, [
124
+ '-c',
125
+ `import importlib.util\nmodules = ${JSON.stringify(ANALYSIS_PYTHON_MODULES)}\nmissing = [name for name in modules if importlib.util.find_spec(name) is None]\nprint(','.join(missing))\nraise SystemExit(bool(missing))`,
126
+ ]);
127
+ if (dependencyCheck.exitCode !== 0) {
128
+ const missing = dependencyCheck.stdout.trim() || 'required analysis packages';
129
+ return {
130
+ status: 'error',
131
+ backend: 'local',
132
+ error: `Local Python is missing ${missing}. Install the Larkup analysis dependencies ` +
133
+ `(for example: pip install ${ANALYSIS_PYTHON_MODULES.join(' ')}) or choose Docker or a remote sandbox provider.`,
134
+ };
135
+ }
136
+ }
137
+ catch {
138
+ return {
139
+ status: 'error',
140
+ backend: 'local',
141
+ error: 'Larkup could not verify the Python analysis dependencies. Choose Docker or a remote sandbox provider.',
142
+ };
143
+ }
118
144
  return { status: 'ready', backend: 'local' };
119
145
  }
120
146
  /** Executes trusted code in a temporary host workspace and collects its output. */
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import { DEFAULT_TIMEOUT_MS, failedResult, runScriptedExecution, safeCleanup, withTimeout, } from '../remote-exec.js';
12
12
  async function loadSdk() {
13
- return (await import('@daytonaio/sdk'));
13
+ return (await import('@daytona/sdk'));
14
14
  }
15
15
  function requireFields(credentials) {
16
16
  const apiKey = credentials.apiKey?.trim();
package/dist/registry.js CHANGED
@@ -114,7 +114,7 @@ export const SANDBOX_PROVIDERS = {
114
114
  id: 'daytona',
115
115
  label: 'Daytona',
116
116
  description: 'Elastic infrastructure for running AI-generated code in fast, isolated sandboxes.',
117
- sdkPackage: '@daytonaio/sdk',
117
+ sdkPackage: '@daytona/sdk',
118
118
  docsUrl: 'https://www.daytona.io/docs/en/sandboxes/',
119
119
  icon: '/icons/daytonaio.png',
120
120
  executionSupport: 'full',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@larkup/sandbox",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -40,8 +40,8 @@
40
40
  "optionalDependencies": {
41
41
  "e2b": "^2.39.0",
42
42
  "@vercel/sandbox": "^3.0.0",
43
- "modal": "^0.9.0",
44
- "@daytonaio/sdk": "^0.204.1",
43
+ "modal": "^0.10.0",
44
+ "@daytona/sdk": "^0.207.0",
45
45
  "@browserbasehq/sdk": "^2.17.0",
46
46
  "playwright-core": "^1.62.1",
47
47
  "@fly/sprites": "^0.2.0",
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { executeLocally } from './local-runner.js';
2
+ import { checkLocalRuntime, executeLocally } from './local-runner.js';
3
3
 
4
4
  describe('executeLocally', () => {
5
5
  it('runs JavaScript without Docker and returns output artifacts', async () => {
@@ -19,4 +19,14 @@ describe('executeLocally', () => {
19
19
  expect.objectContaining({ name: 'result.txt', mimeType: 'text/plain' }),
20
20
  ]);
21
21
  });
22
+
23
+ it('does not mark a bare Python installation as analysis-ready', async () => {
24
+ const health = await checkLocalRuntime();
25
+ expect(health.backend).toBe('local');
26
+ if (health.status === 'ready') {
27
+ expect(health.error).toBeUndefined();
28
+ } else {
29
+ expect(health.error).toMatch(/Python|analysis dependenc/i);
30
+ }
31
+ });
22
32
  });
@@ -16,6 +16,11 @@ type Command = { executable: string; args: string[] };
16
16
 
17
17
  let pythonCommand: Command | null | undefined;
18
18
 
19
+ // Keep this list in sync with the capabilities advertised by executeAnalysis
20
+ // and analyzeCorpusWithCode. A bare Python installation is not an analysis
21
+ // runtime, so it must not make those tools appear available.
22
+ const ANALYSIS_PYTHON_MODULES = ['numpy', 'pandas', 'matplotlib', 'scipy', 'sklearn', 'seaborn'];
23
+
19
24
  function run(command: Command, args: string[], cwd?: string, timeoutMs = 10_000) {
20
25
  return new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve, reject) => {
21
26
  const child = spawn(command.executable, [...command.args, ...args], {
@@ -49,7 +54,7 @@ function run(command: Command, args: string[], cwd?: string, timeoutMs = 10_000)
49
54
  resolve({
50
55
  stdout,
51
56
  stderr: timedOut ? `${stderr}\nExecution timed out.`.trim() : stderr,
52
- exitCode: timedOut ? 124 : code ?? 1,
57
+ exitCode: timedOut ? 124 : (code ?? 1),
53
58
  });
54
59
  });
55
60
  });
@@ -60,14 +65,14 @@ async function resolvePython(): Promise<Command | null> {
60
65
  const candidates: Command[] = process.env.LARKUP_PYTHON
61
66
  ? [{ executable: process.env.LARKUP_PYTHON, args: [] }]
62
67
  : process.platform === 'win32'
63
- ? [
64
- { executable: 'py', args: ['-3'] },
65
- { executable: 'python', args: [] },
66
- ]
67
- : [
68
- { executable: 'python3', args: [] },
69
- { executable: 'python', args: [] },
70
- ];
68
+ ? [
69
+ { executable: 'py', args: ['-3'] },
70
+ { executable: 'python', args: [] },
71
+ ]
72
+ : [
73
+ { executable: 'python3', args: [] },
74
+ { executable: 'python', args: [] },
75
+ ];
71
76
 
72
77
  for (const candidate of candidates) {
73
78
  try {
@@ -134,6 +139,32 @@ export async function checkLocalRuntime(): Promise<SandboxHealthCheck> {
134
139
  'Local code execution needs Python 3. Install Python or choose Docker or a remote sandbox provider.',
135
140
  };
136
141
  }
142
+
143
+ try {
144
+ const dependencyCheck = await run(python, [
145
+ '-c',
146
+ `import importlib.util\nmodules = ${JSON.stringify(
147
+ ANALYSIS_PYTHON_MODULES,
148
+ )}\nmissing = [name for name in modules if importlib.util.find_spec(name) is None]\nprint(','.join(missing))\nraise SystemExit(bool(missing))`,
149
+ ]);
150
+ if (dependencyCheck.exitCode !== 0) {
151
+ const missing = dependencyCheck.stdout.trim() || 'required analysis packages';
152
+ return {
153
+ status: 'error',
154
+ backend: 'local',
155
+ error:
156
+ `Local Python is missing ${missing}. Install the Larkup analysis dependencies ` +
157
+ `(for example: pip install ${ANALYSIS_PYTHON_MODULES.join(' ')}) or choose Docker or a remote sandbox provider.`,
158
+ };
159
+ }
160
+ } catch {
161
+ return {
162
+ status: 'error',
163
+ backend: 'local',
164
+ error:
165
+ 'Larkup could not verify the Python analysis dependencies. Choose Docker or a remote sandbox provider.',
166
+ };
167
+ }
137
168
  return { status: 'ready', backend: 'local' };
138
169
  }
139
170
 
@@ -5,7 +5,7 @@ const deleteMock = vi.fn();
5
5
  const createMock = vi.fn();
6
6
  const listMock = vi.fn();
7
7
 
8
- vi.mock('@daytonaio/sdk', () => ({
8
+ vi.mock('@daytona/sdk', () => ({
9
9
  Daytona: vi.fn().mockImplementation(function () {
10
10
  return { create: createMock, list: listMock };
11
11
  }),
@@ -18,12 +18,17 @@ beforeEach(() => {
18
18
  deleteMock.mockReset();
19
19
  createMock.mockReset();
20
20
  listMock.mockReset();
21
- createMock.mockResolvedValue({ process: { executeCommand: executeCommandMock }, delete: deleteMock });
21
+ createMock.mockResolvedValue({
22
+ process: { executeCommand: executeCommandMock },
23
+ delete: deleteMock,
24
+ });
22
25
  });
23
26
 
24
27
  describe('daytonaAdapter.verifyCredentials', () => {
25
28
  it('requires an API key', async () => {
26
- await expect(daytonaAdapter.verifyCredentials({})).rejects.toThrow('Daytona API key is required.');
29
+ await expect(daytonaAdapter.verifyCredentials({})).rejects.toThrow(
30
+ 'Daytona API key is required.',
31
+ );
27
32
  });
28
33
 
29
34
  it('uses list() as the cheap credential check', async () => {
@@ -38,7 +43,10 @@ describe('daytonaAdapter.verifyCredentials', () => {
38
43
  describe('daytonaAdapter.execute — merged stdout/stderr', () => {
39
44
  it('puts successful output in stdout only', async () => {
40
45
  executeCommandMock.mockResolvedValue({ exitCode: 0, result: 'all good\n' });
41
- const result = await daytonaAdapter.execute({ code: 'print(1)', language: 'python' }, { apiKey: 'k' });
46
+ const result = await daytonaAdapter.execute(
47
+ { code: 'print(1)', language: 'python' },
48
+ { apiKey: 'k' },
49
+ );
42
50
  expect(result.stdout).toBe('all good\n');
43
51
  expect(result.stderr).toBe('');
44
52
  expect(result.exitCode).toBe(0);
@@ -46,7 +54,10 @@ describe('daytonaAdapter.execute — merged stdout/stderr', () => {
46
54
 
47
55
  it('mirrors the combined output into stderr when the command fails', async () => {
48
56
  executeCommandMock.mockResolvedValue({ exitCode: 1, result: 'Traceback...\n' });
49
- const result = await daytonaAdapter.execute({ code: 'raise ValueError()', language: 'python' }, { apiKey: 'k' });
57
+ const result = await daytonaAdapter.execute(
58
+ { code: 'raise ValueError()', language: 'python' },
59
+ { apiKey: 'k' },
60
+ );
50
61
  expect(result.stdout).toBe('Traceback...\n');
51
62
  expect(result.stderr).toBe('Traceback...\n');
52
63
  expect(result.exitCode).toBe(1);
@@ -48,7 +48,7 @@ interface DaytonaModule {
48
48
  }
49
49
 
50
50
  async function loadSdk(): Promise<DaytonaModule> {
51
- return (await import('@daytonaio/sdk')) as unknown as DaytonaModule;
51
+ return (await import('@daytona/sdk')) as unknown as DaytonaModule;
52
52
  }
53
53
 
54
54
  function requireFields(credentials: Record<string, string>): { apiKey: string; apiUrl?: string } {
package/src/registry.ts CHANGED
@@ -126,7 +126,7 @@ export const SANDBOX_PROVIDERS: Record<
126
126
  label: 'Daytona',
127
127
  description:
128
128
  'Elastic infrastructure for running AI-generated code in fast, isolated sandboxes.',
129
- sdkPackage: '@daytonaio/sdk',
129
+ sdkPackage: '@daytona/sdk',
130
130
  docsUrl: 'https://www.daytona.io/docs/en/sandboxes/',
131
131
  icon: '/icons/daytonaio.png',
132
132
  executionSupport: 'full',