runwork 0.24.0 → 0.24.1

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.
@@ -81,6 +81,16 @@ export interface AgentDefinition {
81
81
  integrations?: string[];
82
82
  /** Entity names the agent can read/write */
83
83
  entities?: string[];
84
+ /**
85
+ * Endpoints on OTHER apps in this workspace that the agent may call, as
86
+ * `'<app>:<METHOD>:<path>'` — e.g. `'labcrm:GET:/v1/portal/catalog'`.
87
+ * `<app>` is the target app's slug; `<path>` is the path exactly as registered,
88
+ * `:param` placeholders included.
89
+ *
90
+ * Declared explicitly, like `entities` and `integrations`: an agent can only
91
+ * call what the app author listed, never an arbitrary endpoint.
92
+ */
93
+ appEndpoints?: string[];
84
94
  /** Memory strategy */
85
95
  memoryStrategy?: MemoryStrategy;
86
96
  /** Custom tools for this agent */
@@ -90,6 +100,27 @@ export interface AgentDefinition {
90
100
  /** Cost/time limits for task agent sandbox execution. Optional overrides. */
91
101
  executionLimits?: ExecutionLimits;
92
102
  }
103
+ /** A parsed `'<app>:<METHOD>:<path>'` agent endpoint reference. */
104
+ export interface AppEndpointRef {
105
+ app: string;
106
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
107
+ path: string;
108
+ }
109
+ /**
110
+ * Parse `'labcrm:GET:/v1/portal/invite/:token'`.
111
+ *
112
+ * Split on the first two colons only: the path itself contains colons for its
113
+ * `:param` segments, so a naive split would mangle every parameterized endpoint.
114
+ * Returns null for anything malformed rather than throwing, so one bad entry in an
115
+ * agent definition costs that one tool instead of the whole agent.
116
+ */
117
+ export declare function parseAppEndpointRef(ref: string): AppEndpointRef | null;
118
+ /**
119
+ * Stable, model-friendly tool name for an endpoint reference, e.g.
120
+ * `call_labcrm_get_v1_portal_invite`. Param segments are dropped so the name
121
+ * stays readable; the full path is in the tool description.
122
+ */
123
+ export declare function appEndpointToolName(ref: AppEndpointRef): string;
93
124
  /**
94
125
  * Custom tool definition for agents
95
126
  */
@@ -64,6 +64,13 @@ export declare class BaseAgent extends AIChatAgent<Env> {
64
64
  * Build tools for accessing entities using AI SDK tool() helper
65
65
  * Uses entity classes directly with EntityContext
66
66
  */
67
+ /**
68
+ * One tool per endpoint the agent is allowed to call on another app.
69
+ *
70
+ * Routed through `callAppEndpoint`, so it works in preview and production
71
+ * alike: a production app cannot HTTP-fetch a sibling's public URL.
72
+ */
73
+ private buildAppEndpointTools;
67
74
  private buildEntityTools;
68
75
  /**
69
76
  * Build tools for running complex tasks via a sandboxed AI sub-agent
@@ -15,11 +15,16 @@ type ZodSchema = z.ZodType<any, any, any>;
15
15
  export type EndpointAuthType = 'apiKey' | 'public';
16
16
  /**
17
17
  * Caller principal type resolved by the platform and passed via the
18
- * `X-Public-Endpoint-Auth-Type` header. `user` and `workspace_key` are
18
+ * `X-Public-Endpoint-Auth-Type` header. `user`, `workspace_key` and `app` are
19
19
  * authenticated principals the platform has already authorized; `api_key`
20
20
  * additionally carries a validated key id; `none` is unauthenticated.
21
+ *
22
+ * `app` means a sibling app in the same workspace called this endpoint through
23
+ * the platform (see `callAppEndpoint`). The platform records which app made the
24
+ * call, but does not forward that id here: it is self-asserted by the caller and
25
+ * must not be used for authorization until app identity is verifiable.
21
26
  */
22
- export type EndpointPrincipalType = 'none' | 'api_key' | 'workspace_key' | 'user';
27
+ export type EndpointPrincipalType = 'none' | 'api_key' | 'workspace_key' | 'user' | 'app';
23
28
  /**
24
29
  * HTTP methods supported by endpoints
25
30
  */
@@ -62,7 +67,7 @@ export interface EndpointContext<TQuery = Record<string, unknown>, TBody = unkno
62
67
  export interface EndpointAuthInfo {
63
68
  /** Authentication requirement declared by the endpoint */
64
69
  type: EndpointAuthType;
65
- /** Resolved caller principal type (api_key, workspace_key, user, none) */
70
+ /** Resolved caller principal type (api_key, workspace_key, user, app, none) */
66
71
  principalType?: EndpointPrincipalType;
67
72
  /** API key ID (if authenticated with an API key) */
68
73
  apiKeyId?: string;
@@ -162,6 +162,34 @@ export interface RegisterAgentRequest extends Record<string, unknown> {
162
162
  * WorkspaceContext - Helper for cross-app data queries
163
163
  * Provides methods to query entities from other apps in the same workspace
164
164
  */
165
+ /**
166
+ * Options for calling a public endpoint on another app in the workspace.
167
+ */
168
+ export interface CallAppEndpointOptions {
169
+ /**
170
+ * Target app, normally its slug as shown in the dashboard (e.g. 'labcrm').
171
+ * An app id or worker name also resolves. If the slug is wrong, the error
172
+ * response lists the slugs available in this workspace.
173
+ */
174
+ app: string;
175
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
176
+ /** Endpoint path exactly as registered, path params included: '/v1/orders/:id'. */
177
+ path: string;
178
+ /** Values for the `:param` segments in `path`. */
179
+ pathParams?: Record<string, string>;
180
+ queryParams?: Record<string, string>;
181
+ /** JSON body. Ignored for GET and HEAD. */
182
+ body?: unknown;
183
+ }
184
+ /**
185
+ * Result of a cross-app endpoint call. `ok` and `status` are the target
186
+ * endpoint's own response status, not the transport's.
187
+ */
188
+ export interface CallAppEndpointResult<T = unknown> {
189
+ ok: boolean;
190
+ status: number;
191
+ data: T;
192
+ }
165
193
  export declare class WorkspaceContext {
166
194
  private env;
167
195
  private workspaceId;
@@ -198,6 +226,45 @@ export declare class WorkspaceContext {
198
226
  * Delete an entity in another app in the workspace
199
227
  */
200
228
  deleteEntity(entityName: string, id: string): Promise<void>;
229
+ /**
230
+ * Transport for cross-app endpoint calls.
231
+ *
232
+ * Deliberately NOT `workspaceFetch`, for two reasons:
233
+ *
234
+ * 1. `workspaceFetch` retries over HTTP whenever the Durable Object returns a
235
+ * non-2xx. That is right for entity CRUD, where a non-2xx means the DO
236
+ * itself failed. Here a non-2xx is the TARGET ENDPOINT'S OWN ANSWER, so
237
+ * retrying would re-send the request — duplicating POSTs — and in production
238
+ * the retry goes to the platform's own domain, which a Workers for Platforms
239
+ * worker cannot fetch: it hangs until timeout, the very failure this function
240
+ * exists to avoid. A status is a result, never a transport error.
241
+ *
242
+ * 2. Production therefore uses the DO binding ONLY, mirroring `workspaceApiFetch`
243
+ * in core-utils.ts, which is the proven path for every other platform call
244
+ * made from a deployed app. Preview and sandbox keep the HTTP path, where the
245
+ * app is reached over a tunnel rather than the dispatch namespace.
246
+ */
247
+ private endpointCallFetch;
248
+ /**
249
+ * Call a public endpoint on another app in this workspace.
250
+ *
251
+ * Production apps run in a Workers for Platforms dispatch namespace and cannot
252
+ * HTTP-fetch the platform's app domain, so a direct `fetch()` to a sibling app's
253
+ * public URL hangs until it times out. This routes through the workspace instead,
254
+ * which reaches the target app via the dispatcher.
255
+ *
256
+ * The call arrives at the target as an `app` principal, which satisfies endpoints
257
+ * declared `auth: 'apiKey'`. No API key is needed or sent.
258
+ *
259
+ * @example
260
+ * const invite = await callAppEndpoint(env, {
261
+ * app: 'labcrm',
262
+ * method: 'GET',
263
+ * path: '/v1/portal/invite/:token',
264
+ * pathParams: { token },
265
+ * });
266
+ */
267
+ callAppEndpoint<T = unknown>(options: CallAppEndpointOptions): Promise<CallAppEndpointResult<T>>;
201
268
  /**
202
269
  * Register an entity with the workspace so other apps can query it
203
270
  */
@@ -430,6 +497,22 @@ export declare function listWorkspaceEntity<T = unknown>(env: Env, entityName: s
430
497
  * @example
431
498
  * const contact = await getWorkspaceEntity<Contact>(env, 'Contact', 'contact-123');
432
499
  */
500
+ /**
501
+ * Call a public endpoint on ANOTHER app in this workspace.
502
+ *
503
+ * Use this instead of `fetch()` against a sibling app's public URL: production apps
504
+ * cannot HTTP-fetch the platform's app domain and such a fetch hangs until timeout.
505
+ *
506
+ * @example
507
+ * const result = await callAppEndpoint(env, {
508
+ * app: 'labcrm',
509
+ * method: 'POST',
510
+ * path: '/v1/portal/orders',
511
+ * body: { items },
512
+ * });
513
+ * if (!result.ok) throw new Error(`CRM rejected the order: ${result.status}`);
514
+ */
515
+ export declare function callAppEndpoint<T = unknown>(env: Env, options: CallAppEndpointOptions): Promise<CallAppEndpointResult<T>>;
433
516
  export declare function getWorkspaceEntity<T = unknown>(env: Env, entityName: string, id: string): Promise<T | null>;
434
517
  /**
435
518
  * Create an entity in ANOTHER app in the workspace (cross-app ONLY)
@@ -1,2 +1,2 @@
1
- export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, initializeWorkspace, } from './core-workspace';
2
- export type { WorkspaceUser, ListUsersOptions, ListUsersResponse, NotifyUserParams, NotifyUserResult, ListEntityRequest, ListEntityResponse, GetEntityRequest, CreateEntityRequest, UpdateEntityRequest, DeleteEntityRequest, RegisterEntityRequest, RegisterAppRequest, RegisterComponentRequest, RegisterScheduleRequest, RegisterWorkflowRequest, RegisterEndpointRequest, RegisterIntegrationRequest, RegisterAgentRequest as WorkspaceRegisterAgentRequest, } from './core-workspace';
1
+ export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, callAppEndpoint, initializeWorkspace, } from './core-workspace';
2
+ export type { WorkspaceUser, ListUsersOptions, ListUsersResponse, NotifyUserParams, NotifyUserResult, ListEntityRequest, ListEntityResponse, GetEntityRequest, CreateEntityRequest, UpdateEntityRequest, DeleteEntityRequest, RegisterEntityRequest, RegisterAppRequest, RegisterComponentRequest, RegisterScheduleRequest, RegisterWorkflowRequest, RegisterEndpointRequest, RegisterIntegrationRequest, CallAppEndpointOptions, CallAppEndpointResult, RegisterAgentRequest as WorkspaceRegisterAgentRequest, } from './core-workspace';
package/dist/index.js CHANGED
@@ -5100,8 +5100,8 @@ export declare function componentRoutes(app: Hono<{
5100
5100
  Bindings: Env;
5101
5101
  }>): void;
5102
5102
  `,
5103
- "workspace.d.ts": `export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, initializeWorkspace, } from './core-workspace';
5104
- export type { WorkspaceUser, ListUsersOptions, ListUsersResponse, NotifyUserParams, NotifyUserResult, ListEntityRequest, ListEntityResponse, GetEntityRequest, CreateEntityRequest, UpdateEntityRequest, DeleteEntityRequest, RegisterEntityRequest, RegisterAppRequest, RegisterComponentRequest, RegisterScheduleRequest, RegisterWorkflowRequest, RegisterEndpointRequest, RegisterIntegrationRequest, RegisterAgentRequest as WorkspaceRegisterAgentRequest, } from './core-workspace';
5103
+ "workspace.d.ts": `export { WorkspaceContext, getWorkspaceContext, listWorkspaceEntity, getWorkspaceEntity, createWorkspaceEntity, updateWorkspaceEntity, deleteWorkspaceEntity, callAppEndpoint, initializeWorkspace, } from './core-workspace';
5104
+ export type { WorkspaceUser, ListUsersOptions, ListUsersResponse, NotifyUserParams, NotifyUserResult, ListEntityRequest, ListEntityResponse, GetEntityRequest, CreateEntityRequest, UpdateEntityRequest, DeleteEntityRequest, RegisterEntityRequest, RegisterAppRequest, RegisterComponentRequest, RegisterScheduleRequest, RegisterWorkflowRequest, RegisterEndpointRequest, RegisterIntegrationRequest, CallAppEndpointOptions, CallAppEndpointResult, RegisterAgentRequest as WorkspaceRegisterAgentRequest, } from './core-workspace';
5105
5105
  `,
5106
5106
  "core-scheduler.d.ts": `/**
5107
5107
  * Core Scheduled Jobs Framework
@@ -5443,11 +5443,16 @@ type ZodSchema = z.ZodType<any, any, any>;
5443
5443
  export type EndpointAuthType = 'apiKey' | 'public';
5444
5444
  /**
5445
5445
  * Caller principal type resolved by the platform and passed via the
5446
- * \`X-Public-Endpoint-Auth-Type\` header. \`user\` and \`workspace_key\` are
5446
+ * \`X-Public-Endpoint-Auth-Type\` header. \`user\`, \`workspace_key\` and \`app\` are
5447
5447
  * authenticated principals the platform has already authorized; \`api_key\`
5448
5448
  * additionally carries a validated key id; \`none\` is unauthenticated.
5449
+ *
5450
+ * \`app\` means a sibling app in the same workspace called this endpoint through
5451
+ * the platform (see \`callAppEndpoint\`). The platform records which app made the
5452
+ * call, but does not forward that id here: it is self-asserted by the caller and
5453
+ * must not be used for authorization until app identity is verifiable.
5449
5454
  */
5450
- export type EndpointPrincipalType = 'none' | 'api_key' | 'workspace_key' | 'user';
5455
+ export type EndpointPrincipalType = 'none' | 'api_key' | 'workspace_key' | 'user' | 'app';
5451
5456
  /**
5452
5457
  * HTTP methods supported by endpoints
5453
5458
  */
@@ -5490,7 +5495,7 @@ export interface EndpointContext<TQuery = Record<string, unknown>, TBody = unkno
5490
5495
  export interface EndpointAuthInfo {
5491
5496
  /** Authentication requirement declared by the endpoint */
5492
5497
  type: EndpointAuthType;
5493
- /** Resolved caller principal type (api_key, workspace_key, user, none) */
5498
+ /** Resolved caller principal type (api_key, workspace_key, user, app, none) */
5494
5499
  principalType?: EndpointPrincipalType;
5495
5500
  /** API key ID (if authenticated with an API key) */
5496
5501
  apiKeyId?: string;
@@ -6319,6 +6324,34 @@ export interface RegisterAgentRequest extends Record<string, unknown> {
6319
6324
  * WorkspaceContext - Helper for cross-app data queries
6320
6325
  * Provides methods to query entities from other apps in the same workspace
6321
6326
  */
6327
+ /**
6328
+ * Options for calling a public endpoint on another app in the workspace.
6329
+ */
6330
+ export interface CallAppEndpointOptions {
6331
+ /**
6332
+ * Target app, normally its slug as shown in the dashboard (e.g. 'labcrm').
6333
+ * An app id or worker name also resolves. If the slug is wrong, the error
6334
+ * response lists the slugs available in this workspace.
6335
+ */
6336
+ app: string;
6337
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
6338
+ /** Endpoint path exactly as registered, path params included: '/v1/orders/:id'. */
6339
+ path: string;
6340
+ /** Values for the \`:param\` segments in \`path\`. */
6341
+ pathParams?: Record<string, string>;
6342
+ queryParams?: Record<string, string>;
6343
+ /** JSON body. Ignored for GET and HEAD. */
6344
+ body?: unknown;
6345
+ }
6346
+ /**
6347
+ * Result of a cross-app endpoint call. \`ok\` and \`status\` are the target
6348
+ * endpoint's own response status, not the transport's.
6349
+ */
6350
+ export interface CallAppEndpointResult<T = unknown> {
6351
+ ok: boolean;
6352
+ status: number;
6353
+ data: T;
6354
+ }
6322
6355
  export declare class WorkspaceContext {
6323
6356
  private env;
6324
6357
  private workspaceId;
@@ -6355,6 +6388,45 @@ export declare class WorkspaceContext {
6355
6388
  * Delete an entity in another app in the workspace
6356
6389
  */
6357
6390
  deleteEntity(entityName: string, id: string): Promise<void>;
6391
+ /**
6392
+ * Transport for cross-app endpoint calls.
6393
+ *
6394
+ * Deliberately NOT \`workspaceFetch\`, for two reasons:
6395
+ *
6396
+ * 1. \`workspaceFetch\` retries over HTTP whenever the Durable Object returns a
6397
+ * non-2xx. That is right for entity CRUD, where a non-2xx means the DO
6398
+ * itself failed. Here a non-2xx is the TARGET ENDPOINT'S OWN ANSWER, so
6399
+ * retrying would re-send the request — duplicating POSTs — and in production
6400
+ * the retry goes to the platform's own domain, which a Workers for Platforms
6401
+ * worker cannot fetch: it hangs until timeout, the very failure this function
6402
+ * exists to avoid. A status is a result, never a transport error.
6403
+ *
6404
+ * 2. Production therefore uses the DO binding ONLY, mirroring \`workspaceApiFetch\`
6405
+ * in core-utils.ts, which is the proven path for every other platform call
6406
+ * made from a deployed app. Preview and sandbox keep the HTTP path, where the
6407
+ * app is reached over a tunnel rather than the dispatch namespace.
6408
+ */
6409
+ private endpointCallFetch;
6410
+ /**
6411
+ * Call a public endpoint on another app in this workspace.
6412
+ *
6413
+ * Production apps run in a Workers for Platforms dispatch namespace and cannot
6414
+ * HTTP-fetch the platform's app domain, so a direct \`fetch()\` to a sibling app's
6415
+ * public URL hangs until it times out. This routes through the workspace instead,
6416
+ * which reaches the target app via the dispatcher.
6417
+ *
6418
+ * The call arrives at the target as an \`app\` principal, which satisfies endpoints
6419
+ * declared \`auth: 'apiKey'\`. No API key is needed or sent.
6420
+ *
6421
+ * @example
6422
+ * const invite = await callAppEndpoint(env, {
6423
+ * app: 'labcrm',
6424
+ * method: 'GET',
6425
+ * path: '/v1/portal/invite/:token',
6426
+ * pathParams: { token },
6427
+ * });
6428
+ */
6429
+ callAppEndpoint<T = unknown>(options: CallAppEndpointOptions): Promise<CallAppEndpointResult<T>>;
6358
6430
  /**
6359
6431
  * Register an entity with the workspace so other apps can query it
6360
6432
  */
@@ -6587,6 +6659,22 @@ export declare function listWorkspaceEntity<T = unknown>(env: Env, entityName: s
6587
6659
  * @example
6588
6660
  * const contact = await getWorkspaceEntity<Contact>(env, 'Contact', 'contact-123');
6589
6661
  */
6662
+ /**
6663
+ * Call a public endpoint on ANOTHER app in this workspace.
6664
+ *
6665
+ * Use this instead of \`fetch()\` against a sibling app's public URL: production apps
6666
+ * cannot HTTP-fetch the platform's app domain and such a fetch hangs until timeout.
6667
+ *
6668
+ * @example
6669
+ * const result = await callAppEndpoint(env, {
6670
+ * app: 'labcrm',
6671
+ * method: 'POST',
6672
+ * path: '/v1/portal/orders',
6673
+ * body: { items },
6674
+ * });
6675
+ * if (!result.ok) throw new Error(\`CRM rejected the order: \${result.status}\`);
6676
+ */
6677
+ export declare function callAppEndpoint<T = unknown>(env: Env, options: CallAppEndpointOptions): Promise<CallAppEndpointResult<T>>;
6590
6678
  export declare function getWorkspaceEntity<T = unknown>(env: Env, entityName: string, id: string): Promise<T | null>;
6591
6679
  /**
6592
6680
  * Create an entity in ANOTHER app in the workspace (cross-app ONLY)
@@ -6914,6 +7002,13 @@ export declare class BaseAgent extends AIChatAgent<Env> {
6914
7002
  * Build tools for accessing entities using AI SDK tool() helper
6915
7003
  * Uses entity classes directly with EntityContext
6916
7004
  */
7005
+ /**
7006
+ * One tool per endpoint the agent is allowed to call on another app.
7007
+ *
7008
+ * Routed through \`callAppEndpoint\`, so it works in preview and production
7009
+ * alike: a production app cannot HTTP-fetch a sibling's public URL.
7010
+ */
7011
+ private buildAppEndpointTools;
6917
7012
  private buildEntityTools;
6918
7013
  /**
6919
7014
  * Build tools for running complex tasks via a sandboxed AI sub-agent
@@ -7353,6 +7448,16 @@ export interface AgentDefinition {
7353
7448
  integrations?: string[];
7354
7449
  /** Entity names the agent can read/write */
7355
7450
  entities?: string[];
7451
+ /**
7452
+ * Endpoints on OTHER apps in this workspace that the agent may call, as
7453
+ * \`'<app>:<METHOD>:<path>'\` — e.g. \`'labcrm:GET:/v1/portal/catalog'\`.
7454
+ * \`<app>\` is the target app's slug; \`<path>\` is the path exactly as registered,
7455
+ * \`:param\` placeholders included.
7456
+ *
7457
+ * Declared explicitly, like \`entities\` and \`integrations\`: an agent can only
7458
+ * call what the app author listed, never an arbitrary endpoint.
7459
+ */
7460
+ appEndpoints?: string[];
7356
7461
  /** Memory strategy */
7357
7462
  memoryStrategy?: MemoryStrategy;
7358
7463
  /** Custom tools for this agent */
@@ -7362,6 +7467,27 @@ export interface AgentDefinition {
7362
7467
  /** Cost/time limits for task agent sandbox execution. Optional overrides. */
7363
7468
  executionLimits?: ExecutionLimits;
7364
7469
  }
7470
+ /** A parsed \`'<app>:<METHOD>:<path>'\` agent endpoint reference. */
7471
+ export interface AppEndpointRef {
7472
+ app: string;
7473
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
7474
+ path: string;
7475
+ }
7476
+ /**
7477
+ * Parse \`'labcrm:GET:/v1/portal/invite/:token'\`.
7478
+ *
7479
+ * Split on the first two colons only: the path itself contains colons for its
7480
+ * \`:param\` segments, so a naive split would mangle every parameterized endpoint.
7481
+ * Returns null for anything malformed rather than throwing, so one bad entry in an
7482
+ * agent definition costs that one tool instead of the whole agent.
7483
+ */
7484
+ export declare function parseAppEndpointRef(ref: string): AppEndpointRef | null;
7485
+ /**
7486
+ * Stable, model-friendly tool name for an endpoint reference, e.g.
7487
+ * \`call_labcrm_get_v1_portal_invite\`. Param segments are dropped so the name
7488
+ * stays readable; the full path is in the tool description.
7489
+ */
7490
+ export declare function appEndpointToolName(ref: AppEndpointRef): string;
7365
7491
  /**
7366
7492
  * Custom tool definition for agents
7367
7493
  */
@@ -7713,7 +7839,7 @@ function createKeyboardListener() {
7713
7839
  }
7714
7840
 
7715
7841
  // src/generated/version.ts
7716
- var VERSION = "0.24.0";
7842
+ var VERSION = "0.24.1";
7717
7843
 
7718
7844
  // src/commands/dev.ts
7719
7845
  var exports_dev = {};
@@ -8762,10 +8888,19 @@ function saveDefaultWorkspace(workspaceId, workspaceName) {
8762
8888
  function hasProjectConfig() {
8763
8889
  return existsSync21(".runwork.json");
8764
8890
  }
8891
+ function matchAppRef(apps, ref) {
8892
+ return apps.find((a) => a.id === ref || a.name === ref || a.slug === ref);
8893
+ }
8894
+ function filterRowsByApp(rows, appRef, apps) {
8895
+ const match = matchAppRef(apps, appRef);
8896
+ if (!match)
8897
+ return null;
8898
+ return rows.filter((row) => row.appId === match.id);
8899
+ }
8765
8900
  async function resolveApp2(client, workspaceId, options = {}) {
8766
8901
  if (options.app) {
8767
8902
  const apps = await client.listApps(workspaceId);
8768
- const match = apps.find((a) => a.id === options.app || a.name === options.app || a.slug === options.app);
8903
+ const match = matchAppRef(apps, options.app);
8769
8904
  if (!match) {
8770
8905
  console.error(`App "${options.app}" not found in workspace.`);
8771
8906
  process.exit(1);
@@ -19327,17 +19462,22 @@ function toRunworkInventory(ctx) {
19327
19462
  mcpServerCount: ctx.mcpServerCount
19328
19463
  };
19329
19464
  }
19330
- function buildAppSkillDescription(appName, registries) {
19465
+ function buildAppSkillDescription(skill, registries) {
19466
+ const appName = skill.name;
19467
+ const fallback = `${appName} - Runwork workspace application`;
19331
19468
  if (!registries)
19332
- return `${appName} - Runwork workspace application`;
19469
+ return fallback;
19470
+ if (!skill.appId)
19471
+ return fallback;
19472
+ const appId = skill.appId;
19333
19473
  const parts = [];
19334
- const appEntities = registries.entities.filter((e) => e.appName === appName);
19335
- const appSchedules = registries.schedules.filter((s) => s.appName === appName);
19336
- const appWorkflows = registries.workflows.filter((w) => w.appName === appName);
19337
- const appAgents = registries.agents.filter((a) => a.appName === appName);
19338
- const appEndpoints = registries.endpoints.filter((e) => e.appName === appName);
19339
- const appFileStorages = registries.fileStorages.filter((f) => f.appName === appName);
19340
- const appComponents = registries.components.filter((c) => c.appName === appName);
19474
+ const appEntities = registries.entities.filter((e) => e.appId === appId);
19475
+ const appSchedules = registries.schedules.filter((s) => s.appId === appId);
19476
+ const appWorkflows = registries.workflows.filter((w) => w.appId === appId);
19477
+ const appAgents = registries.agents.filter((a) => a.appId === appId);
19478
+ const appEndpoints = registries.endpoints.filter((e) => e.appId === appId);
19479
+ const appFileStorages = registries.fileStorages.filter((f) => f.appId === appId);
19480
+ const appComponents = registries.components.filter((c) => c.appId === appId);
19341
19481
  if (appEntities.length > 0)
19342
19482
  parts.push(`entities (${appEntities.map((e) => e.entityName).join(", ")})`);
19343
19483
  if (appFileStorages.length > 0)
@@ -19353,7 +19493,7 @@ function buildAppSkillDescription(appName, registries) {
19353
19493
  if (appComponents.length > 0)
19354
19494
  parts.push(`components (${appComponents.map((c) => c.componentName).join(", ")})`);
19355
19495
  if (parts.length === 0)
19356
- return `${appName} - Runwork workspace application`;
19496
+ return fallback;
19357
19497
  return `${appName} - Runwork workspace app with ${parts.join(", ")}. Use this skill when you need data or capabilities from this app.`;
19358
19498
  }
19359
19499
  function generateIntroSkill(ctx) {
@@ -19877,7 +20017,12 @@ var listCommand3 = new Command17("list").description("List entities registered i
19877
20017
  try {
19878
20018
  let entities = await client.listEntities(workspaceId);
19879
20019
  if (opts.app) {
19880
- entities = entities.filter((e) => e.appId === opts.app || e.appName === opts.app);
20020
+ const filtered = filterRowsByApp(entities, opts.app, await client.listApps(workspaceId));
20021
+ if (filtered === null) {
20022
+ console.error(`App "${opts.app}" not found in this workspace.`);
20023
+ process.exit(1);
20024
+ }
20025
+ entities = filtered;
19881
20026
  }
19882
20027
  if (opts.preview) {
19883
20028
  entities = entities.filter((e) => e.deploymentMode === "preview");
@@ -20226,7 +20371,12 @@ var listCommand4 = new Command18("list").description("List workflows in a worksp
20226
20371
  try {
20227
20372
  let workflows = await client.listWorkflows(workspaceId);
20228
20373
  if (opts.app) {
20229
- workflows = workflows.filter((w) => w.appId === opts.app || w.appName === opts.app);
20374
+ const filtered = filterRowsByApp(workflows, opts.app, await client.listApps(workspaceId));
20375
+ if (filtered === null) {
20376
+ console.error(`App "${opts.app}" not found in this workspace.`);
20377
+ process.exit(1);
20378
+ }
20379
+ workflows = filtered;
20230
20380
  }
20231
20381
  if (useJson) {
20232
20382
  jsonOut({ workflows });
@@ -20585,7 +20735,10 @@ function truncate3(text2, max) {
20585
20735
  return first;
20586
20736
  return first.slice(0, max - 3) + "...";
20587
20737
  }
20588
- var listCommand6 = new Command20("list").description("List workspace public endpoints").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "Filter by app name or ID").action(async (opts, command) => {
20738
+ function filterEndpointsByApp(endpoints, appRef, apps) {
20739
+ return filterRowsByApp(endpoints, appRef, apps);
20740
+ }
20741
+ var listCommand6 = new Command20("list").description("List workspace public endpoints").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <slug>", "Filter by app slug, name, or ID").action(async (opts, command) => {
20589
20742
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
20590
20743
  const credentials = requireAuth();
20591
20744
  const client = new ApiClient(credentials);
@@ -20593,7 +20746,12 @@ var listCommand6 = new Command20("list").description("List workspace public endp
20593
20746
  try {
20594
20747
  let endpoints = await client.listEndpoints(workspaceId);
20595
20748
  if (opts.app) {
20596
- endpoints = endpoints.filter((e) => e.appId === opts.app || e.appName === opts.app);
20749
+ const filtered = filterEndpointsByApp(endpoints, opts.app, await client.listApps(workspaceId));
20750
+ if (filtered === null) {
20751
+ console.error(`App "${opts.app}" not found in this workspace.`);
20752
+ process.exit(1);
20753
+ }
20754
+ endpoints = filtered;
20597
20755
  }
20598
20756
  if (useJson) {
20599
20757
  jsonOut({ endpoints });
@@ -20623,7 +20781,11 @@ Workspace: ${workspaceName || workspaceId}
20623
20781
  process.exit(1);
20624
20782
  }
20625
20783
  });
20626
- var callCommand2 = new Command20("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <name>", "App name or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method, path4, opts, command) => {
20784
+ function methodsForPath(endpoints, path4) {
20785
+ const methods = endpoints.filter((e) => e.endpointPath === path4).map((e) => e.method.toUpperCase());
20786
+ return [...new Set(methods)].sort();
20787
+ }
20788
+ var callCommand2 = new Command20("call").description("Call a workspace endpoint directly").argument("<method>", "HTTP method (GET, POST, PUT, DELETE, etc.)").argument("<path>", "Endpoint path (e.g. /my-endpoint)").option("--workspace <name-or-id>", "Workspace name or ID").option("--app <slug>", "App slug, name, or ID (narrows endpoint lookup)").option("--body <json>", "Request body as JSON string").option("--header <header>", 'Request header (format: "Key: Value", repeatable)', (val, prev) => [...prev, val], []).option("--query <string>", 'Query string to append to the URL (e.g. "foo=bar&baz=1")').option("--api-key <key>", "API key for Authorization: Bearer header").action(async (method, path4, opts, command) => {
20627
20789
  const useJson = shouldOutputJson(command.optsWithGlobals().json);
20628
20790
  const credentials = requireAuth();
20629
20791
  const client = new ApiClient(credentials);
@@ -20631,13 +20793,23 @@ var callCommand2 = new Command20("call").description("Call a workspace endpoint
20631
20793
  try {
20632
20794
  let endpoints = await client.listEndpoints(workspaceId);
20633
20795
  if (opts.app) {
20634
- endpoints = endpoints.filter((e) => e.appId === opts.app || e.appName === opts.app);
20796
+ const filtered = filterEndpointsByApp(endpoints, opts.app, await client.listApps(workspaceId));
20797
+ if (filtered === null) {
20798
+ console.error(`App "${opts.app}" not found in this workspace.`);
20799
+ process.exit(1);
20800
+ }
20801
+ endpoints = filtered;
20635
20802
  }
20636
20803
  const targetMethod = method.toUpperCase();
20637
20804
  const endpoint = endpoints.find((e) => e.method.toUpperCase() === targetMethod && e.endpointPath === path4);
20638
20805
  if (!endpoint) {
20639
20806
  console.error(`Endpoint not found: ${targetMethod} ${path4}`);
20640
- if (endpoints.length > 0) {
20807
+ const otherMethods = methodsForPath(endpoints, path4);
20808
+ if (otherMethods.length > 0) {
20809
+ console.error(`
20810
+ ${path4} is registered, but not for ${targetMethod}. Try: ${otherMethods.join(", ")}`);
20811
+ console.error(` runwork endpoints call ${otherMethods[0]} ${path4}`);
20812
+ } else if (endpoints.length > 0) {
20641
20813
  console.error(`
20642
20814
  Available endpoints:`);
20643
20815
  for (const e of endpoints) {
@@ -20907,7 +21079,12 @@ var listCommand8 = new Command22("list").description("List components registered
20907
21079
  try {
20908
21080
  let components = await client.listComponents(workspaceId);
20909
21081
  if (opts.app) {
20910
- components = components.filter((c) => c.appId === opts.app || c.appName === opts.app);
21082
+ const filtered = filterRowsByApp(components, opts.app, await client.listApps(workspaceId));
21083
+ if (filtered === null) {
21084
+ console.error(`App "${opts.app}" not found in this workspace.`);
21085
+ process.exit(1);
21086
+ }
21087
+ components = filtered;
20911
21088
  }
20912
21089
  if (useJson) {
20913
21090
  jsonOut({ components });
@@ -21040,7 +21217,12 @@ var listCommand10 = new Command24("list").description("List agents in workspace"
21040
21217
  try {
21041
21218
  let agents = await client.listAgents(workspaceId);
21042
21219
  if (opts.app) {
21043
- agents = agents.filter((a) => a.appId === opts.app || a.appName === opts.app);
21220
+ const filtered = filterRowsByApp(agents, opts.app, await client.listApps(workspaceId));
21221
+ if (filtered === null) {
21222
+ console.error(`App "${opts.app}" not found in this workspace.`);
21223
+ process.exit(1);
21224
+ }
21225
+ agents = filtered;
21044
21226
  }
21045
21227
  if (useJson) {
21046
21228
  jsonOut({ agents });
@@ -22574,7 +22756,7 @@ This account is not a member of "${state.workspaceName || state.workspaceId}".`)
22574
22756
  name: s.name,
22575
22757
  filename: s.name.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
22576
22758
  content: s.content,
22577
- description: s.source === "app" ? buildAppSkillDescription(s.name, registries) || `${s.name} - Runwork workspace application` : `${s.name} - Runwork workspace skill`
22759
+ description: s.source === "app" ? buildAppSkillDescription(s, registries) || `${s.name} - Runwork workspace application` : `${s.name} - Runwork workspace skill`
22578
22760
  }));
22579
22761
  const allSkillFiles = [...builtInSkills, ...workspaceSkillFiles];
22580
22762
  const written = await adapter2.writeSkills(allSkillFiles, scope);
@@ -23337,7 +23519,7 @@ var buildPluginCommand = new Command29("build-plugin").description("Build an ins
23337
23519
  name: s.name,
23338
23520
  filename: s.name.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
23339
23521
  content: s.content,
23340
- description: s.source === "app" ? buildAppSkillDescription(s.name, registries) || `${s.name} - Runwork workspace application` : `${s.name} - Runwork workspace skill`
23522
+ description: s.source === "app" ? buildAppSkillDescription(s, registries) || `${s.name} - Runwork workspace application` : `${s.name} - Runwork workspace skill`
23341
23523
  }))
23342
23524
  ];
23343
23525
  const teamInstructions = onboardingConfig?.config?.teamInstructions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runwork",
3
- "version": "0.24.0",
3
+ "version": "0.24.1",
4
4
  "description": "CLI for Runwork: develop, preview, and deploy Runwork apps from your local machine.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Runwork, Inc. <info@runwork.ai> (https://www.runwork.ai)",