@elevasis/sdk 0.3.3 → 0.4.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/dist/cli.cjs CHANGED
@@ -39746,9 +39746,15 @@ var ResourceRegistry = class {
39746
39746
  }
39747
39747
  /**
39748
39748
  * Pre-serialized organization data cache
39749
- * Computed once at construction, never invalidated (static registry)
39749
+ * Computed once at construction for static orgs, updated incrementally for runtime orgs
39750
39750
  */
39751
39751
  serializedCache;
39752
+ /**
39753
+ * Runtime-registered organizations (external deployments)
39754
+ * Tracks which orgs were added at runtime vs. static startup.
39755
+ * Used to guard against unregistering static orgs and to store remote config.
39756
+ */
39757
+ runtimeOrgs = /* @__PURE__ */ new Map();
39752
39758
  /**
39753
39759
  * Validates registry on construction
39754
39760
  * - Checks for duplicate resourceIds within organizations
@@ -39848,6 +39854,72 @@ var ResourceRegistry = class {
39848
39854
  return this.registry;
39849
39855
  }
39850
39856
  // ============================================================================
39857
+ // Runtime Organization Registration (External Deployments)
39858
+ // ============================================================================
39859
+ /**
39860
+ * Register an external organization at runtime
39861
+ *
39862
+ * Called during deploy pipeline when an external developer deploys their bundle.
39863
+ * Adds the org's stub definitions to the registry and stores remote config
39864
+ * for worker thread execution branching.
39865
+ *
39866
+ * - If orgName conflicts with a static (startup) org, throws an error
39867
+ * - If orgName is already runtime-registered (redeploy), unregisters first
39868
+ *
39869
+ * @param orgName - Organization name (used as registry key)
39870
+ * @param org - Stub resource definitions (workflows/agents with placeholder handlers)
39871
+ * @param remote - Remote configuration (bundle path, deployment ID, env vars)
39872
+ * @throws Error if orgName conflicts with a static organization
39873
+ */
39874
+ registerOrganization(orgName, org, remote) {
39875
+ if (this.registry[orgName] && !this.runtimeOrgs.has(orgName)) {
39876
+ throw new Error(`Organization '${orgName}' conflicts with a static organization`);
39877
+ }
39878
+ if (this.runtimeOrgs.has(orgName)) {
39879
+ this.unregisterOrganization(orgName);
39880
+ }
39881
+ this.registry[orgName] = org;
39882
+ this.runtimeOrgs.set(orgName, remote);
39883
+ this.serializedCache.set(orgName, serializeOrganization(org));
39884
+ }
39885
+ /**
39886
+ * Unregister a runtime-registered organization
39887
+ *
39888
+ * Only removes organizations that were registered at runtime (via registerOrganization).
39889
+ * Static organizations loaded at startup are protected and cannot be unregistered.
39890
+ * No-op if the org is not runtime-registered.
39891
+ *
39892
+ * @param orgName - Organization name to unregister
39893
+ */
39894
+ unregisterOrganization(orgName) {
39895
+ if (!this.runtimeOrgs.has(orgName)) return;
39896
+ delete this.registry[orgName];
39897
+ this.runtimeOrgs.delete(orgName);
39898
+ this.serializedCache.delete(orgName);
39899
+ }
39900
+ /**
39901
+ * Get remote configuration for an organization
39902
+ *
39903
+ * Returns the RemoteOrgConfig if the org was registered at runtime,
39904
+ * or null if it's a static org or doesn't exist.
39905
+ * Used by the execution coordinator to branch between local and worker execution.
39906
+ *
39907
+ * @param orgName - Organization name
39908
+ * @returns Remote config or null
39909
+ */
39910
+ getRemoteConfig(orgName) {
39911
+ return this.runtimeOrgs.get(orgName) ?? null;
39912
+ }
39913
+ /**
39914
+ * Check if an organization is a remote (externally deployed) organization
39915
+ *
39916
+ * @param orgName - Organization name
39917
+ * @returns true if the org was registered at runtime
39918
+ */
39919
+ isRemote(orgName) {
39920
+ return this.runtimeOrgs.has(orgName);
39921
+ }
39922
+ // ============================================================================
39851
39923
  // Resource Manifest Accessors
39852
39924
  // ============================================================================
