struere 0.14.2 → 0.14.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/dist/bin/struere.js +461 -83
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/keys.d.ts +3 -0
- package/dist/cli/commands/keys.d.ts.map +1 -0
- package/dist/cli/commands/triggers.d.ts.map +1 -1
- package/dist/cli/index.js +461 -83
- package/dist/cli/utils/apiKeys.d.ts +31 -0
- package/dist/cli/utils/apiKeys.d.ts.map +1 -0
- package/dist/cli/utils/convex.d.ts +1 -0
- package/dist/cli/utils/convex.d.ts.map +1 -1
- package/dist/cli/utils/extractor.d.ts +1 -0
- package/dist/cli/utils/extractor.d.ts.map +1 -1
- package/dist/cli/utils/logs.d.ts +4 -3
- package/dist/cli/utils/logs.d.ts.map +1 -1
- package/dist/cli/utils/plugin.d.ts +1 -0
- package/dist/cli/utils/plugin.d.ts.map +1 -1
- package/dist/cli/utils/threads.d.ts +1 -0
- package/dist/cli/utils/threads.d.ts.map +1 -1
- package/dist/cli/utils/triggers.d.ts +12 -10
- package/dist/cli/utils/triggers.d.ts.map +1 -1
- package/dist/client/chatClient.d.ts +8 -0
- package/dist/client/chatClient.d.ts.map +1 -0
- package/dist/client/dataClient.d.ts +21 -0
- package/dist/client/dataClient.d.ts.map +1 -0
- package/dist/client/index.d.ts +13 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +245 -0
- package/dist/client/transport.d.ts +35 -0
- package/dist/client/transport.d.ts.map +1 -0
- package/dist/client/types.d.ts +130 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/define/agent.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
package/dist/bin/struere.js
CHANGED
|
@@ -680,7 +680,8 @@ async function _fireTrigger(options) {
|
|
|
680
680
|
slug: options.slug,
|
|
681
681
|
environment: options.environment,
|
|
682
682
|
entityId: options.entityId,
|
|
683
|
-
data: options.data
|
|
683
|
+
data: options.data,
|
|
684
|
+
...options.organizationId && { organizationId: options.organizationId }
|
|
684
685
|
}
|
|
685
686
|
}),
|
|
686
687
|
signal: AbortSignal.timeout(60000)
|
|
@@ -2053,6 +2054,7 @@ export interface AgentConfig {
|
|
|
2053
2054
|
systemPrompt: string | (() => string | Promise<string>)
|
|
2054
2055
|
model?: ModelConfig
|
|
2055
2056
|
tools?: string[]
|
|
2057
|
+
roles?: string[]
|
|
2056
2058
|
firstMessageSuggestions?: string[]
|
|
2057
2059
|
threadContextParams?: Array<{
|
|
2058
2060
|
name: string
|
|
@@ -2070,6 +2072,7 @@ export interface JSONSchemaProperty {
|
|
|
2070
2072
|
items?: JSONSchemaProperty
|
|
2071
2073
|
properties?: Record<string, JSONSchemaProperty>
|
|
2072
2074
|
required?: string[]
|
|
2075
|
+
references?: string
|
|
2073
2076
|
}
|
|
2074
2077
|
|
|
2075
2078
|
export interface JSONSchema {
|
|
@@ -2115,6 +2118,7 @@ export interface FieldMaskConfig {
|
|
|
2115
2118
|
export interface RoleConfig {
|
|
2116
2119
|
name: string
|
|
2117
2120
|
description?: string
|
|
2121
|
+
agentAccess?: string[]
|
|
2118
2122
|
policies: PolicyConfig[]
|
|
2119
2123
|
scopeRules?: ScopeRuleConfig[]
|
|
2120
2124
|
fieldMasks?: FieldMaskConfig[]
|
|
@@ -2126,26 +2130,37 @@ export interface TriggerAction {
|
|
|
2126
2130
|
as?: string
|
|
2127
2131
|
}
|
|
2128
2132
|
|
|
2133
|
+
export interface TriggerOnEntity {
|
|
2134
|
+
entityType: string
|
|
2135
|
+
action: 'created' | 'updated' | 'deleted'
|
|
2136
|
+
condition?: Record<string, unknown>
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
export interface TriggerOnSchedule {
|
|
2140
|
+
schedule: string
|
|
2141
|
+
timezone?: string
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
export interface TriggerSchedule {
|
|
2145
|
+
delay?: number
|
|
2146
|
+
at?: string
|
|
2147
|
+
offset?: number
|
|
2148
|
+
cancelPrevious?: boolean
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
export interface TriggerRetry {
|
|
2152
|
+
maxAttempts?: number
|
|
2153
|
+
backoffMs?: number
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2129
2156
|
export interface TriggerConfig {
|
|
2130
2157
|
name: string
|
|
2131
2158
|
slug: string
|
|
2132
2159
|
description?: string
|
|
2133
|
-
on:
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
condition?: Record<string, unknown>
|
|
2137
|
-
}
|
|
2160
|
+
on: TriggerOnEntity | TriggerOnSchedule
|
|
2161
|
+
schedule?: TriggerSchedule
|
|
2162
|
+
retry?: TriggerRetry
|
|
2138
2163
|
actions: TriggerAction[]
|
|
2139
|
-
schedule?: {
|
|
2140
|
-
delay?: number
|
|
2141
|
-
at?: string
|
|
2142
|
-
offset?: number
|
|
2143
|
-
cancelPrevious?: boolean
|
|
2144
|
-
}
|
|
2145
|
-
retry?: {
|
|
2146
|
-
maxAttempts?: number
|
|
2147
|
-
backoffMs?: number
|
|
2148
|
-
}
|
|
2149
2164
|
}
|
|
2150
2165
|
|
|
2151
2166
|
export interface RouterAgentRef {
|
|
@@ -3150,7 +3165,8 @@ function extractAgentPayload(agent, customToolsMap) {
|
|
|
3150
3165
|
maxTokens: agent.model?.maxTokens,
|
|
3151
3166
|
reasoning: agent.model?.reasoning
|
|
3152
3167
|
},
|
|
3153
|
-
tools
|
|
3168
|
+
tools,
|
|
3169
|
+
roles: agent.roles
|
|
3154
3170
|
};
|
|
3155
3171
|
}
|
|
3156
3172
|
function extractHandlerCode(handler) {
|
|
@@ -3633,7 +3649,10 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3633
3649
|
const apiKey = getApiKey();
|
|
3634
3650
|
const nonInteractive = !isInteractive();
|
|
3635
3651
|
if (nonInteractive) {
|
|
3636
|
-
console.error("Error: struere dev
|
|
3652
|
+
console.error(chalk7.red("Error:"), "`struere dev` requires an interactive terminal (TTY) to render its watch UI.");
|
|
3653
|
+
console.error(chalk7.gray(" - For a one-shot sync, use:"), chalk7.cyan("struere sync [--env development]"));
|
|
3654
|
+
console.error(chalk7.gray(" - For continuous deployment in CI/CD, use:"), chalk7.cyan("struere deploy"));
|
|
3655
|
+
console.error(chalk7.gray(" - To run dev in the foreground, attach a TTY (avoid backgrounding with `&` or piping output)."));
|
|
3637
3656
|
process.exit(1);
|
|
3638
3657
|
}
|
|
3639
3658
|
console.log();
|
|
@@ -5849,7 +5868,8 @@ async function queryThreads(options) {
|
|
|
5849
5868
|
environment: options.environment,
|
|
5850
5869
|
...options.agentId && { agentId: options.agentId },
|
|
5851
5870
|
...options.channel && { channel: options.channel },
|
|
5852
|
-
...options.limit && { limit: options.limit }
|
|
5871
|
+
...options.limit && { limit: options.limit },
|
|
5872
|
+
...options.organizationId && { organizationId: options.organizationId }
|
|
5853
5873
|
});
|
|
5854
5874
|
if (result.error || !result.data)
|
|
5855
5875
|
return result;
|
|
@@ -5865,20 +5885,21 @@ async function queryThreads(options) {
|
|
|
5865
5885
|
}
|
|
5866
5886
|
return result;
|
|
5867
5887
|
}
|
|
5868
|
-
async function queryThreadDetail(threadId, messageLimit) {
|
|
5888
|
+
async function queryThreadDetail(threadId, messageLimit, organizationId) {
|
|
5869
5889
|
return convexQuery2("threads:getWithMessages", {
|
|
5870
5890
|
id: threadId,
|
|
5871
|
-
...messageLimit && { messageLimit }
|
|
5891
|
+
...messageLimit && { messageLimit },
|
|
5892
|
+
...organizationId && { organizationId }
|
|
5872
5893
|
});
|
|
5873
5894
|
}
|
|
5874
|
-
async function queryThreadExecutions(threadId) {
|
|
5875
|
-
return convexQuery2("executions:getByThread", { threadId });
|
|
5895
|
+
async function queryThreadExecutions(threadId, organizationId) {
|
|
5896
|
+
return convexQuery2("executions:getByThread", { threadId, ...organizationId && { organizationId } });
|
|
5876
5897
|
}
|
|
5877
|
-
async function resolveThreadId(shortId, environment) {
|
|
5898
|
+
async function resolveThreadId(shortId, environment, organizationId) {
|
|
5878
5899
|
if (shortId.includes("|") || shortId.length > 20) {
|
|
5879
5900
|
return { data: shortId };
|
|
5880
5901
|
}
|
|
5881
|
-
const result = await queryThreads({ environment: environment ?? "development", limit: 100 });
|
|
5902
|
+
const result = await queryThreads({ environment: environment ?? "development", limit: 100, organizationId });
|
|
5882
5903
|
if (result.error || !result.data)
|
|
5883
5904
|
return { error: result.error ?? "Could not fetch threads" };
|
|
5884
5905
|
const threads = result.data;
|
|
@@ -5887,7 +5908,7 @@ async function resolveThreadId(shortId, environment) {
|
|
|
5887
5908
|
for (const env of ["production", "development", "eval"]) {
|
|
5888
5909
|
if (env === (environment ?? "development"))
|
|
5889
5910
|
continue;
|
|
5890
|
-
const envResult = await queryThreads({ environment: env, limit: 100 });
|
|
5911
|
+
const envResult = await queryThreads({ environment: env, limit: 100, organizationId });
|
|
5891
5912
|
if (envResult.data) {
|
|
5892
5913
|
const envThreads = envResult.data;
|
|
5893
5914
|
const envMatch = envThreads.find((t) => t._id.endsWith(shortId));
|
|
@@ -5989,7 +6010,8 @@ logsCommand.command("list", { isDefault: true }).description("List recent conver
|
|
|
5989
6010
|
agentId,
|
|
5990
6011
|
channel: opts.channel,
|
|
5991
6012
|
phone: opts.phone,
|
|
5992
|
-
limit: parseInt(opts.limit, 10)
|
|
6013
|
+
limit: parseInt(opts.limit, 10),
|
|
6014
|
+
organizationId: orgId
|
|
5993
6015
|
});
|
|
5994
6016
|
if (error || !data) {
|
|
5995
6017
|
spinner?.fail("Failed to fetch conversations");
|
|
@@ -6026,8 +6048,9 @@ logsCommand.command("list", { isDefault: true }).description("List recent conver
|
|
|
6026
6048
|
logsCommand.command("view <thread-id>").description("View conversation messages").option("--env <environment>", "Environment hint for resolving short IDs").option("--exec", "Include execution details").option("--verbose", "Show full tool call arguments and results").option("--tail", "Show most recent messages (use with --limit)").option("--json", "Output raw JSON").option("--limit <n>", "Message limit", "100").action(async (rawThreadId, opts) => {
|
|
6027
6049
|
await ensureAuth2();
|
|
6028
6050
|
const spinner = opts.json ? null : ora12();
|
|
6051
|
+
const orgId = getOrgId2();
|
|
6029
6052
|
spinner?.start("Resolving thread");
|
|
6030
|
-
const resolved = await resolveThreadId(rawThreadId, opts.env);
|
|
6053
|
+
const resolved = await resolveThreadId(rawThreadId, opts.env, orgId);
|
|
6031
6054
|
if (resolved.error || !resolved.data) {
|
|
6032
6055
|
spinner?.fail("Thread not found");
|
|
6033
6056
|
console.log(chalk16.red("Error:"), resolved.error || `No thread matched "${rawThreadId}"`);
|
|
@@ -6037,7 +6060,7 @@ logsCommand.command("view <thread-id>").description("View conversation messages"
|
|
|
6037
6060
|
spinner?.stop();
|
|
6038
6061
|
spinner?.start("Fetching conversation");
|
|
6039
6062
|
const fetchLimit = opts.tail ? 1000 : parseInt(opts.limit, 10);
|
|
6040
|
-
const { data, error } = await queryThreadDetail(threadId, fetchLimit);
|
|
6063
|
+
const { data, error } = await queryThreadDetail(threadId, fetchLimit, orgId);
|
|
6041
6064
|
if (error || !data) {
|
|
6042
6065
|
spinner?.fail("Failed to fetch conversation");
|
|
6043
6066
|
console.log(chalk16.red("Error:"), error || "Thread not found");
|
|
@@ -6047,7 +6070,7 @@ logsCommand.command("view <thread-id>").description("View conversation messages"
|
|
|
6047
6070
|
const result = data;
|
|
6048
6071
|
let executions = [];
|
|
6049
6072
|
if (opts.exec) {
|
|
6050
|
-
const execResult = await queryThreadExecutions(threadId);
|
|
6073
|
+
const execResult = await queryThreadExecutions(threadId, orgId);
|
|
6051
6074
|
if (execResult.data) {
|
|
6052
6075
|
executions = execResult.data;
|
|
6053
6076
|
}
|
|
@@ -7666,51 +7689,54 @@ async function convexMutation5(path, args) {
|
|
|
7666
7689
|
}
|
|
7667
7690
|
return json.value;
|
|
7668
7691
|
}
|
|
7669
|
-
async function listTriggers(environment) {
|
|
7670
|
-
return convexQuery6("triggers:list", { environment });
|
|
7692
|
+
async function listTriggers(environment, organizationId) {
|
|
7693
|
+
return convexQuery6("triggers:list", { environment, ...organizationId && { organizationId } });
|
|
7671
7694
|
}
|
|
7672
|
-
async function getTrigger(slug, environment) {
|
|
7673
|
-
return convexQuery6("triggers:getBySlug", { slug, environment });
|
|
7695
|
+
async function getTrigger(slug, environment, organizationId) {
|
|
7696
|
+
return convexQuery6("triggers:getBySlug", { slug, environment, ...organizationId && { organizationId } });
|
|
7674
7697
|
}
|
|
7675
7698
|
async function listTriggerRuns(options) {
|
|
7676
7699
|
return convexQuery6("triggers:listRuns", {
|
|
7677
7700
|
environment: options.environment,
|
|
7678
7701
|
...options.status && { status: options.status },
|
|
7679
7702
|
...options.triggerSlug && { triggerSlug: options.triggerSlug },
|
|
7680
|
-
...options.limit && { limit: options.limit }
|
|
7703
|
+
...options.limit && { limit: options.limit },
|
|
7704
|
+
...options.organizationId && { organizationId: options.organizationId }
|
|
7681
7705
|
});
|
|
7682
7706
|
}
|
|
7683
|
-
async function getTriggerRunDetail(runId, environment) {
|
|
7707
|
+
async function getTriggerRunDetail(runId, environment, organizationId) {
|
|
7684
7708
|
return convexQuery6("triggers:getRunDetail", {
|
|
7685
7709
|
runId,
|
|
7686
|
-
...environment && { environment }
|
|
7710
|
+
...environment && { environment },
|
|
7711
|
+
...organizationId && { organizationId }
|
|
7687
7712
|
});
|
|
7688
7713
|
}
|
|
7689
|
-
async function getTriggerRunStats(environment) {
|
|
7690
|
-
return convexQuery6("triggers:getRunStats", { environment });
|
|
7714
|
+
async function getTriggerRunStats(environment, organizationId) {
|
|
7715
|
+
return convexQuery6("triggers:getRunStats", { environment, ...organizationId && { organizationId } });
|
|
7691
7716
|
}
|
|
7692
|
-
async function getLastRunStatuses(environment) {
|
|
7693
|
-
return convexQuery6("triggers:getLastRunStatuses", { environment });
|
|
7717
|
+
async function getLastRunStatuses(environment, organizationId) {
|
|
7718
|
+
return convexQuery6("triggers:getLastRunStatuses", { environment, ...organizationId && { organizationId } });
|
|
7694
7719
|
}
|
|
7695
|
-
async function cancelTriggerRun(runId, environment) {
|
|
7696
|
-
return convexMutation5("triggers:cancelRun", { runId, environment });
|
|
7720
|
+
async function cancelTriggerRun(runId, environment, organizationId) {
|
|
7721
|
+
return convexMutation5("triggers:cancelRun", { runId, environment, ...organizationId && { organizationId } });
|
|
7697
7722
|
}
|
|
7698
|
-
async function retryTriggerRun(runId, environment) {
|
|
7699
|
-
return convexMutation5("triggers:retryRun", { runId, environment });
|
|
7723
|
+
async function retryTriggerRun(runId, environment, organizationId) {
|
|
7724
|
+
return convexMutation5("triggers:retryRun", { runId, environment, ...organizationId && { organizationId } });
|
|
7700
7725
|
}
|
|
7701
|
-
async function toggleTrigger(slug, enabled, environment) {
|
|
7726
|
+
async function toggleTrigger(slug, enabled, environment, organizationId) {
|
|
7702
7727
|
const path = enabled ? "triggers:enable" : "triggers:disable";
|
|
7703
|
-
return convexMutation5(path, { slug, environment });
|
|
7728
|
+
return convexMutation5(path, { slug, environment, ...organizationId && { organizationId } });
|
|
7704
7729
|
}
|
|
7705
7730
|
async function listTriggerExecutions(options) {
|
|
7706
7731
|
return convexQuery6("triggers:listExecutions", {
|
|
7707
7732
|
environment: options.environment,
|
|
7708
7733
|
...options.triggerSlug && { triggerSlug: options.triggerSlug },
|
|
7709
|
-
...options.limit && { limit: options.limit }
|
|
7734
|
+
...options.limit && { limit: options.limit },
|
|
7735
|
+
...options.organizationId && { organizationId: options.organizationId }
|
|
7710
7736
|
});
|
|
7711
7737
|
}
|
|
7712
|
-
async function getTriggerExecutionDetail(eventId, environment) {
|
|
7713
|
-
return convexQuery6("triggers:getExecutionDetail", { eventId, ...environment && { environment } });
|
|
7738
|
+
async function getTriggerExecutionDetail(eventId, environment, organizationId) {
|
|
7739
|
+
return convexQuery6("triggers:getExecutionDetail", { eventId, ...environment && { environment }, ...organizationId && { organizationId } });
|
|
7714
7740
|
}
|
|
7715
7741
|
async function convexAction3(path, args) {
|
|
7716
7742
|
const token = getToken3();
|
|
@@ -7737,11 +7763,15 @@ async function convexAction3(path, args) {
|
|
|
7737
7763
|
}
|
|
7738
7764
|
return json.value;
|
|
7739
7765
|
}
|
|
7740
|
-
async function retryImmediateExecution(eventId, environment) {
|
|
7741
|
-
return convexAction3("triggers:retryImmediateExecution", { eventId, environment });
|
|
7766
|
+
async function retryImmediateExecution(eventId, environment, organizationId) {
|
|
7767
|
+
return convexAction3("triggers:retryImmediateExecution", { eventId, environment, ...organizationId && { organizationId } });
|
|
7742
7768
|
}
|
|
7743
7769
|
|
|
7744
7770
|
// src/cli/commands/triggers.ts
|
|
7771
|
+
function getOrgId3() {
|
|
7772
|
+
const project = loadProject(process.cwd());
|
|
7773
|
+
return project?.organization.id;
|
|
7774
|
+
}
|
|
7745
7775
|
async function withTriggerAuthRetry(fn) {
|
|
7746
7776
|
try {
|
|
7747
7777
|
return await fn();
|
|
@@ -7909,10 +7939,11 @@ triggersCommand.command("list", { isDefault: true }).description("List all trigg
|
|
|
7909
7939
|
await ensureAuth5();
|
|
7910
7940
|
const spinner = opts.json ? null : ora14();
|
|
7911
7941
|
try {
|
|
7942
|
+
const orgId = getOrgId3();
|
|
7912
7943
|
spinner?.start("Fetching triggers");
|
|
7913
7944
|
const [triggers, statuses] = await Promise.all([
|
|
7914
|
-
listTriggers(opts.env),
|
|
7915
|
-
getLastRunStatuses(opts.env)
|
|
7945
|
+
listTriggers(opts.env, orgId),
|
|
7946
|
+
getLastRunStatuses(opts.env, orgId)
|
|
7916
7947
|
]);
|
|
7917
7948
|
let filtered = triggers;
|
|
7918
7949
|
if (opts.failed) {
|
|
@@ -7958,7 +7989,7 @@ triggersCommand.command("get <slug>").description("View trigger details").option
|
|
|
7958
7989
|
const spinner = opts.json ? null : ora14();
|
|
7959
7990
|
try {
|
|
7960
7991
|
spinner?.start("Fetching trigger");
|
|
7961
|
-
const trigger = await getTrigger(slug, opts.env);
|
|
7992
|
+
const trigger = await getTrigger(slug, opts.env, getOrgId3());
|
|
7962
7993
|
if (!trigger) {
|
|
7963
7994
|
spinner?.fail("Trigger not found");
|
|
7964
7995
|
if (opts.json) {
|
|
@@ -8041,7 +8072,8 @@ triggersCommand.command("runs [slug]").description("List trigger runs").option("
|
|
|
8041
8072
|
environment: opts.env,
|
|
8042
8073
|
status: opts.status,
|
|
8043
8074
|
triggerSlug: slug,
|
|
8044
|
-
limit: parseInt(opts.limit, 10)
|
|
8075
|
+
limit: parseInt(opts.limit, 10),
|
|
8076
|
+
organizationId: getOrgId3()
|
|
8045
8077
|
});
|
|
8046
8078
|
spinner?.succeed(`Found ${runs.length} runs`);
|
|
8047
8079
|
if (opts.json) {
|
|
@@ -8083,7 +8115,7 @@ triggersCommand.command("run <run-id>").description("View trigger run details").
|
|
|
8083
8115
|
const spinner = opts.json ? null : ora14();
|
|
8084
8116
|
try {
|
|
8085
8117
|
spinner?.start("Fetching run");
|
|
8086
|
-
const run = await getTriggerRunDetail(runId, opts.env);
|
|
8118
|
+
const run = await getTriggerRunDetail(runId, opts.env, getOrgId3());
|
|
8087
8119
|
if (!run) {
|
|
8088
8120
|
spinner?.fail("Run not found");
|
|
8089
8121
|
if (opts.json) {
|
|
@@ -8127,8 +8159,9 @@ triggersCommand.command("stats").description("Show trigger run statistics").opti
|
|
|
8127
8159
|
await ensureAuth5();
|
|
8128
8160
|
const spinner = opts.json ? null : ora14();
|
|
8129
8161
|
try {
|
|
8162
|
+
const orgId = getOrgId3();
|
|
8130
8163
|
spinner?.start("Fetching statistics");
|
|
8131
|
-
const stats = await getTriggerRunStats(opts.env);
|
|
8164
|
+
const stats = await getTriggerRunStats(opts.env, orgId);
|
|
8132
8165
|
spinner?.succeed("Run statistics");
|
|
8133
8166
|
if (opts.json) {
|
|
8134
8167
|
console.log(JSON.stringify(stats, null, 2));
|
|
@@ -8153,7 +8186,7 @@ triggersCommand.command("stats").description("Show trigger run statistics").opti
|
|
|
8153
8186
|
console.log(` ${chalk20.gray("\u2500".repeat(18))}`);
|
|
8154
8187
|
console.log(` ${chalk20.bold("Total".padEnd(12))} ${chalk20.bold(String(total).padStart(6))}`);
|
|
8155
8188
|
console.log();
|
|
8156
|
-
const executions = await listTriggerExecutions({ environment: opts.env, limit: 50 });
|
|
8189
|
+
const executions = await listTriggerExecutions({ environment: opts.env, limit: 50, organizationId: orgId });
|
|
8157
8190
|
const recentFailures = executions.filter((e) => e.eventType === "trigger.failed");
|
|
8158
8191
|
const recentSuccesses = executions.length - recentFailures.length;
|
|
8159
8192
|
console.log(chalk20.bold(` Recent Executions`));
|
|
@@ -8185,7 +8218,8 @@ triggersCommand.command("logs [slug]").description("View trigger execution histo
|
|
|
8185
8218
|
const executions = await withTriggerAuthRetry(() => listTriggerExecutions({
|
|
8186
8219
|
environment: opts.env,
|
|
8187
8220
|
triggerSlug: slug,
|
|
8188
|
-
limit: parseInt(opts.limit, 10)
|
|
8221
|
+
limit: parseInt(opts.limit, 10),
|
|
8222
|
+
organizationId: getOrgId3()
|
|
8189
8223
|
}));
|
|
8190
8224
|
spinner?.succeed(`Found ${executions.length} executions`);
|
|
8191
8225
|
if (opts.json) {
|
|
@@ -8245,6 +8279,7 @@ triggersCommand.command("log <identifier>").description("View detailed trigger e
|
|
|
8245
8279
|
await ensureAuth5();
|
|
8246
8280
|
const spinner = opts.json ? null : ora14();
|
|
8247
8281
|
try {
|
|
8282
|
+
const orgId = getOrgId3();
|
|
8248
8283
|
const nth = parseInt(opts.nth, 10);
|
|
8249
8284
|
if (isNaN(nth) || nth < 1) {
|
|
8250
8285
|
console.error(chalk20.red("Error:"), "--nth must be a positive integer (e.g., --nth 1 for most recent)");
|
|
@@ -8257,7 +8292,8 @@ triggersCommand.command("log <identifier>").description("View detailed trigger e
|
|
|
8257
8292
|
const executions = await withTriggerAuthRetry(() => listTriggerExecutions({
|
|
8258
8293
|
environment: opts.env,
|
|
8259
8294
|
triggerSlug: identifier,
|
|
8260
|
-
limit: nth
|
|
8295
|
+
limit: nth,
|
|
8296
|
+
organizationId: orgId
|
|
8261
8297
|
}));
|
|
8262
8298
|
if (!executions.length) {
|
|
8263
8299
|
spinner?.fail(`No executions found for trigger "${identifier}" in ${opts.env}`);
|
|
@@ -8275,7 +8311,7 @@ triggersCommand.command("log <identifier>").description("View detailed trigger e
|
|
|
8275
8311
|
spinner?.succeed(`Found execution for "${identifier}"`);
|
|
8276
8312
|
}
|
|
8277
8313
|
spinner?.start("Fetching execution detail");
|
|
8278
|
-
const event = await withTriggerAuthRetry(() => getTriggerExecutionDetail(eventId, opts.env));
|
|
8314
|
+
const event = await withTriggerAuthRetry(() => getTriggerExecutionDetail(eventId, opts.env, orgId));
|
|
8279
8315
|
if (!event) {
|
|
8280
8316
|
spinner?.fail("Execution not found");
|
|
8281
8317
|
if (opts.json) {
|
|
@@ -8337,7 +8373,7 @@ triggersCommand.command("retry <run-id>").description("Retry a failed or dead ru
|
|
|
8337
8373
|
}
|
|
8338
8374
|
try {
|
|
8339
8375
|
spinner?.start("Retrying run...");
|
|
8340
|
-
await retryTriggerRun(runId, environment);
|
|
8376
|
+
await retryTriggerRun(runId, environment, getOrgId3());
|
|
8341
8377
|
spinner?.succeed(chalk20.green(`Run ${runId} queued for retry`));
|
|
8342
8378
|
if (opts.json) {
|
|
8343
8379
|
console.log(JSON.stringify({ success: true, runId }));
|
|
@@ -8368,7 +8404,7 @@ triggersCommand.command("cancel <run-id>").description("Cancel a pending run").o
|
|
|
8368
8404
|
}
|
|
8369
8405
|
try {
|
|
8370
8406
|
spinner?.start("Cancelling run...");
|
|
8371
|
-
await cancelTriggerRun(runId, environment);
|
|
8407
|
+
await cancelTriggerRun(runId, environment, getOrgId3());
|
|
8372
8408
|
spinner?.succeed(chalk20.green(`Run ${runId} cancelled`));
|
|
8373
8409
|
if (opts.json) {
|
|
8374
8410
|
console.log(JSON.stringify({ success: true, runId }));
|
|
@@ -8399,7 +8435,7 @@ triggersCommand.command("enable <slug>").description("Enable a trigger").option(
|
|
|
8399
8435
|
}
|
|
8400
8436
|
try {
|
|
8401
8437
|
spinner?.start("Enabling trigger...");
|
|
8402
|
-
await toggleTrigger(slug, true, environment);
|
|
8438
|
+
await toggleTrigger(slug, true, environment, getOrgId3());
|
|
8403
8439
|
spinner?.succeed(chalk20.green(`Trigger ${slug} enabled`));
|
|
8404
8440
|
if (opts.json) {
|
|
8405
8441
|
console.log(JSON.stringify({ success: true, slug }));
|
|
@@ -8430,7 +8466,7 @@ triggersCommand.command("disable <slug>").description("Disable a trigger").optio
|
|
|
8430
8466
|
}
|
|
8431
8467
|
try {
|
|
8432
8468
|
spinner?.start("Disabling trigger...");
|
|
8433
|
-
await toggleTrigger(slug, false, environment);
|
|
8469
|
+
await toggleTrigger(slug, false, environment, getOrgId3());
|
|
8434
8470
|
spinner?.succeed(chalk20.green(`Trigger ${slug} disabled`));
|
|
8435
8471
|
if (opts.json) {
|
|
8436
8472
|
console.log(JSON.stringify({ success: true, slug }));
|
|
@@ -8461,7 +8497,7 @@ triggersCommand.command("retry-event <event-id>").description("Retry a failed im
|
|
|
8461
8497
|
}
|
|
8462
8498
|
try {
|
|
8463
8499
|
spinner?.start("Retrying failed execution...");
|
|
8464
|
-
const result = await retryImmediateExecution(eventId, environment);
|
|
8500
|
+
const result = await retryImmediateExecution(eventId, environment, getOrgId3());
|
|
8465
8501
|
if (result.success) {
|
|
8466
8502
|
spinner?.succeed(chalk20.green(`Execution retried successfully`));
|
|
8467
8503
|
} else {
|
|
@@ -8509,7 +8545,8 @@ triggersCommand.command("fire <slug>").description("Manually fire a trigger").op
|
|
|
8509
8545
|
slug,
|
|
8510
8546
|
environment,
|
|
8511
8547
|
entityId: opts.entity,
|
|
8512
|
-
data
|
|
8548
|
+
data,
|
|
8549
|
+
organizationId: getOrgId3()
|
|
8513
8550
|
});
|
|
8514
8551
|
if (error) {
|
|
8515
8552
|
spinner?.fail("Trigger execution failed");
|
|
@@ -8667,12 +8704,14 @@ async function listThreads(options) {
|
|
|
8667
8704
|
return convexQuery7("threads:listWithPreviews", {
|
|
8668
8705
|
environment: options.environment,
|
|
8669
8706
|
channel: options.channel,
|
|
8670
|
-
limit: options.limit
|
|
8707
|
+
limit: options.limit,
|
|
8708
|
+
...options.organizationId && { organizationId: options.organizationId }
|
|
8671
8709
|
});
|
|
8672
8710
|
}
|
|
8673
8711
|
async function getThreadWithMessages(options) {
|
|
8674
8712
|
return convexQuery7("threads:getWithMessages", {
|
|
8675
|
-
id: options.threadId
|
|
8713
|
+
id: options.threadId,
|
|
8714
|
+
...options.organizationId && { organizationId: options.organizationId }
|
|
8676
8715
|
});
|
|
8677
8716
|
}
|
|
8678
8717
|
async function archiveThread(options) {
|
|
@@ -9298,7 +9337,7 @@ function printExecutionMeta(meta) {
|
|
|
9298
9337
|
console.log(chalk24.dim(`Tool errors: ${chalk24.yellow(String(meta.errorCount))}`));
|
|
9299
9338
|
}
|
|
9300
9339
|
}
|
|
9301
|
-
var chatCommand = new Command22("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").option("--follow", "Continue in interactive mode after sending a message").action(async (slug, options) => {
|
|
9340
|
+
var chatCommand = new Command22("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 structured JSON including thread ID, message, usage, and per-tool-call execution metadata.").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").option("--follow", "Continue in interactive mode after sending a message").action(async (slug, options) => {
|
|
9302
9341
|
const spinner = ora18();
|
|
9303
9342
|
const cwd = process.cwd();
|
|
9304
9343
|
const nonInteractive = !isInteractive();
|
|
@@ -9436,7 +9475,17 @@ var chatCommand = new Command22("chat").description("Chat with an agent or via a
|
|
|
9436
9475
|
spinner.succeed("Message sent");
|
|
9437
9476
|
const routerResult = result;
|
|
9438
9477
|
if (jsonMode) {
|
|
9439
|
-
const output = {
|
|
9478
|
+
const output = { threadId: result.threadId, message: result.message, usage: result.usage };
|
|
9479
|
+
if (result._executionMeta) {
|
|
9480
|
+
output.executionMeta = {
|
|
9481
|
+
iterationCount: result._executionMeta.iterationCount,
|
|
9482
|
+
model: result._executionMeta.model,
|
|
9483
|
+
durationMs: result._executionMeta.durationMs,
|
|
9484
|
+
toolCalls: result._executionMeta.toolCallSummary,
|
|
9485
|
+
errorCount: result._executionMeta.errorCount,
|
|
9486
|
+
permissionDenialCount: result._executionMeta.permissionDenialCount
|
|
9487
|
+
};
|
|
9488
|
+
}
|
|
9440
9489
|
if (routerResult.routedToAgent) {
|
|
9441
9490
|
output.routedToAgent = routerResult.routedToAgent;
|
|
9442
9491
|
output.routedToAgentSlug = routerResult.routedToAgentSlug;
|
|
@@ -10450,8 +10499,8 @@ function checkModelConfig(resources) {
|
|
|
10450
10499
|
hint: "Check agent model config - temperature should be 0-2"
|
|
10451
10500
|
};
|
|
10452
10501
|
}
|
|
10453
|
-
async function checkStuckThreads(environment) {
|
|
10454
|
-
const threads = await withAuthRetry2(() => listThreads({ environment, limit: 100 }));
|
|
10502
|
+
async function checkStuckThreads(environment, organizationId) {
|
|
10503
|
+
const threads = await withAuthRetry2(() => listThreads({ environment, limit: 100, organizationId }));
|
|
10455
10504
|
const issues = [];
|
|
10456
10505
|
const now = Date.now();
|
|
10457
10506
|
const fiveMinutes = 5 * 60 * 1000;
|
|
@@ -10480,8 +10529,8 @@ async function checkStuckThreads(environment) {
|
|
|
10480
10529
|
hint: "Run `struere threads archive <id>` to archive stuck threads"
|
|
10481
10530
|
};
|
|
10482
10531
|
}
|
|
10483
|
-
async function checkTriggerHealth(environment) {
|
|
10484
|
-
const executions = await withAuthRetry2(() => listTriggerExecutions({ environment, limit: 100 }));
|
|
10532
|
+
async function checkTriggerHealth(environment, organizationId) {
|
|
10533
|
+
const executions = await withAuthRetry2(() => listTriggerExecutions({ environment, limit: 100, organizationId }));
|
|
10485
10534
|
if (executions.length === 0) {
|
|
10486
10535
|
return {
|
|
10487
10536
|
id: "trigger-health",
|
|
@@ -10528,8 +10577,8 @@ async function checkTriggerHealth(environment) {
|
|
|
10528
10577
|
hint: "Run `struere triggers logs <slug>` to investigate failures"
|
|
10529
10578
|
};
|
|
10530
10579
|
}
|
|
10531
|
-
async function checkSyncDrift(resources, environment) {
|
|
10532
|
-
const { state, error } = await withAuthRetry2(() => getSyncState(
|
|
10580
|
+
async function checkSyncDrift(resources, environment, organizationId) {
|
|
10581
|
+
const { state, error } = await withAuthRetry2(() => getSyncState(organizationId, environment));
|
|
10533
10582
|
if (error || !state) {
|
|
10534
10583
|
return {
|
|
10535
10584
|
id: "sync-drift",
|
|
@@ -10638,6 +10687,8 @@ var doctorCommand = new Command25("doctor").description("Run diagnostic checks o
|
|
|
10638
10687
|
const spinner = opts.json ? null : ora20();
|
|
10639
10688
|
const cwd = process.cwd();
|
|
10640
10689
|
const environment = opts.env;
|
|
10690
|
+
const project = loadProject(cwd);
|
|
10691
|
+
const organizationId = project?.organization.id;
|
|
10641
10692
|
try {
|
|
10642
10693
|
spinner?.start("Loading resources...");
|
|
10643
10694
|
const resources = await loadAllResources(cwd);
|
|
@@ -10648,9 +10699,9 @@ var doctorCommand = new Command25("doctor").description("Run diagnostic checks o
|
|
|
10648
10699
|
runCheck(() => checkTemplateApprovals(resources)),
|
|
10649
10700
|
runCheck(() => checkEntityTypeReferences(resources)),
|
|
10650
10701
|
runCheck(() => checkModelConfig(resources)),
|
|
10651
|
-
runCheck(() => checkStuckThreads(environment)),
|
|
10652
|
-
runCheck(() => checkTriggerHealth(environment)),
|
|
10653
|
-
runCheck(() => checkSyncDrift(resources, environment))
|
|
10702
|
+
runCheck(() => checkStuckThreads(environment, organizationId)),
|
|
10703
|
+
runCheck(() => checkTriggerHealth(environment, organizationId)),
|
|
10704
|
+
runCheck(() => checkSyncDrift(resources, environment, organizationId))
|
|
10654
10705
|
]);
|
|
10655
10706
|
spinner?.stop();
|
|
10656
10707
|
const checks = results.map((r) => r.status === "fulfilled" ? r.value : { id: "unknown", label: "Unknown", status: "warn", message: `Check failed: ${r.reason}` });
|
|
@@ -10704,10 +10755,332 @@ var doctorCommand = new Command25("doctor").description("Run diagnostic checks o
|
|
|
10704
10755
|
process.exit(1);
|
|
10705
10756
|
}
|
|
10706
10757
|
});
|
|
10758
|
+
|
|
10759
|
+
// src/cli/commands/keys.ts
|
|
10760
|
+
init_credentials();
|
|
10761
|
+
import { Command as Command26 } from "commander";
|
|
10762
|
+
import chalk29 from "chalk";
|
|
10763
|
+
import ora21 from "ora";
|
|
10764
|
+
import { input as input3, confirm as confirm8 } from "@inquirer/prompts";
|
|
10765
|
+
init_convex();
|
|
10766
|
+
|
|
10767
|
+
// src/cli/utils/apiKeys.ts
|
|
10768
|
+
init_credentials();
|
|
10769
|
+
init_config();
|
|
10770
|
+
function getToken5() {
|
|
10771
|
+
const credentials = loadCredentials();
|
|
10772
|
+
const apiKey = getApiKey();
|
|
10773
|
+
const token = apiKey || credentials?.token;
|
|
10774
|
+
if (!token)
|
|
10775
|
+
throw new Error("Not authenticated");
|
|
10776
|
+
return token;
|
|
10777
|
+
}
|
|
10778
|
+
async function convexQuery8(path, args) {
|
|
10779
|
+
const token = getToken5();
|
|
10780
|
+
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
10781
|
+
method: "POST",
|
|
10782
|
+
headers: {
|
|
10783
|
+
"Content-Type": "application/json",
|
|
10784
|
+
Authorization: `Bearer ${token}`
|
|
10785
|
+
},
|
|
10786
|
+
body: JSON.stringify({ path, args })
|
|
10787
|
+
});
|
|
10788
|
+
const text = await response.text();
|
|
10789
|
+
let json;
|
|
10790
|
+
try {
|
|
10791
|
+
json = JSON.parse(text);
|
|
10792
|
+
} catch {
|
|
10793
|
+
throw new Error(text || `HTTP ${response.status}`);
|
|
10794
|
+
}
|
|
10795
|
+
if (!response.ok) {
|
|
10796
|
+
throw new Error(json.errorData?.message || json.errorMessage || text);
|
|
10797
|
+
}
|
|
10798
|
+
if (json.status === "error") {
|
|
10799
|
+
throw new Error(json.errorMessage || "Unknown error from Convex");
|
|
10800
|
+
}
|
|
10801
|
+
return json.value;
|
|
10802
|
+
}
|
|
10803
|
+
async function convexMutation6(path, args) {
|
|
10804
|
+
const token = getToken5();
|
|
10805
|
+
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
10806
|
+
method: "POST",
|
|
10807
|
+
headers: {
|
|
10808
|
+
"Content-Type": "application/json",
|
|
10809
|
+
Authorization: `Bearer ${token}`
|
|
10810
|
+
},
|
|
10811
|
+
body: JSON.stringify({ path, args })
|
|
10812
|
+
});
|
|
10813
|
+
const text = await response.text();
|
|
10814
|
+
let json;
|
|
10815
|
+
try {
|
|
10816
|
+
json = JSON.parse(text);
|
|
10817
|
+
} catch {
|
|
10818
|
+
throw new Error(text || `HTTP ${response.status}`);
|
|
10819
|
+
}
|
|
10820
|
+
if (!response.ok) {
|
|
10821
|
+
throw new Error(json.errorData?.message || json.errorMessage || text);
|
|
10822
|
+
}
|
|
10823
|
+
if (json.status === "error") {
|
|
10824
|
+
throw new Error(json.errorMessage || "Unknown error from Convex");
|
|
10825
|
+
}
|
|
10826
|
+
return json.value;
|
|
10827
|
+
}
|
|
10828
|
+
async function listApiKeys() {
|
|
10829
|
+
return convexQuery8("apiKeys:list", {});
|
|
10830
|
+
}
|
|
10831
|
+
async function createApiKey(args) {
|
|
10832
|
+
return convexMutation6("apiKeys:create", {
|
|
10833
|
+
name: args.name,
|
|
10834
|
+
environment: args.environment,
|
|
10835
|
+
permissions: args.permissions ?? ["*"]
|
|
10836
|
+
});
|
|
10837
|
+
}
|
|
10838
|
+
async function removeApiKey(id) {
|
|
10839
|
+
return convexMutation6("apiKeys:remove", { id });
|
|
10840
|
+
}
|
|
10841
|
+
|
|
10842
|
+
// src/cli/commands/keys.ts
|
|
10843
|
+
async function withKeyAuthRetry(fn) {
|
|
10844
|
+
try {
|
|
10845
|
+
return await fn();
|
|
10846
|
+
} catch (err) {
|
|
10847
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10848
|
+
if (msg.includes("Unauthenticated") || msg.includes("OIDC") || msg.includes("token") || msg.includes("expired")) {
|
|
10849
|
+
const refreshed = await refreshToken();
|
|
10850
|
+
if (!refreshed)
|
|
10851
|
+
throw err;
|
|
10852
|
+
return fn();
|
|
10853
|
+
}
|
|
10854
|
+
throw err;
|
|
10855
|
+
}
|
|
10856
|
+
}
|
|
10857
|
+
async function ensureAuth9() {
|
|
10858
|
+
const cwd = process.cwd();
|
|
10859
|
+
const nonInteractive = !isInteractive();
|
|
10860
|
+
if (!hasProject(cwd)) {
|
|
10861
|
+
if (nonInteractive) {
|
|
10862
|
+
console.error(chalk29.red("No struere.json found. Run struere init first."));
|
|
10863
|
+
process.exit(1);
|
|
10864
|
+
}
|
|
10865
|
+
console.log(chalk29.yellow("No struere.json found - initializing project..."));
|
|
10866
|
+
console.log();
|
|
10867
|
+
const success = await runInit(cwd);
|
|
10868
|
+
if (!success) {
|
|
10869
|
+
process.exit(1);
|
|
10870
|
+
}
|
|
10871
|
+
console.log();
|
|
10872
|
+
}
|
|
10873
|
+
let credentials = loadCredentials();
|
|
10874
|
+
const apiKey = getApiKey();
|
|
10875
|
+
if (!credentials && !apiKey) {
|
|
10876
|
+
if (nonInteractive) {
|
|
10877
|
+
console.error(chalk29.red("Not authenticated. Set STRUERE_API_KEY or run struere login."));
|
|
10878
|
+
process.exit(1);
|
|
10879
|
+
}
|
|
10880
|
+
console.log(chalk29.yellow("Not logged in - authenticating..."));
|
|
10881
|
+
console.log();
|
|
10882
|
+
credentials = await performLogin();
|
|
10883
|
+
if (!credentials) {
|
|
10884
|
+
console.log(chalk29.red("Authentication failed"));
|
|
10885
|
+
process.exit(1);
|
|
10886
|
+
}
|
|
10887
|
+
console.log();
|
|
10888
|
+
}
|
|
10889
|
+
return true;
|
|
10890
|
+
}
|
|
10891
|
+
function relativeTime4(ts) {
|
|
10892
|
+
const diff = Date.now() - ts;
|
|
10893
|
+
const seconds = Math.floor(diff / 1000);
|
|
10894
|
+
if (seconds < 60)
|
|
10895
|
+
return `${seconds}s ago`;
|
|
10896
|
+
const minutes = Math.floor(seconds / 60);
|
|
10897
|
+
if (minutes < 60)
|
|
10898
|
+
return `${minutes}m ago`;
|
|
10899
|
+
const hours = Math.floor(minutes / 60);
|
|
10900
|
+
if (hours < 24)
|
|
10901
|
+
return `${hours}h ago`;
|
|
10902
|
+
const days = Math.floor(hours / 24);
|
|
10903
|
+
return `${days}d ago`;
|
|
10904
|
+
}
|
|
10905
|
+
function maskedPrefix(prefix) {
|
|
10906
|
+
return `${prefix}****`;
|
|
10907
|
+
}
|
|
10908
|
+
function isValidEnvironment(value) {
|
|
10909
|
+
return value === "development" || value === "production" || value === "eval";
|
|
10910
|
+
}
|
|
10911
|
+
var keysCommand = new Command26("keys").description("Manage API keys");
|
|
10912
|
+
keysCommand.command("list", { isDefault: true }).description("List API keys").option("--env <environment>", "Filter by environment (development|production|eval)").option("--json", "Output raw JSON").action(async (opts) => {
|
|
10913
|
+
await ensureAuth9();
|
|
10914
|
+
const spinner = opts.json ? null : ora21();
|
|
10915
|
+
try {
|
|
10916
|
+
spinner?.start("Fetching API keys");
|
|
10917
|
+
let keys = await withKeyAuthRetry(() => listApiKeys());
|
|
10918
|
+
if (opts.env) {
|
|
10919
|
+
if (!isValidEnvironment(opts.env)) {
|
|
10920
|
+
spinner?.fail(`Invalid environment: ${opts.env}`);
|
|
10921
|
+
process.exit(1);
|
|
10922
|
+
}
|
|
10923
|
+
keys = keys.filter((k) => k.environment === opts.env);
|
|
10924
|
+
}
|
|
10925
|
+
spinner?.succeed(`Found ${keys.length} API key${keys.length === 1 ? "" : "s"}${opts.env ? ` (${opts.env})` : ""}`);
|
|
10926
|
+
if (opts.json) {
|
|
10927
|
+
console.log(JSON.stringify(keys, null, 2));
|
|
10928
|
+
return;
|
|
10929
|
+
}
|
|
10930
|
+
console.log();
|
|
10931
|
+
renderTable([
|
|
10932
|
+
{ key: "id", label: "ID", width: 14 },
|
|
10933
|
+
{ key: "name", label: "Name", width: 24 },
|
|
10934
|
+
{ key: "prefix", label: "Prefix", width: 22 },
|
|
10935
|
+
{ key: "environment", label: "Env", width: 12 },
|
|
10936
|
+
{ key: "created", label: "Created", width: 12 },
|
|
10937
|
+
{ key: "lastUsed", label: "Last Used", width: 12 }
|
|
10938
|
+
], keys.map((k) => ({
|
|
10939
|
+
id: k.id.slice(-12),
|
|
10940
|
+
name: k.name,
|
|
10941
|
+
prefix: maskedPrefix(k.keyPrefix),
|
|
10942
|
+
environment: k.environment,
|
|
10943
|
+
created: relativeTime4(k.createdAt),
|
|
10944
|
+
lastUsed: k.lastUsedAt ? relativeTime4(k.lastUsedAt) : chalk29.gray("-")
|
|
10945
|
+
})));
|
|
10946
|
+
console.log();
|
|
10947
|
+
} catch (err) {
|
|
10948
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10949
|
+
spinner?.fail("Failed to fetch API keys");
|
|
10950
|
+
if (opts.json) {
|
|
10951
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
10952
|
+
} else {
|
|
10953
|
+
console.log(chalk29.red("Error:"), message);
|
|
10954
|
+
}
|
|
10955
|
+
process.exit(1);
|
|
10956
|
+
}
|
|
10957
|
+
});
|
|
10958
|
+
keysCommand.command("create").description("Create a new API key").option("--name <name>", "Key name").option("--env <environment>", "Environment (development|production|eval)", "development").option("--json", "Output raw JSON").option("--confirm", "Skip production confirmation").action(async (opts) => {
|
|
10959
|
+
await ensureAuth9();
|
|
10960
|
+
if (!isValidEnvironment(opts.env)) {
|
|
10961
|
+
const message = `Invalid environment: ${opts.env}`;
|
|
10962
|
+
if (opts.json) {
|
|
10963
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
10964
|
+
} else {
|
|
10965
|
+
console.log(chalk29.red("Error:"), message);
|
|
10966
|
+
}
|
|
10967
|
+
process.exit(1);
|
|
10968
|
+
}
|
|
10969
|
+
const environment = opts.env;
|
|
10970
|
+
let name = opts.name;
|
|
10971
|
+
if (!name || !name.trim()) {
|
|
10972
|
+
if (!isInteractive()) {
|
|
10973
|
+
const message = "--name is required in non-interactive mode";
|
|
10974
|
+
if (opts.json) {
|
|
10975
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
10976
|
+
} else {
|
|
10977
|
+
console.log(chalk29.red("Error:"), message);
|
|
10978
|
+
}
|
|
10979
|
+
process.exit(1);
|
|
10980
|
+
}
|
|
10981
|
+
name = await input3({
|
|
10982
|
+
message: "API key name:",
|
|
10983
|
+
validate: (v) => v.trim().length > 0 || "Name is required"
|
|
10984
|
+
});
|
|
10985
|
+
}
|
|
10986
|
+
name = name.trim();
|
|
10987
|
+
if (environment === "production" && !opts.confirm && !opts.json && isInteractive()) {
|
|
10988
|
+
const ok = await confirm8({
|
|
10989
|
+
message: chalk29.yellow("Create API key in PRODUCTION environment?"),
|
|
10990
|
+
default: false
|
|
10991
|
+
});
|
|
10992
|
+
if (!ok) {
|
|
10993
|
+
console.log(chalk29.gray("Cancelled"));
|
|
10994
|
+
process.exit(0);
|
|
10995
|
+
}
|
|
10996
|
+
}
|
|
10997
|
+
const spinner = opts.json ? null : ora21();
|
|
10998
|
+
try {
|
|
10999
|
+
spinner?.start("Creating API key");
|
|
11000
|
+
const result = await withKeyAuthRetry(() => createApiKey({ name, environment }));
|
|
11001
|
+
spinner?.succeed(chalk29.green(`Created API key ${chalk29.cyan(result.name)}`));
|
|
11002
|
+
if (opts.json) {
|
|
11003
|
+
console.log(JSON.stringify({
|
|
11004
|
+
id: result.id,
|
|
11005
|
+
name: result.name,
|
|
11006
|
+
prefix: result.keyPrefix,
|
|
11007
|
+
key: result.key,
|
|
11008
|
+
environment,
|
|
11009
|
+
createdAt: result.createdAt
|
|
11010
|
+
}, null, 2));
|
|
11011
|
+
return;
|
|
11012
|
+
}
|
|
11013
|
+
console.log();
|
|
11014
|
+
console.log(chalk29.bold(" " + chalk29.yellow("Save this key now \u2014 it will not be shown again.")));
|
|
11015
|
+
console.log();
|
|
11016
|
+
console.log(` ${chalk29.gray("Key:")} ${chalk29.cyan(result.key)}`);
|
|
11017
|
+
console.log(` ${chalk29.gray("Name:")} ${result.name}`);
|
|
11018
|
+
console.log(` ${chalk29.gray("Prefix:")} ${result.keyPrefix}`);
|
|
11019
|
+
console.log(` ${chalk29.gray("Environment:")} ${environment}`);
|
|
11020
|
+
console.log(` ${chalk29.gray("ID:")} ${result.id}`);
|
|
11021
|
+
console.log();
|
|
11022
|
+
} catch (err) {
|
|
11023
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11024
|
+
spinner?.fail("Failed to create API key");
|
|
11025
|
+
if (opts.json) {
|
|
11026
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
11027
|
+
} else {
|
|
11028
|
+
console.log(chalk29.red("Error:"), message);
|
|
11029
|
+
}
|
|
11030
|
+
process.exit(1);
|
|
11031
|
+
}
|
|
11032
|
+
});
|
|
11033
|
+
keysCommand.command("revoke <id-or-prefix>").description("Revoke an API key (delete)").option("--confirm", "Skip confirmation prompt").option("--json", "Output raw JSON").action(async (idOrPrefix, opts) => {
|
|
11034
|
+
await ensureAuth9();
|
|
11035
|
+
const spinner = opts.json ? null : ora21();
|
|
11036
|
+
try {
|
|
11037
|
+
spinner?.start("Looking up API key");
|
|
11038
|
+
const keys = await withKeyAuthRetry(() => listApiKeys());
|
|
11039
|
+
const target = keys.find((k) => k.id === idOrPrefix) ?? keys.find((k) => k.id.endsWith(idOrPrefix)) ?? keys.find((k) => k.keyPrefix === idOrPrefix) ?? keys.find((k) => k.keyPrefix.startsWith(idOrPrefix));
|
|
11040
|
+
if (!target) {
|
|
11041
|
+
spinner?.fail(`API key not found: ${idOrPrefix}`);
|
|
11042
|
+
if (opts.json) {
|
|
11043
|
+
console.log(JSON.stringify({ success: false, error: "API key not found" }));
|
|
11044
|
+
}
|
|
11045
|
+
process.exit(1);
|
|
11046
|
+
}
|
|
11047
|
+
spinner?.succeed(`Found ${chalk29.cyan(target.name)} (${maskedPrefix(target.keyPrefix)}, ${target.environment})`);
|
|
11048
|
+
if (!opts.confirm && !opts.json) {
|
|
11049
|
+
if (!isInteractive()) {
|
|
11050
|
+
console.log(chalk29.red("Error:"), "Use --confirm to revoke in non-interactive mode");
|
|
11051
|
+
process.exit(1);
|
|
11052
|
+
}
|
|
11053
|
+
const ok = await confirm8({
|
|
11054
|
+
message: `Revoke this key? This cannot be undone.`,
|
|
11055
|
+
default: false
|
|
11056
|
+
});
|
|
11057
|
+
if (!ok) {
|
|
11058
|
+
console.log(chalk29.gray("Cancelled"));
|
|
11059
|
+
process.exit(0);
|
|
11060
|
+
}
|
|
11061
|
+
}
|
|
11062
|
+
const revokeSpinner = opts.json ? null : ora21();
|
|
11063
|
+
revokeSpinner?.start("Revoking API key");
|
|
11064
|
+
await withKeyAuthRetry(() => removeApiKey(target.id));
|
|
11065
|
+
revokeSpinner?.succeed(chalk29.green(`Revoked ${chalk29.cyan(target.name)}`));
|
|
11066
|
+
if (opts.json) {
|
|
11067
|
+
console.log(JSON.stringify({ success: true, id: target.id, name: target.name }));
|
|
11068
|
+
}
|
|
11069
|
+
} catch (err) {
|
|
11070
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11071
|
+
spinner?.fail("Failed to revoke API key");
|
|
11072
|
+
if (opts.json) {
|
|
11073
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
11074
|
+
} else {
|
|
11075
|
+
console.log(chalk29.red("Error:"), message);
|
|
11076
|
+
}
|
|
11077
|
+
process.exit(1);
|
|
11078
|
+
}
|
|
11079
|
+
});
|
|
10707
11080
|
// package.json
|
|
10708
11081
|
var package_default = {
|
|
10709
11082
|
name: "struere",
|
|
10710
|
-
version: "0.14.
|
|
11083
|
+
version: "0.14.4",
|
|
10711
11084
|
description: "Build, test, and deploy AI agents",
|
|
10712
11085
|
keywords: [
|
|
10713
11086
|
"ai",
|
|
@@ -10742,13 +11115,17 @@ var package_default = {
|
|
|
10742
11115
|
".": {
|
|
10743
11116
|
import: "./dist/index.js",
|
|
10744
11117
|
types: "./dist/index.d.ts"
|
|
11118
|
+
},
|
|
11119
|
+
"./client": {
|
|
11120
|
+
import: "./dist/client/index.js",
|
|
11121
|
+
types: "./dist/client/index.d.ts"
|
|
10745
11122
|
}
|
|
10746
11123
|
},
|
|
10747
11124
|
files: [
|
|
10748
11125
|
"dist"
|
|
10749
11126
|
],
|
|
10750
11127
|
scripts: {
|
|
10751
|
-
build: "bun build ./src/cli/index.ts --outdir ./dist/cli --target bun --external commander --external chalk --external ora --external chokidar --external yaml --external @inquirer/prompts && bun build ./src/index.ts --outdir ./dist --target node && bun build ./src/bin/struere.ts --outdir ./dist/bin --target bun --external commander --external chalk --external ora --external chokidar --external yaml --external @inquirer/prompts && tsc --emitDeclarationOnly && chmod +x ./dist/bin/struere.js",
|
|
11128
|
+
build: "bun build ./src/cli/index.ts --outdir ./dist/cli --target bun --external commander --external chalk --external ora --external chokidar --external yaml --external @inquirer/prompts && bun build ./src/index.ts --outdir ./dist --target node && bun build ./src/client/index.ts --outdir ./dist/client --target browser && bun build ./src/bin/struere.ts --outdir ./dist/bin --target bun --external commander --external chalk --external ora --external chokidar --external yaml --external @inquirer/prompts && tsc --emitDeclarationOnly && chmod +x ./dist/bin/struere.js",
|
|
10752
11129
|
dev: "tsc --watch",
|
|
10753
11130
|
test: "bun test",
|
|
10754
11131
|
prepublishOnly: "bun run build"
|
|
@@ -10832,4 +11209,5 @@ program.addCommand(chatCommand);
|
|
|
10832
11209
|
program.addCommand(whatsappCommand);
|
|
10833
11210
|
program.addCommand(diffCommand);
|
|
10834
11211
|
program.addCommand(doctorCommand);
|
|
11212
|
+
program.addCommand(keysCommand);
|
|
10835
11213
|
program.parse();
|