struere 0.12.6 → 0.12.8
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/bin/struere.js +499 -181
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/compile-prompt.d.ts.map +1 -1
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/run-tool.d.ts.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/sync.d.ts.map +1 -1
- package/dist/cli/commands/triggers.d.ts.map +1 -1
- package/dist/cli/index.js +499 -181
- package/dist/cli/utils/convex.d.ts +44 -2
- package/dist/cli/utils/convex.d.ts.map +1 -1
- package/dist/cli/utils/loader.d.ts +1 -0
- package/dist/cli/utils/loader.d.ts.map +1 -1
- package/dist/cli/utils/plugin.d.ts +1 -1
- package/dist/cli/utils/plugin.d.ts.map +1 -1
- package/dist/cli/utils/triggers.d.ts +3 -2
- package/dist/cli/utils/triggers.d.ts.map +1 -1
- package/dist/cli/utils/validator.d.ts +8 -0
- package/dist/cli/utils/validator.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/bin/struere.js
CHANGED
|
@@ -33,11 +33,24 @@ __export(exports_convex, {
|
|
|
33
33
|
getSyncState: () => getSyncState,
|
|
34
34
|
getSiteUrl: () => getSiteUrl,
|
|
35
35
|
getPullState: () => getPullState,
|
|
36
|
+
fireTrigger: () => fireTrigger,
|
|
36
37
|
createOrganization: () => createOrganization,
|
|
37
38
|
compilePrompt: () => compilePrompt,
|
|
38
39
|
chatWithRouter: () => chatWithRouter,
|
|
39
40
|
chatWithAgent: () => chatWithAgent
|
|
40
41
|
});
|
|
42
|
+
function isAuthErrorMessage(error) {
|
|
43
|
+
return error.includes("Unauthenticated") || error.includes("OIDC") || error.includes("token") || error.includes("expired");
|
|
44
|
+
}
|
|
45
|
+
async function withAuthRetry(fn) {
|
|
46
|
+
const result = await fn();
|
|
47
|
+
if (!result.error || !isAuthErrorMessage(result.error))
|
|
48
|
+
return result;
|
|
49
|
+
const refreshed = await refreshToken();
|
|
50
|
+
if (!refreshed)
|
|
51
|
+
return result;
|
|
52
|
+
return fn();
|
|
53
|
+
}
|
|
41
54
|
async function refreshToken() {
|
|
42
55
|
const credentials = loadCredentials();
|
|
43
56
|
if (!credentials?.sessionId)
|
|
@@ -211,6 +224,9 @@ async function syncViaHttp(apiKey, payload) {
|
|
|
211
224
|
return json;
|
|
212
225
|
}
|
|
213
226
|
async function syncOrganization(payload) {
|
|
227
|
+
return withAuthRetry(() => _syncOrganization(payload));
|
|
228
|
+
}
|
|
229
|
+
async function _syncOrganization(payload) {
|
|
214
230
|
const credentials = loadCredentials();
|
|
215
231
|
const apiKey = getApiKey();
|
|
216
232
|
if (apiKey && !credentials?.token) {
|
|
@@ -274,6 +290,9 @@ async function syncOrganization(payload) {
|
|
|
274
290
|
return { success: false, error: `Unexpected response: ${text}` };
|
|
275
291
|
}
|
|
276
292
|
async function getSyncState(organizationId, environment) {
|
|
293
|
+
return withAuthRetry(() => _getSyncState(organizationId, environment));
|
|
294
|
+
}
|
|
295
|
+
async function _getSyncState(organizationId, environment) {
|
|
277
296
|
const credentials = loadCredentials();
|
|
278
297
|
const apiKey = getApiKey();
|
|
279
298
|
if (apiKey && !credentials?.token) {
|
|
@@ -330,6 +349,9 @@ async function getSyncState(organizationId, environment) {
|
|
|
330
349
|
return { error: `Unexpected response: ${JSON.stringify(result)}` };
|
|
331
350
|
}
|
|
332
351
|
async function compilePrompt(options) {
|
|
352
|
+
return withAuthRetry(() => _compilePrompt(options));
|
|
353
|
+
}
|
|
354
|
+
async function _compilePrompt(options) {
|
|
333
355
|
const credentials = loadCredentials();
|
|
334
356
|
const apiKey = getApiKey();
|
|
335
357
|
if (apiKey && !credentials?.token) {
|
|
@@ -440,6 +462,9 @@ async function compilePrompt(options) {
|
|
|
440
462
|
return { error: `Unexpected response: ${text}` };
|
|
441
463
|
}
|
|
442
464
|
async function runTool(options) {
|
|
465
|
+
return withAuthRetry(() => _runTool(options));
|
|
466
|
+
}
|
|
467
|
+
async function _runTool(options) {
|
|
443
468
|
const credentials = loadCredentials();
|
|
444
469
|
const apiKey = getApiKey();
|
|
445
470
|
if (apiKey && !credentials?.token) {
|
|
@@ -484,6 +509,43 @@ async function runTool(options) {
|
|
|
484
509
|
if (!token) {
|
|
485
510
|
return { error: "Not authenticated" };
|
|
486
511
|
}
|
|
512
|
+
if (!options.agentSlug) {
|
|
513
|
+
const response2 = await fetch(`${CONVEX_URL}/api/action`, {
|
|
514
|
+
method: "POST",
|
|
515
|
+
headers: {
|
|
516
|
+
"Content-Type": "application/json",
|
|
517
|
+
Authorization: `Bearer ${token}`
|
|
518
|
+
},
|
|
519
|
+
body: JSON.stringify({
|
|
520
|
+
path: "toolTesting:runTool",
|
|
521
|
+
args: {
|
|
522
|
+
environment: options.environment,
|
|
523
|
+
toolName: options.toolName,
|
|
524
|
+
toolArgs: options.toolArgs,
|
|
525
|
+
organizationId: options.organizationId
|
|
526
|
+
}
|
|
527
|
+
}),
|
|
528
|
+
signal: AbortSignal.timeout(30000)
|
|
529
|
+
});
|
|
530
|
+
const text2 = await response2.text();
|
|
531
|
+
let json2;
|
|
532
|
+
try {
|
|
533
|
+
json2 = JSON.parse(text2);
|
|
534
|
+
} catch {
|
|
535
|
+
return { error: text2 || `HTTP ${response2.status}` };
|
|
536
|
+
}
|
|
537
|
+
if (!response2.ok) {
|
|
538
|
+
const msg = json2.errorData?.message || json2.errorMessage || text2;
|
|
539
|
+
return { error: msg };
|
|
540
|
+
}
|
|
541
|
+
if (json2.status === "success" && json2.value) {
|
|
542
|
+
return { result: json2.value };
|
|
543
|
+
}
|
|
544
|
+
if (json2.status === "error") {
|
|
545
|
+
return { error: json2.errorData?.message || json2.errorMessage || "Unknown error from Convex" };
|
|
546
|
+
}
|
|
547
|
+
return { error: `Unexpected response: ${text2}` };
|
|
548
|
+
}
|
|
487
549
|
const agentResponse = await fetch(`${CONVEX_URL}/api/query`, {
|
|
488
550
|
method: "POST",
|
|
489
551
|
headers: {
|
|
@@ -545,7 +607,97 @@ async function runTool(options) {
|
|
|
545
607
|
}
|
|
546
608
|
return { error: `Unexpected response: ${text}` };
|
|
547
609
|
}
|
|
610
|
+
async function fireTrigger(options) {
|
|
611
|
+
return withAuthRetry(() => _fireTrigger(options));
|
|
612
|
+
}
|
|
613
|
+
async function _fireTrigger(options) {
|
|
614
|
+
const credentials = loadCredentials();
|
|
615
|
+
const apiKey = getApiKey();
|
|
616
|
+
if (apiKey && !credentials?.token) {
|
|
617
|
+
const siteUrl = getSiteUrl();
|
|
618
|
+
try {
|
|
619
|
+
const response2 = await fetch(`${siteUrl}/v1/fire-trigger`, {
|
|
620
|
+
method: "POST",
|
|
621
|
+
headers: {
|
|
622
|
+
"Content-Type": "application/json",
|
|
623
|
+
Authorization: `Bearer ${apiKey}`
|
|
624
|
+
},
|
|
625
|
+
body: JSON.stringify({
|
|
626
|
+
slug: options.slug,
|
|
627
|
+
entityId: options.entityId,
|
|
628
|
+
data: options.data
|
|
629
|
+
}),
|
|
630
|
+
signal: AbortSignal.timeout(60000)
|
|
631
|
+
});
|
|
632
|
+
const text2 = await response2.text();
|
|
633
|
+
let json2;
|
|
634
|
+
try {
|
|
635
|
+
json2 = JSON.parse(text2);
|
|
636
|
+
} catch {
|
|
637
|
+
return { error: text2 || `HTTP ${response2.status}` };
|
|
638
|
+
}
|
|
639
|
+
if (!response2.ok) {
|
|
640
|
+
return { error: json2.error || text2 };
|
|
641
|
+
}
|
|
642
|
+
return { result: json2 };
|
|
643
|
+
} catch (err) {
|
|
644
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
645
|
+
return { error: "Request timed out after 60s" };
|
|
646
|
+
}
|
|
647
|
+
return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
if (credentials?.sessionId) {
|
|
651
|
+
await refreshToken();
|
|
652
|
+
}
|
|
653
|
+
const freshCredentials = loadCredentials();
|
|
654
|
+
const token = apiKey || freshCredentials?.token;
|
|
655
|
+
if (!token) {
|
|
656
|
+
return { error: "Not authenticated" };
|
|
657
|
+
}
|
|
658
|
+
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
659
|
+
method: "POST",
|
|
660
|
+
headers: {
|
|
661
|
+
"Content-Type": "application/json",
|
|
662
|
+
Authorization: `Bearer ${token}`
|
|
663
|
+
},
|
|
664
|
+
body: JSON.stringify({
|
|
665
|
+
path: "triggers:fire",
|
|
666
|
+
args: {
|
|
667
|
+
slug: options.slug,
|
|
668
|
+
environment: options.environment,
|
|
669
|
+
entityId: options.entityId,
|
|
670
|
+
data: options.data
|
|
671
|
+
}
|
|
672
|
+
}),
|
|
673
|
+
signal: AbortSignal.timeout(60000)
|
|
674
|
+
});
|
|
675
|
+
const text = await response.text();
|
|
676
|
+
let json;
|
|
677
|
+
try {
|
|
678
|
+
json = JSON.parse(text);
|
|
679
|
+
} catch {
|
|
680
|
+
return { error: text || `HTTP ${response.status}` };
|
|
681
|
+
}
|
|
682
|
+
if (!response.ok) {
|
|
683
|
+
const msg = json.errorData?.message || json.errorMessage || text;
|
|
684
|
+
return { error: msg };
|
|
685
|
+
}
|
|
686
|
+
if (json.status === "success" && json.value) {
|
|
687
|
+
return { result: json.value };
|
|
688
|
+
}
|
|
689
|
+
if (json.status === "success" && json.value === null) {
|
|
690
|
+
return { error: `Trigger not found: ${options.slug}` };
|
|
691
|
+
}
|
|
692
|
+
if (json.status === "error") {
|
|
693
|
+
return { error: json.errorData?.message || json.errorMessage || "Unknown error from Convex" };
|
|
694
|
+
}
|
|
695
|
+
return { error: `Unexpected response: ${text}` };
|
|
696
|
+
}
|
|
548
697
|
async function chatWithAgent(options) {
|
|
698
|
+
return withAuthRetry(() => _chatWithAgent(options));
|
|
699
|
+
}
|
|
700
|
+
async function _chatWithAgent(options) {
|
|
549
701
|
const credentials = loadCredentials();
|
|
550
702
|
const apiKey = getApiKey();
|
|
551
703
|
if (apiKey && !credentials?.token) {
|
|
@@ -639,6 +791,9 @@ async function chatWithAgent(options) {
|
|
|
639
791
|
}
|
|
640
792
|
}
|
|
641
793
|
async function chatWithRouter(options) {
|
|
794
|
+
return withAuthRetry(() => _chatWithRouter(options));
|
|
795
|
+
}
|
|
796
|
+
async function _chatWithRouter(options) {
|
|
642
797
|
const credentials = loadCredentials();
|
|
643
798
|
const apiKey = getApiKey();
|
|
644
799
|
if (credentials?.sessionId) {
|
|
@@ -698,6 +853,9 @@ async function chatWithRouter(options) {
|
|
|
698
853
|
}
|
|
699
854
|
}
|
|
700
855
|
async function getPullState(organizationId, environment = "development") {
|
|
856
|
+
return withAuthRetry(() => _getPullState(organizationId, environment));
|
|
857
|
+
}
|
|
858
|
+
async function _getPullState(organizationId, environment = "development") {
|
|
701
859
|
const credentials = loadCredentials();
|
|
702
860
|
const apiKey = getApiKey();
|
|
703
861
|
if (apiKey && !credentials?.token) {
|
|
@@ -803,7 +961,7 @@ async function getValidToken() {
|
|
|
803
961
|
if (!credentials?.token)
|
|
804
962
|
return { error: "Not authenticated. Run `struere login`." };
|
|
805
963
|
const expiry = getJwtExpiry(credentials.token);
|
|
806
|
-
const needsRefresh = !expiry || expiry.getTime() - Date.now() <
|
|
964
|
+
const needsRefresh = !expiry || expiry.getTime() - Date.now() < 300000;
|
|
807
965
|
if (!needsRefresh)
|
|
808
966
|
return { token: credentials.token };
|
|
809
967
|
const { refreshToken: refreshToken2 } = await Promise.resolve().then(() => (init_convex(), exports_convex));
|
|
@@ -1684,7 +1842,7 @@ function defineTrigger(config) {
|
|
|
1684
1842
|
if (!config.slug) throw new Error('Trigger slug is required')
|
|
1685
1843
|
if (!config.on) throw new Error('Trigger "on" configuration is required')
|
|
1686
1844
|
if (config.on.schedule) {
|
|
1687
|
-
const parts = config.on.schedule.trim().split(
|
|
1845
|
+
const parts = config.on.schedule.trim().split(/\\s+/)
|
|
1688
1846
|
if (parts.length !== 5) throw new Error('Invalid cron expression: expected 5 fields, got ' + parts.length)
|
|
1689
1847
|
} else {
|
|
1690
1848
|
if (!config.on.entityType) throw new Error('Trigger entityType is required')
|
|
@@ -1735,11 +1893,32 @@ function defineTools(tools) {
|
|
|
1735
1893
|
})
|
|
1736
1894
|
}
|
|
1737
1895
|
|
|
1896
|
+
function defineRouter(config) {
|
|
1897
|
+
const VALID_OPERATORS = ['eq', 'neq', 'in', 'contains', 'regex', 'gt', 'lt', 'exists']
|
|
1898
|
+
if (!config.name) throw new Error('Router name is required')
|
|
1899
|
+
if (!config.slug) throw new Error('Router slug is required')
|
|
1900
|
+
if (!config.agents || config.agents.length === 0) throw new Error('Router must have at least one agent')
|
|
1901
|
+
var agentSlugs = new Set(config.agents.map(function(a) { return a.slug }))
|
|
1902
|
+
if (!agentSlugs.has(config.fallback)) throw new Error('Router fallback "' + config.fallback + '" must reference an agent slug in the agents array')
|
|
1903
|
+
if (config.mode === 'rules') {
|
|
1904
|
+
if (!config.rules || config.rules.length === 0) throw new Error('Router with mode "rules" must have at least one rule')
|
|
1905
|
+
for (var rule of config.rules) {
|
|
1906
|
+
if (!rule.conditions || rule.conditions.length === 0) throw new Error('Each router rule must have at least one condition')
|
|
1907
|
+
if (!agentSlugs.has(rule.route)) throw new Error('Router rule route "' + rule.route + '" must reference an agent slug in the agents array')
|
|
1908
|
+
for (var condition of rule.conditions) {
|
|
1909
|
+
if (!condition.field) throw new Error('Router rule condition field is required')
|
|
1910
|
+
if (!VALID_OPERATORS.includes(condition.operator)) throw new Error('Router rule condition operator must be one of: ' + VALID_OPERATORS.join(', '))
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
return config
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1738
1917
|
function defineEntityType() {
|
|
1739
1918
|
throw new Error('defineEntityType has been renamed to defineData. Please update your imports: import { defineData } from "struere"')
|
|
1740
1919
|
}
|
|
1741
1920
|
|
|
1742
|
-
export { defineAgent, defineRole, defineData, defineEntityType, defineTrigger, defineTools }
|
|
1921
|
+
export { defineAgent, defineRole, defineData, defineEntityType, defineTrigger, defineTools, defineRouter }
|
|
1743
1922
|
`;
|
|
1744
1923
|
function registerStruerePlugin() {
|
|
1745
1924
|
if (registered)
|
|
@@ -1956,12 +2135,43 @@ export interface TriggerConfig {
|
|
|
1956
2135
|
}
|
|
1957
2136
|
}
|
|
1958
2137
|
|
|
2138
|
+
export interface RouterAgentRef {
|
|
2139
|
+
slug: string
|
|
2140
|
+
description: string
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
export interface RouterRuleCondition {
|
|
2144
|
+
field: string
|
|
2145
|
+
operator: 'eq' | 'neq' | 'in' | 'contains' | 'regex' | 'gt' | 'lt' | 'exists'
|
|
2146
|
+
value?: unknown
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
export interface RouterRule {
|
|
2150
|
+
conditions: RouterRuleCondition[]
|
|
2151
|
+
route: string
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
export interface RouterConfig {
|
|
2155
|
+
name: string
|
|
2156
|
+
slug: string
|
|
2157
|
+
description?: string
|
|
2158
|
+
mode: 'rules' | 'classify'
|
|
2159
|
+
agents: RouterAgentRef[]
|
|
2160
|
+
rules?: RouterRule[]
|
|
2161
|
+
fallback: string
|
|
2162
|
+
classifyModel?: { model: string; temperature?: number; maxTokens?: number }
|
|
2163
|
+
contextMessages?: number
|
|
2164
|
+
maxTransfers?: number
|
|
2165
|
+
inactivityResetMs?: number
|
|
2166
|
+
}
|
|
2167
|
+
|
|
1959
2168
|
export function defineAgent(config: AgentConfig): AgentConfig
|
|
1960
2169
|
export function defineRole(config: RoleConfig): RoleConfig
|
|
1961
2170
|
export function defineData(config: EntityTypeConfig): EntityTypeConfig
|
|
1962
2171
|
export function defineEntityType(config: EntityTypeConfig): never
|
|
1963
2172
|
export function defineTrigger(config: TriggerConfig): TriggerConfig
|
|
1964
2173
|
export function defineTools(tools: ToolDefinition[]): ToolReference[]
|
|
2174
|
+
export function defineRouter(config: RouterConfig): RouterConfig
|
|
1965
2175
|
`;
|
|
1966
2176
|
function generateTypeDeclarations(cwd) {
|
|
1967
2177
|
const struereDir = join4(cwd, ".struere");
|
|
@@ -2010,6 +2220,26 @@ async function importUserFile(filePath) {
|
|
|
2010
2220
|
${detail}`);
|
|
2011
2221
|
}
|
|
2012
2222
|
}
|
|
2223
|
+
function formatResourceSummary(resources) {
|
|
2224
|
+
const parts = [];
|
|
2225
|
+
if (resources.agents.length > 0)
|
|
2226
|
+
parts.push(`${resources.agents.length} agents`);
|
|
2227
|
+
if (resources.entityTypes.length > 0)
|
|
2228
|
+
parts.push(`${resources.entityTypes.length} data types`);
|
|
2229
|
+
if (resources.roles.length > 0)
|
|
2230
|
+
parts.push(`${resources.roles.length} roles`);
|
|
2231
|
+
if (resources.customTools.length > 0)
|
|
2232
|
+
parts.push(`${resources.customTools.length} custom tools`);
|
|
2233
|
+
if (resources.routers.length > 0)
|
|
2234
|
+
parts.push(`${resources.routers.length} routers`);
|
|
2235
|
+
if (resources.triggers.length > 0)
|
|
2236
|
+
parts.push(`${resources.triggers.length} triggers`);
|
|
2237
|
+
if (resources.evalSuites.length > 0)
|
|
2238
|
+
parts.push(`${resources.evalSuites.length} eval suites`);
|
|
2239
|
+
if (resources.fixtures.length > 0)
|
|
2240
|
+
parts.push(`${resources.fixtures.length} fixtures`);
|
|
2241
|
+
return `Loaded ${parts.join(", ") || "no resources"}`;
|
|
2242
|
+
}
|
|
2013
2243
|
async function loadAllResources(cwd) {
|
|
2014
2244
|
const errors = [];
|
|
2015
2245
|
const agents = await loadTsDirectory(join5(cwd, "agents"));
|
|
@@ -2902,6 +3132,59 @@ function extractHandlerCode(handler) {
|
|
|
2902
3132
|
return code;
|
|
2903
3133
|
}
|
|
2904
3134
|
|
|
3135
|
+
// src/cli/utils/validator.ts
|
|
3136
|
+
var INTEGRATION_PREFIXES = {
|
|
3137
|
+
"whatsapp.": "WhatsApp (Kapso)",
|
|
3138
|
+
"calendar.": "Google Calendar",
|
|
3139
|
+
"airtable.": "Airtable",
|
|
3140
|
+
"email.": "Resend",
|
|
3141
|
+
"payment.": "Flow / Polar"
|
|
3142
|
+
};
|
|
3143
|
+
function validateResources(payload, resources) {
|
|
3144
|
+
const warnings = [];
|
|
3145
|
+
const errors = [];
|
|
3146
|
+
const agentSlugs = new Set(payload.agents.map((a) => a.slug));
|
|
3147
|
+
if (payload.routers) {
|
|
3148
|
+
for (const router of payload.routers) {
|
|
3149
|
+
for (const agentRef of router.agents) {
|
|
3150
|
+
if (!agentSlugs.has(agentRef.slug)) {
|
|
3151
|
+
errors.push(`Router "${router.name}" references agent "${agentRef.slug}" but no agent with that slug exists`);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
if (!agentSlugs.has(router.fallback)) {
|
|
3155
|
+
errors.push(`Router "${router.name}" has fallback "${router.fallback}" but no agent with that slug exists`);
|
|
3156
|
+
}
|
|
3157
|
+
if (router.rules) {
|
|
3158
|
+
for (const rule of router.rules) {
|
|
3159
|
+
if (!agentSlugs.has(rule.route)) {
|
|
3160
|
+
errors.push(`Router "${router.name}" has rule routing to "${rule.route}" but no agent with that slug exists`);
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
const entityTypeSlugs = new Set(payload.entityTypes.map((et) => et.slug));
|
|
3167
|
+
if (payload.triggers) {
|
|
3168
|
+
for (const trigger of payload.triggers) {
|
|
3169
|
+
if (trigger.entityType && !entityTypeSlugs.has(trigger.entityType)) {
|
|
3170
|
+
errors.push(`Trigger "${trigger.name}" references entity type "${trigger.entityType}" but no entity type with that slug exists`);
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
const seenIntegrations = new Set;
|
|
3175
|
+
for (const agent of payload.agents) {
|
|
3176
|
+
for (const toolName of agent.tools) {
|
|
3177
|
+
for (const [prefix, integration] of Object.entries(INTEGRATION_PREFIXES)) {
|
|
3178
|
+
if (toolName.startsWith(prefix) && !seenIntegrations.has(integration)) {
|
|
3179
|
+
seenIntegrations.add(integration);
|
|
3180
|
+
warnings.push(`Agent "${agent.name}" uses ${toolName} \u2014 ensure ${integration} integration is configured`);
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
return { warnings, errors };
|
|
3186
|
+
}
|
|
3187
|
+
|
|
2905
3188
|
// src/cli/commands/sync.ts
|
|
2906
3189
|
async function performDevSync(cwd, organizationId) {
|
|
2907
3190
|
generateTypeDeclarations(cwd);
|
|
@@ -2912,6 +3195,16 @@ ${resources.errors.join(`
|
|
|
2912
3195
|
`)}`);
|
|
2913
3196
|
}
|
|
2914
3197
|
const payload = extractSyncPayload(resources);
|
|
3198
|
+
const validation = validateResources(payload, resources);
|
|
3199
|
+
for (const warning of validation.warnings) {
|
|
3200
|
+
console.log(chalk6.yellow(`\u26A0 ${warning}`));
|
|
3201
|
+
}
|
|
3202
|
+
if (validation.errors.length > 0) {
|
|
3203
|
+
for (const error of validation.errors) {
|
|
3204
|
+
console.log(chalk6.red(`\u2716 ${error}`));
|
|
3205
|
+
}
|
|
3206
|
+
throw new Error(`${validation.errors.length} validation error(s) \u2014 fix the issues above before syncing`);
|
|
3207
|
+
}
|
|
2915
3208
|
const devResult = await syncOrganization({
|
|
2916
3209
|
agents: payload.agents,
|
|
2917
3210
|
tools: payload.tools,
|
|
@@ -2981,6 +3274,7 @@ async function checkForDeletions(resources, organizationId, environment) {
|
|
|
2981
3274
|
return deletions;
|
|
2982
3275
|
}
|
|
2983
3276
|
async function syncToEnvironment(cwd, organizationId, environment) {
|
|
3277
|
+
generateTypeDeclarations(cwd);
|
|
2984
3278
|
const resources = await loadAllResources(cwd);
|
|
2985
3279
|
if (resources.errors.length > 0) {
|
|
2986
3280
|
throw new Error(`${resources.errors.length} resource loading error(s):
|
|
@@ -2988,6 +3282,16 @@ ${resources.errors.join(`
|
|
|
2988
3282
|
`)}`);
|
|
2989
3283
|
}
|
|
2990
3284
|
const payload = extractSyncPayload(resources);
|
|
3285
|
+
const validation = validateResources(payload, resources);
|
|
3286
|
+
for (const warning of validation.warnings) {
|
|
3287
|
+
console.log(chalk6.yellow(`\u26A0 ${warning}`));
|
|
3288
|
+
}
|
|
3289
|
+
if (validation.errors.length > 0) {
|
|
3290
|
+
for (const error of validation.errors) {
|
|
3291
|
+
console.log(chalk6.red(`\u2716 ${error}`));
|
|
3292
|
+
}
|
|
3293
|
+
throw new Error(`${validation.errors.length} validation error(s) \u2014 fix the issues above before syncing`);
|
|
3294
|
+
}
|
|
2991
3295
|
if (environment === "eval") {
|
|
2992
3296
|
const result = await syncOrganization({
|
|
2993
3297
|
agents: payload.agents,
|
|
@@ -3055,6 +3359,7 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
|
|
|
3055
3359
|
output.info(`Environment: ${environment}${syncEval && environment === "development" ? " + eval" : ""}`);
|
|
3056
3360
|
console.log();
|
|
3057
3361
|
}
|
|
3362
|
+
generateTypeDeclarations(cwd);
|
|
3058
3363
|
if (!jsonMode)
|
|
3059
3364
|
output.start("Loading resources");
|
|
3060
3365
|
let resources;
|
|
@@ -3072,7 +3377,7 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
|
|
|
3072
3377
|
process.exit(1);
|
|
3073
3378
|
}
|
|
3074
3379
|
if (!jsonMode && !options.dryRun)
|
|
3075
|
-
output.succeed(
|
|
3380
|
+
output.succeed(formatResourceSummary(resources));
|
|
3076
3381
|
} catch (error) {
|
|
3077
3382
|
if (jsonMode) {
|
|
3078
3383
|
console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }));
|
|
@@ -3181,32 +3486,13 @@ var syncCommand = new Command5("sync").description("Sync resources to Convex and
|
|
|
3181
3486
|
}));
|
|
3182
3487
|
}
|
|
3183
3488
|
} catch (error) {
|
|
3184
|
-
if (
|
|
3185
|
-
|
|
3186
|
-
clearCredentials();
|
|
3187
|
-
const newCredentials = await performLogin();
|
|
3188
|
-
if (!newCredentials) {
|
|
3189
|
-
output.error("Authentication failed");
|
|
3190
|
-
process.exit(1);
|
|
3191
|
-
}
|
|
3192
|
-
output.start("Syncing to Convex");
|
|
3193
|
-
try {
|
|
3194
|
-
const result = await syncToEnvironment(cwd, project.organization.id, environment);
|
|
3195
|
-
output.succeed(`Synced to ${environment}`);
|
|
3196
|
-
} catch (retryError) {
|
|
3197
|
-
output.fail("Sync failed");
|
|
3198
|
-
output.error(retryError instanceof Error ? retryError.message : String(retryError));
|
|
3199
|
-
process.exit(1);
|
|
3200
|
-
}
|
|
3489
|
+
if (jsonMode) {
|
|
3490
|
+
console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }));
|
|
3201
3491
|
} else {
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
} else {
|
|
3205
|
-
output.fail("Sync failed");
|
|
3206
|
-
output.error(error instanceof Error ? error.message : String(error));
|
|
3207
|
-
}
|
|
3208
|
-
process.exit(1);
|
|
3492
|
+
output.fail("Sync failed");
|
|
3493
|
+
output.error(error instanceof Error ? error.message : String(error));
|
|
3209
3494
|
}
|
|
3495
|
+
process.exit(1);
|
|
3210
3496
|
}
|
|
3211
3497
|
});
|
|
3212
3498
|
|
|
@@ -3273,7 +3559,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3273
3559
|
spinner.start("Loading resources");
|
|
3274
3560
|
try {
|
|
3275
3561
|
loadedResources = await loadAllResources(cwd);
|
|
3276
|
-
spinner.succeed(
|
|
3562
|
+
spinner.succeed(formatResourceSummary(loadedResources));
|
|
3277
3563
|
for (const err of loadedResources.errors) {
|
|
3278
3564
|
console.log(chalk7.red(" \u2716"), err);
|
|
3279
3565
|
}
|
|
@@ -3320,28 +3606,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3320
3606
|
await performDevSync(cwd, project.organization.id);
|
|
3321
3607
|
spinner.succeed("Synced to development");
|
|
3322
3608
|
} catch (error) {
|
|
3323
|
-
if (
|
|
3324
|
-
spinner.fail("Session expired - re-authenticating...");
|
|
3325
|
-
clearCredentials();
|
|
3326
|
-
credentials = await performLogin();
|
|
3327
|
-
if (!credentials) {
|
|
3328
|
-
console.log(chalk7.red("Authentication failed"));
|
|
3329
|
-
process.exit(1);
|
|
3330
|
-
}
|
|
3331
|
-
spinner.start("Syncing to Convex");
|
|
3332
|
-
try {
|
|
3333
|
-
await performDevSync(cwd, project.organization.id);
|
|
3334
|
-
spinner.succeed("Synced to development");
|
|
3335
|
-
} catch (retryError) {
|
|
3336
|
-
spinner.fail("Sync failed");
|
|
3337
|
-
console.log(chalk7.red("Error:"), retryError instanceof Error ? retryError.message : String(retryError));
|
|
3338
|
-
}
|
|
3339
|
-
} else if (isAuthError(error) && nonInteractive) {
|
|
3340
|
-
spinner.fail("API key authentication failed");
|
|
3341
|
-
console.log(chalk7.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
3342
|
-
console.log(chalk7.gray("Check that STRUERE_API_KEY is valid and not expired."));
|
|
3343
|
-
process.exit(1);
|
|
3344
|
-
} else if (isOrgAccessError(error)) {
|
|
3609
|
+
if (isOrgAccessError(error)) {
|
|
3345
3610
|
spinner.fail("Organization access denied");
|
|
3346
3611
|
console.log();
|
|
3347
3612
|
console.log(chalk7.red("You do not have access to organization:"), chalk7.cyan(project.organization.name));
|
|
@@ -3391,26 +3656,8 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3391
3656
|
await performDevSync(cwd, project.organization.id);
|
|
3392
3657
|
syncSpinner.succeed("Synced");
|
|
3393
3658
|
} catch (error) {
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
clearCredentials();
|
|
3397
|
-
const newCredentials = await performLogin();
|
|
3398
|
-
if (!newCredentials) {
|
|
3399
|
-
console.log(chalk7.red("Authentication failed"));
|
|
3400
|
-
return;
|
|
3401
|
-
}
|
|
3402
|
-
const retrySyncSpinner = ora6("Syncing...").start();
|
|
3403
|
-
try {
|
|
3404
|
-
await performDevSync(cwd, project.organization.id);
|
|
3405
|
-
retrySyncSpinner.succeed("Synced");
|
|
3406
|
-
} catch (retryError) {
|
|
3407
|
-
retrySyncSpinner.fail("Sync failed");
|
|
3408
|
-
console.log(chalk7.red("Error:"), retryError instanceof Error ? retryError.message : String(retryError));
|
|
3409
|
-
}
|
|
3410
|
-
} else {
|
|
3411
|
-
syncSpinner.fail("Sync failed");
|
|
3412
|
-
console.log(chalk7.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
3413
|
-
}
|
|
3659
|
+
syncSpinner.fail("Sync failed");
|
|
3660
|
+
console.log(chalk7.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
3414
3661
|
}
|
|
3415
3662
|
};
|
|
3416
3663
|
const handleFileChange = (path, action) => {
|
|
@@ -3502,13 +3749,14 @@ var deployCommand = new Command7("deploy").description("Deploy all resources to
|
|
|
3502
3749
|
}
|
|
3503
3750
|
console.log();
|
|
3504
3751
|
}
|
|
3752
|
+
generateTypeDeclarations(cwd);
|
|
3505
3753
|
if (!jsonMode)
|
|
3506
3754
|
spinner.start("Loading resources");
|
|
3507
3755
|
let resources;
|
|
3508
3756
|
try {
|
|
3509
3757
|
resources = await loadAllResources(cwd);
|
|
3510
3758
|
if (!jsonMode)
|
|
3511
|
-
spinner.succeed(
|
|
3759
|
+
spinner.succeed(formatResourceSummary(resources));
|
|
3512
3760
|
for (const err of resources.errors) {
|
|
3513
3761
|
if (!jsonMode)
|
|
3514
3762
|
console.log(chalk8.red(" \u2716"), err);
|
|
@@ -3541,6 +3789,28 @@ var deployCommand = new Command7("deploy").description("Deploy all resources to
|
|
|
3541
3789
|
return;
|
|
3542
3790
|
}
|
|
3543
3791
|
const payload = extractSyncPayload(resources);
|
|
3792
|
+
const validation = validateResources(payload, resources);
|
|
3793
|
+
if (validation.warnings.length > 0 || validation.errors.length > 0) {
|
|
3794
|
+
if (!jsonMode) {
|
|
3795
|
+
for (const warning of validation.warnings) {
|
|
3796
|
+
console.log(chalk8.yellow(`\u26A0 ${warning}`));
|
|
3797
|
+
}
|
|
3798
|
+
for (const error of validation.errors) {
|
|
3799
|
+
console.log(chalk8.red(`\u2716 ${error}`));
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
if (validation.errors.length > 0) {
|
|
3803
|
+
if (jsonMode) {
|
|
3804
|
+
console.log(JSON.stringify({ success: false, error: `${validation.errors.length} validation error(s)`, errors: validation.errors, warnings: validation.warnings }));
|
|
3805
|
+
} else {
|
|
3806
|
+
console.log();
|
|
3807
|
+
console.log(chalk8.red(`${validation.errors.length} validation error(s) \u2014 fix the issues above before deploying`));
|
|
3808
|
+
}
|
|
3809
|
+
process.exit(1);
|
|
3810
|
+
}
|
|
3811
|
+
if (!jsonMode)
|
|
3812
|
+
console.log();
|
|
3813
|
+
}
|
|
3544
3814
|
if (!jsonMode)
|
|
3545
3815
|
spinner.start("Checking remote state");
|
|
3546
3816
|
let deletions = [];
|
|
@@ -3679,51 +3949,7 @@ var deployCommand = new Command7("deploy").description("Deploy all resources to
|
|
|
3679
3949
|
console.log();
|
|
3680
3950
|
}
|
|
3681
3951
|
} catch (error) {
|
|
3682
|
-
if (
|
|
3683
|
-
if (!jsonMode)
|
|
3684
|
-
spinner.fail("Session expired - re-authenticating...");
|
|
3685
|
-
clearCredentials();
|
|
3686
|
-
credentials = await performLogin();
|
|
3687
|
-
if (!credentials) {
|
|
3688
|
-
if (jsonMode) {
|
|
3689
|
-
console.log(JSON.stringify({ success: false, error: "Authentication failed" }));
|
|
3690
|
-
} else {
|
|
3691
|
-
console.log(chalk8.red("Authentication failed"));
|
|
3692
|
-
}
|
|
3693
|
-
process.exit(1);
|
|
3694
|
-
}
|
|
3695
|
-
if (!jsonMode)
|
|
3696
|
-
spinner.start("Deploying to production");
|
|
3697
|
-
try {
|
|
3698
|
-
const syncResult = await syncOrganization({
|
|
3699
|
-
agents: payload.agents,
|
|
3700
|
-
entityTypes: payload.entityTypes,
|
|
3701
|
-
roles: payload.roles,
|
|
3702
|
-
triggers: payload.triggers,
|
|
3703
|
-
organizationId: project.organization.id,
|
|
3704
|
-
environment: "production"
|
|
3705
|
-
});
|
|
3706
|
-
if (!syncResult.success) {
|
|
3707
|
-
throw new Error(syncResult.error || "Deploy failed");
|
|
3708
|
-
}
|
|
3709
|
-
if (!jsonMode) {
|
|
3710
|
-
spinner.succeed("Deployed to production");
|
|
3711
|
-
console.log();
|
|
3712
|
-
console.log(chalk8.green("Success!"), "All resources deployed to production");
|
|
3713
|
-
console.log();
|
|
3714
|
-
} else {
|
|
3715
|
-
console.log(JSON.stringify({ success: true, environment: "production" }));
|
|
3716
|
-
}
|
|
3717
|
-
} catch (retryError) {
|
|
3718
|
-
if (jsonMode) {
|
|
3719
|
-
console.log(JSON.stringify({ success: false, error: retryError instanceof Error ? retryError.message : String(retryError) }));
|
|
3720
|
-
} else {
|
|
3721
|
-
spinner.fail("Deployment failed");
|
|
3722
|
-
console.log(chalk8.red("Error:"), retryError instanceof Error ? retryError.message : String(retryError));
|
|
3723
|
-
}
|
|
3724
|
-
process.exit(1);
|
|
3725
|
-
}
|
|
3726
|
-
} else if (isOrgAccessError(error)) {
|
|
3952
|
+
if (isOrgAccessError(error)) {
|
|
3727
3953
|
if (jsonMode) {
|
|
3728
3954
|
console.log(JSON.stringify({ success: false, error: `Organization access denied: ${project.organization.name}` }));
|
|
3729
3955
|
} else {
|
|
@@ -4057,6 +4283,7 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4057
4283
|
}
|
|
4058
4284
|
console.log();
|
|
4059
4285
|
}
|
|
4286
|
+
generateTypeDeclarations(cwd);
|
|
4060
4287
|
if (!jsonMode)
|
|
4061
4288
|
spinner.start("Loading local resources");
|
|
4062
4289
|
let localResources;
|
|
@@ -7094,6 +7321,7 @@ import ora14 from "ora";
|
|
|
7094
7321
|
// src/cli/utils/triggers.ts
|
|
7095
7322
|
init_credentials();
|
|
7096
7323
|
init_config();
|
|
7324
|
+
init_convex();
|
|
7097
7325
|
function getToken3() {
|
|
7098
7326
|
const credentials = loadCredentials();
|
|
7099
7327
|
const apiKey = getApiKey();
|
|
@@ -7195,8 +7423,8 @@ async function listTriggerExecutions(options) {
|
|
|
7195
7423
|
...options.limit && { limit: options.limit }
|
|
7196
7424
|
});
|
|
7197
7425
|
}
|
|
7198
|
-
async function getTriggerExecutionDetail(eventId) {
|
|
7199
|
-
return convexQuery6("triggers:getExecutionDetail", { eventId });
|
|
7426
|
+
async function getTriggerExecutionDetail(eventId, environment) {
|
|
7427
|
+
return convexQuery6("triggers:getExecutionDetail", { eventId, ...environment && { environment } });
|
|
7200
7428
|
}
|
|
7201
7429
|
async function convexAction3(path, args) {
|
|
7202
7430
|
const token = getToken3();
|
|
@@ -7522,7 +7750,7 @@ triggersCommand.command("runs [slug]").description("List trigger runs").option("
|
|
|
7522
7750
|
}
|
|
7523
7751
|
console.log();
|
|
7524
7752
|
renderTable([
|
|
7525
|
-
{ key: "id", label: "ID", width:
|
|
7753
|
+
{ key: "id", label: "ID", width: 40 },
|
|
7526
7754
|
{ key: "trigger", label: "Trigger", width: 16 },
|
|
7527
7755
|
{ key: "status", label: "Status", width: 10 },
|
|
7528
7756
|
{ key: "attempts", label: "Attempts", width: 8 },
|
|
@@ -7649,7 +7877,7 @@ triggersCommand.command("stats").description("Show trigger run statistics").opti
|
|
|
7649
7877
|
process.exit(1);
|
|
7650
7878
|
}
|
|
7651
7879
|
});
|
|
7652
|
-
triggersCommand.command("logs [slug]").description("View trigger execution history").option("--env <environment>", "Environment", "development").option("--limit <n>", "Maximum results", "10").option("--json", "Output raw JSON").action(async (slug, opts) => {
|
|
7880
|
+
triggersCommand.command("logs [slug]").description("View trigger execution history").option("--env <environment>", "Environment", "development").option("--limit <n>", "Maximum results", "10").option("--json", "Output raw JSON").option("-v, --verbose", "Show full error messages").action(async (slug, opts) => {
|
|
7653
7881
|
await ensureAuth5();
|
|
7654
7882
|
const spinner = ora14();
|
|
7655
7883
|
try {
|
|
@@ -7666,12 +7894,12 @@ triggersCommand.command("logs [slug]").description("View trigger execution histo
|
|
|
7666
7894
|
}
|
|
7667
7895
|
console.log();
|
|
7668
7896
|
renderTable([
|
|
7669
|
-
{ key: "id", label: "ID", width:
|
|
7897
|
+
{ key: "id", label: "ID", width: 40 },
|
|
7670
7898
|
{ key: "trigger", label: "Trigger", width: 16 },
|
|
7671
7899
|
{ key: "status", label: "Status", width: 8 },
|
|
7672
7900
|
{ key: "steps", label: "Steps", width: 7 },
|
|
7673
7901
|
{ key: "duration", label: "Duration", width: 10 },
|
|
7674
|
-
{ key: "error", label: "Error", width:
|
|
7902
|
+
{ key: "error", label: "Error", width: 50 },
|
|
7675
7903
|
{ key: "time", label: "Time", width: 10 }
|
|
7676
7904
|
], executions.map((e) => {
|
|
7677
7905
|
const status = e.eventType === "trigger.executed" ? "success" : "failed";
|
|
@@ -7684,10 +7912,23 @@ triggersCommand.command("logs [slug]").description("View trigger execution histo
|
|
|
7684
7912
|
status: statusColor4(status),
|
|
7685
7913
|
steps: `${passed}/${log.length}`,
|
|
7686
7914
|
duration: `${totalMs}ms`,
|
|
7687
|
-
error: status === "failed" ? (e.payload?.error ?? "").slice(0,
|
|
7915
|
+
error: status === "failed" ? (e.payload?.error ?? "").slice(0, 80) : "",
|
|
7688
7916
|
time: relativeTime2(e.timestamp ?? Date.now())
|
|
7689
7917
|
};
|
|
7690
7918
|
}));
|
|
7919
|
+
if (opts.verbose) {
|
|
7920
|
+
const failures = executions.filter((e) => e.eventType === "trigger.failed");
|
|
7921
|
+
if (failures.length) {
|
|
7922
|
+
console.log();
|
|
7923
|
+
console.log(chalk20.bold("Error Details"));
|
|
7924
|
+
console.log(chalk20.gray("\u2500".repeat(60)));
|
|
7925
|
+
for (const f of failures) {
|
|
7926
|
+
console.log(` ${chalk20.cyan(f.payload?.triggerSlug ?? "")} ${chalk20.gray(relativeTime2(f.timestamp ?? Date.now()))}`);
|
|
7927
|
+
console.log(` ${chalk20.red(f.payload?.error ?? "Unknown error")}`);
|
|
7928
|
+
console.log();
|
|
7929
|
+
}
|
|
7930
|
+
}
|
|
7931
|
+
}
|
|
7691
7932
|
console.log();
|
|
7692
7933
|
} catch (err) {
|
|
7693
7934
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -7700,12 +7941,36 @@ triggersCommand.command("logs [slug]").description("View trigger execution histo
|
|
|
7700
7941
|
process.exit(1);
|
|
7701
7942
|
}
|
|
7702
7943
|
});
|
|
7703
|
-
triggersCommand.command("log <
|
|
7944
|
+
triggersCommand.command("log <identifier>").description("View detailed trigger execution log (by event ID or trigger slug)").option("--env <environment>", "Environment", "development").option("--nth <n>", "Show nth most recent execution (when using slug)", "1").option("--json", "Output raw JSON").option("-v, --verbose", "Show detailed agent tool calls").action(async (identifier, opts) => {
|
|
7704
7945
|
await ensureAuth5();
|
|
7705
7946
|
const spinner = ora14();
|
|
7706
7947
|
try {
|
|
7948
|
+
let eventId = identifier;
|
|
7949
|
+
const isConvexId = identifier.includes("_") || identifier.length > 30;
|
|
7950
|
+
if (!isConvexId) {
|
|
7951
|
+
spinner.start("Resolving trigger slug to latest execution");
|
|
7952
|
+
const executions = await listTriggerExecutions({
|
|
7953
|
+
environment: opts.env,
|
|
7954
|
+
triggerSlug: identifier,
|
|
7955
|
+
limit: parseInt(opts.nth, 10)
|
|
7956
|
+
});
|
|
7957
|
+
if (!executions.length) {
|
|
7958
|
+
spinner.fail(`No executions found for trigger "${identifier}" in ${opts.env}`);
|
|
7959
|
+
if (opts.json) {
|
|
7960
|
+
console.log(JSON.stringify({ success: false, error: `No executions found for trigger "${identifier}"` }));
|
|
7961
|
+
}
|
|
7962
|
+
process.exit(1);
|
|
7963
|
+
}
|
|
7964
|
+
const idx = parseInt(opts.nth, 10) - 1;
|
|
7965
|
+
if (idx >= executions.length) {
|
|
7966
|
+
spinner.fail(`Only ${executions.length} executions found, cannot get #${opts.nth}`);
|
|
7967
|
+
process.exit(1);
|
|
7968
|
+
}
|
|
7969
|
+
eventId = executions[idx]._id;
|
|
7970
|
+
spinner.succeed(`Found execution for "${identifier}"`);
|
|
7971
|
+
}
|
|
7707
7972
|
spinner.start("Fetching execution detail");
|
|
7708
|
-
const event = await getTriggerExecutionDetail(eventId);
|
|
7973
|
+
const event = await getTriggerExecutionDetail(eventId, opts.env);
|
|
7709
7974
|
if (!event) {
|
|
7710
7975
|
spinner.fail("Execution not found");
|
|
7711
7976
|
if (opts.json) {
|
|
@@ -7911,6 +8176,79 @@ triggersCommand.command("retry-event <event-id>").description("Retry a failed im
|
|
|
7911
8176
|
process.exit(1);
|
|
7912
8177
|
}
|
|
7913
8178
|
});
|
|
8179
|
+
triggersCommand.command("fire <slug>").description("Manually fire a trigger").option("--env <environment>", "Environment (development|production|eval)", "development").option("--entity <entityId>", "Entity ID to provide as context").option("--data <json>", "JSON data for template context").option("--json", "Output raw JSON").option("--confirm", "Skip production confirmation").option("-v, --verbose", "Show detailed agent tool calls").action(async (slug, opts) => {
|
|
8180
|
+
await ensureAuth5();
|
|
8181
|
+
const spinner = ora14();
|
|
8182
|
+
const environment = opts.env;
|
|
8183
|
+
if (environment === "production" && !opts.confirm && isInteractive()) {
|
|
8184
|
+
const readline = await import("readline");
|
|
8185
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8186
|
+
await new Promise((resolve) => {
|
|
8187
|
+
rl.question(chalk20.yellow(`WARNING: Firing trigger in PRODUCTION environment.
|
|
8188
|
+
Press Enter to continue or Ctrl+C to cancel: `), resolve);
|
|
8189
|
+
});
|
|
8190
|
+
rl.close();
|
|
8191
|
+
}
|
|
8192
|
+
let data;
|
|
8193
|
+
if (opts.data) {
|
|
8194
|
+
try {
|
|
8195
|
+
data = JSON.parse(opts.data);
|
|
8196
|
+
} catch {
|
|
8197
|
+
console.log(chalk20.red("Error: --data must be valid JSON"));
|
|
8198
|
+
process.exit(1);
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
try {
|
|
8202
|
+
spinner.start(`Firing trigger ${chalk20.cyan(slug)}...`);
|
|
8203
|
+
const { result, error } = await fireTrigger({
|
|
8204
|
+
slug,
|
|
8205
|
+
environment,
|
|
8206
|
+
entityId: opts.entity,
|
|
8207
|
+
data
|
|
8208
|
+
});
|
|
8209
|
+
if (error) {
|
|
8210
|
+
spinner.fail("Trigger execution failed");
|
|
8211
|
+
if (opts.json) {
|
|
8212
|
+
console.log(JSON.stringify({ success: false, error }));
|
|
8213
|
+
} else {
|
|
8214
|
+
console.log(chalk20.red("Error:"), error);
|
|
8215
|
+
}
|
|
8216
|
+
process.exit(1);
|
|
8217
|
+
}
|
|
8218
|
+
if (!result) {
|
|
8219
|
+
spinner.fail("No result returned");
|
|
8220
|
+
process.exit(1);
|
|
8221
|
+
}
|
|
8222
|
+
if (result.success) {
|
|
8223
|
+
spinner.succeed(chalk20.green(`Trigger ${chalk20.cyan(slug)} fired successfully`));
|
|
8224
|
+
} else {
|
|
8225
|
+
spinner.fail(chalk20.red(`Trigger ${chalk20.cyan(slug)} execution failed`));
|
|
8226
|
+
}
|
|
8227
|
+
if (opts.json) {
|
|
8228
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8229
|
+
return;
|
|
8230
|
+
}
|
|
8231
|
+
console.log();
|
|
8232
|
+
console.log(` ${chalk20.gray("Trigger:")} ${chalk20.cyan(result.trigger.name)} (${result.trigger.slug})`);
|
|
8233
|
+
console.log(` ${chalk20.gray("Environment:")} ${chalk20.cyan(result.environment)}`);
|
|
8234
|
+
console.log(` ${chalk20.gray("Status:")} ${result.success ? chalk20.green("success") : chalk20.red("failed")}`);
|
|
8235
|
+
if (result.executionLog?.length) {
|
|
8236
|
+
renderExecutionLog(result.executionLog, opts.verbose);
|
|
8237
|
+
}
|
|
8238
|
+
if (!result.success) {
|
|
8239
|
+
process.exit(1);
|
|
8240
|
+
}
|
|
8241
|
+
} catch (err) {
|
|
8242
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8243
|
+
spinner.fail("Failed to fire trigger");
|
|
8244
|
+
if (opts.json) {
|
|
8245
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
8246
|
+
} else {
|
|
8247
|
+
console.log(chalk20.red("Error:"), message);
|
|
8248
|
+
}
|
|
8249
|
+
process.exit(1);
|
|
8250
|
+
}
|
|
8251
|
+
});
|
|
7914
8252
|
|
|
7915
8253
|
// src/cli/commands/compile-prompt.ts
|
|
7916
8254
|
init_credentials();
|
|
@@ -7918,7 +8256,7 @@ import { Command as Command19 } from "commander";
|
|
|
7918
8256
|
import chalk21 from "chalk";
|
|
7919
8257
|
import ora15 from "ora";
|
|
7920
8258
|
init_convex();
|
|
7921
|
-
var compilePromptCommand = new Command19("compile-prompt").description("Compile and preview an agent's system prompt after template processing").argument("<agent-slug>", "Agent slug to compile prompt for").option("--env <env>", "Environment: development | production", "development").option("--message <msg>", "Sample message for template context").option("--channel <channel>", "Sample channel (whatsapp, widget, api, dashboard)").option("--param <key=value...>", "Custom thread param (repeatable)", (val, acc) => {
|
|
8259
|
+
var compilePromptCommand = new Command19("compile-prompt").description("Compile and preview an agent's system prompt after template processing").argument("<agent-slug>", "Agent slug to compile prompt for").option("--env <env>", "Environment: development | production | eval", "development").option("--message <msg>", "Sample message for template context").option("--channel <channel>", "Sample channel (whatsapp, widget, api, dashboard)").option("--param <key=value...>", "Custom thread param (repeatable)", (val, acc) => {
|
|
7922
8260
|
acc.push(val);
|
|
7923
8261
|
return acc;
|
|
7924
8262
|
}, []).option("--json", "Output full JSON (raw + compiled + context)").option("--raw", "Show raw uncompiled template instead of compiled").action(async (agentSlug, options) => {
|
|
@@ -8001,26 +8339,7 @@ var compilePromptCommand = new Command19("compile-prompt").description("Compile
|
|
|
8001
8339
|
threadMetadata: Object.keys(threadMetadata).length > 0 ? threadMetadata : undefined
|
|
8002
8340
|
});
|
|
8003
8341
|
};
|
|
8004
|
-
|
|
8005
|
-
if (error && isAuthError(error) && !nonInteractive) {
|
|
8006
|
-
if (!jsonMode)
|
|
8007
|
-
spinner.fail("Session expired - re-authenticating...");
|
|
8008
|
-
clearCredentials();
|
|
8009
|
-
credentials = await performLogin();
|
|
8010
|
-
if (!credentials) {
|
|
8011
|
-
if (jsonMode) {
|
|
8012
|
-
console.log(JSON.stringify({ success: false, error: "Authentication failed" }));
|
|
8013
|
-
} else {
|
|
8014
|
-
console.log(chalk21.red("Authentication failed"));
|
|
8015
|
-
}
|
|
8016
|
-
process.exit(1);
|
|
8017
|
-
}
|
|
8018
|
-
const retry = await doCompile();
|
|
8019
|
-
result = retry.result;
|
|
8020
|
-
error = retry.error;
|
|
8021
|
-
if (!jsonMode && !error)
|
|
8022
|
-
spinner.succeed("Compiled prompt");
|
|
8023
|
-
}
|
|
8342
|
+
const { result, error } = await doCompile();
|
|
8024
8343
|
if (error) {
|
|
8025
8344
|
if (jsonMode) {
|
|
8026
8345
|
console.log(JSON.stringify({ success: false, error }));
|
|
@@ -8068,7 +8387,7 @@ import { Command as Command20 } from "commander";
|
|
|
8068
8387
|
import chalk22 from "chalk";
|
|
8069
8388
|
import ora16 from "ora";
|
|
8070
8389
|
init_convex();
|
|
8071
|
-
var runToolCommand = new Command20("run-tool").description("Run a tool as it would execute during a real agent conversation").argument("<
|
|
8390
|
+
var runToolCommand = new Command20("run-tool").description("Run a tool as it would execute during a real agent conversation").argument("<tool-name>", "Tool name (e.g., entity.query, run_scrapers)").option("--agent <slug>", "Agent slug (optional \u2014 omit to run without agent context)").option("--env <environment>", "Environment: development | production | eval", "development").option("--args <json>", "Tool arguments as JSON string", "{}").option("--args-file <path>", "Read tool arguments from a JSON file").option("--json", "Output full JSON result").option("--confirm", "Skip production confirmation prompt").action(async (toolName, options) => {
|
|
8072
8391
|
const spinner = ora16();
|
|
8073
8392
|
const cwd = process.cwd();
|
|
8074
8393
|
const nonInteractive = !isInteractive();
|
|
@@ -8137,6 +8456,9 @@ var runToolCommand = new Command20("run-tool").description("Run a tool as it wou
|
|
|
8137
8456
|
process.exit(1);
|
|
8138
8457
|
}
|
|
8139
8458
|
const environment = options.env;
|
|
8459
|
+
if (!options.agent && !toolName.includes(".") && !jsonMode) {
|
|
8460
|
+
console.log(chalk22.dim(`Tip: Running without agent context. Use --agent <slug> to run with a specific agent.`));
|
|
8461
|
+
}
|
|
8140
8462
|
if (environment === "production" && !options.confirm && !nonInteractive) {
|
|
8141
8463
|
const readline = await import("readline");
|
|
8142
8464
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -8148,37 +8470,18 @@ var runToolCommand = new Command20("run-tool").description("Run a tool as it wou
|
|
|
8148
8470
|
rl.close();
|
|
8149
8471
|
}
|
|
8150
8472
|
if (!jsonMode) {
|
|
8151
|
-
spinner.start(`Running ${chalk22.cyan(toolName)} on ${chalk22.cyan(
|
|
8473
|
+
spinner.start(`Running ${chalk22.cyan(toolName)}${options.agent ? ` on ${chalk22.cyan(options.agent)}` : ""} (${environment})`);
|
|
8152
8474
|
}
|
|
8153
8475
|
const doRunTool = async () => {
|
|
8154
8476
|
return runTool({
|
|
8155
|
-
agentSlug,
|
|
8477
|
+
agentSlug: options.agent,
|
|
8156
8478
|
toolName,
|
|
8157
8479
|
toolArgs,
|
|
8158
8480
|
environment,
|
|
8159
8481
|
organizationId: project?.organization.id
|
|
8160
8482
|
});
|
|
8161
8483
|
};
|
|
8162
|
-
|
|
8163
|
-
if (error && isAuthError(error) && !nonInteractive) {
|
|
8164
|
-
if (!jsonMode)
|
|
8165
|
-
spinner.fail("Session expired - re-authenticating...");
|
|
8166
|
-
clearCredentials();
|
|
8167
|
-
credentials = await performLogin();
|
|
8168
|
-
if (!credentials) {
|
|
8169
|
-
if (jsonMode) {
|
|
8170
|
-
console.log(JSON.stringify({ success: false, error: "Authentication failed" }));
|
|
8171
|
-
} else {
|
|
8172
|
-
console.log(chalk22.red("Authentication failed"));
|
|
8173
|
-
}
|
|
8174
|
-
process.exit(1);
|
|
8175
|
-
}
|
|
8176
|
-
const retry = await doRunTool();
|
|
8177
|
-
result = retry.result;
|
|
8178
|
-
error = retry.error;
|
|
8179
|
-
if (!jsonMode && !error)
|
|
8180
|
-
spinner.succeed(`Ran ${chalk22.cyan(toolName)}`);
|
|
8181
|
-
}
|
|
8484
|
+
const { result, error } = await doRunTool();
|
|
8182
8485
|
if (error) {
|
|
8183
8486
|
if (jsonMode) {
|
|
8184
8487
|
console.log(JSON.stringify({ success: false, error }));
|
|
@@ -8205,7 +8508,7 @@ var runToolCommand = new Command20("run-tool").description("Run a tool as it wou
|
|
|
8205
8508
|
process.exit(1);
|
|
8206
8509
|
}
|
|
8207
8510
|
if (!jsonMode) {
|
|
8208
|
-
spinner.succeed(`Ran ${chalk22.cyan(toolName)} on ${chalk22.cyan(result.agent.slug)} (${result.environment}) in ${result.durationMs}ms`);
|
|
8511
|
+
spinner.succeed(`Ran ${chalk22.cyan(toolName)}${result.agent ? ` on ${chalk22.cyan(result.agent.slug)}` : ""} (${result.environment}) in ${result.durationMs}ms`);
|
|
8209
8512
|
}
|
|
8210
8513
|
if (jsonMode) {
|
|
8211
8514
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -8226,7 +8529,18 @@ import chalk23 from "chalk";
|
|
|
8226
8529
|
import ora17 from "ora";
|
|
8227
8530
|
import readline from "readline";
|
|
8228
8531
|
init_convex();
|
|
8229
|
-
|
|
8532
|
+
function printExecutionMeta(meta) {
|
|
8533
|
+
console.log(chalk23.dim(`Model: ${meta.model} | Duration: ${meta.durationMs}ms`));
|
|
8534
|
+
if (meta.toolCallSummary.length > 0) {
|
|
8535
|
+
console.log(chalk23.dim("Tool calls:"));
|
|
8536
|
+
for (const tc of meta.toolCallSummary) {
|
|
8537
|
+
const status = tc.status === "success" ? chalk23.green("ok") : chalk23.red(tc.status);
|
|
8538
|
+
const err = tc.errorMessage ? chalk23.red(` \u2014 ${tc.errorMessage}`) : "";
|
|
8539
|
+
console.log(chalk23.dim(` ${tc.name} ${status} ${tc.durationMs}ms${err}`));
|
|
8540
|
+
}
|
|
8541
|
+
}
|
|
8542
|
+
}
|
|
8543
|
+
var chatCommand = new Command21("chat").description("Chat with an agent or via a router").argument("<slug>", "Agent slug (or router slug when --router is used)").option("--env <environment>", "Environment: development | production | eval", "development").option("--thread <id>", "Continue an existing thread").option("--message <msg>", "Single message mode (send and exit)").option("--json", "Output JSON").option("--channel <channel>", "Channel identifier", "api").option("-v, --verbose", "Show execution metadata (model, duration, tool calls)").option("--confirm", "Skip production warning prompt").option("--router", "Chat via a router instead of directly with an agent").option("--phone <number>", "Sender phone number for routing rules").action(async (slug, options) => {
|
|
8230
8544
|
const spinner = ora17();
|
|
8231
8545
|
const cwd = process.cwd();
|
|
8232
8546
|
const nonInteractive = !isInteractive();
|
|
@@ -8374,16 +8688,18 @@ var chatCommand = new Command21("chat").description("Chat with an agent or via a
|
|
|
8374
8688
|
console.log("\u2500".repeat(60));
|
|
8375
8689
|
console.log();
|
|
8376
8690
|
if (routerResult.routedToAgent) {
|
|
8377
|
-
console.log(chalk23.
|
|
8378
|
-
|
|
8691
|
+
console.log(chalk23.green(`${routerResult.routedToAgent}`) + chalk23.dim(` (${routerResult.routedToAgentSlug})`) + chalk23.magenta(" \u2190 routed") + chalk23.dim(":"));
|
|
8692
|
+
} else {
|
|
8693
|
+
console.log(chalk23.green("Agent:"));
|
|
8379
8694
|
}
|
|
8380
|
-
console.log(chalk23.green("Agent:"));
|
|
8381
8695
|
console.log(result.message);
|
|
8382
8696
|
console.log();
|
|
8383
8697
|
if (options.verbose) {
|
|
8384
8698
|
console.log(chalk23.dim(`Thread: ${result.threadId}`));
|
|
8385
8699
|
console.log(chalk23.dim(`Tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out (${result.usage.totalTokens} total)`));
|
|
8386
|
-
|
|
8700
|
+
if (result._executionMeta) {
|
|
8701
|
+
printExecutionMeta(result._executionMeta);
|
|
8702
|
+
}
|
|
8387
8703
|
} else {
|
|
8388
8704
|
console.log(chalk23.dim(`Thread: ${result.threadId} | Tokens: ${result.usage.totalTokens}`));
|
|
8389
8705
|
}
|
|
@@ -8485,16 +8801,18 @@ var chatCommand = new Command21("chat").description("Chat with an agent or via a
|
|
|
8485
8801
|
const interactiveRouterResult = result;
|
|
8486
8802
|
console.log();
|
|
8487
8803
|
if (interactiveRouterResult.routedToAgent) {
|
|
8488
|
-
console.log(chalk23.
|
|
8489
|
-
|
|
8804
|
+
console.log(chalk23.green(`${interactiveRouterResult.routedToAgent}`) + chalk23.dim(` (${interactiveRouterResult.routedToAgentSlug})`) + chalk23.magenta(" \u2190 routed") + chalk23.dim(":"));
|
|
8805
|
+
} else {
|
|
8806
|
+
console.log(chalk23.green("Agent:"));
|
|
8490
8807
|
}
|
|
8491
|
-
console.log(chalk23.green("Agent:"));
|
|
8492
8808
|
console.log(result.message);
|
|
8493
8809
|
console.log();
|
|
8494
8810
|
if (options.verbose) {
|
|
8495
8811
|
console.log(chalk23.dim(`Thread: ${result.threadId}`));
|
|
8496
8812
|
console.log(chalk23.dim(`Tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out (${result.usage.totalTokens} total)`));
|
|
8497
|
-
|
|
8813
|
+
if (result._executionMeta) {
|
|
8814
|
+
printExecutionMeta(result._executionMeta);
|
|
8815
|
+
}
|
|
8498
8816
|
} else {
|
|
8499
8817
|
console.log(chalk23.dim(`Tokens: ${result.usage.totalTokens}`));
|
|
8500
8818
|
}
|
|
@@ -8710,7 +9028,7 @@ whatsappCommand.command("set-agent <connection> <agent-slug>").description("Assi
|
|
|
8710
9028
|
// package.json
|
|
8711
9029
|
var package_default = {
|
|
8712
9030
|
name: "struere",
|
|
8713
|
-
version: "0.12.
|
|
9031
|
+
version: "0.12.8",
|
|
8714
9032
|
description: "Build, test, and deploy AI agents",
|
|
8715
9033
|
keywords: [
|
|
8716
9034
|
"ai",
|