39853
39925
  /**
@@ -40233,13 +40305,13 @@ function registerDeployCommand(program3) {
40233
40305
  console.log("");
40234
40306
  }
40235
40307
  const bundleSpinner = ora("Bundling...").start();
40236
- const wrapperPath = (0, import_path2.resolve)("__elevasis_serve.ts");
40308
+ const wrapperPath = (0, import_path2.resolve)("__elevasis_worker.ts");
40237
40309
  const bundleOutfile = (0, import_path2.resolve)("dist/bundle.js");
40238
40310
  try {
40239
40311
  const entryImport = entryPath.replace(/\.ts$/, ".js");
40240
40312
  const wrapperContent = `import org from ${JSON.stringify(entryImport)}
40241
- import { startServer } from '@elevasis/sdk/server'
40242
- startServer(org)
40313
+ import { startWorker } from '@elevasis/sdk/worker'
40314
+ startWorker(org)
40243
40315
  `;
40244
40316
  await (0, import_promises.writeFile)(wrapperPath, wrapperContent, "utf-8");
40245
40317
  await (0, import_promises.mkdir)((0, import_path2.resolve)("dist"), { recursive: true });
@@ -40703,7 +40775,7 @@ var import_path3 = require("path");
40703
40775
  var import_promises2 = require("fs/promises");
40704
40776
 
40705
40777
  // src/cli/version.ts
40706
- var SDK_VERSION = "0.3.3";
40778
+ var SDK_VERSION = "0.4.0";
40707
40779
 
40708
40780
  // src/cli/commands/init.ts
40709
40781
  var SCAFFOLD_FILES = [
package/dist/index.d.ts CHANGED
@@ -1054,6 +1054,22 @@ interface IterationContext {
1054
1054
  * - Command View data generation
1055
1055
  */
1056
1056
 
1057
+ /**
1058
+ * Configuration for a remotely-deployed organization
1059
+ *
1060
+ * Stored alongside runtime-registered organizations to support
1061
+ * worker thread execution branching and credential management.
1062
+ */
1063
+ interface RemoteOrgConfig {
1064
+ /** Path to the esbuild bundle on disk */
1065
+ bundlePath: string;
1066
+ /** Deployment record ID */
1067
+ deploymentId: string;
1068
+ /** Developer-provided environment variables injected into the worker */
1069
+ envVars?: Record<string, string>;
1070
+ /** Platform tool name -> credential name mapping */
1071
+ toolCredentials?: Record<string, string>;
1072
+ }
1057
1073
  /**
1058
1074
  * Organization-specific resource collection
1059
1075
  *
@@ -1084,9 +1100,15 @@ declare class ResourceRegistry {
1084
1100
  private registry;
1085
1101
  /**
1086
1102
  * Pre-serialized organization data cache
1087
- * Computed once at construction, never invalidated (static registry)
1103
+ * Computed once at construction for static orgs, updated incrementally for runtime orgs
1088
1104
  */
1089
1105
  private serializedCache;
1106
+ /**
1107
+ * Runtime-registered organizations (external deployments)
1108
+ * Tracks which orgs were added at runtime vs. static startup.
1109
+ * Used to guard against unregistering static orgs and to store remote config.
1110
+ */
1111
+ private runtimeOrgs;
1090
1112
  constructor(registry: OrganizationRegistry);
1091
1113
  /**
1092
1114
  * Validates registry on construction
@@ -1122,6 +1144,50 @@ declare class ResourceRegistry {
1122
1144
  * NOTE: For debugging only - returns raw registry data
1123
1145
  */
1124
1146
  listAllResources(): OrganizationRegistry;
