@amodalai/runtime 0.1.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.
- package/LICENSE +21 -0
- package/dist/.last_build +0 -0
- package/dist/src/agent/agent-runner.d.ts +13 -0
- package/dist/src/agent/agent-runner.js +827 -0
- package/dist/src/agent/agent-runner.js.map +1 -0
- package/dist/src/agent/agent-runner.test.d.ts +6 -0
- package/dist/src/agent/agent-runner.test.js +552 -0
- package/dist/src/agent/agent-runner.test.js.map +1 -0
- package/dist/src/agent/agent-types.d.ts +57 -0
- package/dist/src/agent/agent-types.js +17 -0
- package/dist/src/agent/agent-types.js.map +1 -0
- package/dist/src/agent/agent-types.test.d.ts +6 -0
- package/dist/src/agent/agent-types.test.js +44 -0
- package/dist/src/agent/agent-types.test.js.map +1 -0
- package/dist/src/agent/automation-bridge.d.ts +24 -0
- package/dist/src/agent/automation-bridge.js +24 -0
- package/dist/src/agent/automation-bridge.js.map +1 -0
- package/dist/src/agent/automation-bridge.test.d.ts +6 -0
- package/dist/src/agent/automation-bridge.test.js +67 -0
- package/dist/src/agent/automation-bridge.test.js.map +1 -0
- package/dist/src/agent/config-watcher.d.ts +20 -0
- package/dist/src/agent/config-watcher.js +68 -0
- package/dist/src/agent/config-watcher.js.map +1 -0
- package/dist/src/agent/config-watcher.test.d.ts +6 -0
- package/dist/src/agent/config-watcher.test.js +83 -0
- package/dist/src/agent/config-watcher.test.js.map +1 -0
- package/dist/src/agent/custom-tools-e2e.test.d.ts +6 -0
- package/dist/src/agent/custom-tools-e2e.test.js +566 -0
- package/dist/src/agent/custom-tools-e2e.test.js.map +1 -0
- package/dist/src/agent/local-server.d.ts +15 -0
- package/dist/src/agent/local-server.js +158 -0
- package/dist/src/agent/local-server.js.map +1 -0
- package/dist/src/agent/local-server.test.d.ts +6 -0
- package/dist/src/agent/local-server.test.js +126 -0
- package/dist/src/agent/local-server.test.js.map +1 -0
- package/dist/src/agent/proactive/delivery.d.ts +21 -0
- package/dist/src/agent/proactive/delivery.js +68 -0
- package/dist/src/agent/proactive/delivery.js.map +1 -0
- package/dist/src/agent/proactive/delivery.test.d.ts +6 -0
- package/dist/src/agent/proactive/delivery.test.js +65 -0
- package/dist/src/agent/proactive/delivery.test.js.map +1 -0
- package/dist/src/agent/proactive/proactive-runner.d.ts +76 -0
- package/dist/src/agent/proactive/proactive-runner.js +201 -0
- package/dist/src/agent/proactive/proactive-runner.js.map +1 -0
- package/dist/src/agent/proactive/proactive-runner.test.d.ts +6 -0
- package/dist/src/agent/proactive/proactive-runner.test.js +265 -0
- package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -0
- package/dist/src/agent/request-helper.d.ts +16 -0
- package/dist/src/agent/request-helper.js +87 -0
- package/dist/src/agent/request-helper.js.map +1 -0
- package/dist/src/agent/routes/automations.d.ts +19 -0
- package/dist/src/agent/routes/automations.js +58 -0
- package/dist/src/agent/routes/automations.js.map +1 -0
- package/dist/src/agent/routes/automations.test.d.ts +6 -0
- package/dist/src/agent/routes/automations.test.js +117 -0
- package/dist/src/agent/routes/automations.test.js.map +1 -0
- package/dist/src/agent/routes/chat.d.ts +35 -0
- package/dist/src/agent/routes/chat.js +88 -0
- package/dist/src/agent/routes/chat.js.map +1 -0
- package/dist/src/agent/routes/chat.test.d.ts +6 -0
- package/dist/src/agent/routes/chat.test.js +115 -0
- package/dist/src/agent/routes/chat.test.js.map +1 -0
- package/dist/src/agent/routes/inspect.d.ts +12 -0
- package/dist/src/agent/routes/inspect.js +40 -0
- package/dist/src/agent/routes/inspect.js.map +1 -0
- package/dist/src/agent/routes/inspect.test.d.ts +6 -0
- package/dist/src/agent/routes/inspect.test.js +80 -0
- package/dist/src/agent/routes/inspect.test.js.map +1 -0
- package/dist/src/agent/routes/stores.d.ts +20 -0
- package/dist/src/agent/routes/stores.js +137 -0
- package/dist/src/agent/routes/stores.js.map +1 -0
- package/dist/src/agent/routes/stores.test.d.ts +6 -0
- package/dist/src/agent/routes/stores.test.js +191 -0
- package/dist/src/agent/routes/stores.test.js.map +1 -0
- package/dist/src/agent/routes/task.d.ts +11 -0
- package/dist/src/agent/routes/task.js +116 -0
- package/dist/src/agent/routes/task.js.map +1 -0
- package/dist/src/agent/routes/task.test.d.ts +6 -0
- package/dist/src/agent/routes/task.test.js +91 -0
- package/dist/src/agent/routes/task.test.js.map +1 -0
- package/dist/src/agent/routes/webhooks.d.ts +17 -0
- package/dist/src/agent/routes/webhooks.js +53 -0
- package/dist/src/agent/routes/webhooks.js.map +1 -0
- package/dist/src/agent/routes/webhooks.test.d.ts +6 -0
- package/dist/src/agent/routes/webhooks.test.js +100 -0
- package/dist/src/agent/routes/webhooks.test.js.map +1 -0
- package/dist/src/agent/session-manager.d.ts +72 -0
- package/dist/src/agent/session-manager.js +214 -0
- package/dist/src/agent/session-manager.js.map +1 -0
- package/dist/src/agent/session-manager.test.d.ts +6 -0
- package/dist/src/agent/session-manager.test.js +145 -0
- package/dist/src/agent/session-manager.test.js.map +1 -0
- package/dist/src/agent/shell-executor-local.d.ts +16 -0
- package/dist/src/agent/shell-executor-local.js +51 -0
- package/dist/src/agent/shell-executor-local.js.map +1 -0
- package/dist/src/agent/shell-executor-local.test.d.ts +6 -0
- package/dist/src/agent/shell-executor-local.test.js +46 -0
- package/dist/src/agent/shell-executor-local.test.js.map +1 -0
- package/dist/src/agent/snapshot-server.d.ts +38 -0
- package/dist/src/agent/snapshot-server.js +114 -0
- package/dist/src/agent/snapshot-server.js.map +1 -0
- package/dist/src/agent/stores-e2e.test.d.ts +6 -0
- package/dist/src/agent/stores-e2e.test.js +433 -0
- package/dist/src/agent/stores-e2e.test.js.map +1 -0
- package/dist/src/agent/tool-context-builder.d.ts +11 -0
- package/dist/src/agent/tool-context-builder.js +84 -0
- package/dist/src/agent/tool-context-builder.js.map +1 -0
- package/dist/src/agent/tool-context-builder.test.d.ts +6 -0
- package/dist/src/agent/tool-context-builder.test.js +152 -0
- package/dist/src/agent/tool-context-builder.test.js.map +1 -0
- package/dist/src/agent/tool-executor-local.d.ts +15 -0
- package/dist/src/agent/tool-executor-local.js +74 -0
- package/dist/src/agent/tool-executor-local.js.map +1 -0
- package/dist/src/agent/tool-executor-local.test.d.ts +6 -0
- package/dist/src/agent/tool-executor-local.test.js +116 -0
- package/dist/src/agent/tool-executor-local.test.js.map +1 -0
- package/dist/src/agent/tool-harness-template.d.ts +23 -0
- package/dist/src/agent/tool-harness-template.js +94 -0
- package/dist/src/agent/tool-harness-template.js.map +1 -0
- package/dist/src/agent/user-context-fetcher.d.ts +25 -0
- package/dist/src/agent/user-context-fetcher.js +79 -0
- package/dist/src/agent/user-context-fetcher.js.map +1 -0
- package/dist/src/agent/user-context-fetcher.test.d.ts +6 -0
- package/dist/src/agent/user-context-fetcher.test.js +121 -0
- package/dist/src/agent/user-context-fetcher.test.js.map +1 -0
- package/dist/src/audit/audit-client.d.ts +46 -0
- package/dist/src/audit/audit-client.js +83 -0
- package/dist/src/audit/audit-client.js.map +1 -0
- package/dist/src/cron/heartbeat-runner.d.ts +24 -0
- package/dist/src/cron/heartbeat-runner.js +87 -0
- package/dist/src/cron/heartbeat-runner.js.map +1 -0
- package/dist/src/cron/heartbeat-runner.test.d.ts +6 -0
- package/dist/src/cron/heartbeat-runner.test.js +120 -0
- package/dist/src/cron/heartbeat-runner.test.js.map +1 -0
- package/dist/src/cron/heartbeat-scheduler.d.ts +26 -0
- package/dist/src/cron/heartbeat-scheduler.js +54 -0
- package/dist/src/cron/heartbeat-scheduler.js.map +1 -0
- package/dist/src/cron/heartbeat-scheduler.test.d.ts +6 -0
- package/dist/src/cron/heartbeat-scheduler.test.js +61 -0
- package/dist/src/cron/heartbeat-scheduler.test.js.map +1 -0
- package/dist/src/index.d.ts +24 -0
- package/dist/src/index.js +118 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/middleware/auth.d.ts +40 -0
- package/dist/src/middleware/auth.js +135 -0
- package/dist/src/middleware/auth.js.map +1 -0
- package/dist/src/middleware/auth.test.d.ts +6 -0
- package/dist/src/middleware/auth.test.js +268 -0
- package/dist/src/middleware/auth.test.js.map +1 -0
- package/dist/src/middleware/error-handler.d.ts +20 -0
- package/dist/src/middleware/error-handler.js +48 -0
- package/dist/src/middleware/error-handler.js.map +1 -0
- package/dist/src/middleware/error-handler.test.d.ts +6 -0
- package/dist/src/middleware/error-handler.test.js +68 -0
- package/dist/src/middleware/error-handler.test.js.map +1 -0
- package/dist/src/middleware/request-validation.d.ts +13 -0
- package/dist/src/middleware/request-validation.js +26 -0
- package/dist/src/middleware/request-validation.js.map +1 -0
- package/dist/src/middleware/request-validation.test.d.ts +6 -0
- package/dist/src/middleware/request-validation.test.js +57 -0
- package/dist/src/middleware/request-validation.test.js.map +1 -0
- package/dist/src/output/email-output.d.ts +10 -0
- package/dist/src/output/email-output.js +12 -0
- package/dist/src/output/email-output.js.map +1 -0
- package/dist/src/output/output-router.d.ts +12 -0
- package/dist/src/output/output-router.js +36 -0
- package/dist/src/output/output-router.js.map +1 -0
- package/dist/src/output/output-router.test.d.ts +6 -0
- package/dist/src/output/output-router.test.js +132 -0
- package/dist/src/output/output-router.test.js.map +1 -0
- package/dist/src/output/slack-output.d.ts +10 -0
- package/dist/src/output/slack-output.js +54 -0
- package/dist/src/output/slack-output.js.map +1 -0
- package/dist/src/output/webhook-output.d.ts +10 -0
- package/dist/src/output/webhook-output.js +25 -0
- package/dist/src/output/webhook-output.js.map +1 -0
- package/dist/src/routes/ai-stream.d.ts +159 -0
- package/dist/src/routes/ai-stream.js +309 -0
- package/dist/src/routes/ai-stream.js.map +1 -0
- package/dist/src/routes/ai-stream.test.d.ts +6 -0
- package/dist/src/routes/ai-stream.test.js +586 -0
- package/dist/src/routes/ai-stream.test.js.map +1 -0
- package/dist/src/routes/ask-user-response.d.ts +30 -0
- package/dist/src/routes/ask-user-response.js +61 -0
- package/dist/src/routes/ask-user-response.js.map +1 -0
- package/dist/src/routes/ask-user-response.test.d.ts +6 -0
- package/dist/src/routes/ask-user-response.test.js +88 -0
- package/dist/src/routes/ask-user-response.test.js.map +1 -0
- package/dist/src/routes/chat-stream.d.ts +14 -0
- package/dist/src/routes/chat-stream.js +84 -0
- package/dist/src/routes/chat-stream.js.map +1 -0
- package/dist/src/routes/chat-stream.test.d.ts +6 -0
- package/dist/src/routes/chat-stream.test.js +155 -0
- package/dist/src/routes/chat-stream.test.js.map +1 -0
- package/dist/src/routes/chat.d.ts +13 -0
- package/dist/src/routes/chat.js +55 -0
- package/dist/src/routes/chat.js.map +1 -0
- package/dist/src/routes/chat.test.d.ts +6 -0
- package/dist/src/routes/chat.test.js +99 -0
- package/dist/src/routes/chat.test.js.map +1 -0
- package/dist/src/routes/health.d.ts +13 -0
- package/dist/src/routes/health.js +23 -0
- package/dist/src/routes/health.js.map +1 -0
- package/dist/src/routes/health.test.d.ts +6 -0
- package/dist/src/routes/health.test.js +45 -0
- package/dist/src/routes/health.test.js.map +1 -0
- package/dist/src/routes/sessions.d.ts +14 -0
- package/dist/src/routes/sessions.js +82 -0
- package/dist/src/routes/sessions.js.map +1 -0
- package/dist/src/routes/webhooks.d.ts +13 -0
- package/dist/src/routes/webhooks.js +43 -0
- package/dist/src/routes/webhooks.js.map +1 -0
- package/dist/src/routes/webhooks.test.d.ts +6 -0
- package/dist/src/routes/webhooks.test.js +80 -0
- package/dist/src/routes/webhooks.test.js.map +1 -0
- package/dist/src/routes/widget-actions.d.ts +49 -0
- package/dist/src/routes/widget-actions.js +78 -0
- package/dist/src/routes/widget-actions.js.map +1 -0
- package/dist/src/server.d.ts +31 -0
- package/dist/src/server.js +129 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/server.test.d.ts +6 -0
- package/dist/src/server.test.js +153 -0
- package/dist/src/server.test.js.map +1 -0
- package/dist/src/session/history-converter.d.ts +21 -0
- package/dist/src/session/history-converter.js +59 -0
- package/dist/src/session/history-converter.js.map +1 -0
- package/dist/src/session/history-converter.test.d.ts +6 -0
- package/dist/src/session/history-converter.test.js +130 -0
- package/dist/src/session/history-converter.test.js.map +1 -0
- package/dist/src/session/session-manager.d.ts +117 -0
- package/dist/src/session/session-manager.js +480 -0
- package/dist/src/session/session-manager.js.map +1 -0
- package/dist/src/session/session-manager.test.d.ts +6 -0
- package/dist/src/session/session-manager.test.js +586 -0
- package/dist/src/session/session-manager.test.js.map +1 -0
- package/dist/src/session/session-runner.d.ts +30 -0
- package/dist/src/session/session-runner.js +771 -0
- package/dist/src/session/session-runner.js.map +1 -0
- package/dist/src/session/session-runner.test.d.ts +6 -0
- package/dist/src/session/session-runner.test.js +842 -0
- package/dist/src/session/session-runner.test.js.map +1 -0
- package/dist/src/stores/index.d.ts +8 -0
- package/dist/src/stores/index.js +9 -0
- package/dist/src/stores/index.js.map +1 -0
- package/dist/src/stores/key-resolver.d.ts +21 -0
- package/dist/src/stores/key-resolver.js +30 -0
- package/dist/src/stores/key-resolver.js.map +1 -0
- package/dist/src/stores/key-resolver.test.d.ts +6 -0
- package/dist/src/stores/key-resolver.test.js +31 -0
- package/dist/src/stores/key-resolver.test.js.map +1 -0
- package/dist/src/stores/pglite-store-backend.d.ts +36 -0
- package/dist/src/stores/pglite-store-backend.js +227 -0
- package/dist/src/stores/pglite-store-backend.js.map +1 -0
- package/dist/src/stores/pglite-store-backend.test.d.ts +6 -0
- package/dist/src/stores/pglite-store-backend.test.js +150 -0
- package/dist/src/stores/pglite-store-backend.test.js.map +1 -0
- package/dist/src/stores/ttl-resolver.d.ts +24 -0
- package/dist/src/stores/ttl-resolver.js +64 -0
- package/dist/src/stores/ttl-resolver.js.map +1 -0
- package/dist/src/stores/ttl-resolver.test.d.ts +6 -0
- package/dist/src/stores/ttl-resolver.test.js +68 -0
- package/dist/src/stores/ttl-resolver.test.js.map +1 -0
- package/dist/src/types.d.ts +227 -0
- package/dist/src/types.js +50 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/types.test.d.ts +6 -0
- package/dist/src/types.test.js +68 -0
- package/dist/src/types.test.js.map +1 -0
- package/dist/src/utils/jwt-verify.d.ts +20 -0
- package/dist/src/utils/jwt-verify.js +34 -0
- package/dist/src/utils/jwt-verify.js.map +1 -0
- package/dist/src/utils/jwt-verify.test.d.ts +6 -0
- package/dist/src/utils/jwt-verify.test.js +156 -0
- package/dist/src/utils/jwt-verify.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { execFile } from 'node:child_process';
|
|
7
|
+
import { promisify } from 'node:util';
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
/**
|
|
10
|
+
* Executes shell commands locally via child_process.
|
|
11
|
+
*/
|
|
12
|
+
export class LocalShellExecutor {
|
|
13
|
+
async exec(command, timeout, signal) {
|
|
14
|
+
try {
|
|
15
|
+
const result = await execFileAsync('bash', ['-c', command], {
|
|
16
|
+
timeout,
|
|
17
|
+
signal,
|
|
18
|
+
maxBuffer: 1024 * 1024, // 1MB
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
stdout: result.stdout,
|
|
22
|
+
stderr: result.stderr,
|
|
23
|
+
exitCode: 0,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Node child_process error
|
|
28
|
+
const execErr = err;
|
|
29
|
+
if (signal.aborted) {
|
|
30
|
+
return {
|
|
31
|
+
stdout: execErr.stdout ?? '',
|
|
32
|
+
stderr: 'Execution aborted',
|
|
33
|
+
exitCode: 130,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (execErr.killed) {
|
|
37
|
+
return {
|
|
38
|
+
stdout: execErr.stdout ?? '',
|
|
39
|
+
stderr: execErr.stderr ?? 'Process killed (timeout)',
|
|
40
|
+
exitCode: 137,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
stdout: execErr.stdout ?? '',
|
|
45
|
+
stderr: execErr.stderr ?? (err instanceof Error ? err.message : String(err)),
|
|
46
|
+
exitCode: typeof execErr.code === 'number' ? execErr.code : 1,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=shell-executor-local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-executor-local.js","sourceRoot":"","sources":["../../../src/agent/shell-executor-local.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAC,SAAS,EAAC,MAAM,WAAW,CAAC;AAGpC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAC7B,KAAK,CAAC,IAAI,CACR,OAAe,EACf,OAAe,EACf,MAAmB;QAEnB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;gBAC1D,OAAO;gBACP,MAAM;gBACN,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM;aAC/B,CAAC,CAAC;YAEH,OAAO;gBACL,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,QAAQ,EAAE,CAAC;aACZ,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,mGAAmG;YACnG,MAAM,OAAO,GAAG,GAAmF,CAAC;YAEpG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO;oBACL,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;oBAC5B,MAAM,EAAE,mBAAmB;oBAC3B,QAAQ,EAAE,GAAG;iBACd,CAAC;YACJ,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,OAAO;oBACL,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;oBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,0BAA0B;oBACpD,QAAQ,EAAE,GAAG;iBACd,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;gBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC5E,QAAQ,EAAE,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aAC9D,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import { LocalShellExecutor } from './shell-executor-local.js';
|
|
8
|
+
describe('LocalShellExecutor', () => {
|
|
9
|
+
const executor = new LocalShellExecutor();
|
|
10
|
+
it('executes a simple command and captures stdout', async () => {
|
|
11
|
+
const result = await executor.exec('echo "hello world"', 5000, AbortSignal.timeout(10000));
|
|
12
|
+
expect(result.stdout.trim()).toBe('hello world');
|
|
13
|
+
expect(result.exitCode).toBe(0);
|
|
14
|
+
});
|
|
15
|
+
it('captures stderr', async () => {
|
|
16
|
+
const result = await executor.exec('echo "error" >&2', 5000, AbortSignal.timeout(10000));
|
|
17
|
+
expect(result.stderr.trim()).toBe('error');
|
|
18
|
+
expect(result.exitCode).toBe(0);
|
|
19
|
+
});
|
|
20
|
+
it('returns non-zero exit code for failing commands', async () => {
|
|
21
|
+
const result = await executor.exec('exit 42', 5000, AbortSignal.timeout(10000));
|
|
22
|
+
expect(result.exitCode).toBe(42);
|
|
23
|
+
});
|
|
24
|
+
it('returns exit code for command not found', async () => {
|
|
25
|
+
const result = await executor.exec('nonexistent_command_xyz', 5000, AbortSignal.timeout(10000));
|
|
26
|
+
expect(result.exitCode).not.toBe(0);
|
|
27
|
+
expect(result.stderr).toBeTruthy();
|
|
28
|
+
});
|
|
29
|
+
it('handles timeout', async () => {
|
|
30
|
+
const result = await executor.exec('sleep 60', 100, AbortSignal.timeout(10000));
|
|
31
|
+
// Should kill the process
|
|
32
|
+
expect(result.exitCode).not.toBe(0);
|
|
33
|
+
});
|
|
34
|
+
it('captures both stdout and stderr', async () => {
|
|
35
|
+
const result = await executor.exec('echo "out" && echo "err" >&2', 5000, AbortSignal.timeout(10000));
|
|
36
|
+
expect(result.stdout.trim()).toBe('out');
|
|
37
|
+
expect(result.stderr.trim()).toBe('err');
|
|
38
|
+
expect(result.exitCode).toBe(0);
|
|
39
|
+
});
|
|
40
|
+
it('executes multi-line commands', async () => {
|
|
41
|
+
const result = await executor.exec('x=5; echo $((x * 2))', 5000, AbortSignal.timeout(10000));
|
|
42
|
+
expect(result.stdout.trim()).toBe('10');
|
|
43
|
+
expect(result.exitCode).toBe(0);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=shell-executor-local.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-executor-local.test.js","sourceRoot":"","sources":["../../../src/agent/shell-executor-local.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import type { AmodalRepo, DeploySnapshot, CustomToolExecutor, CustomShellExecutor } from '@amodalai/core';
|
|
7
|
+
import type { ServerInstance } from '../server.js';
|
|
8
|
+
/**
|
|
9
|
+
* Config for creating a server from a local snapshot.
|
|
10
|
+
*
|
|
11
|
+
* Exactly one source must be provided:
|
|
12
|
+
* - `snapshotPath` — load from a local JSON file
|
|
13
|
+
* - `snapshot` — use a pre-loaded DeploySnapshot object
|
|
14
|
+
* - `repo` — use a pre-loaded AmodalRepo
|
|
15
|
+
*/
|
|
16
|
+
export interface SnapshotServerConfig {
|
|
17
|
+
/** Path to a resolved-config.json snapshot file. */
|
|
18
|
+
snapshotPath?: string;
|
|
19
|
+
/** A pre-loaded DeploySnapshot object. */
|
|
20
|
+
snapshot?: DeploySnapshot;
|
|
21
|
+
/** A pre-loaded AmodalRepo (e.g. from snapshotToRepo). */
|
|
22
|
+
repo?: AmodalRepo;
|
|
23
|
+
port: number;
|
|
24
|
+
host?: string;
|
|
25
|
+
sessionTtlMs?: number;
|
|
26
|
+
corsOrigin?: string;
|
|
27
|
+
/** Optional custom tool executor (e.g., Daytona sandbox executor) */
|
|
28
|
+
toolExecutor?: CustomToolExecutor;
|
|
29
|
+
/** Optional custom shell executor (e.g., Daytona sandbox executor) */
|
|
30
|
+
shellExecutor?: CustomShellExecutor;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates an Express server that runs from an immutable deploy snapshot.
|
|
34
|
+
*
|
|
35
|
+
* This is the local testing path: the CLI builds a snapshot and tests it
|
|
36
|
+
* locally before deploying to the platform.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createSnapshotServer(config: SnapshotServerConfig): Promise<ServerInstance>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import express from 'express';
|
|
7
|
+
import { loadSnapshotFromFile, snapshotToRepo } from '@amodalai/core';
|
|
8
|
+
import { AgentSessionManager } from './session-manager.js';
|
|
9
|
+
import { LocalToolExecutor } from './tool-executor-local.js';
|
|
10
|
+
import { createChatRouter } from './routes/chat.js';
|
|
11
|
+
import { createTaskRouter } from './routes/task.js';
|
|
12
|
+
import { errorHandler } from '../middleware/error-handler.js';
|
|
13
|
+
/**
|
|
14
|
+
* Creates an Express server that runs from an immutable deploy snapshot.
|
|
15
|
+
*
|
|
16
|
+
* This is the local testing path: the CLI builds a snapshot and tests it
|
|
17
|
+
* locally before deploying to the platform.
|
|
18
|
+
*/
|
|
19
|
+
export async function createSnapshotServer(config) {
|
|
20
|
+
let repo;
|
|
21
|
+
let deployId;
|
|
22
|
+
if (config.repo) {
|
|
23
|
+
repo = config.repo;
|
|
24
|
+
deployId = repo.origin;
|
|
25
|
+
}
|
|
26
|
+
else if (config.snapshot) {
|
|
27
|
+
repo = snapshotToRepo(config.snapshot, `snapshot:${config.snapshot.deployId}`);
|
|
28
|
+
deployId = config.snapshot.deployId;
|
|
29
|
+
}
|
|
30
|
+
else if (config.snapshotPath) {
|
|
31
|
+
const snapshot = await loadSnapshotFromFile(config.snapshotPath);
|
|
32
|
+
repo = snapshotToRepo(snapshot, config.snapshotPath);
|
|
33
|
+
deployId = snapshot.deployId;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
throw new Error('One of snapshotPath, snapshot, or repo must be provided');
|
|
37
|
+
}
|
|
38
|
+
// Set up tool executor — use injected executor if provided, otherwise local
|
|
39
|
+
let toolExecutor = config.toolExecutor;
|
|
40
|
+
if (!toolExecutor && repo.tools.length > 0) {
|
|
41
|
+
toolExecutor = new LocalToolExecutor();
|
|
42
|
+
}
|
|
43
|
+
const sessionManager = new AgentSessionManager(repo, {
|
|
44
|
+
ttlMs: config.sessionTtlMs,
|
|
45
|
+
toolExecutor,
|
|
46
|
+
shellExecutor: config.shellExecutor,
|
|
47
|
+
});
|
|
48
|
+
const app = express();
|
|
49
|
+
// CORS
|
|
50
|
+
const corsOrigin = config.corsOrigin ?? '*';
|
|
51
|
+
app.use((_req, res, next) => {
|
|
52
|
+
res.header('Access-Control-Allow-Origin', corsOrigin);
|
|
53
|
+
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
|
54
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
|
55
|
+
if (_req.method === 'OPTIONS') {
|
|
56
|
+
res.sendStatus(204);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
next();
|
|
60
|
+
});
|
|
61
|
+
app.use(express.json());
|
|
62
|
+
// Health
|
|
63
|
+
const startedAt = Date.now();
|
|
64
|
+
app.get('/health', (_req, res) => {
|
|
65
|
+
res.json({
|
|
66
|
+
status: 'ok',
|
|
67
|
+
mode: 'snapshot',
|
|
68
|
+
deploy_id: deployId,
|
|
69
|
+
agent_name: repo.config.name,
|
|
70
|
+
connections: repo.connections.size,
|
|
71
|
+
skills: repo.skills.length,
|
|
72
|
+
uptime_ms: Date.now() - startedAt,
|
|
73
|
+
active_sessions: sessionManager.size,
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
// Routes
|
|
77
|
+
app.use(createChatRouter({ sessionManager }));
|
|
78
|
+
app.use(createTaskRouter({ sessionManager }));
|
|
79
|
+
// Error handler (must be last)
|
|
80
|
+
app.use(errorHandler);
|
|
81
|
+
let server = null;
|
|
82
|
+
const host = config.host ?? '0.0.0.0';
|
|
83
|
+
const port = config.port;
|
|
84
|
+
return {
|
|
85
|
+
app,
|
|
86
|
+
async start() {
|
|
87
|
+
return new Promise((resolve) => {
|
|
88
|
+
const httpServer = app.listen(port, host, () => {
|
|
89
|
+
process.stderr.write(`[INFO] Snapshot server listening on ${host}:${port}\n`);
|
|
90
|
+
process.stderr.write(`[INFO] Deploy: ${deployId}, Agent: ${repo.config.name}\n`);
|
|
91
|
+
resolve(httpServer);
|
|
92
|
+
});
|
|
93
|
+
server = httpServer;
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
async stop() {
|
|
97
|
+
if (server) {
|
|
98
|
+
const s = server;
|
|
99
|
+
await new Promise((resolve, reject) => {
|
|
100
|
+
s.close((err) => {
|
|
101
|
+
if (err)
|
|
102
|
+
reject(err);
|
|
103
|
+
else
|
|
104
|
+
resolve();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
server = null;
|
|
108
|
+
}
|
|
109
|
+
await sessionManager.shutdown();
|
|
110
|
+
process.stderr.write('[INFO] Snapshot server stopped\n');
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=snapshot-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-server.js","sourceRoot":"","sources":["../../../src/agent/snapshot-server.ts"],"names":[],"mappings":"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"}
|