@stackbone/cli 0.2.3 → 0.2.4
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/main.js +494 -209
- package/package.json +1 -1
- package/stackbone-cli-0.2.4.tgz +0 -0
- package/stackbone-cli-0.2.3.tgz +0 -0
package/main.js
CHANGED
|
@@ -2988,7 +2988,7 @@ var DEV_HMAC_SECRET = "dev-stackbone-local-emulator-hmac-secret";
|
|
|
2988
2988
|
//#endregion
|
|
2989
2989
|
//#region ../../libs/runtime/agent-emulator/src/lib/server/contract.ts
|
|
2990
2990
|
init_src$14();
|
|
2991
|
-
var STACKBONE_CLI_BUILD_VERSION = "0.2.
|
|
2991
|
+
var STACKBONE_CLI_BUILD_VERSION = "0.2.4";
|
|
2992
2992
|
/**
|
|
2993
2993
|
* Capabilities the local emulator advertises on `GET /api/contract`, derived
|
|
2994
2994
|
* from the route registry above so the advertised set and the mounted routes
|
|
@@ -13712,7 +13712,15 @@ var init_trigger_descriptor = __esmMin((() => {
|
|
|
13712
13712
|
/** Dot-path, per item, to the sortable marker used to compute the next cursor. */
|
|
13713
13713
|
field: z.string(),
|
|
13714
13714
|
/** Request arg set to the stored cursor so the provider filters server-side. */
|
|
13715
|
-
param: z.string()
|
|
13715
|
+
param: z.string(),
|
|
13716
|
+
/**
|
|
13717
|
+
* Optional template for the parameter value — when present, the stored cursor
|
|
13718
|
+
* is interpolated into this template via `{cursor}` instead of injected as a
|
|
13719
|
+
* bare value. Use when the provider needs a full expression rather than a raw
|
|
13720
|
+
* value, e.g. `receivedDateTime gt {cursor}` for OData `$filter` params.
|
|
13721
|
+
* Absent = backward-compatible bare-value injection.
|
|
13722
|
+
*/
|
|
13723
|
+
cursorTemplate: z.string().optional()
|
|
13716
13724
|
}), z.object({
|
|
13717
13725
|
kind: z.literal("opaque"),
|
|
13718
13726
|
/** Dot-path in the list response to the next opaque token. */
|
|
@@ -13732,6 +13740,23 @@ var init_trigger_descriptor = __esmMin((() => {
|
|
|
13732
13740
|
pageToken: z.object({
|
|
13733
13741
|
requestParam: z.string(),
|
|
13734
13742
|
responsePath: z.string()
|
|
13743
|
+
}).optional(),
|
|
13744
|
+
/**
|
|
13745
|
+
* Offset-based pagination via `$skip`/`$top` — an alternative to `pageToken`
|
|
13746
|
+
* for providers whose OpenAPI spec does not expose the page cursor (e.g.
|
|
13747
|
+
* Microsoft Graph, which paginates via `@odata.nextLink` URLs but only
|
|
13748
|
+
* exposes `$skip` as a query parameter). When present, the engine calls the
|
|
13749
|
+
* list operation with `pageSizeParam` set to `stride` on every request, and
|
|
13750
|
+
* increments `param` by `stride` each page. Stops when a page returns fewer
|
|
13751
|
+
* items than `stride`. Mutually exclusive with `pageToken`.
|
|
13752
|
+
*/
|
|
13753
|
+
pageSkip: z.object({
|
|
13754
|
+
/** Query param name for the offset, e.g. `$skip`. */
|
|
13755
|
+
param: z.string(),
|
|
13756
|
+
/** Query param name for the page size, e.g. `$top`. */
|
|
13757
|
+
pageSizeParam: z.string(),
|
|
13758
|
+
/** Number of items per page, also the stride for incrementing `param`. */
|
|
13759
|
+
stride: z.number()
|
|
13735
13760
|
}).optional()
|
|
13736
13761
|
});
|
|
13737
13762
|
triggerItemStepSchema = z.object({
|
|
@@ -13900,6 +13925,173 @@ var init_registry_store = __esmMin((() => {
|
|
|
13900
13925
|
};
|
|
13901
13926
|
}));
|
|
13902
13927
|
//#endregion
|
|
13928
|
+
//#region ../../libs/shared/connect-registry/src/lib/catalog/gmail/gmail.connector.ts
|
|
13929
|
+
var GMAIL_CONNECTOR;
|
|
13930
|
+
var init_gmail_connector = __esmMin((() => {
|
|
13931
|
+
GMAIL_CONNECTOR = {
|
|
13932
|
+
id: "gmail",
|
|
13933
|
+
displayName: "Gmail",
|
|
13934
|
+
description: "Send email and read messages from a connected Gmail account.",
|
|
13935
|
+
logoUrl: "https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://mail.google.com&size=64",
|
|
13936
|
+
category: "email",
|
|
13937
|
+
protocol: "openapi",
|
|
13938
|
+
baseUrl: "https://gmail.googleapis.com/gmail/v1/users/me",
|
|
13939
|
+
authMode: "oauth",
|
|
13940
|
+
placement: { kind: "bearer" },
|
|
13941
|
+
scopes: [
|
|
13942
|
+
"openid",
|
|
13943
|
+
"email",
|
|
13944
|
+
"profile",
|
|
13945
|
+
"https://www.googleapis.com/auth/gmail.readonly",
|
|
13946
|
+
"https://www.googleapis.com/auth/gmail.send"
|
|
13947
|
+
],
|
|
13948
|
+
authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
13949
|
+
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
13950
|
+
authorizeParams: {
|
|
13951
|
+
access_type: "offline",
|
|
13952
|
+
prompt: "consent"
|
|
13953
|
+
},
|
|
13954
|
+
specSource: {
|
|
13955
|
+
kind: "url",
|
|
13956
|
+
url: "https://api.apis.guru/v2/specs/googleapis.com/gmail/v1/openapi.json"
|
|
13957
|
+
},
|
|
13958
|
+
triggers: [{
|
|
13959
|
+
id: "message-received",
|
|
13960
|
+
displayName: "Message received",
|
|
13961
|
+
description: "Fires when a new message arrives in the inbox.",
|
|
13962
|
+
sampleData: {
|
|
13963
|
+
messageId: "18e0a1b2c3d4e5f6",
|
|
13964
|
+
threadId: "18e0a1b2c3d4e5f6",
|
|
13965
|
+
from: "Ada Lovelace <ada@example.com>",
|
|
13966
|
+
to: "agent@stackbone.ai",
|
|
13967
|
+
subject: "Quarterly report",
|
|
13968
|
+
snippet: "Here is the quarterly report you asked for…",
|
|
13969
|
+
date: "Mon, 10 Jun 2024 09:15:00 +0000",
|
|
13970
|
+
raw: {
|
|
13971
|
+
messageId: "18e0a1b2c3d4e5f6",
|
|
13972
|
+
threadId: "18e0a1b2c3d4e5f6",
|
|
13973
|
+
historyId: "987654"
|
|
13974
|
+
}
|
|
13975
|
+
},
|
|
13976
|
+
poll: {
|
|
13977
|
+
kind: "strategy",
|
|
13978
|
+
strategy: "gmail.history"
|
|
13979
|
+
}
|
|
13980
|
+
}]
|
|
13981
|
+
};
|
|
13982
|
+
}));
|
|
13983
|
+
//#endregion
|
|
13984
|
+
//#region ../../libs/shared/connect-registry/src/lib/catalog/outlook/outlook.connector.ts
|
|
13985
|
+
var OUTLOOK_CONNECTOR;
|
|
13986
|
+
var init_outlook_connector = __esmMin((() => {
|
|
13987
|
+
OUTLOOK_CONNECTOR = {
|
|
13988
|
+
id: "outlook",
|
|
13989
|
+
displayName: "Outlook",
|
|
13990
|
+
description: "Send email and read messages from a connected Outlook account.",
|
|
13991
|
+
logoUrl: "https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://microsoft.com&size=64",
|
|
13992
|
+
category: "email",
|
|
13993
|
+
protocol: "openapi",
|
|
13994
|
+
baseUrl: "https://graph.microsoft.com/v1.0",
|
|
13995
|
+
authMode: "oauth",
|
|
13996
|
+
placement: { kind: "bearer" },
|
|
13997
|
+
scopes: [
|
|
13998
|
+
"openid",
|
|
13999
|
+
"email",
|
|
14000
|
+
"profile",
|
|
14001
|
+
"Mail.Read",
|
|
14002
|
+
"Mail.Send",
|
|
14003
|
+
"offline_access"
|
|
14004
|
+
],
|
|
14005
|
+
authorizeUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
|
14006
|
+
tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
14007
|
+
specSource: {
|
|
14008
|
+
kind: "url",
|
|
14009
|
+
url: "https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/openapi/v1.0/default.yaml"
|
|
14010
|
+
},
|
|
14011
|
+
authorizeParams: { prompt: "consent" },
|
|
14012
|
+
triggers: [{
|
|
14013
|
+
id: "message-received",
|
|
14014
|
+
displayName: "Message received",
|
|
14015
|
+
description: "Fires when a new message arrives in the Inbox.",
|
|
14016
|
+
sampleData: {
|
|
14017
|
+
messageId: "AAMkAD...",
|
|
14018
|
+
conversationId: "AAQkAD...",
|
|
14019
|
+
from: {
|
|
14020
|
+
name: "Ada Lovelace",
|
|
14021
|
+
address: "ada@example.com"
|
|
14022
|
+
},
|
|
14023
|
+
subject: "Quarterly report",
|
|
14024
|
+
snippet: "Here is the quarterly report...",
|
|
14025
|
+
date: "2024-06-10T09:15:00Z",
|
|
14026
|
+
isRead: false
|
|
14027
|
+
},
|
|
14028
|
+
poll: {
|
|
14029
|
+
kind: "declarative",
|
|
14030
|
+
list: {
|
|
14031
|
+
operationId: "me.mailFolders.ListMessages",
|
|
14032
|
+
args: { "mailFolder-id": "Inbox" },
|
|
14033
|
+
itemsPath: "value",
|
|
14034
|
+
pageSkip: {
|
|
14035
|
+
param: "$skip",
|
|
14036
|
+
pageSizeParam: "$top",
|
|
14037
|
+
stride: 100
|
|
14038
|
+
}
|
|
14039
|
+
},
|
|
14040
|
+
cursor: {
|
|
14041
|
+
kind: "timestamp",
|
|
14042
|
+
field: "receivedDateTime",
|
|
14043
|
+
param: "$filter",
|
|
14044
|
+
cursorTemplate: "receivedDateTime gt {cursor}"
|
|
14045
|
+
},
|
|
14046
|
+
dedup: { idPath: "id" },
|
|
14047
|
+
map: {
|
|
14048
|
+
messageId: "id",
|
|
14049
|
+
conversationId: "conversationId",
|
|
14050
|
+
from: "from",
|
|
14051
|
+
subject: "subject",
|
|
14052
|
+
snippet: "bodyPreview",
|
|
14053
|
+
date: "receivedDateTime",
|
|
14054
|
+
isRead: "isRead"
|
|
14055
|
+
}
|
|
14056
|
+
}
|
|
14057
|
+
}]
|
|
14058
|
+
};
|
|
14059
|
+
}));
|
|
14060
|
+
//#endregion
|
|
14061
|
+
//#region ../../libs/shared/connect-registry/src/lib/catalog/telegram/telegram.connector.ts
|
|
14062
|
+
var TELEGRAM_CONNECTOR;
|
|
14063
|
+
var init_telegram_connector = __esmMin((() => {
|
|
14064
|
+
TELEGRAM_CONNECTOR = {
|
|
14065
|
+
id: "telegram",
|
|
14066
|
+
displayName: "Telegram",
|
|
14067
|
+
description: "Send and receive messages through a Telegram bot.",
|
|
14068
|
+
logoUrl: "https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://telegram.org/&size=64",
|
|
14069
|
+
category: "messaging",
|
|
14070
|
+
protocol: "openapi",
|
|
14071
|
+
baseUrl: "https://api.telegram.org",
|
|
14072
|
+
authMode: "api_key",
|
|
14073
|
+
placement: { kind: "bearer" },
|
|
14074
|
+
scopes: []
|
|
14075
|
+
};
|
|
14076
|
+
}));
|
|
14077
|
+
//#endregion
|
|
14078
|
+
//#region ../../libs/shared/connect-registry/src/lib/catalog/whatsapp/whatsapp.connector.ts
|
|
14079
|
+
var WHATSAPP_CONNECTOR;
|
|
14080
|
+
var init_whatsapp_connector = __esmMin((() => {
|
|
14081
|
+
WHATSAPP_CONNECTOR = {
|
|
14082
|
+
id: "whatsapp",
|
|
14083
|
+
displayName: "WhatsApp",
|
|
14084
|
+
description: "Send and receive messages through a WhatsApp bot.",
|
|
14085
|
+
logoUrl: "https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://www.whatsapp.com/&size=64",
|
|
14086
|
+
category: "messaging",
|
|
14087
|
+
protocol: "openapi",
|
|
14088
|
+
baseUrl: "https://api.whatsapp.com/v1",
|
|
14089
|
+
authMode: "api_key",
|
|
14090
|
+
placement: { kind: "bearer" },
|
|
14091
|
+
scopes: []
|
|
14092
|
+
};
|
|
14093
|
+
}));
|
|
14094
|
+
//#endregion
|
|
13903
14095
|
//#region ../../libs/shared/connect-registry/src/lib/catalog/built-in-catalog.ts
|
|
13904
14096
|
/**
|
|
13905
14097
|
* Seed `store` with the built-in catalog. Returns `loadFromJson`'s outcome so the
|
|
@@ -13911,91 +14103,15 @@ function loadBuiltInCatalog(store) {
|
|
|
13911
14103
|
}
|
|
13912
14104
|
var BUILT_IN_CONNECTOR_DOCS;
|
|
13913
14105
|
var init_built_in_catalog = __esmMin((() => {
|
|
14106
|
+
init_gmail_connector();
|
|
14107
|
+
init_outlook_connector();
|
|
14108
|
+
init_telegram_connector();
|
|
14109
|
+
init_whatsapp_connector();
|
|
13914
14110
|
BUILT_IN_CONNECTOR_DOCS = [
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
logoUrl: "https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://mail.google.com&size=64",
|
|
13920
|
-
category: "email",
|
|
13921
|
-
protocol: "openapi",
|
|
13922
|
-
baseUrl: "https://gmail.googleapis.com/gmail/v1/users/me",
|
|
13923
|
-
authMode: "oauth",
|
|
13924
|
-
placement: { kind: "bearer" },
|
|
13925
|
-
scopes: [
|
|
13926
|
-
"openid",
|
|
13927
|
-
"email",
|
|
13928
|
-
"profile",
|
|
13929
|
-
"https://www.googleapis.com/auth/gmail.readonly",
|
|
13930
|
-
"https://www.googleapis.com/auth/gmail.send"
|
|
13931
|
-
],
|
|
13932
|
-
authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
13933
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
13934
|
-
authorizeParams: {
|
|
13935
|
-
access_type: "offline",
|
|
13936
|
-
prompt: "consent"
|
|
13937
|
-
},
|
|
13938
|
-
specSource: {
|
|
13939
|
-
kind: "url",
|
|
13940
|
-
url: "https://api.apis.guru/v2/specs/googleapis.com/gmail/v1/openapi.json"
|
|
13941
|
-
},
|
|
13942
|
-
triggers: [{
|
|
13943
|
-
id: "message-received",
|
|
13944
|
-
displayName: "Message received",
|
|
13945
|
-
description: "Fires when a new message arrives in the inbox.",
|
|
13946
|
-
sampleData: {
|
|
13947
|
-
messageId: "18e0a1b2c3d4e5f6",
|
|
13948
|
-
threadId: "18e0a1b2c3d4e5f6",
|
|
13949
|
-
from: "Ada Lovelace <ada@example.com>",
|
|
13950
|
-
to: "agent@stackbone.ai",
|
|
13951
|
-
subject: "Quarterly report",
|
|
13952
|
-
snippet: "Here is the quarterly report you asked for…",
|
|
13953
|
-
date: "Mon, 10 Jun 2024 09:15:00 +0000",
|
|
13954
|
-
raw: {
|
|
13955
|
-
messageId: "18e0a1b2c3d4e5f6",
|
|
13956
|
-
threadId: "18e0a1b2c3d4e5f6",
|
|
13957
|
-
historyId: "987654"
|
|
13958
|
-
}
|
|
13959
|
-
},
|
|
13960
|
-
poll: {
|
|
13961
|
-
kind: "strategy",
|
|
13962
|
-
strategy: "gmail.history"
|
|
13963
|
-
}
|
|
13964
|
-
}]
|
|
13965
|
-
},
|
|
13966
|
-
{
|
|
13967
|
-
id: "outlook",
|
|
13968
|
-
displayName: "Outlook",
|
|
13969
|
-
description: "Send email and read messages from a connected Outlook account.",
|
|
13970
|
-
logoUrl: "https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://microsoft.com&size=64",
|
|
13971
|
-
category: "email",
|
|
13972
|
-
protocol: "openapi",
|
|
13973
|
-
baseUrl: "https://graph.microsoft.com/v1.0",
|
|
13974
|
-
authMode: "oauth",
|
|
13975
|
-
placement: { kind: "bearer" },
|
|
13976
|
-
scopes: [
|
|
13977
|
-
"openid",
|
|
13978
|
-
"email",
|
|
13979
|
-
"profile",
|
|
13980
|
-
"Mail.Read",
|
|
13981
|
-
"Mail.Send",
|
|
13982
|
-
"offline_access"
|
|
13983
|
-
],
|
|
13984
|
-
authorizeUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
|
13985
|
-
tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token"
|
|
13986
|
-
},
|
|
13987
|
-
{
|
|
13988
|
-
id: "telegram",
|
|
13989
|
-
displayName: "Telegram",
|
|
13990
|
-
description: "Send and receive messages through a Telegram bot.",
|
|
13991
|
-
logoUrl: "https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://telegram.org/&size=64",
|
|
13992
|
-
category: "messaging",
|
|
13993
|
-
protocol: "openapi",
|
|
13994
|
-
baseUrl: "https://api.telegram.org",
|
|
13995
|
-
authMode: "api_key",
|
|
13996
|
-
placement: { kind: "bearer" },
|
|
13997
|
-
scopes: []
|
|
13998
|
-
}
|
|
14111
|
+
GMAIL_CONNECTOR,
|
|
14112
|
+
OUTLOOK_CONNECTOR,
|
|
14113
|
+
TELEGRAM_CONNECTOR,
|
|
14114
|
+
WHATSAPP_CONNECTOR
|
|
13999
14115
|
];
|
|
14000
14116
|
}));
|
|
14001
14117
|
//#endregion
|
|
@@ -14568,14 +14684,17 @@ function latestTimestamp(items, field) {
|
|
|
14568
14684
|
function createDeclarativePoll(spec) {
|
|
14569
14685
|
return async (ctx, cursor) => {
|
|
14570
14686
|
const baseArgs = { ...spec.list.args ?? {} };
|
|
14571
|
-
if (cursor !== null && cursor !== void 0) if (spec.cursor.kind === "timestamp") baseArgs[spec.cursor.param] = cursor;
|
|
14687
|
+
if (cursor !== null && cursor !== void 0) if (spec.cursor.kind === "timestamp") baseArgs[spec.cursor.param] = spec.cursor.cursorTemplate ? spec.cursor.cursorTemplate.replace("{cursor}", String(cursor)) : cursor;
|
|
14572
14688
|
else baseArgs[spec.cursor.requestParam] = cursor;
|
|
14573
14689
|
const rawItems = [];
|
|
14574
14690
|
let opaqueNext;
|
|
14575
14691
|
let pageToken;
|
|
14576
14692
|
for (let page = 0; page < MAX_PAGES; page += 1) {
|
|
14577
14693
|
const args = { ...baseArgs };
|
|
14578
|
-
if (
|
|
14694
|
+
if (spec.list.pageSkip) {
|
|
14695
|
+
args[spec.list.pageSkip.pageSizeParam] = spec.list.pageSkip.stride;
|
|
14696
|
+
if (page > 0) args[spec.list.pageSkip.param] = page * spec.list.pageSkip.stride;
|
|
14697
|
+
} else if (pageToken !== null && pageToken !== void 0 && spec.list.pageToken) args[spec.list.pageToken.requestParam] = pageToken;
|
|
14579
14698
|
const response = await ctx.runOperation(spec.list.operationId, args);
|
|
14580
14699
|
const items = getPath(response, spec.list.itemsPath);
|
|
14581
14700
|
if (Array.isArray(items)) rawItems.push(...items);
|
|
@@ -14583,8 +14702,12 @@ function createDeclarativePoll(spec) {
|
|
|
14583
14702
|
const next = getPath(response, spec.cursor.responsePath);
|
|
14584
14703
|
if (next !== null && next !== void 0) opaqueNext = next;
|
|
14585
14704
|
}
|
|
14586
|
-
|
|
14587
|
-
|
|
14705
|
+
if (spec.list.pageSkip) {
|
|
14706
|
+
if (!Array.isArray(items) || items.length < spec.list.pageSkip.stride) break;
|
|
14707
|
+
} else {
|
|
14708
|
+
pageToken = spec.list.pageToken ? getPath(response, spec.list.pageToken.responsePath) : void 0;
|
|
14709
|
+
if (pageToken === null || pageToken === void 0) break;
|
|
14710
|
+
}
|
|
14588
14711
|
}
|
|
14589
14712
|
let items = rawItems;
|
|
14590
14713
|
if (spec.item) {
|
|
@@ -14610,6 +14733,113 @@ var init_declarative_poll = __esmMin((() => {
|
|
|
14610
14733
|
MAX_PAGES = 100;
|
|
14611
14734
|
}));
|
|
14612
14735
|
//#endregion
|
|
14736
|
+
//#region ../../libs/shared/connect-registry/src/lib/catalog/gmail/gmail.history-strategy.ts
|
|
14737
|
+
function isGmailCursor(cursor) {
|
|
14738
|
+
return typeof cursor === "object" && cursor !== null && typeof cursor.historyId === "string" && cursor.historyId.length > 0;
|
|
14739
|
+
}
|
|
14740
|
+
/** Read a single header value (case-insensitive) off a Gmail message payload. */
|
|
14741
|
+
function header(message, name) {
|
|
14742
|
+
const match = (message.payload?.headers ?? []).find((h) => (h.name ?? "").toLowerCase() === name.toLowerCase());
|
|
14743
|
+
return typeof match?.value === "string" ? match.value : "";
|
|
14744
|
+
}
|
|
14745
|
+
/** Fetch one message (metadata format) and normalize it to a poll item. */
|
|
14746
|
+
async function fetchMessageEvent(ctx, id) {
|
|
14747
|
+
const message = await ctx.runOperation("gmail.users.messages.get", {
|
|
14748
|
+
userId: USER_ID,
|
|
14749
|
+
id,
|
|
14750
|
+
format: "metadata"
|
|
14751
|
+
});
|
|
14752
|
+
const payload = {
|
|
14753
|
+
messageId: message.id ?? id,
|
|
14754
|
+
threadId: message.threadId ?? "",
|
|
14755
|
+
from: header(message, "From"),
|
|
14756
|
+
to: header(message, "To"),
|
|
14757
|
+
subject: header(message, "Subject"),
|
|
14758
|
+
snippet: typeof message.snippet === "string" ? message.snippet : "",
|
|
14759
|
+
date: header(message, "Date"),
|
|
14760
|
+
raw: {
|
|
14761
|
+
messageId: message.id ?? id,
|
|
14762
|
+
threadId: message.threadId ?? "",
|
|
14763
|
+
historyId: typeof message.historyId === "string" ? message.historyId : null
|
|
14764
|
+
}
|
|
14765
|
+
};
|
|
14766
|
+
return {
|
|
14767
|
+
id: message.id ?? id,
|
|
14768
|
+
payload
|
|
14769
|
+
};
|
|
14770
|
+
}
|
|
14771
|
+
function readHistoryId(event) {
|
|
14772
|
+
const raw = (event?.payload)?.raw;
|
|
14773
|
+
return raw && typeof raw.historyId === "string" ? raw.historyId : null;
|
|
14774
|
+
}
|
|
14775
|
+
/**
|
|
14776
|
+
* Bootstrap path (empty cursor): list the most recent inbox messages, normalize
|
|
14777
|
+
* them, and seed the cursor from the newest message's `historyId`. Dedup is the
|
|
14778
|
+
* platform's job (by message id), so a first poll legitimately returns the recent
|
|
14779
|
+
* window and the next poll resumes from the history API.
|
|
14780
|
+
*/
|
|
14781
|
+
async function bootstrap(ctx) {
|
|
14782
|
+
const items = await mapWithConcurrency(((await ctx.runOperation("gmail.users.messages.list", {
|
|
14783
|
+
userId: USER_ID,
|
|
14784
|
+
maxResults: BOOTSTRAP_MAX_RESULTS,
|
|
14785
|
+
labelIds: "INBOX"
|
|
14786
|
+
})).messages ?? []).map((m) => m.id).filter((id) => typeof id === "string" && id.length > 0), 6, (id) => fetchMessageEvent(ctx, id));
|
|
14787
|
+
const seedHistoryId = readHistoryId(items[0]);
|
|
14788
|
+
return {
|
|
14789
|
+
items,
|
|
14790
|
+
nextCursor: seedHistoryId ? { historyId: seedHistoryId } : null
|
|
14791
|
+
};
|
|
14792
|
+
}
|
|
14793
|
+
/**
|
|
14794
|
+
* Incremental path (valid cursor): pull history records added since the persisted
|
|
14795
|
+
* `historyId` via `history.list`, drain EVERY page (so messages on pages 2+ are
|
|
14796
|
+
* never skipped when the cursor advances), normalize each new arrival, and move
|
|
14797
|
+
* the cursor to the response's latest `historyId`.
|
|
14798
|
+
*/
|
|
14799
|
+
async function pollFromCursor(ctx, cursor) {
|
|
14800
|
+
const addedIds = [];
|
|
14801
|
+
let latestHistoryId = cursor.historyId;
|
|
14802
|
+
let pageToken;
|
|
14803
|
+
for (let page = 0; page < MAX_HISTORY_PAGES; page += 1) {
|
|
14804
|
+
const history = await ctx.runOperation("gmail.users.history.list", {
|
|
14805
|
+
userId: USER_ID,
|
|
14806
|
+
startHistoryId: cursor.historyId,
|
|
14807
|
+
historyTypes: "messageAdded",
|
|
14808
|
+
labelId: "INBOX",
|
|
14809
|
+
...pageToken ? { pageToken } : {}
|
|
14810
|
+
});
|
|
14811
|
+
for (const record of history.history ?? []) for (const added of record.messagesAdded ?? []) {
|
|
14812
|
+
const id = added.message?.id;
|
|
14813
|
+
if (typeof id === "string" && id.length > 0) addedIds.push(id);
|
|
14814
|
+
}
|
|
14815
|
+
if (typeof history.historyId === "string" && history.historyId.length > 0) latestHistoryId = history.historyId;
|
|
14816
|
+
if (typeof history.nextPageToken === "string" && history.nextPageToken.length > 0) pageToken = history.nextPageToken;
|
|
14817
|
+
else break;
|
|
14818
|
+
}
|
|
14819
|
+
return {
|
|
14820
|
+
items: await mapWithConcurrency(addedIds, 6, (id) => fetchMessageEvent(ctx, id)),
|
|
14821
|
+
nextCursor: { historyId: latestHistoryId }
|
|
14822
|
+
};
|
|
14823
|
+
}
|
|
14824
|
+
var USER_ID, BOOTSTRAP_MAX_RESULTS, MAX_HISTORY_PAGES, gmailHistoryPoll;
|
|
14825
|
+
var init_gmail_history_strategy = __esmMin((() => {
|
|
14826
|
+
init_concurrency();
|
|
14827
|
+
USER_ID = "me";
|
|
14828
|
+
BOOTSTRAP_MAX_RESULTS = 25;
|
|
14829
|
+
MAX_HISTORY_PAGES = 100;
|
|
14830
|
+
gmailHistoryPoll = async (ctx, cursor) => {
|
|
14831
|
+
if (!isGmailCursor(cursor)) return bootstrap(ctx);
|
|
14832
|
+
return pollFromCursor(ctx, cursor);
|
|
14833
|
+
};
|
|
14834
|
+
}));
|
|
14835
|
+
//#endregion
|
|
14836
|
+
//#region ../../libs/shared/connect-registry/src/lib/catalog/built-in-strategies.ts
|
|
14837
|
+
var BUILT_IN_STRATEGIES;
|
|
14838
|
+
var init_built_in_strategies = __esmMin((() => {
|
|
14839
|
+
init_gmail_history_strategy();
|
|
14840
|
+
BUILT_IN_STRATEGIES = { "gmail.history": gmailHistoryPoll };
|
|
14841
|
+
}));
|
|
14842
|
+
//#endregion
|
|
14613
14843
|
//#region ../../libs/shared/connect-registry/src/index.ts
|
|
14614
14844
|
var init_src$3 = __esmMin((() => {
|
|
14615
14845
|
init_types$1();
|
|
@@ -14622,6 +14852,7 @@ var init_src$3 = __esmMin((() => {
|
|
|
14622
14852
|
init_trigger_descriptor();
|
|
14623
14853
|
init_declarative_poll();
|
|
14624
14854
|
init_concurrency();
|
|
14855
|
+
init_built_in_strategies();
|
|
14625
14856
|
}));
|
|
14626
14857
|
//#endregion
|
|
14627
14858
|
//#region ../../libs/platform/connect-broker/src/lib/executor/spec-introspection.ts
|
|
@@ -16695,8 +16926,14 @@ function invalidRequest(message) {
|
|
|
16695
16926
|
}
|
|
16696
16927
|
//#endregion
|
|
16697
16928
|
//#region ../../libs/runtime/agent-emulator/src/lib/deep-agents/registry.ts
|
|
16698
|
-
var DEEP_AGENTS_WELL_KNOWN_DIR, isPlainRecord, readConfigStrings, toMetadata, isDeepAgentDefinition, bundleAndLoad, loadPrebuilt, createDeepAgentRegistry, errMessage$9, matchChangedPathsToAgents;
|
|
16929
|
+
var SYSTEM_DEEP_AGENTS, isInternalDeepAgent, DEEP_AGENTS_WELL_KNOWN_DIR, isPlainRecord, readConfigStrings, toMetadata, isDeepAgentDefinition, bundleAndLoad, loadPrebuilt, createDeepAgentRegistry, errMessage$9, matchChangedPathsToAgents;
|
|
16699
16930
|
var init_registry$1 = __esmMin((() => {
|
|
16931
|
+
SYSTEM_DEEP_AGENTS = new Set(["rag-ingest"]);
|
|
16932
|
+
isInternalDeepAgent = (agent) => {
|
|
16933
|
+
if (agent.$internal === false) return false;
|
|
16934
|
+
if (agent.$internal === true) return true;
|
|
16935
|
+
return SYSTEM_DEEP_AGENTS.has(agent.name);
|
|
16936
|
+
};
|
|
16700
16937
|
DEEP_AGENTS_WELL_KNOWN_DIR = ".well-known/deep-agents";
|
|
16701
16938
|
isPlainRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16702
16939
|
readConfigStrings = (config) => {
|
|
@@ -16788,7 +17025,8 @@ var init_registry$1 = __esmMin((() => {
|
|
|
16788
17025
|
metadata: toMetadata(def)
|
|
16789
17026
|
},
|
|
16790
17027
|
createGraph: def.createGraph.bind(def),
|
|
16791
|
-
supportsCheckpointer: def.capabilities?.checkpointer === true
|
|
17028
|
+
supportsCheckpointer: def.capabilities?.checkpointer === true,
|
|
17029
|
+
$internal: isInternalDeepAgent(agent)
|
|
16792
17030
|
});
|
|
16793
17031
|
logger.info(`deep agent "${agent.name}" ready (model ${def.metadata.model}).`);
|
|
16794
17032
|
return true;
|
|
@@ -16829,7 +17067,7 @@ var init_registry$1 = __esmMin((() => {
|
|
|
16829
17067
|
return {
|
|
16830
17068
|
list: () => {
|
|
16831
17069
|
const checkpointerReady = opts.checkpointer?.status?.() === "ready";
|
|
16832
|
-
return [...registered.values()].map((e) => ({
|
|
17070
|
+
return [...registered.values()].filter((e) => !e.$internal).map((e) => ({
|
|
16833
17071
|
name: e.view.name,
|
|
16834
17072
|
metadata: e.view.metadata,
|
|
16835
17073
|
durable: e.supportsCheckpointer && checkpointerReady
|
|
@@ -22240,13 +22478,19 @@ var init_workflow_step_world_port = __esmMin((() => {
|
|
|
22240
22478
|
}));
|
|
22241
22479
|
//#endregion
|
|
22242
22480
|
//#region ../../libs/runtime/agent-emulator/src/lib/workflow/registry.ts
|
|
22243
|
-
var hasDeclaredSchema, workflowStartTrigger, buildManifest;
|
|
22481
|
+
var hasDeclaredSchema, workflowStartTrigger, SYSTEM_WORKFLOWS, isInternalWorkflow, buildManifest;
|
|
22244
22482
|
var init_registry = __esmMin((() => {
|
|
22245
22483
|
hasDeclaredSchema = (pair) => pair != null && (pair.input != null || pair.output != null);
|
|
22246
22484
|
workflowStartTrigger = (name) => `POST /api/workflows/${name}/start`;
|
|
22485
|
+
SYSTEM_WORKFLOWS = new Set(["rag-ingest"]);
|
|
22486
|
+
isInternalWorkflow = (workflow) => {
|
|
22487
|
+
if (workflow.$internal === false) return false;
|
|
22488
|
+
if (workflow.$internal === true) return true;
|
|
22489
|
+
return SYSTEM_WORKFLOWS.has(workflow.name);
|
|
22490
|
+
};
|
|
22247
22491
|
buildManifest = (input) => ({
|
|
22248
22492
|
agents: [],
|
|
22249
|
-
workflows: input.workspace.workflows.map((w) => {
|
|
22493
|
+
workflows: input.workspace.workflows.filter((w) => !isInternalWorkflow(w)).map((w) => {
|
|
22250
22494
|
const steps = input.workflowSteps?.get(w.name);
|
|
22251
22495
|
return {
|
|
22252
22496
|
name: w.name,
|
|
@@ -22488,6 +22732,28 @@ var init_workflow_start_service = __esmMin((() => {
|
|
|
22488
22732
|
return triggerWorkflowStartAndWait(deps, name, input);
|
|
22489
22733
|
}
|
|
22490
22734
|
});
|
|
22735
|
+
}));
|
|
22736
|
+
//#endregion
|
|
22737
|
+
//#region ../../libs/runtime/agent-emulator/src/lib/workflow/approval-recorder-bridge.ts
|
|
22738
|
+
var createApprovalRecorder;
|
|
22739
|
+
var init_approval_recorder_bridge = __esmMin((() => {
|
|
22740
|
+
createApprovalRecorder = (deps) => ({ async request(args) {
|
|
22741
|
+
const context = deps.getInvocationContext?.();
|
|
22742
|
+
const enriched = { ...args };
|
|
22743
|
+
if (context?.runId !== void 0) enriched["runId"] = context.runId;
|
|
22744
|
+
if (context?.requestedByStepId !== void 0) enriched["requestedByStepId"] = context.requestedByStepId;
|
|
22745
|
+
try {
|
|
22746
|
+
const result = await deps.request(enriched);
|
|
22747
|
+
if (result.error) {
|
|
22748
|
+
const code = result.error.code ?? "approval_persist_failed";
|
|
22749
|
+
const message = result.error.message ?? "Failed to write the approval to the agent database.";
|
|
22750
|
+
throw new Error(`requestApproval could not persist the approvals row (${code}): ${message} The workflow step will retry — a HITL decision is never quietly lost.`);
|
|
22751
|
+
}
|
|
22752
|
+
} catch (err) {
|
|
22753
|
+
console.error("[approval-recorder] failed to persist approvals row:", err instanceof Error ? err.message : String(err));
|
|
22754
|
+
throw err;
|
|
22755
|
+
}
|
|
22756
|
+
} });
|
|
22491
22757
|
})), DEFAULT_TZ, TICK_JOB_NAME$1, DECL_PREFIX, DYN_PREFIX, declSchedulerId, dynSchedulerId, planDeclarativeReconcile, expandDeclaredSchedules, parseSchedulerId, consoleLogger$2, WorkflowCronScheduler, createWorkflowSchedulerBridge;
|
|
22492
22758
|
var init_workflow_cron_scheduler = __esmMin((() => {
|
|
22493
22759
|
DEFAULT_TZ = "UTC";
|
|
@@ -23057,111 +23323,11 @@ var init_intake_scheduler = __esmMin((() => {
|
|
|
23057
23323
|
};
|
|
23058
23324
|
}));
|
|
23059
23325
|
//#endregion
|
|
23060
|
-
//#region ../../libs/runtime/agent-emulator/src/lib/connect-inbound/gmail-history-strategy.ts
|
|
23061
|
-
function isGmailCursor(cursor) {
|
|
23062
|
-
return typeof cursor === "object" && cursor !== null && typeof cursor.historyId === "string" && cursor.historyId.length > 0;
|
|
23063
|
-
}
|
|
23064
|
-
/** Read a single header value (case-insensitive) off a Gmail message payload. */
|
|
23065
|
-
function header(message, name) {
|
|
23066
|
-
const match = (message.payload?.headers ?? []).find((h) => (h.name ?? "").toLowerCase() === name.toLowerCase());
|
|
23067
|
-
return typeof match?.value === "string" ? match.value : "";
|
|
23068
|
-
}
|
|
23069
|
-
/** Fetch one message (metadata format) and normalize it to a poll item. */
|
|
23070
|
-
async function fetchMessageEvent(ctx, id) {
|
|
23071
|
-
const message = await ctx.runOperation("gmail.users.messages.get", {
|
|
23072
|
-
userId: USER_ID,
|
|
23073
|
-
id,
|
|
23074
|
-
format: "metadata"
|
|
23075
|
-
});
|
|
23076
|
-
const payload = {
|
|
23077
|
-
messageId: message.id ?? id,
|
|
23078
|
-
threadId: message.threadId ?? "",
|
|
23079
|
-
from: header(message, "From"),
|
|
23080
|
-
to: header(message, "To"),
|
|
23081
|
-
subject: header(message, "Subject"),
|
|
23082
|
-
snippet: typeof message.snippet === "string" ? message.snippet : "",
|
|
23083
|
-
date: header(message, "Date"),
|
|
23084
|
-
raw: {
|
|
23085
|
-
messageId: message.id ?? id,
|
|
23086
|
-
threadId: message.threadId ?? "",
|
|
23087
|
-
historyId: typeof message.historyId === "string" ? message.historyId : null
|
|
23088
|
-
}
|
|
23089
|
-
};
|
|
23090
|
-
return {
|
|
23091
|
-
id: message.id ?? id,
|
|
23092
|
-
payload
|
|
23093
|
-
};
|
|
23094
|
-
}
|
|
23095
|
-
function readHistoryId(event) {
|
|
23096
|
-
const raw = (event?.payload)?.raw;
|
|
23097
|
-
return raw && typeof raw.historyId === "string" ? raw.historyId : null;
|
|
23098
|
-
}
|
|
23099
|
-
/**
|
|
23100
|
-
* Bootstrap path (empty cursor): list the most recent inbox messages, normalize
|
|
23101
|
-
* them, and seed the cursor from the newest message's `historyId`. Dedup is the
|
|
23102
|
-
* platform's job (by message id), so a first poll legitimately returns the recent
|
|
23103
|
-
* window and the next poll resumes from the history API.
|
|
23104
|
-
*/
|
|
23105
|
-
async function bootstrap(ctx) {
|
|
23106
|
-
const items = await mapWithConcurrency(((await ctx.runOperation("gmail.users.messages.list", {
|
|
23107
|
-
userId: USER_ID,
|
|
23108
|
-
maxResults: BOOTSTRAP_MAX_RESULTS,
|
|
23109
|
-
labelIds: "INBOX"
|
|
23110
|
-
})).messages ?? []).map((m) => m.id).filter((id) => typeof id === "string" && id.length > 0), 6, (id) => fetchMessageEvent(ctx, id));
|
|
23111
|
-
const seedHistoryId = readHistoryId(items[0]);
|
|
23112
|
-
return {
|
|
23113
|
-
items,
|
|
23114
|
-
nextCursor: seedHistoryId ? { historyId: seedHistoryId } : null
|
|
23115
|
-
};
|
|
23116
|
-
}
|
|
23117
|
-
/**
|
|
23118
|
-
* Incremental path (valid cursor): pull history records added since the persisted
|
|
23119
|
-
* `historyId` via `history.list`, drain EVERY page (so messages on pages 2+ are
|
|
23120
|
-
* never skipped when the cursor advances), normalize each new arrival, and move
|
|
23121
|
-
* the cursor to the response's latest `historyId`.
|
|
23122
|
-
*/
|
|
23123
|
-
async function pollFromCursor(ctx, cursor) {
|
|
23124
|
-
const addedIds = [];
|
|
23125
|
-
let latestHistoryId = cursor.historyId;
|
|
23126
|
-
let pageToken;
|
|
23127
|
-
for (let page = 0; page < MAX_HISTORY_PAGES; page += 1) {
|
|
23128
|
-
const history = await ctx.runOperation("gmail.users.history.list", {
|
|
23129
|
-
userId: USER_ID,
|
|
23130
|
-
startHistoryId: cursor.historyId,
|
|
23131
|
-
historyTypes: "messageAdded",
|
|
23132
|
-
labelId: "INBOX",
|
|
23133
|
-
...pageToken ? { pageToken } : {}
|
|
23134
|
-
});
|
|
23135
|
-
for (const record of history.history ?? []) for (const added of record.messagesAdded ?? []) {
|
|
23136
|
-
const id = added.message?.id;
|
|
23137
|
-
if (typeof id === "string" && id.length > 0) addedIds.push(id);
|
|
23138
|
-
}
|
|
23139
|
-
if (typeof history.historyId === "string" && history.historyId.length > 0) latestHistoryId = history.historyId;
|
|
23140
|
-
if (typeof history.nextPageToken === "string" && history.nextPageToken.length > 0) pageToken = history.nextPageToken;
|
|
23141
|
-
else break;
|
|
23142
|
-
}
|
|
23143
|
-
return {
|
|
23144
|
-
items: await mapWithConcurrency(addedIds, 6, (id) => fetchMessageEvent(ctx, id)),
|
|
23145
|
-
nextCursor: { historyId: latestHistoryId }
|
|
23146
|
-
};
|
|
23147
|
-
}
|
|
23148
|
-
var USER_ID, BOOTSTRAP_MAX_RESULTS, MAX_HISTORY_PAGES, gmailHistoryPoll;
|
|
23149
|
-
var init_gmail_history_strategy = __esmMin((() => {
|
|
23150
|
-
init_src$3();
|
|
23151
|
-
USER_ID = "me";
|
|
23152
|
-
BOOTSTRAP_MAX_RESULTS = 25;
|
|
23153
|
-
MAX_HISTORY_PAGES = 100;
|
|
23154
|
-
gmailHistoryPoll = async (ctx, cursor) => {
|
|
23155
|
-
if (!isGmailCursor(cursor)) return bootstrap(ctx);
|
|
23156
|
-
return pollFromCursor(ctx, cursor);
|
|
23157
|
-
};
|
|
23158
|
-
}));
|
|
23159
|
-
//#endregion
|
|
23160
23326
|
//#region ../../libs/runtime/agent-emulator/src/lib/connect-inbound/trigger-strategies.ts
|
|
23161
23327
|
var STRATEGIES, resolveStrategy;
|
|
23162
23328
|
var init_trigger_strategies = __esmMin((() => {
|
|
23163
|
-
|
|
23164
|
-
STRATEGIES = {
|
|
23329
|
+
init_src$3();
|
|
23330
|
+
STRATEGIES = { ...BUILT_IN_STRATEGIES };
|
|
23165
23331
|
resolveStrategy = (name) => STRATEGIES[name] ?? null;
|
|
23166
23332
|
}));
|
|
23167
23333
|
//#endregion
|
|
@@ -23392,6 +23558,7 @@ var init_runtime_mount = __esmMin((() => {
|
|
|
23392
23558
|
init_workflow_run_projector();
|
|
23393
23559
|
init_workflow_invoker();
|
|
23394
23560
|
init_workflow_start_service();
|
|
23561
|
+
init_approval_recorder_bridge();
|
|
23395
23562
|
init_workflow_cron_scheduler();
|
|
23396
23563
|
init_workflow_hook_resume();
|
|
23397
23564
|
init_workflow_frame_sse();
|
|
@@ -23471,6 +23638,11 @@ var init_runtime_mount = __esmMin((() => {
|
|
|
23471
23638
|
let setWorkflowStarter;
|
|
23472
23639
|
let setWorkflowScheduler;
|
|
23473
23640
|
let setDeepAgentInvoker;
|
|
23641
|
+
let setAiUsageReporter;
|
|
23642
|
+
let setApprovalRecorder;
|
|
23643
|
+
let approvalRequest;
|
|
23644
|
+
let setConnectorInvoker;
|
|
23645
|
+
let connectorInvoker;
|
|
23474
23646
|
try {
|
|
23475
23647
|
const sdk = await importProject("@stackbone/sdk");
|
|
23476
23648
|
runWithInvocationContext = sdk.runWithInvocationContext;
|
|
@@ -23478,12 +23650,34 @@ var init_runtime_mount = __esmMin((() => {
|
|
|
23478
23650
|
setWorkflowStarter = sdk.setWorkflowStarter;
|
|
23479
23651
|
setWorkflowScheduler = sdk.setWorkflowScheduler;
|
|
23480
23652
|
setDeepAgentInvoker = sdk.setDeepAgentInvoker;
|
|
23653
|
+
setAiUsageReporter = sdk.setAiUsageReporter;
|
|
23654
|
+
setApprovalRecorder = sdk.setApprovalRecorder;
|
|
23655
|
+
setConnectorInvoker = sdk.setConnectorInvoker;
|
|
23656
|
+
connectorInvoker = sdk.createConnectInvoker?.();
|
|
23657
|
+
const ambientStackbone = sdk.stackbone;
|
|
23658
|
+
if (ambientStackbone) approvalRequest = async (args) => {
|
|
23659
|
+
const approval = ambientStackbone.approval;
|
|
23660
|
+
if (!approval?.request) return {
|
|
23661
|
+
data: null,
|
|
23662
|
+
error: {
|
|
23663
|
+
code: "approval_unavailable",
|
|
23664
|
+
message: "The project SDK exposes no ambient approval writer."
|
|
23665
|
+
}
|
|
23666
|
+
};
|
|
23667
|
+
return approval.request(args);
|
|
23668
|
+
};
|
|
23669
|
+
else approvalRequest = void 0;
|
|
23481
23670
|
} catch {
|
|
23482
23671
|
runWithInvocationContext = void 0;
|
|
23483
23672
|
getInvocationContext = void 0;
|
|
23484
23673
|
setWorkflowStarter = void 0;
|
|
23485
23674
|
setWorkflowScheduler = void 0;
|
|
23486
23675
|
setDeepAgentInvoker = void 0;
|
|
23676
|
+
setAiUsageReporter = void 0;
|
|
23677
|
+
setApprovalRecorder = void 0;
|
|
23678
|
+
approvalRequest = void 0;
|
|
23679
|
+
setConnectorInvoker = void 0;
|
|
23680
|
+
connectorInvoker = void 0;
|
|
23487
23681
|
}
|
|
23488
23682
|
const stepUrl = pathToFileURL(resolve(projectRoot, WELL_KNOWN_DIR$2, "step.mjs")).href;
|
|
23489
23683
|
await (runtimeEnv.generation ? import(`${stepUrl}?v=${runtimeEnv.generation}`) : import(stepUrl));
|
|
@@ -23495,7 +23689,12 @@ var init_runtime_mount = __esmMin((() => {
|
|
|
23495
23689
|
resumeHook,
|
|
23496
23690
|
setWorkflowStarter,
|
|
23497
23691
|
setWorkflowScheduler,
|
|
23498
|
-
setDeepAgentInvoker
|
|
23692
|
+
setDeepAgentInvoker,
|
|
23693
|
+
setAiUsageReporter,
|
|
23694
|
+
setApprovalRecorder,
|
|
23695
|
+
approvalRequest,
|
|
23696
|
+
setConnectorInvoker,
|
|
23697
|
+
connectorInvoker
|
|
23499
23698
|
};
|
|
23500
23699
|
};
|
|
23501
23700
|
mountWorkflowRuntime = async (app, opts) => {
|
|
@@ -23581,6 +23780,21 @@ var init_runtime_mount = __esmMin((() => {
|
|
|
23581
23780
|
return invoker(name, input, options);
|
|
23582
23781
|
});
|
|
23583
23782
|
}
|
|
23783
|
+
if (rt.setAiUsageReporter) {
|
|
23784
|
+
const invocations = opts.invocations;
|
|
23785
|
+
rt.setAiUsageReporter((usage) => {
|
|
23786
|
+
const runId = rt.getInvocationContext?.()?.runId;
|
|
23787
|
+
if (!runId || !invocations) return;
|
|
23788
|
+
invocations.addRunTokens(runId, usage).catch((err) => {
|
|
23789
|
+
console.warn(`[ai-usage] token fold failed for run ${runId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
23790
|
+
});
|
|
23791
|
+
});
|
|
23792
|
+
}
|
|
23793
|
+
if (rt.setApprovalRecorder && rt.approvalRequest) rt.setApprovalRecorder(createApprovalRecorder({
|
|
23794
|
+
request: rt.approvalRequest,
|
|
23795
|
+
...rt.getInvocationContext ? { getInvocationContext: rt.getInvocationContext } : {}
|
|
23796
|
+
}));
|
|
23797
|
+
if (rt.setConnectorInvoker && rt.connectorInvoker) rt.setConnectorInvoker(rt.connectorInvoker);
|
|
23584
23798
|
return rt;
|
|
23585
23799
|
}).catch((err) => {
|
|
23586
23800
|
runtimePromise = null;
|
|
@@ -23811,7 +24025,11 @@ var init_runtime_mount = __esmMin((() => {
|
|
|
23811
24025
|
await cronScheduler?.close();
|
|
23812
24026
|
await intakeRuntime?.close();
|
|
23813
24027
|
if (runtimePromise) try {
|
|
23814
|
-
|
|
24028
|
+
const rt = await runtimePromise;
|
|
24029
|
+
rt.setDeepAgentInvoker?.(void 0);
|
|
24030
|
+
rt.setAiUsageReporter?.(void 0);
|
|
24031
|
+
rt.setApprovalRecorder?.(void 0);
|
|
24032
|
+
rt.setConnectorInvoker?.(void 0);
|
|
23815
24033
|
} catch {}
|
|
23816
24034
|
},
|
|
23817
24035
|
triggerWorkflowStart: (name, input) => triggerWorkflowStart(startDeps, name, input),
|
|
@@ -30830,6 +31048,62 @@ var findWorkflowFiles = async (projectRoot, extraModules = []) => {
|
|
|
30830
31048
|
return files;
|
|
30831
31049
|
};
|
|
30832
31050
|
/**
|
|
31051
|
+
* Scan the final `workflow.vm.js` text for any `require(...)` call and throw an
|
|
31052
|
+
* actionable error if one is found.
|
|
31053
|
+
*
|
|
31054
|
+
* The workflow VM bundle runs on `node:vm`, which has NO `require`. A `require(`
|
|
31055
|
+
* token surviving into the bundle means something reachable from a workflow body
|
|
31056
|
+
* (a helper, a transitive import) dragged a Node-only dependency into the VM graph
|
|
31057
|
+
* — the Workflow SDK (WDK) compiler inlines the whole module, and the inlined
|
|
31058
|
+
* `require()` throws `ReferenceError: require is not defined` at instantiation,
|
|
31059
|
+
* crashing EVERY workflow in the project with an opaque `USER_ERROR` / "Unknown
|
|
31060
|
+
* error" (the bug this guard makes impossible to ship silently).
|
|
31061
|
+
*
|
|
31062
|
+
* Pure + exported so it is unit-testable in isolation (prior art:
|
|
31063
|
+
* `foldSchemasIntoManifest`). False-positive discipline: it matches `require(`
|
|
31064
|
+
* only as a CALL shape, not the substring inside a comment or a string literal
|
|
31065
|
+
* that is not actually invoked — the VM bundle is generated code, so a literal
|
|
31066
|
+
* `require(` in a string is still a smell worth flagging, but the guard reports
|
|
31067
|
+
* the surrounding context so a human can tell a real leak from a benign mention.
|
|
31068
|
+
*/
|
|
31069
|
+
var assertNoLeakedNodeRequire = (bundleText) => {
|
|
31070
|
+
const requirePattern = /require\s*\(\s*['"`]/g;
|
|
31071
|
+
const matches = [];
|
|
31072
|
+
const lines = bundleText.split("\n");
|
|
31073
|
+
for (const match of bundleText.matchAll(requirePattern)) {
|
|
31074
|
+
const index = match.index ?? 0;
|
|
31075
|
+
let line = 1;
|
|
31076
|
+
let column = 1;
|
|
31077
|
+
let consumed = 0;
|
|
31078
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
31079
|
+
const lineText = lines[i];
|
|
31080
|
+
if (lineText === void 0) break;
|
|
31081
|
+
const lineEnd = consumed + lineText.length + 1;
|
|
31082
|
+
if (index < lineEnd) {
|
|
31083
|
+
line = i + 1;
|
|
31084
|
+
column = index - consumed + 1;
|
|
31085
|
+
break;
|
|
31086
|
+
}
|
|
31087
|
+
consumed = lineEnd;
|
|
31088
|
+
}
|
|
31089
|
+
const start = Math.max(0, index - 80);
|
|
31090
|
+
const end = Math.min(bundleText.length, index + 120);
|
|
31091
|
+
const snippet = bundleText.slice(start, end).replace(/\s+/g, " ").trim();
|
|
31092
|
+
matches.push({
|
|
31093
|
+
index,
|
|
31094
|
+
line,
|
|
31095
|
+
column,
|
|
31096
|
+
snippet
|
|
31097
|
+
});
|
|
31098
|
+
}
|
|
31099
|
+
if (matches.length === 0) return;
|
|
31100
|
+
const first = matches[0];
|
|
31101
|
+
if (!first) return;
|
|
31102
|
+
const listing = matches.slice(0, 5).map((m, i) => ` ${i + 1}. line ${m.line}:${m.column} …${m.snippet}…`).join("\n");
|
|
31103
|
+
const more = matches.length > 5 ? `\n (and ${matches.length - 5} more)` : "";
|
|
31104
|
+
throw new Error(`Workflow VM bundle contains ${matches.length} require() call(s) — the workflow VM (node:vm) has no \`require\`, so the bundle will crash at instantiation with \`ReferenceError: require is not defined\`, breaking EVERY workflow in this project.\nThis means a Node-only dependency (e.g. node:crypto, the Postgres driver, the OpenAI / AWS SDKs) is reachable from a workflow body or a "use step" that was not properly externalized. The most common cause is a workflow-steps helper that touches Node at module scope — it must reach Node only through a runtime-planted binding (see @stackbone/sdk/workflow-steps/*) or be wrapped in a "use step" that the WDK stubs out of the VM graph.\nFirst occurrence: line ${first.line}:${first.column}\n${listing}${more}\nFix: move the Node-bearing code behind a runtime binding, wrap the call in a "use step" function, or import the helper from @stackbone/sdk/workflow-steps/* (the per-domain entry that the WDK keeps out of the VM body).`);
|
|
31105
|
+
};
|
|
31106
|
+
/**
|
|
30833
31107
|
* Build the workspace's workflows into `<projectRoot>/.well-known/workflow/v1/`:
|
|
30834
31108
|
* - `step.mjs` — steps bundle (runtime external)
|
|
30835
31109
|
* - `workflow.vm.js` — the workflow VM bundle text fed to `workflowEntrypoint`
|
|
@@ -30858,7 +31132,7 @@ var buildWorkflows = async (projectRoot, workflows, logger) => {
|
|
|
30858
31132
|
stepsBundlePath: `./${WELL_KNOWN_DIR}/step.mjs`,
|
|
30859
31133
|
workflowsBundlePath: `./${WELL_KNOWN_DIR}/workflow.vm.js`,
|
|
30860
31134
|
webhookBundlePath: `./${WELL_KNOWN_DIR}/webhook.mjs`,
|
|
30861
|
-
externalPackages: [
|
|
31135
|
+
externalPackages: []
|
|
30862
31136
|
});
|
|
30863
31137
|
const prevCwd = process.cwd();
|
|
30864
31138
|
let manifest;
|
|
@@ -30885,6 +31159,7 @@ var buildWorkflows = async (projectRoot, workflows, logger) => {
|
|
|
30885
31159
|
const streaming = await detectStreamingWorkflows(projectRoot, workflows);
|
|
30886
31160
|
foldSchemasIntoManifest(manifest, workflows, schemas, streaming, schedules);
|
|
30887
31161
|
await writeFile(resolve(wkDir, "workflow.vm.js"), interimBundleText, "utf8");
|
|
31162
|
+
assertNoLeakedNodeRequire(interimBundleText);
|
|
30888
31163
|
await writeFile(resolve(wkDir, "manifest.json"), JSON.stringify(manifest), "utf8");
|
|
30889
31164
|
for (const name of [
|
|
30890
31165
|
"step.mjs",
|
|
@@ -31179,7 +31454,8 @@ var loadWorkspace = async (projectRoot) => {
|
|
|
31179
31454
|
if (!isWorkspace(workspace)) throw new Error(`${configPath} must default-export a workspace with \`agents\` and \`workflows\` arrays (via \`defineWorkspace({ agents, workflows })\`).`);
|
|
31180
31455
|
return {
|
|
31181
31456
|
agents: workspace.agents,
|
|
31182
|
-
workflows: workspace.workflows
|
|
31457
|
+
workflows: workspace.workflows,
|
|
31458
|
+
deepAgents: workspace.deepAgents
|
|
31183
31459
|
};
|
|
31184
31460
|
};
|
|
31185
31461
|
//#endregion
|
|
@@ -31249,10 +31525,11 @@ var discoverDeepAgents = async (root) => {
|
|
|
31249
31525
|
/**
|
|
31250
31526
|
* Derive `{ agents, workflows, deepAgents }` for the workspace rooted at `root`.
|
|
31251
31527
|
* `agents` is always `[]` (there is no server-per-agent runtime). A `stackbone.config.ts`
|
|
31252
|
-
* override wins for workflows
|
|
31253
|
-
*
|
|
31254
|
-
* omitted
|
|
31255
|
-
*
|
|
31528
|
+
* override wins for workflows AND deep agents; when the config declares `deepAgents`,
|
|
31529
|
+
* those win over auto-discovery (use to mark agents as `$internal` or customize the
|
|
31530
|
+
* registry). When omitted, deep agents are discovered by folder convention and
|
|
31531
|
+
* `deepAgents` is omitted entirely when none are found so an empty workspace is
|
|
31532
|
+
* byte-identical to before.
|
|
31256
31533
|
*/
|
|
31257
31534
|
var discoverWorkspace = async (root) => {
|
|
31258
31535
|
const deepAgents = await discoverDeepAgents(root);
|
|
@@ -31260,10 +31537,18 @@ var discoverWorkspace = async (root) => {
|
|
|
31260
31537
|
...ws,
|
|
31261
31538
|
deepAgents
|
|
31262
31539
|
};
|
|
31263
|
-
if (await fileExists$1(resolve(root, "stackbone.config.ts")))
|
|
31264
|
-
|
|
31265
|
-
|
|
31266
|
-
|
|
31540
|
+
if (await fileExists$1(resolve(root, "stackbone.config.ts"))) {
|
|
31541
|
+
const ws = await loadWorkspace(root);
|
|
31542
|
+
const resultDeepAgents = ws.deepAgents ?? deepAgents;
|
|
31543
|
+
const baseResult = {
|
|
31544
|
+
agents: [],
|
|
31545
|
+
workflows: ws.workflows
|
|
31546
|
+
};
|
|
31547
|
+
return resultDeepAgents.length === 0 ? baseResult : {
|
|
31548
|
+
...baseResult,
|
|
31549
|
+
deepAgents: resultDeepAgents
|
|
31550
|
+
};
|
|
31551
|
+
}
|
|
31267
31552
|
return withDeepAgents({
|
|
31268
31553
|
agents: [],
|
|
31269
31554
|
workflows: await discoverWorkflows(root)
|
package/package.json
CHANGED
|
Binary file
|
package/stackbone-cli-0.2.3.tgz
DELETED
|
Binary file
|