1147
+ /**
1148
+ * Register an external organization at runtime
1149
+ *
1150
+ * Called during deploy pipeline when an external developer deploys their bundle.
1151
+ * Adds the org's stub definitions to the registry and stores remote config
1152
+ * for worker thread execution branching.
1153
+ *
1154
+ * - If orgName conflicts with a static (startup) org, throws an error
1155
+ * - If orgName is already runtime-registered (redeploy), unregisters first
1156
+ *
1157
+ * @param orgName - Organization name (used as registry key)
1158
+ * @param org - Stub resource definitions (workflows/agents with placeholder handlers)
1159
+ * @param remote - Remote configuration (bundle path, deployment ID, env vars)
1160
+ * @throws Error if orgName conflicts with a static organization
1161
+ */
1162
+ registerOrganization(orgName: string, org: OrganizationResources, remote: RemoteOrgConfig): void;
1163
+ /**
1164
+ * Unregister a runtime-registered organization
1165
+ *
1166
+ * Only removes organizations that were registered at runtime (via registerOrganization).
1167
+ * Static organizations loaded at startup are protected and cannot be unregistered.
1168
+ * No-op if the org is not runtime-registered.
1169
+ *
1170
+ * @param orgName - Organization name to unregister
1171
+ */
1172
+ unregisterOrganization(orgName: string): void;
1173
+ /**
1174
+ * Get remote configuration for an organization
1175
+ *
1176
+ * Returns the RemoteOrgConfig if the org was registered at runtime,
1177
+ * or null if it's a static org or doesn't exist.
1178
+ * Used by the execution coordinator to branch between local and worker execution.
1179
+ *
1180
+ * @param orgName - Organization name
1181
+ * @returns Remote config or null
1182
+ */
1183
+ getRemoteConfig(orgName: string): RemoteOrgConfig | null;
1184
+ /**
1185
+ * Check if an organization is a remote (externally deployed) organization
1186
+ *
1187
+ * @param orgName - Organization name
1188
+ * @returns true if the org was registered at runtime
1189
+ */
1190
+ isRemote(orgName: string): boolean;
1125
1191
  /**
1126
1192
  * Get triggers for an organization
1127
1193
  * @param organizationName - Organization name
package/dist/index.js CHANGED
@@ -3162,9 +3162,15 @@ var ResourceRegistry = class {
3162
3162
  }
3163
3163
  /**
3164
3164
  * Pre-serialized organization data cache
3165
- * Computed once at construction, never invalidated (static registry)
3165
+ * Computed once at construction for static orgs, updated incrementally for runtime orgs
3166
3166
  */
3167
3167
  serializedCache;
3168
+ /**
3169
+ * Runtime-registered organizations (external deployments)
3170
+ * Tracks which orgs were added at runtime vs. static startup.
3171
+ * Used to guard against unregistering static orgs and to store remote config.
3172
+ */
3173
+ runtimeOrgs = /* @__PURE__ */ new Map();
3168
3174
  /**
3169
3175
  * Validates registry on construction
3170
3176
  * - Checks for duplicate resourceIds within organizations
@@ -3264,6 +3270,72 @@ var ResourceRegistry = class {
3264
3270
  return this.registry;
3265
3271
  }
3266
3272
  // ============================================================================
3273
+ // Runtime Organization Registration (External Deployments)
3274
+ // ============================================================================
3275
+ /**
3276
+ * Register an external organization at runtime
3277
+ *
3278
+ * Called during deploy pipeline when an external developer deploys their bundle.
3279
+ * Adds the org's stub definitions to the registry and stores remote config
3280
+ * for worker thread execution branching.
3281
+ *
3282
+ * - If orgName conflicts with a static (startup) org, throws an error
3283
+ * - If orgName is already runtime-registered (redeploy), unregisters first
3284
+ *
3285
+ * @param orgName - Organization name (used as registry key)
3286
+ * @param org - Stub resource definitions (workflows/agents with placeholder handlers)
3287
+ * @param remote - Remote configuration (bundle path, deployment ID, env vars)
3288
+ * @throws Error if orgName conflicts with a static organization
3289
+ */
3290
+ registerOrganization(orgName, org, remote) {
3291
+ if (this.registry[orgName] && !this.runtimeOrgs.has(orgName)) {
3292
+ throw new Error(`Organization '${orgName}' conflicts with a static organization`);
3293
+ }
3294
+ if (this.runtimeOrgs.has(orgName)) {
3295
+ this.unregisterOrganization(orgName);
3296
+ }
3297
+ this.registry[orgName] = org;
3298
+ this.runtimeOrgs.set(orgName, remote);
3299
+ this.serializedCache.set(orgName, serializeOrganization(org));
3300
+ }
3301
+ /**
3302
+ * Unregister a runtime-registered organization
3303
+ *
3304
+ * Only removes organizations that were registered at runtime (via registerOrganization).
3305
+ * Static organizations loaded at startup are protected and cannot be unregistered.
3306
+ * No-op if the org is not runtime-registered.
3307
+ *
3308
+ * @param orgName - Organization name to unregister
3309
+ */
3310
+ unregisterOrganization(orgName) {
3311
+ if (!this.runtimeOrgs.has(orgName)) return;
3312
+ delete this.registry[orgName];
3313
+ this.runtimeOrgs.delete(orgName);
3314
+ this.serializedCache.delete(orgName);
3315
+ }
3316
+ /**
3317
+ * Get remote configuration for an organization
3318
+ *
3319
+ * Returns the RemoteOrgConfig if the org was registered at runtime,
3320
+ * or null if it's a static org or doesn't exist.
3321
+ * Used by the execution coordinator to branch between local and worker execution.
3322
+ *
3323
+ * @param orgName - Organization name
3324
+ * @returns Remote config or null
3325
+ */
3326
+ getRemoteConfig(orgName) {
3327
+ return this.runtimeOrgs.get(orgName) ?? null;
3328
+ }
3329
+ /**
3330
+ * Check if an organization is a remote (externally deployed) organization
3331
+ *
3332
+ * @param orgName - Organization name
3333
+ * @returns true if the org was registered at runtime
3334
+ */
3335
+ isRemote(orgName) {
3336
+ return this.runtimeOrgs.has(orgName);
3337
+ }
3338
+ // ============================================================================
3267
3339
  // Resource Manifest Accessors
3268
3340
  // ============================================================================
3269
3341
  /**
@@ -0,0 +1,121 @@
1
+ import { parentPort } from 'worker_threads';
2
+
3
+ // src/worker/index.ts
4
+ function resolveNext(next, data) {
5
+ if (next === null) return null;
6
+ if (next.type === "linear") return next.target;
7
+ for (const route of next.routes) {
8
+ if (route.condition(data)) return route.target;
9
+ }
10
+ return next.default;
11
+ }
12
+ async function executeWorkflow(workflow, input) {
13
+ const logs = [];
14
+ const origLog = console.log;
15
+ const origWarn = console.warn;
16
+ const origError = console.error;
17
+ const capture = (level, orig) => (...args) => {
18
+ logs.push({ level, message: args.map(String).join(" ") });
19
+ orig(...args);
20
+ };
21
+ console.log = capture("info", origLog);
22
+ console.warn = capture("warn", origWarn);
23
+ console.error = capture("error", origError);
24
+ try {
25
+ let currentData = workflow.contract.inputSchema ? workflow.contract.inputSchema.parse(input) : input;
26
+ let stepId = workflow.entryPoint;
27
+ while (stepId !== null) {
28
+ const step = workflow.steps[stepId];
29
+ if (!step) {
30
+ throw new Error(`Step '${stepId}' not found in workflow '${workflow.config.resourceId}'`);
31
+ }
32
+ const stepInput = step.inputSchema.parse(currentData);
33
+ const rawOutput = await step.handler(stepInput, {
34
+ executionId: "",
35
+ organizationId: "",
36
+ organizationName: "",
37
+ resourceId: workflow.config.resourceId,
38
+ executionDepth: 0,
39
+ store: /* @__PURE__ */ new Map(),
40
+ logger: {
41
+ debug: (msg) => console.log(`[debug] ${msg}`),
42
+ info: (msg) => console.log(`[info] ${msg}`),
43
+ warn: (msg) => console.warn(`[warn] ${msg}`),
44
+ error: (msg) => console.error(`[error] ${msg}`)
45
+ }
46
+ });
47
+ currentData = step.outputSchema.parse(rawOutput);
48
+ stepId = resolveNext(step.next, currentData);
49
+ }
50
+ if (workflow.contract.outputSchema) {
51
+ currentData = workflow.contract.outputSchema.parse(currentData);
52
+ }
53
+ return { output: currentData, logs };
54
+ } finally {
55
+ console.log = origLog;
56
+ console.warn = origWarn;
57
+ console.error = origError;
58
+ }
59
+ }
60
+ function startWorker(org) {
61
+ const workflows = new Map(
62
+ (org.workflows ?? []).map((w) => [w.config.resourceId, w])
63
+ );
64
+ const agents = new Map(
65
+ (org.agents ?? []).map((a) => [a.config.resourceId, a])
66
+ );
67
+ parentPort.on("message", async (msg) => {
68
+ if (msg.type === "manifest") {
69
+ parentPort.postMessage({
70
+ type: "manifest",
71
+ workflows: (org.workflows ?? []).map((w) => ({
72
+ resourceId: w.config.resourceId,
73
+ name: w.config.name,
74
+ type: w.config.type,
75
+ status: w.config.status,
76
+ description: w.config.description,
77
+ version: w.config.version
78
+ })),
79
+ agents: (org.agents ?? []).map((a) => ({
80
+ resourceId: a.config.resourceId,
81
+ name: a.config.name,
82
+ type: a.config.type,
83
+ status: a.config.status,
84
+ description: a.config.description,
85
+ version: a.config.version
86
+ }))
87
+ });
88
+ return;
89
+ }
90
+ if (msg.type === "execute") {
91
+ const { resourceId, input } = msg;
92
+ const workflow = workflows.get(resourceId);
93
+ if (workflow) {
94
+ try {
95
+ const { output, logs } = await executeWorkflow(workflow, input);
96
+ parentPort.postMessage({ type: "result", status: "completed", output, logs });
97
+ } catch (err) {
98
+ parentPort.postMessage({ type: "result", status: "failed", error: String(err), logs: [] });
99
+ }
100
+ return;
101
+ }
102
+ if (agents.has(resourceId)) {
103
+ parentPort.postMessage({
104
+ type: "result",
105
+ status: "failed",
106
+ error: "Agent execution not yet supported in worker runtime",
107
+ logs: []
108
+ });
109
+ return;
110
+ }
111
+ parentPort.postMessage({
112
+ type: "result",
113
+ status: "failed",
114
+ error: `Resource not found: ${resourceId}`,
115
+ logs: []
116
+ });
117
+ }
118
+ });
119
+ }
120
+
121
+ export { startWorker };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/sdk",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "SDK for building Elevasis organization resources",
5
5
  "comment:bin": "IMPORTANT: This package shares the 'elevasis' binary name with @repo/cli. They never conflict because @elevasis/sdk must NEVER be added as a dependency of any workspace package (apps/*, packages/*, organizations/*). Workspace projects use @repo/cli for the 'elevasis' binary. External developers (outside the workspace) get this SDK's binary via npm install.",
6
6
  "type": "module",
@@ -13,14 +13,14 @@
13
13
  "types": "./dist/index.d.ts",
14
14
  "import": "./dist/index.js"
15
15
  },
16
- "./server": {
17
- "import": "./dist/server/index.js"
16
+ "./worker": {
17
+ "import": "./dist/worker/index.js"
18
18
  }
19
19
  },
20
20
  "files": [
21
21
  "dist/index.js",
22
22
  "dist/index.d.ts",
23
- "dist/server/index.js",
23
+ "dist/worker/index.js",
24
24
  "dist/cli.cjs"
25
25
  ],
26
26
  "scripts": {
@@ -1,174 +0,0 @@
1
- import { createServer } from 'http';
2
-
3
- // src/server/index.ts
4
- function readBody(req) {
5
- return new Promise((resolve, reject) => {
6
- const chunks = [];
7
- req.on("data", (chunk) => chunks.push(chunk));
8
- req.on("end", () => resolve(Buffer.concat(chunks).toString()));
9
- req.on("error", reject);
10
- });
11
- }
12
- function json(res, status, data) {
13
- res.writeHead(status, { "Content-Type": "application/json" });
14
- res.end(JSON.stringify(data));
15
- }
16
- function resolveNext(next, data) {
17
- if (next === null) return null;
18
- if (next.type === "linear") return next.target;
19
- for (const route of next.routes) {
20
- if (route.condition(data)) return route.target;
21
- }
22
- return next.default;
23
- }
24
- async function executeWorkflow(workflow, input, context) {
25
- let currentData = workflow.contract.inputSchema.parse(input);
26
- let stepId = workflow.entryPoint;
27
- while (stepId !== null) {
28
- if (context.signal?.aborted) {
29
- throw new Error("Execution cancelled");
30
- }
31
- const step = workflow.steps[stepId];
32
- if (!step) {
33
- throw new Error(`Step '${stepId}' not found in workflow '${workflow.config.resourceId}'`);
34
- }
35
- const stepInput = step.inputSchema.parse(currentData);
36
- const rawOutput = await step.handler(stepInput, context);
37
- currentData = step.outputSchema.parse(rawOutput);
38
- stepId = resolveNext(step.next, currentData);
39
- }
40
- if (workflow.contract.outputSchema) {
41
- currentData = workflow.contract.outputSchema.parse(currentData);
42
- }
43
- return currentData;
44
- }
45
- function withLogCapture(fn) {
46
- const logs = [];
47
- const orig = { log: console.log, warn: console.warn, error: console.error };
48
- const capture = (level, origFn) => (...args) => {
49
- logs.push({ level, message: args.map(String).join(" "), timestamp: Date.now() });
50
- origFn(...args);
51
- };
52
- console.log = capture("info", orig.log);
53
- console.warn = capture("warn", orig.warn);
54
- console.error = capture("error", orig.error);
55
- return fn().then((result) => ({ result, logs })).finally(() => {
56
- console.log = orig.log;
57
- console.warn = orig.warn;
58
- console.error = orig.error;
59
- });
60
- }
61
- function startServer(org) {
62
- const port = parseInt(process.env.PORT || "3000");
63
- const workflows = new Map(
64
- (org.workflows ?? []).map((w) => [w.config.resourceId, w])
65
- );
66
- const agents = new Map(
67
- (org.agents ?? []).map((a) => [a.config.resourceId, a])
68
- );
69
- const controllers = /* @__PURE__ */ new Map();
70
- const server = createServer(async (req, res) => {
71
- try {
72
- if (req.url === "/health" && req.method === "GET") {
73
- res.writeHead(200).end("ok");
74
- return;
75
- }
76
- if (req.url === "/manifest" && req.method === "GET") {
77
- json(res, 200, {
78
- workflows: (org.workflows ?? []).map((w) => ({
79
- resourceId: w.config.resourceId,
80
- name: w.config.name,
81
- type: w.config.type,
82
- status: w.config.status,
83
- description: w.config.description,
84
- version: w.config.version
85
- })),
86
- agents: (org.agents ?? []).map((a) => ({
87
- resourceId: a.config.resourceId,
88
- name: a.config.name,
89
- type: a.config.type,
90
- status: a.config.status,
91
- description: a.config.description,
92
- version: a.config.version
93
- }))
94
- });
95
- return;
96
- }
97
- if (req.url === "/execute" && req.method === "POST") {
98
- const body = JSON.parse(await readBody(req));
99
- const { resourceId, executionId, input } = body;
100
- const workflow = workflows.get(resourceId);
101
- if (workflow) {
102
- const controller = new AbortController();
103
- controllers.set(executionId, controller);
104
- const deadline = req.headers["x-elevasis-deadline"];
105
- const timer = deadline ? setTimeout(() => controller.abort(), Number(deadline) - Date.now()) : void 0;
106
- const context = {
107
- executionId,
108
- organizationId: "",
109
- organizationName: "",
110
- resourceId,
111
- executionDepth: 0,
112
- store: /* @__PURE__ */ new Map(),
113
- signal: controller.signal,
114
- logger: {
115
- debug: (msg) => console.log(`[debug] ${msg}`),
116
- info: (msg) => console.log(`[info] ${msg}`),
117
- warn: (msg) => console.warn(`[warn] ${msg}`),
118
- error: (msg) => console.error(`[error] ${msg}`)
119
- }
120
- };
121
- try {
122
- const { result: output, logs } = await withLogCapture(
123
- () => executeWorkflow(workflow, input, context)
124
- );
125
- json(res, 200, { status: "completed", output, logs });
126
- } catch (err) {
127
- const { logs } = await withLogCapture(async () => {
128
- });
129
- json(res, 500, { status: "failed", error: String(err), logs });
130
- } finally {
131
- controllers.delete(executionId);
132
- if (timer) clearTimeout(timer);
133
- }
134
- return;
135
- }
136
- const agent = agents.get(resourceId);
137
- if (agent) {
138
- json(res, 501, {
139
- status: "failed",
140
- error: `Agent execution is not supported in SDK server v0.3.0. Resource '${resourceId}' is an agent.`,
141
- logs: []
142
- });
143
- return;
144
- }
145
- json(res, 404, { error: `Resource not found: ${resourceId}` });
146
- return;
147
- }
148
- if (req.url === "/cancel" && req.method === "POST") {
149
- const body = JSON.parse(await readBody(req));
150
- const { executionId } = body;
151
- const controller = controllers.get(executionId);
152
- if (controller) {
153
- controller.abort();
154
- controllers.delete(executionId);
155
- json(res, 200, { cancelled: true });
156
- } else {
157
- json(res, 404, { error: `No running execution: ${executionId}` });
158
- }
159
- return;
160
- }
161
- res.writeHead(404).end();
162
- } catch (err) {
163
- console.error("Unhandled server error:", err);
164
- if (!res.headersSent) {
165
- json(res, 500, { error: "Internal server error" });
166
- }
167
- }
168
- });
169
- server.listen(port, () => {
170
- console.log(`Elevasis SDK server listening on port ${port}`);
171
- });
172
- }
173
-
174
- export { startServer };