struere 0.10.6 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/struere.js +907 -109
- package/dist/cli/commands/docs.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/triggers.d.ts +3 -0
- package/dist/cli/commands/triggers.d.ts.map +1 -0
- package/dist/cli/index.js +907 -109
- package/dist/cli/utils/plugin.d.ts +1 -1
- package/dist/cli/utils/skill.d.ts +2 -0
- package/dist/cli/utils/skill.d.ts.map +1 -0
- package/dist/cli/utils/triggers.d.ts +108 -0
- package/dist/cli/utils/triggers.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/bin/struere.js
CHANGED
|
@@ -945,7 +945,7 @@ slug: "basic-agent-tests"
|
|
|
945
945
|
agent: "${agentSlug}"
|
|
946
946
|
description: "Verify agent responds correctly and uses tools appropriately"
|
|
947
947
|
tags: ["smoke-test"]
|
|
948
|
-
judgeModel: "
|
|
948
|
+
judgeModel: "openai/gpt-5-mini"
|
|
949
949
|
judgePrompt: "Evaluate whether the agent responds correctly and uses appropriate tools. Be lenient on phrasing but strict on factual accuracy."
|
|
950
950
|
|
|
951
951
|
cases:
|
|
@@ -1002,7 +1002,7 @@ slug: "${slug}"
|
|
|
1002
1002
|
agent: "${agentSlug}"
|
|
1003
1003
|
description: "TODO: Describe what this eval suite tests"
|
|
1004
1004
|
tags: []
|
|
1005
|
-
judgeModel: "
|
|
1005
|
+
judgeModel: "openai/gpt-5-mini"
|
|
1006
1006
|
judgePrompt: "TODO: Custom instructions for the judge (e.g. strictness level, focus areas)"
|
|
1007
1007
|
|
|
1008
1008
|
cases:
|
|
@@ -1102,7 +1102,7 @@ export default defineAgent({
|
|
|
1102
1102
|
version: "0.1.0",
|
|
1103
1103
|
description: "${displayName} Agent",
|
|
1104
1104
|
model: {
|
|
1105
|
-
model: "
|
|
1105
|
+
model: "openai/gpt-5-mini",
|
|
1106
1106
|
temperature: 0.7,
|
|
1107
1107
|
maxTokens: 4096,
|
|
1108
1108
|
},
|
|
@@ -1435,7 +1435,7 @@ function defineAgent(config) {
|
|
|
1435
1435
|
if (!config.systemPrompt) throw new Error('System prompt is required')
|
|
1436
1436
|
return {
|
|
1437
1437
|
model: {
|
|
1438
|
-
model: '
|
|
1438
|
+
model: 'openai/gpt-5-mini',
|
|
1439
1439
|
temperature: 0.7,
|
|
1440
1440
|
maxTokens: 4096,
|
|
1441
1441
|
},
|
|
@@ -1795,8 +1795,8 @@ function generateTypeDeclarations(cwd) {
|
|
|
1795
1795
|
import { Command as Command2 } from "commander";
|
|
1796
1796
|
import chalk2 from "chalk";
|
|
1797
1797
|
import ora2 from "ora";
|
|
1798
|
-
import { join as
|
|
1799
|
-
import { existsSync as
|
|
1798
|
+
import { join as join7, dirname as dirname3 } from "path";
|
|
1799
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
1800
1800
|
|
|
1801
1801
|
// src/cli/utils/loader.ts
|
|
1802
1802
|
import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync4 } from "fs";
|
|
@@ -1924,6 +1924,43 @@ function getResourceDirectories(cwd) {
|
|
|
1924
1924
|
};
|
|
1925
1925
|
}
|
|
1926
1926
|
|
|
1927
|
+
// src/cli/utils/skill.ts
|
|
1928
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1929
|
+
import { dirname as dirname2, join as join6 } from "path";
|
|
1930
|
+
var SKILL_URL = "https://docs.struere.dev/skill";
|
|
1931
|
+
var SKILL_PATH = ".claude/skills/struere-developer/SKILL.md";
|
|
1932
|
+
var FALLBACK_SKILL = `---
|
|
1933
|
+
name: struere-developer
|
|
1934
|
+
description: "Build, configure, and deploy AI agents on the Struere platform. Use when working with Struere projects (struere.json present), defining agents/data-types/roles/triggers, using the Struere SDK (defineAgent, defineData, defineRole, defineTrigger, defineTools), running struere CLI commands, calling the Struere Chat API, or debugging agent behavior."
|
|
1935
|
+
metadata:
|
|
1936
|
+
author: struere
|
|
1937
|
+
version: 1.0.0
|
|
1938
|
+
category: developer-tools
|
|
1939
|
+
---
|
|
1940
|
+
|
|
1941
|
+
# Struere Developer Guide
|
|
1942
|
+
|
|
1943
|
+
Fetch the full skill from: ${SKILL_URL}
|
|
1944
|
+
`;
|
|
1945
|
+
async function installSkill(cwd) {
|
|
1946
|
+
const filePath = join6(cwd, SKILL_PATH);
|
|
1947
|
+
const dir = dirname2(filePath);
|
|
1948
|
+
if (!existsSync6(dir)) {
|
|
1949
|
+
mkdirSync4(dir, { recursive: true });
|
|
1950
|
+
}
|
|
1951
|
+
let content;
|
|
1952
|
+
try {
|
|
1953
|
+
const controller = new AbortController;
|
|
1954
|
+
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
1955
|
+
const response = await fetch(SKILL_URL, { signal: controller.signal });
|
|
1956
|
+
clearTimeout(timeout);
|
|
1957
|
+
content = await response.text();
|
|
1958
|
+
} catch {
|
|
1959
|
+
content = FALLBACK_SKILL;
|
|
1960
|
+
}
|
|
1961
|
+
writeFileSync4(filePath, content);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1927
1964
|
// src/cli/commands/docs.ts
|
|
1928
1965
|
var TEMPLATE_URL = "https://docs.struere.dev/llms-workspace.txt";
|
|
1929
1966
|
var FALLBACK_TEMPLATE = `# Struere Workspace
|
|
@@ -1998,12 +2035,12 @@ async function fetchTemplate() {
|
|
|
1998
2035
|
}
|
|
1999
2036
|
}
|
|
2000
2037
|
function writeTarget(cwd, target, content) {
|
|
2001
|
-
const filePath =
|
|
2002
|
-
const dir =
|
|
2003
|
-
if (!
|
|
2004
|
-
|
|
2038
|
+
const filePath = join7(cwd, TARGET_FILES[target]);
|
|
2039
|
+
const dir = dirname3(filePath);
|
|
2040
|
+
if (!existsSync7(dir)) {
|
|
2041
|
+
mkdirSync5(dir, { recursive: true });
|
|
2005
2042
|
}
|
|
2006
|
-
|
|
2043
|
+
writeFileSync5(filePath, content);
|
|
2007
2044
|
}
|
|
2008
2045
|
async function generateDocs(cwd, targets) {
|
|
2009
2046
|
const generated = [];
|
|
@@ -2032,6 +2069,7 @@ async function generateDocs(cwd, targets) {
|
|
|
2032
2069
|
writeTarget(cwd, target, content);
|
|
2033
2070
|
generated.push(TARGET_FILES[target]);
|
|
2034
2071
|
}
|
|
2072
|
+
await installSkill(cwd);
|
|
2035
2073
|
return { generated };
|
|
2036
2074
|
}
|
|
2037
2075
|
var docsCommand = new Command2("docs").description("Generate AI context files (CLAUDE.md, .cursorrules, copilot-instructions) from live docs").option("--claude", "Generate CLAUDE.md only").option("--cursor", "Generate .cursorrules only").option("--copilot", "Generate .github/copilot-instructions.md only").action(async (options) => {
|
|
@@ -2314,6 +2352,7 @@ async function runInit(cwd, selectedOrg) {
|
|
|
2314
2352
|
} catch {
|
|
2315
2353
|
console.log(chalk5.yellow("\u26A0"), "Could not fetch docs for CLAUDE.md");
|
|
2316
2354
|
}
|
|
2355
|
+
await installSkill(cwd);
|
|
2317
2356
|
console.log();
|
|
2318
2357
|
console.log(chalk5.green("\u2713"), "Project initialized");
|
|
2319
2358
|
return true;
|
|
@@ -2417,6 +2456,7 @@ var initCommand = new Command4("init").description("Initialize a new Struere org
|
|
|
2417
2456
|
} catch {
|
|
2418
2457
|
console.log(chalk5.yellow("\u26A0"), "Could not fetch docs for CLAUDE.md");
|
|
2419
2458
|
}
|
|
2459
|
+
await installSkill(cwd);
|
|
2420
2460
|
console.log();
|
|
2421
2461
|
console.log(chalk5.green("Success!"), "Project initialized");
|
|
2422
2462
|
console.log();
|
|
@@ -2440,8 +2480,8 @@ import { Command as Command6 } from "commander";
|
|
|
2440
2480
|
import chalk7 from "chalk";
|
|
2441
2481
|
import ora6 from "ora";
|
|
2442
2482
|
import chokidar from "chokidar";
|
|
2443
|
-
import { join as
|
|
2444
|
-
import { existsSync as
|
|
2483
|
+
import { join as join8 } from "path";
|
|
2484
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2445
2485
|
|
|
2446
2486
|
// src/cli/commands/sync.ts
|
|
2447
2487
|
import { Command as Command5 } from "commander";
|
|
@@ -2615,7 +2655,7 @@ function extractAgentPayload(agent, customToolsMap) {
|
|
|
2615
2655
|
threadContextParams: agent.threadContextParams,
|
|
2616
2656
|
systemPrompt,
|
|
2617
2657
|
model: {
|
|
2618
|
-
model: agent.model?.model || "
|
|
2658
|
+
model: agent.model?.model || "openai/gpt-5-mini",
|
|
2619
2659
|
temperature: agent.model?.temperature,
|
|
2620
2660
|
maxTokens: agent.model?.maxTokens
|
|
2621
2661
|
},
|
|
@@ -3329,8 +3369,8 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3329
3369
|
}
|
|
3330
3370
|
console.log();
|
|
3331
3371
|
}
|
|
3332
|
-
const claudeMdPath =
|
|
3333
|
-
if (!
|
|
3372
|
+
const claudeMdPath = join8(cwd, "CLAUDE.md");
|
|
3373
|
+
if (!existsSync8(claudeMdPath)) {
|
|
3334
3374
|
try {
|
|
3335
3375
|
const { generated } = await generateDocs(cwd, ["claude"]);
|
|
3336
3376
|
if (generated.length > 0) {
|
|
@@ -3441,7 +3481,7 @@ var devCommand = new Command6("dev").description("Watch files and sync to develo
|
|
|
3441
3481
|
dirs.evals,
|
|
3442
3482
|
dirs.triggers,
|
|
3443
3483
|
dirs.fixtures
|
|
3444
|
-
].filter((p) =>
|
|
3484
|
+
].filter((p) => existsSync8(p));
|
|
3445
3485
|
const watcher = chokidar.watch(watchPaths, {
|
|
3446
3486
|
ignoreInitial: true,
|
|
3447
3487
|
ignored: [/node_modules/, /\.struere-tmp-/, /evals\/runs\//],
|
|
@@ -4254,8 +4294,8 @@ var statusCommand = new Command11("status").description("Compare local vs remote
|
|
|
4254
4294
|
import { Command as Command12 } from "commander";
|
|
4255
4295
|
import chalk13 from "chalk";
|
|
4256
4296
|
import ora10 from "ora";
|
|
4257
|
-
import { existsSync as
|
|
4258
|
-
import { join as
|
|
4297
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
4298
|
+
import { join as join9 } from "path";
|
|
4259
4299
|
|
|
4260
4300
|
// src/cli/utils/generator.ts
|
|
4261
4301
|
var BUILTIN_TOOLS2 = [
|
|
@@ -4625,13 +4665,13 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4625
4665
|
const created = [];
|
|
4626
4666
|
const skipped = [];
|
|
4627
4667
|
const ensureDir2 = (dir) => {
|
|
4628
|
-
if (!
|
|
4629
|
-
|
|
4668
|
+
if (!existsSync9(dir)) {
|
|
4669
|
+
mkdirSync6(dir, { recursive: true });
|
|
4630
4670
|
}
|
|
4631
4671
|
};
|
|
4632
4672
|
const writeOrSkip = (relativePath, content) => {
|
|
4633
|
-
const fullPath =
|
|
4634
|
-
if (
|
|
4673
|
+
const fullPath = join9(cwd, relativePath);
|
|
4674
|
+
if (existsSync9(fullPath) && !options.force) {
|
|
4635
4675
|
skipped.push(relativePath);
|
|
4636
4676
|
return false;
|
|
4637
4677
|
}
|
|
@@ -4639,16 +4679,16 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4639
4679
|
created.push(relativePath);
|
|
4640
4680
|
return true;
|
|
4641
4681
|
}
|
|
4642
|
-
ensureDir2(
|
|
4643
|
-
|
|
4682
|
+
ensureDir2(join9(cwd, relativePath.split("/").slice(0, -1).join("/")));
|
|
4683
|
+
writeFileSync6(fullPath, content);
|
|
4644
4684
|
created.push(relativePath);
|
|
4645
4685
|
return true;
|
|
4646
4686
|
};
|
|
4647
|
-
ensureDir2(
|
|
4648
|
-
ensureDir2(
|
|
4649
|
-
ensureDir2(
|
|
4650
|
-
ensureDir2(
|
|
4651
|
-
ensureDir2(
|
|
4687
|
+
ensureDir2(join9(cwd, "agents"));
|
|
4688
|
+
ensureDir2(join9(cwd, "entity-types"));
|
|
4689
|
+
ensureDir2(join9(cwd, "roles"));
|
|
4690
|
+
ensureDir2(join9(cwd, "triggers"));
|
|
4691
|
+
ensureDir2(join9(cwd, "tools"));
|
|
4652
4692
|
const agentSlugs = [];
|
|
4653
4693
|
for (const agent of state.agents) {
|
|
4654
4694
|
if (!agent.systemPrompt && agent.tools.length === 0)
|
|
@@ -4700,6 +4740,7 @@ var pullCommand = new Command12("pull").description("Pull remote resources to lo
|
|
|
4700
4740
|
if (content)
|
|
4701
4741
|
writeOrSkip("triggers/index.ts", content);
|
|
4702
4742
|
}
|
|
4743
|
+
await installSkill(cwd);
|
|
4703
4744
|
if (options.json) {
|
|
4704
4745
|
console.log(JSON.stringify({
|
|
4705
4746
|
created,
|
|
@@ -5582,8 +5623,8 @@ logsCommand.command("view <thread-id>").description("View conversation messages"
|
|
|
5582
5623
|
import { Command as Command15 } from "commander";
|
|
5583
5624
|
import chalk17 from "chalk";
|
|
5584
5625
|
import ora13 from "ora";
|
|
5585
|
-
import { join as
|
|
5586
|
-
import { mkdirSync as
|
|
5626
|
+
import { join as join10 } from "path";
|
|
5627
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
5587
5628
|
|
|
5588
5629
|
// src/cli/utils/evals.ts
|
|
5589
5630
|
function getToken3() {
|
|
@@ -6016,15 +6057,15 @@ var runCommand = new Command15("run").description("Run an eval suite").argument(
|
|
|
6016
6057
|
const agentSlug = suiteSlug;
|
|
6017
6058
|
const timestamp = new Date().toISOString().replace(/:/g, "-").replace(/\.\d+Z$/, "");
|
|
6018
6059
|
const folderName = `${timestamp}_${suiteSlug}`;
|
|
6019
|
-
const outDir =
|
|
6020
|
-
|
|
6060
|
+
const outDir = join10(cwd, "evals", "runs", folderName);
|
|
6061
|
+
mkdirSync7(outDir, { recursive: true });
|
|
6021
6062
|
const summaryMd = generateSummaryMd(suite.name, suite.slug, agentSlug, run, results);
|
|
6022
|
-
|
|
6063
|
+
writeFileSync7(join10(outDir, "_summary.md"), summaryMd);
|
|
6023
6064
|
for (const r of results) {
|
|
6024
6065
|
const label = statusLabel(r);
|
|
6025
6066
|
const fileName = `${label}_${slugify3(r.caseName)}.md`;
|
|
6026
6067
|
const caseMd = generateCaseMd(r);
|
|
6027
|
-
|
|
6068
|
+
writeFileSync7(join10(outDir, fileName), caseMd);
|
|
6028
6069
|
}
|
|
6029
6070
|
const relativePath = `evals/runs/${folderName}/`;
|
|
6030
6071
|
console.log();
|
|
@@ -6823,15 +6864,771 @@ var integrationCommand = new Command17("integration").description("Manage integr
|
|
|
6823
6864
|
console.log();
|
|
6824
6865
|
});
|
|
6825
6866
|
|
|
6826
|
-
// src/cli/commands/
|
|
6867
|
+
// src/cli/commands/triggers.ts
|
|
6827
6868
|
import { Command as Command18 } from "commander";
|
|
6828
6869
|
import chalk20 from "chalk";
|
|
6829
6870
|
import ora14 from "ora";
|
|
6830
|
-
|
|
6871
|
+
|
|
6872
|
+
// src/cli/utils/triggers.ts
|
|
6873
|
+
function getToken6() {
|
|
6874
|
+
const credentials = loadCredentials();
|
|
6875
|
+
const apiKey = getApiKey();
|
|
6876
|
+
const token = apiKey || credentials?.token;
|
|
6877
|
+
if (!token)
|
|
6878
|
+
throw new Error("Not authenticated");
|
|
6879
|
+
return token;
|
|
6880
|
+
}
|
|
6881
|
+
async function convexQuery6(path, args) {
|
|
6882
|
+
const token = getToken6();
|
|
6883
|
+
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
6884
|
+
method: "POST",
|
|
6885
|
+
headers: {
|
|
6886
|
+
"Content-Type": "application/json",
|
|
6887
|
+
Authorization: `Bearer ${token}`
|
|
6888
|
+
},
|
|
6889
|
+
body: JSON.stringify({ path, args })
|
|
6890
|
+
});
|
|
6891
|
+
const text = await response.text();
|
|
6892
|
+
let json;
|
|
6893
|
+
try {
|
|
6894
|
+
json = JSON.parse(text);
|
|
6895
|
+
} catch {
|
|
6896
|
+
throw new Error(text || `HTTP ${response.status}`);
|
|
6897
|
+
}
|
|
6898
|
+
if (!response.ok) {
|
|
6899
|
+
throw new Error(json.errorData?.message || json.errorMessage || text);
|
|
6900
|
+
}
|
|
6901
|
+
if (json.status === "error") {
|
|
6902
|
+
throw new Error(json.errorMessage || "Unknown error from Convex");
|
|
6903
|
+
}
|
|
6904
|
+
return json.value;
|
|
6905
|
+
}
|
|
6906
|
+
async function convexMutation4(path, args) {
|
|
6907
|
+
const token = getToken6();
|
|
6908
|
+
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
6909
|
+
method: "POST",
|
|
6910
|
+
headers: {
|
|
6911
|
+
"Content-Type": "application/json",
|
|
6912
|
+
Authorization: `Bearer ${token}`
|
|
6913
|
+
},
|
|
6914
|
+
body: JSON.stringify({ path, args })
|
|
6915
|
+
});
|
|
6916
|
+
const text = await response.text();
|
|
6917
|
+
let json;
|
|
6918
|
+
try {
|
|
6919
|
+
json = JSON.parse(text);
|
|
6920
|
+
} catch {
|
|
6921
|
+
throw new Error(text || `HTTP ${response.status}`);
|
|
6922
|
+
}
|
|
6923
|
+
if (!response.ok) {
|
|
6924
|
+
throw new Error(json.errorData?.message || json.errorMessage || text);
|
|
6925
|
+
}
|
|
6926
|
+
if (json.status === "error") {
|
|
6927
|
+
throw new Error(json.errorMessage || "Unknown error from Convex");
|
|
6928
|
+
}
|
|
6929
|
+
return json.value;
|
|
6930
|
+
}
|
|
6931
|
+
async function listTriggers(environment) {
|
|
6932
|
+
return convexQuery6("triggers:list", { environment });
|
|
6933
|
+
}
|
|
6934
|
+
async function getTrigger(slug, environment) {
|
|
6935
|
+
return convexQuery6("triggers:getBySlug", { slug, environment });
|
|
6936
|
+
}
|
|
6937
|
+
async function listTriggerRuns(options) {
|
|
6938
|
+
return convexQuery6("triggers:listRuns", {
|
|
6939
|
+
environment: options.environment,
|
|
6940
|
+
...options.status && { status: options.status },
|
|
6941
|
+
...options.triggerSlug && { triggerSlug: options.triggerSlug },
|
|
6942
|
+
...options.limit && { limit: options.limit }
|
|
6943
|
+
});
|
|
6944
|
+
}
|
|
6945
|
+
async function getTriggerRunDetail(runId, environment) {
|
|
6946
|
+
return convexQuery6("triggers:getRunDetail", {
|
|
6947
|
+
runId,
|
|
6948
|
+
...environment && { environment }
|
|
6949
|
+
});
|
|
6950
|
+
}
|
|
6951
|
+
async function getTriggerRunStats(environment) {
|
|
6952
|
+
return convexQuery6("triggers:getRunStats", { environment });
|
|
6953
|
+
}
|
|
6954
|
+
async function getLastRunStatuses(environment) {
|
|
6955
|
+
return convexQuery6("triggers:getLastRunStatuses", { environment });
|
|
6956
|
+
}
|
|
6957
|
+
async function cancelTriggerRun(runId, environment) {
|
|
6958
|
+
return convexMutation4("triggers:cancelRun", { runId, environment });
|
|
6959
|
+
}
|
|
6960
|
+
async function retryTriggerRun(runId, environment) {
|
|
6961
|
+
return convexMutation4("triggers:retryRun", { runId, environment });
|
|
6962
|
+
}
|
|
6963
|
+
async function toggleTrigger(slug, enabled, environment) {
|
|
6964
|
+
const path = enabled ? "triggers:enable" : "triggers:disable";
|
|
6965
|
+
return convexMutation4(path, { slug, environment });
|
|
6966
|
+
}
|
|
6967
|
+
async function listTriggerExecutions(options) {
|
|
6968
|
+
return convexQuery6("triggers:listExecutions", {
|
|
6969
|
+
environment: options.environment,
|
|
6970
|
+
...options.triggerSlug && { triggerSlug: options.triggerSlug },
|
|
6971
|
+
...options.limit && { limit: options.limit }
|
|
6972
|
+
});
|
|
6973
|
+
}
|
|
6974
|
+
async function getTriggerExecutionDetail(eventId) {
|
|
6975
|
+
return convexQuery6("triggers:getExecutionDetail", { eventId });
|
|
6976
|
+
}
|
|
6977
|
+
|
|
6978
|
+
// src/cli/commands/triggers.ts
|
|
6979
|
+
async function ensureAuth5() {
|
|
6980
|
+
const cwd = process.cwd();
|
|
6981
|
+
const nonInteractive = !isInteractive();
|
|
6982
|
+
if (!hasProject(cwd)) {
|
|
6983
|
+
if (nonInteractive) {
|
|
6984
|
+
console.error(chalk20.red("No struere.json found. Run struere init first."));
|
|
6985
|
+
process.exit(1);
|
|
6986
|
+
}
|
|
6987
|
+
console.log(chalk20.yellow("No struere.json found - initializing project..."));
|
|
6988
|
+
console.log();
|
|
6989
|
+
const success = await runInit(cwd);
|
|
6990
|
+
if (!success) {
|
|
6991
|
+
process.exit(1);
|
|
6992
|
+
}
|
|
6993
|
+
console.log();
|
|
6994
|
+
}
|
|
6995
|
+
let credentials = loadCredentials();
|
|
6996
|
+
const apiKey = getApiKey();
|
|
6997
|
+
if (!credentials && !apiKey) {
|
|
6998
|
+
if (nonInteractive) {
|
|
6999
|
+
console.error(chalk20.red("Not authenticated. Set STRUERE_API_KEY or run struere login."));
|
|
7000
|
+
process.exit(1);
|
|
7001
|
+
}
|
|
7002
|
+
console.log(chalk20.yellow("Not logged in - authenticating..."));
|
|
7003
|
+
console.log();
|
|
7004
|
+
credentials = await performLogin();
|
|
7005
|
+
if (!credentials) {
|
|
7006
|
+
console.log(chalk20.red("Authentication failed"));
|
|
7007
|
+
process.exit(1);
|
|
7008
|
+
}
|
|
7009
|
+
console.log();
|
|
7010
|
+
}
|
|
7011
|
+
return true;
|
|
7012
|
+
}
|
|
7013
|
+
function relativeTime2(ts) {
|
|
7014
|
+
const diff = Date.now() - ts;
|
|
7015
|
+
const seconds = Math.floor(diff / 1000);
|
|
7016
|
+
if (seconds < 60)
|
|
7017
|
+
return `${seconds}s ago`;
|
|
7018
|
+
const minutes = Math.floor(seconds / 60);
|
|
7019
|
+
if (minutes < 60)
|
|
7020
|
+
return `${minutes}m ago`;
|
|
7021
|
+
const hours = Math.floor(minutes / 60);
|
|
7022
|
+
if (hours < 24)
|
|
7023
|
+
return `${hours}h ago`;
|
|
7024
|
+
const days = Math.floor(hours / 24);
|
|
7025
|
+
return `${days}d ago`;
|
|
7026
|
+
}
|
|
7027
|
+
function statusColor4(status) {
|
|
7028
|
+
switch (status) {
|
|
7029
|
+
case "completed":
|
|
7030
|
+
case "success":
|
|
7031
|
+
return chalk20.green(status);
|
|
7032
|
+
case "pending":
|
|
7033
|
+
return chalk20.yellow(status);
|
|
7034
|
+
case "running":
|
|
7035
|
+
return chalk20.cyan(status);
|
|
7036
|
+
case "failed":
|
|
7037
|
+
case "dead":
|
|
7038
|
+
return chalk20.red(status);
|
|
7039
|
+
default:
|
|
7040
|
+
return chalk20.gray(status);
|
|
7041
|
+
}
|
|
7042
|
+
}
|
|
7043
|
+
function renderAgentChatStep(entry, stepNum, verbose) {
|
|
7044
|
+
const stepStatus = entry.status === "success" ? chalk20.green("success") : chalk20.red("failed");
|
|
7045
|
+
const result = entry.result;
|
|
7046
|
+
const meta = result?._executionMeta;
|
|
7047
|
+
const agentSlug = result?.agentSlug;
|
|
7048
|
+
const threadId = result?.threadId;
|
|
7049
|
+
const response = result?.response;
|
|
7050
|
+
const toolCallSummary = meta?.toolCallSummary;
|
|
7051
|
+
const iterationCount = meta?.iterationCount;
|
|
7052
|
+
const errorCount = meta?.errorCount;
|
|
7053
|
+
const model = meta?.model;
|
|
7054
|
+
console.log(` Step ${stepNum}: ${chalk20.cyan("agent.chat")} \u2192 ${stepStatus} (${entry.durationMs}ms)`);
|
|
7055
|
+
if (entry.as)
|
|
7056
|
+
console.log(` ${chalk20.gray("as:")} ${entry.as}`);
|
|
7057
|
+
const parts = [];
|
|
7058
|
+
if (agentSlug)
|
|
7059
|
+
parts.push(`Agent: ${chalk20.cyan(agentSlug)}`);
|
|
7060
|
+
if (threadId)
|
|
7061
|
+
parts.push(`Thread: ${chalk20.dim(String(threadId).slice(-12))}`);
|
|
7062
|
+
if (iterationCount)
|
|
7063
|
+
parts.push(`${iterationCount} iteration${iterationCount > 1 ? "s" : ""}`);
|
|
7064
|
+
if (parts.length)
|
|
7065
|
+
console.log(` ${parts.join(" | ")}`);
|
|
7066
|
+
if (toolCallSummary?.length) {
|
|
7067
|
+
const ok = toolCallSummary.filter((t) => t.status === "success").length;
|
|
7068
|
+
const errors = toolCallSummary.filter((t) => t.status !== "success").length;
|
|
7069
|
+
const tokenInfo = meta ? `Tokens: ${result?.usage?.inputTokens ?? 0} in / ${result?.usage?.outputTokens ?? 0} out` : "";
|
|
7070
|
+
console.log(` Tools: ${toolCallSummary.length} calls (${chalk20.green(`${ok} ok`)}${errors > 0 ? `, ${chalk20.red(`${errors} errors`)}` : ""})${tokenInfo ? ` | ${tokenInfo}` : ""}`);
|
|
7071
|
+
}
|
|
7072
|
+
if (iterationCount && iterationCount >= 10) {
|
|
7073
|
+
console.log(` ${chalk20.red("!!")} ${chalk20.yellow("Agent hit maximum iteration limit (10) - response may be incomplete")}`);
|
|
7074
|
+
}
|
|
7075
|
+
if (errorCount && errorCount > 0 && entry.status === "success") {
|
|
7076
|
+
console.log(` ${chalk20.yellow("!")} ${chalk20.yellow(`${errorCount} tool error${errorCount > 1 ? "s" : ""} occurred (agent self-corrected)`)}`);
|
|
7077
|
+
}
|
|
7078
|
+
if (verbose && toolCallSummary?.length) {
|
|
7079
|
+
console.log();
|
|
7080
|
+
console.log(` ${chalk20.bold("Agent Tool Calls")}`);
|
|
7081
|
+
console.log(` ${chalk20.gray("\xB7".repeat(50))}`);
|
|
7082
|
+
for (const tc of toolCallSummary) {
|
|
7083
|
+
const tcStatus = tc.status === "success" ? chalk20.green("ok") : chalk20.red(String(tc.status));
|
|
7084
|
+
console.log(` ${chalk20.dim(String(tc.name).padEnd(20))} ${tcStatus} (${tc.durationMs}ms)`);
|
|
7085
|
+
if (tc.errorMessage) {
|
|
7086
|
+
console.log(` ${chalk20.red(String(tc.errorMessage).slice(0, 120))}`);
|
|
7087
|
+
}
|
|
7088
|
+
}
|
|
7089
|
+
console.log(` ${chalk20.gray("\xB7".repeat(50))}`);
|
|
7090
|
+
}
|
|
7091
|
+
if (response) {
|
|
7092
|
+
const truncated = response.length > 200 ? response.slice(0, 200) + "..." : response;
|
|
7093
|
+
console.log(` ${chalk20.gray("Response:")} ${truncated}`);
|
|
7094
|
+
}
|
|
7095
|
+
if (entry.status === "success" && threadId && (errorCount ?? 0) > 0) {
|
|
7096
|
+
console.log(` ${chalk20.dim(`Hint: Run \`struere logs view ${threadId} --exec\` for full agent transcript`)}`);
|
|
7097
|
+
}
|
|
7098
|
+
if (entry.error)
|
|
7099
|
+
console.log(` ${chalk20.red("Error:")} ${entry.error}`);
|
|
7100
|
+
console.log();
|
|
7101
|
+
}
|
|
7102
|
+
function renderExecutionLog(executionLog, verbose) {
|
|
7103
|
+
console.log();
|
|
7104
|
+
console.log(chalk20.bold("Execution Log"));
|
|
7105
|
+
console.log(chalk20.gray("\u2500".repeat(60)));
|
|
7106
|
+
executionLog.forEach((entry, i) => {
|
|
7107
|
+
if (entry.tool === "agent.chat") {
|
|
7108
|
+
renderAgentChatStep(entry, i + 1, verbose ?? false);
|
|
7109
|
+
return;
|
|
7110
|
+
}
|
|
7111
|
+
const stepStatus = entry.status === "success" ? chalk20.green("success") : chalk20.red("failed");
|
|
7112
|
+
console.log(` Step ${i + 1}: ${chalk20.cyan(String(entry.tool))} \u2192 ${stepStatus} (${entry.durationMs}ms)`);
|
|
7113
|
+
if (entry.as)
|
|
7114
|
+
console.log(` ${chalk20.gray("as:")} ${entry.as}`);
|
|
7115
|
+
console.log(` ${chalk20.gray("Args:")} ${JSON.stringify(entry.args, null, 2).split(`
|
|
7116
|
+
`).join(`
|
|
7117
|
+
`)}`);
|
|
7118
|
+
if (entry.result)
|
|
7119
|
+
console.log(` ${chalk20.gray("Result:")} ${JSON.stringify(entry.result, null, 2).split(`
|
|
7120
|
+
`).join(`
|
|
7121
|
+
`)}`);
|
|
7122
|
+
if (entry.error)
|
|
7123
|
+
console.log(` ${chalk20.red("Error:")} ${entry.error}`);
|
|
7124
|
+
console.log();
|
|
7125
|
+
});
|
|
7126
|
+
}
|
|
7127
|
+
var triggersCommand = new Command18("triggers").description("Manage triggers and automation runs");
|
|
7128
|
+
triggersCommand.command("list", { isDefault: true }).description("List all triggers").option("--env <environment>", "Environment (development|production|eval)", "development").option("--json", "Output raw JSON").option("--failed", "Show only triggers with recent failures").action(async (opts) => {
|
|
7129
|
+
await ensureAuth5();
|
|
7130
|
+
const spinner = ora14();
|
|
7131
|
+
try {
|
|
7132
|
+
spinner.start("Fetching triggers");
|
|
7133
|
+
const [triggers, statuses] = await Promise.all([
|
|
7134
|
+
listTriggers(opts.env),
|
|
7135
|
+
getLastRunStatuses(opts.env)
|
|
7136
|
+
]);
|
|
7137
|
+
let filtered = triggers;
|
|
7138
|
+
if (opts.failed) {
|
|
7139
|
+
filtered = triggers.filter((t) => statuses[t.slug]?.status === "failed");
|
|
7140
|
+
}
|
|
7141
|
+
spinner.succeed(`Found ${filtered.length} triggers${opts.failed ? " (failed only)" : ""}`);
|
|
7142
|
+
if (opts.json) {
|
|
7143
|
+
console.log(JSON.stringify(filtered, null, 2));
|
|
7144
|
+
return;
|
|
7145
|
+
}
|
|
7146
|
+
console.log();
|
|
7147
|
+
renderTable([
|
|
7148
|
+
{ key: "name", label: "Name", width: 20 },
|
|
7149
|
+
{ key: "slug", label: "Slug", width: 18 },
|
|
7150
|
+
{ key: "entityType", label: "Entity", width: 14 },
|
|
7151
|
+
{ key: "action", label: "Action", width: 10 },
|
|
7152
|
+
{ key: "enabled", label: "Enabled", width: 8 },
|
|
7153
|
+
{ key: "lastRun", label: "Last Run", width: 12 },
|
|
7154
|
+
{ key: "lastError", label: "Last Error", width: 25 },
|
|
7155
|
+
{ key: "updated", label: "Updated", width: 10 }
|
|
7156
|
+
], filtered.map((t) => ({
|
|
7157
|
+
name: t.name ?? "",
|
|
7158
|
+
slug: t.slug ?? "",
|
|
7159
|
+
entityType: t.entityType ?? "",
|
|
7160
|
+
action: t.action ?? "",
|
|
7161
|
+
enabled: t.enabled ? chalk20.green("\u2713") : chalk20.red("\u2717"),
|
|
7162
|
+
lastRun: statuses[t.slug] ? statusColor4(statuses[t.slug].status) : chalk20.gray("-"),
|
|
7163
|
+
lastError: statuses[t.slug]?.status === "failed" ? chalk20.red((statuses[t.slug].error ?? "").slice(0, 23)) : "",
|
|
7164
|
+
updated: relativeTime2(t.updatedAt ?? Date.now())
|
|
7165
|
+
})));
|
|
7166
|
+
console.log();
|
|
7167
|
+
} catch (err) {
|
|
7168
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7169
|
+
spinner.fail("Failed to fetch triggers");
|
|
7170
|
+
if (opts.json) {
|
|
7171
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7172
|
+
} else {
|
|
7173
|
+
console.log(chalk20.red("Error:"), message);
|
|
7174
|
+
}
|
|
7175
|
+
process.exit(1);
|
|
7176
|
+
}
|
|
7177
|
+
});
|
|
7178
|
+
triggersCommand.command("get <slug>").description("View trigger details").option("--env <environment>", "Environment", "development").option("--json", "Output raw JSON").action(async (slug, opts) => {
|
|
7179
|
+
await ensureAuth5();
|
|
7180
|
+
const spinner = ora14();
|
|
7181
|
+
try {
|
|
7182
|
+
spinner.start("Fetching trigger");
|
|
7183
|
+
const trigger = await getTrigger(slug, opts.env);
|
|
7184
|
+
if (!trigger) {
|
|
7185
|
+
spinner.fail("Trigger not found");
|
|
7186
|
+
if (opts.json) {
|
|
7187
|
+
console.log(JSON.stringify({ success: false, error: "Trigger not found" }));
|
|
7188
|
+
}
|
|
7189
|
+
process.exit(1);
|
|
7190
|
+
}
|
|
7191
|
+
spinner.succeed("Trigger loaded");
|
|
7192
|
+
if (opts.json) {
|
|
7193
|
+
console.log(JSON.stringify(trigger, null, 2));
|
|
7194
|
+
return;
|
|
7195
|
+
}
|
|
7196
|
+
console.log();
|
|
7197
|
+
console.log(` ${chalk20.gray("Name:")} ${chalk20.cyan(trigger.name)}`);
|
|
7198
|
+
console.log(` ${chalk20.gray("Slug:")} ${chalk20.cyan(trigger.slug)}`);
|
|
7199
|
+
console.log(` ${chalk20.gray("Description:")} ${chalk20.cyan(trigger.description || "-")}`);
|
|
7200
|
+
console.log(` ${chalk20.gray("Entity Type:")} ${chalk20.cyan(trigger.entityType)}`);
|
|
7201
|
+
console.log(` ${chalk20.gray("Action:")} ${chalk20.cyan(trigger.action)}`);
|
|
7202
|
+
console.log(` ${chalk20.gray("Enabled:")} ${trigger.enabled ? chalk20.green("\u2713") : chalk20.red("\u2717")}`);
|
|
7203
|
+
console.log(` ${chalk20.gray("Created:")} ${chalk20.cyan(relativeTime2(trigger.createdAt ?? Date.now()))}`);
|
|
7204
|
+
console.log(` ${chalk20.gray("Updated:")} ${chalk20.cyan(relativeTime2(trigger.updatedAt ?? Date.now()))}`);
|
|
7205
|
+
if (trigger.condition) {
|
|
7206
|
+
console.log();
|
|
7207
|
+
console.log(` ${chalk20.gray("Condition:")}`);
|
|
7208
|
+
console.log(` ${JSON.stringify(trigger.condition, null, 2).split(`
|
|
7209
|
+
`).join(`
|
|
7210
|
+
`)}`);
|
|
7211
|
+
}
|
|
7212
|
+
if (trigger.schedule) {
|
|
7213
|
+
console.log();
|
|
7214
|
+
console.log(` ${chalk20.gray("Schedule:")}`);
|
|
7215
|
+
for (const [key, value] of Object.entries(trigger.schedule)) {
|
|
7216
|
+
console.log(` ${chalk20.gray(key + ":")} ${chalk20.cyan(String(value))}`);
|
|
7217
|
+
}
|
|
7218
|
+
}
|
|
7219
|
+
if (trigger.retry) {
|
|
7220
|
+
console.log();
|
|
7221
|
+
console.log(` ${chalk20.gray("Retry:")}`);
|
|
7222
|
+
for (const [key, value] of Object.entries(trigger.retry)) {
|
|
7223
|
+
console.log(` ${chalk20.gray(key + ":")} ${chalk20.cyan(String(value))}`);
|
|
7224
|
+
}
|
|
7225
|
+
}
|
|
7226
|
+
if (trigger.actions?.length) {
|
|
7227
|
+
console.log();
|
|
7228
|
+
console.log(` ${chalk20.gray("Actions:")}`);
|
|
7229
|
+
trigger.actions.forEach((action, i) => {
|
|
7230
|
+
console.log(` ${chalk20.dim("Step " + (i + 1) + ":")} ${chalk20.cyan(action.tool)}${action.as ? ` (as: ${action.as})` : ""}`);
|
|
7231
|
+
if (action.args) {
|
|
7232
|
+
console.log(` ${JSON.stringify(action.args, null, 2).split(`
|
|
7233
|
+
`).join(`
|
|
7234
|
+
`)}`);
|
|
7235
|
+
}
|
|
7236
|
+
});
|
|
7237
|
+
}
|
|
7238
|
+
console.log();
|
|
7239
|
+
} catch (err) {
|
|
7240
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7241
|
+
spinner.fail("Failed to fetch trigger");
|
|
7242
|
+
if (opts.json) {
|
|
7243
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7244
|
+
} else {
|
|
7245
|
+
console.log(chalk20.red("Error:"), message);
|
|
7246
|
+
}
|
|
7247
|
+
process.exit(1);
|
|
7248
|
+
}
|
|
7249
|
+
});
|
|
7250
|
+
triggersCommand.command("runs [slug]").description("List trigger runs").option("--env <environment>", "Environment", "development").option("--status <status>", "Filter by status (pending|running|completed|failed|dead)").option("--limit <n>", "Maximum results", "20").option("--json", "Output raw JSON").action(async (slug, opts) => {
|
|
7251
|
+
await ensureAuth5();
|
|
7252
|
+
const spinner = ora14();
|
|
7253
|
+
try {
|
|
7254
|
+
spinner.start("Fetching runs");
|
|
7255
|
+
const runs = await listTriggerRuns({
|
|
7256
|
+
environment: opts.env,
|
|
7257
|
+
status: opts.status,
|
|
7258
|
+
triggerSlug: slug,
|
|
7259
|
+
limit: parseInt(opts.limit, 10)
|
|
7260
|
+
});
|
|
7261
|
+
spinner.succeed(`Found ${runs.length} runs`);
|
|
7262
|
+
if (opts.json) {
|
|
7263
|
+
console.log(JSON.stringify(runs, null, 2));
|
|
7264
|
+
return;
|
|
7265
|
+
}
|
|
7266
|
+
console.log();
|
|
7267
|
+
renderTable([
|
|
7268
|
+
{ key: "id", label: "ID", width: 24 },
|
|
7269
|
+
{ key: "trigger", label: "Trigger", width: 16 },
|
|
7270
|
+
{ key: "status", label: "Status", width: 10 },
|
|
7271
|
+
{ key: "attempts", label: "Attempts", width: 8 },
|
|
7272
|
+
{ key: "entity", label: "Entity", width: 14 },
|
|
7273
|
+
{ key: "error", label: "Error", width: 30 },
|
|
7274
|
+
{ key: "time", label: "Time", width: 10 }
|
|
7275
|
+
], runs.map((r) => ({
|
|
7276
|
+
id: r._id ?? "",
|
|
7277
|
+
trigger: r.triggerSlug ?? "",
|
|
7278
|
+
status: statusColor4(r.status),
|
|
7279
|
+
attempts: r.attempts ?? "",
|
|
7280
|
+
entity: r.entityId ? r.entityId.slice(-12) : "",
|
|
7281
|
+
error: r.errorMessage ?? "",
|
|
7282
|
+
time: relativeTime2(r.createdAt ?? Date.now())
|
|
7283
|
+
})));
|
|
7284
|
+
console.log();
|
|
7285
|
+
} catch (err) {
|
|
7286
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7287
|
+
spinner.fail("Failed to fetch runs");
|
|
7288
|
+
if (opts.json) {
|
|
7289
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7290
|
+
} else {
|
|
7291
|
+
console.log(chalk20.red("Error:"), message);
|
|
7292
|
+
}
|
|
7293
|
+
process.exit(1);
|
|
7294
|
+
}
|
|
7295
|
+
});
|
|
7296
|
+
triggersCommand.command("run <run-id>").description("View trigger run details").option("--env <environment>", "Environment", "development").option("--json", "Output raw JSON").option("-v, --verbose", "Show detailed agent tool calls").action(async (runId, opts) => {
|
|
7297
|
+
await ensureAuth5();
|
|
7298
|
+
const spinner = ora14();
|
|
7299
|
+
try {
|
|
7300
|
+
spinner.start("Fetching run");
|
|
7301
|
+
const run = await getTriggerRunDetail(runId, opts.env);
|
|
7302
|
+
if (!run) {
|
|
7303
|
+
spinner.fail("Run not found");
|
|
7304
|
+
if (opts.json) {
|
|
7305
|
+
console.log(JSON.stringify({ success: false, error: "Run not found" }));
|
|
7306
|
+
}
|
|
7307
|
+
process.exit(1);
|
|
7308
|
+
}
|
|
7309
|
+
spinner.succeed("Run loaded");
|
|
7310
|
+
if (opts.json) {
|
|
7311
|
+
console.log(JSON.stringify(run, null, 2));
|
|
7312
|
+
return;
|
|
7313
|
+
}
|
|
7314
|
+
console.log();
|
|
7315
|
+
console.log(` ${chalk20.gray("Trigger:")} ${chalk20.cyan(run.triggerSlug)}`);
|
|
7316
|
+
console.log(` ${chalk20.gray("Status:")} ${statusColor4(run.status)}`);
|
|
7317
|
+
console.log(` ${chalk20.gray("Entity:")} ${chalk20.cyan(run.entityId)}`);
|
|
7318
|
+
console.log(` ${chalk20.gray("Attempts:")} ${chalk20.cyan(`${run.attempts} / ${run.maxAttempts}`)}`);
|
|
7319
|
+
console.log(` ${chalk20.gray("Scheduled:")} ${chalk20.cyan(new Date(run.scheduledFor).toISOString())}`);
|
|
7320
|
+
console.log(` ${chalk20.gray("Started:")} ${chalk20.cyan(run.startedAt ? new Date(run.startedAt).toISOString() : "-")}`);
|
|
7321
|
+
console.log(` ${chalk20.gray("Completed:")} ${chalk20.cyan(run.completedAt ? new Date(run.completedAt).toISOString() : "-")}`);
|
|
7322
|
+
if (run.errorMessage) {
|
|
7323
|
+
console.log(` ${chalk20.gray("Error:")} ${chalk20.red(run.errorMessage)}`);
|
|
7324
|
+
}
|
|
7325
|
+
const executionLog = run.result?.executionLog;
|
|
7326
|
+
if (executionLog?.length) {
|
|
7327
|
+
renderExecutionLog(executionLog, opts.verbose);
|
|
7328
|
+
}
|
|
7329
|
+
console.log();
|
|
7330
|
+
} catch (err) {
|
|
7331
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7332
|
+
spinner.fail("Failed to fetch run");
|
|
7333
|
+
if (opts.json) {
|
|
7334
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7335
|
+
} else {
|
|
7336
|
+
console.log(chalk20.red("Error:"), message);
|
|
7337
|
+
}
|
|
7338
|
+
process.exit(1);
|
|
7339
|
+
}
|
|
7340
|
+
});
|
|
7341
|
+
triggersCommand.command("stats").description("Show trigger run statistics").option("--env <environment>", "Environment", "development").option("--json", "Output raw JSON").action(async (opts) => {
|
|
7342
|
+
await ensureAuth5();
|
|
7343
|
+
const spinner = ora14();
|
|
7344
|
+
try {
|
|
7345
|
+
spinner.start("Fetching statistics");
|
|
7346
|
+
const stats = await getTriggerRunStats(opts.env);
|
|
7347
|
+
spinner.succeed("Run statistics");
|
|
7348
|
+
if (opts.json) {
|
|
7349
|
+
console.log(JSON.stringify(stats, null, 2));
|
|
7350
|
+
return;
|
|
7351
|
+
}
|
|
7352
|
+
console.log();
|
|
7353
|
+
console.log(chalk20.bold(` Run Statistics (${opts.env})`));
|
|
7354
|
+
console.log();
|
|
7355
|
+
const statuses = [
|
|
7356
|
+
{ key: "pending", color: chalk20.yellow },
|
|
7357
|
+
{ key: "running", color: chalk20.cyan },
|
|
7358
|
+
{ key: "completed", color: chalk20.green },
|
|
7359
|
+
{ key: "failed", color: chalk20.red },
|
|
7360
|
+
{ key: "dead", color: chalk20.gray }
|
|
7361
|
+
];
|
|
7362
|
+
let total = 0;
|
|
7363
|
+
for (const { key, color } of statuses) {
|
|
7364
|
+
const count = stats[key] ?? 0;
|
|
7365
|
+
total += count;
|
|
7366
|
+
console.log(` ${color(key.padEnd(12))} ${String(count).padStart(6)}`);
|
|
7367
|
+
}
|
|
7368
|
+
console.log(` ${chalk20.gray("\u2500".repeat(18))}`);
|
|
7369
|
+
console.log(` ${chalk20.bold("Total".padEnd(12))} ${chalk20.bold(String(total).padStart(6))}`);
|
|
7370
|
+
console.log();
|
|
7371
|
+
const executions = await listTriggerExecutions({ environment: opts.env, limit: 50 });
|
|
7372
|
+
const recentFailures = executions.filter((e) => e.eventType === "trigger.failed");
|
|
7373
|
+
const recentSuccesses = executions.length - recentFailures.length;
|
|
7374
|
+
console.log(chalk20.bold(` Recent Executions`));
|
|
7375
|
+
console.log();
|
|
7376
|
+
console.log(` ${chalk20.green("Succeeded".padEnd(12))} ${String(recentSuccesses).padStart(6)}`);
|
|
7377
|
+
console.log(` ${chalk20.red("Failed".padEnd(12))} ${String(recentFailures.length).padStart(6)}`);
|
|
7378
|
+
if (recentFailures.length > 0) {
|
|
7379
|
+
const last = recentFailures[0];
|
|
7380
|
+
console.log();
|
|
7381
|
+
console.log(` ${chalk20.gray("Last failure:")} ${last.payload?.triggerSlug ?? "unknown"} (${relativeTime2(last.timestamp)})`);
|
|
7382
|
+
}
|
|
7383
|
+
console.log();
|
|
7384
|
+
} catch (err) {
|
|
7385
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7386
|
+
spinner.fail("Failed to fetch statistics");
|
|
7387
|
+
if (opts.json) {
|
|
7388
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7389
|
+
} else {
|
|
7390
|
+
console.log(chalk20.red("Error:"), message);
|
|
7391
|
+
}
|
|
7392
|
+
process.exit(1);
|
|
7393
|
+
}
|
|
7394
|
+
});
|
|
7395
|
+
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) => {
|
|
7396
|
+
await ensureAuth5();
|
|
7397
|
+
const spinner = ora14();
|
|
7398
|
+
try {
|
|
7399
|
+
spinner.start("Fetching execution logs");
|
|
7400
|
+
const executions = await listTriggerExecutions({
|
|
7401
|
+
environment: opts.env,
|
|
7402
|
+
triggerSlug: slug,
|
|
7403
|
+
limit: parseInt(opts.limit, 10)
|
|
7404
|
+
});
|
|
7405
|
+
spinner.succeed(`Found ${executions.length} executions`);
|
|
7406
|
+
if (opts.json) {
|
|
7407
|
+
console.log(JSON.stringify(executions, null, 2));
|
|
7408
|
+
return;
|
|
7409
|
+
}
|
|
7410
|
+
console.log();
|
|
7411
|
+
renderTable([
|
|
7412
|
+
{ key: "id", label: "ID", width: 24 },
|
|
7413
|
+
{ key: "trigger", label: "Trigger", width: 16 },
|
|
7414
|
+
{ key: "status", label: "Status", width: 8 },
|
|
7415
|
+
{ key: "steps", label: "Steps", width: 7 },
|
|
7416
|
+
{ key: "duration", label: "Duration", width: 10 },
|
|
7417
|
+
{ key: "error", label: "Error", width: 30 },
|
|
7418
|
+
{ key: "time", label: "Time", width: 10 }
|
|
7419
|
+
], executions.map((e) => {
|
|
7420
|
+
const status = e.eventType === "trigger.executed" ? "success" : "failed";
|
|
7421
|
+
const log = e.payload?.executionLog ?? [];
|
|
7422
|
+
const totalMs = log.reduce((sum, s) => sum + (s.durationMs || 0), 0);
|
|
7423
|
+
const passed = log.filter((s) => s.status === "success").length;
|
|
7424
|
+
return {
|
|
7425
|
+
id: e._id ?? "",
|
|
7426
|
+
trigger: e.payload?.triggerSlug ?? "",
|
|
7427
|
+
status: statusColor4(status),
|
|
7428
|
+
steps: `${passed}/${log.length}`,
|
|
7429
|
+
duration: `${totalMs}ms`,
|
|
7430
|
+
error: status === "failed" ? (e.payload?.error ?? "").slice(0, 28) : "",
|
|
7431
|
+
time: relativeTime2(e.timestamp ?? Date.now())
|
|
7432
|
+
};
|
|
7433
|
+
}));
|
|
7434
|
+
console.log();
|
|
7435
|
+
} catch (err) {
|
|
7436
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7437
|
+
spinner.fail("Failed to fetch execution logs");
|
|
7438
|
+
if (opts.json) {
|
|
7439
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7440
|
+
} else {
|
|
7441
|
+
console.log(chalk20.red("Error:"), message);
|
|
7442
|
+
}
|
|
7443
|
+
process.exit(1);
|
|
7444
|
+
}
|
|
7445
|
+
});
|
|
7446
|
+
triggersCommand.command("log <event-id>").description("View detailed trigger execution log").option("--json", "Output raw JSON").option("-v, --verbose", "Show detailed agent tool calls").action(async (eventId, opts) => {
|
|
7447
|
+
await ensureAuth5();
|
|
7448
|
+
const spinner = ora14();
|
|
7449
|
+
try {
|
|
7450
|
+
spinner.start("Fetching execution detail");
|
|
7451
|
+
const event = await getTriggerExecutionDetail(eventId);
|
|
7452
|
+
if (!event) {
|
|
7453
|
+
spinner.fail("Execution not found");
|
|
7454
|
+
if (opts.json) {
|
|
7455
|
+
console.log(JSON.stringify({ success: false, error: "Execution not found" }));
|
|
7456
|
+
}
|
|
7457
|
+
process.exit(1);
|
|
7458
|
+
}
|
|
7459
|
+
spinner.succeed("Execution loaded");
|
|
7460
|
+
if (opts.json) {
|
|
7461
|
+
console.log(JSON.stringify(event, null, 2));
|
|
7462
|
+
return;
|
|
7463
|
+
}
|
|
7464
|
+
const status = event.eventType === "trigger.executed" ? "success" : "failed";
|
|
7465
|
+
console.log();
|
|
7466
|
+
console.log(` ${chalk20.gray("Trigger:")} ${chalk20.cyan(event.payload?.triggerSlug ?? "")}`);
|
|
7467
|
+
console.log(` ${chalk20.gray("Status:")} ${statusColor4(status)}`);
|
|
7468
|
+
console.log(` ${chalk20.gray("Timestamp:")} ${chalk20.cyan(new Date(event.timestamp).toISOString())}`);
|
|
7469
|
+
if (event.entityId) {
|
|
7470
|
+
console.log(` ${chalk20.gray("Entity:")} ${chalk20.cyan(event.entityId)}`);
|
|
7471
|
+
}
|
|
7472
|
+
if (status === "failed" && event.payload?.error) {
|
|
7473
|
+
console.log(` ${chalk20.gray("Error:")} ${chalk20.red(event.payload.error)}`);
|
|
7474
|
+
}
|
|
7475
|
+
const executionLog = event.payload?.executionLog;
|
|
7476
|
+
if (executionLog?.length) {
|
|
7477
|
+
renderExecutionLog(executionLog, opts.verbose);
|
|
7478
|
+
}
|
|
7479
|
+
if (status === "failed" && event.payload?.triggerData) {
|
|
7480
|
+
console.log(chalk20.bold("Trigger Data"));
|
|
7481
|
+
console.log(chalk20.gray("\u2500".repeat(60)));
|
|
7482
|
+
console.log(` ${JSON.stringify(event.payload.triggerData, null, 2).split(`
|
|
7483
|
+
`).join(`
|
|
7484
|
+
`)}`);
|
|
7485
|
+
console.log();
|
|
7486
|
+
}
|
|
7487
|
+
} catch (err) {
|
|
7488
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7489
|
+
spinner.fail("Failed to fetch execution detail");
|
|
7490
|
+
if (opts.json) {
|
|
7491
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7492
|
+
} else {
|
|
7493
|
+
console.log(chalk20.red("Error:"), message);
|
|
7494
|
+
}
|
|
7495
|
+
process.exit(1);
|
|
7496
|
+
}
|
|
7497
|
+
});
|
|
7498
|
+
triggersCommand.command("retry <run-id>").description("Retry a failed or dead run").option("--env <environment>", "Environment", "development").option("--json", "Output raw JSON").option("--confirm", "Skip production confirmation").action(async (runId, opts) => {
|
|
7499
|
+
await ensureAuth5();
|
|
7500
|
+
const spinner = ora14();
|
|
7501
|
+
const environment = opts.env;
|
|
7502
|
+
if (environment === "production" && !opts.confirm && isInteractive()) {
|
|
7503
|
+
const readline = await import("readline");
|
|
7504
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7505
|
+
await new Promise((resolve) => {
|
|
7506
|
+
rl.question(chalk20.yellow(`WARNING: Retrying run in PRODUCTION environment.
|
|
7507
|
+
Press Enter to continue or Ctrl+C to cancel: `), resolve);
|
|
7508
|
+
});
|
|
7509
|
+
rl.close();
|
|
7510
|
+
}
|
|
7511
|
+
try {
|
|
7512
|
+
spinner.start("Retrying run...");
|
|
7513
|
+
await retryTriggerRun(runId, environment);
|
|
7514
|
+
spinner.succeed(chalk20.green(`Run ${runId} queued for retry`));
|
|
7515
|
+
if (opts.json) {
|
|
7516
|
+
console.log(JSON.stringify({ success: true, runId }));
|
|
7517
|
+
}
|
|
7518
|
+
} catch (err) {
|
|
7519
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7520
|
+
spinner.fail("Failed to retry run");
|
|
7521
|
+
if (opts.json) {
|
|
7522
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7523
|
+
} else {
|
|
7524
|
+
console.log(chalk20.red("Error:"), message);
|
|
7525
|
+
}
|
|
7526
|
+
process.exit(1);
|
|
7527
|
+
}
|
|
7528
|
+
});
|
|
7529
|
+
triggersCommand.command("cancel <run-id>").description("Cancel a pending run").option("--env <environment>", "Environment", "development").option("--json", "Output raw JSON").option("--confirm", "Skip production confirmation").action(async (runId, opts) => {
|
|
7530
|
+
await ensureAuth5();
|
|
7531
|
+
const spinner = ora14();
|
|
7532
|
+
const environment = opts.env;
|
|
7533
|
+
if (environment === "production" && !opts.confirm && isInteractive()) {
|
|
7534
|
+
const readline = await import("readline");
|
|
7535
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7536
|
+
await new Promise((resolve) => {
|
|
7537
|
+
rl.question(chalk20.yellow(`WARNING: Cancelling run in PRODUCTION environment.
|
|
7538
|
+
Press Enter to continue or Ctrl+C to cancel: `), resolve);
|
|
7539
|
+
});
|
|
7540
|
+
rl.close();
|
|
7541
|
+
}
|
|
7542
|
+
try {
|
|
7543
|
+
spinner.start("Cancelling run...");
|
|
7544
|
+
await cancelTriggerRun(runId, environment);
|
|
7545
|
+
spinner.succeed(chalk20.green(`Run ${runId} cancelled`));
|
|
7546
|
+
if (opts.json) {
|
|
7547
|
+
console.log(JSON.stringify({ success: true, runId }));
|
|
7548
|
+
}
|
|
7549
|
+
} catch (err) {
|
|
7550
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7551
|
+
spinner.fail("Failed to cancel run");
|
|
7552
|
+
if (opts.json) {
|
|
7553
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7554
|
+
} else {
|
|
7555
|
+
console.log(chalk20.red("Error:"), message);
|
|
7556
|
+
}
|
|
7557
|
+
process.exit(1);
|
|
7558
|
+
}
|
|
7559
|
+
});
|
|
7560
|
+
triggersCommand.command("enable <slug>").description("Enable a trigger").option("--env <environment>", "Environment", "development").option("--json", "Output raw JSON").option("--confirm", "Skip production confirmation").action(async (slug, opts) => {
|
|
7561
|
+
await ensureAuth5();
|
|
7562
|
+
const spinner = ora14();
|
|
7563
|
+
const environment = opts.env;
|
|
7564
|
+
if (environment === "production" && !opts.confirm && isInteractive()) {
|
|
7565
|
+
const readline = await import("readline");
|
|
7566
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7567
|
+
await new Promise((resolve) => {
|
|
7568
|
+
rl.question(chalk20.yellow(`WARNING: Enabling trigger in PRODUCTION environment.
|
|
7569
|
+
Press Enter to continue or Ctrl+C to cancel: `), resolve);
|
|
7570
|
+
});
|
|
7571
|
+
rl.close();
|
|
7572
|
+
}
|
|
7573
|
+
try {
|
|
7574
|
+
spinner.start("Enabling trigger...");
|
|
7575
|
+
await toggleTrigger(slug, true, environment);
|
|
7576
|
+
spinner.succeed(chalk20.green(`Trigger ${slug} enabled`));
|
|
7577
|
+
if (opts.json) {
|
|
7578
|
+
console.log(JSON.stringify({ success: true, slug }));
|
|
7579
|
+
}
|
|
7580
|
+
} catch (err) {
|
|
7581
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7582
|
+
spinner.fail("Failed to enable trigger");
|
|
7583
|
+
if (opts.json) {
|
|
7584
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7585
|
+
} else {
|
|
7586
|
+
console.log(chalk20.red("Error:"), message);
|
|
7587
|
+
}
|
|
7588
|
+
process.exit(1);
|
|
7589
|
+
}
|
|
7590
|
+
});
|
|
7591
|
+
triggersCommand.command("disable <slug>").description("Disable a trigger").option("--env <environment>", "Environment", "development").option("--json", "Output raw JSON").option("--confirm", "Skip production confirmation").action(async (slug, opts) => {
|
|
7592
|
+
await ensureAuth5();
|
|
7593
|
+
const spinner = ora14();
|
|
7594
|
+
const environment = opts.env;
|
|
7595
|
+
if (environment === "production" && !opts.confirm && isInteractive()) {
|
|
7596
|
+
const readline = await import("readline");
|
|
7597
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7598
|
+
await new Promise((resolve) => {
|
|
7599
|
+
rl.question(chalk20.yellow(`WARNING: Disabling trigger in PRODUCTION environment.
|
|
7600
|
+
Press Enter to continue or Ctrl+C to cancel: `), resolve);
|
|
7601
|
+
});
|
|
7602
|
+
rl.close();
|
|
7603
|
+
}
|
|
7604
|
+
try {
|
|
7605
|
+
spinner.start("Disabling trigger...");
|
|
7606
|
+
await toggleTrigger(slug, false, environment);
|
|
7607
|
+
spinner.succeed(chalk20.green(`Trigger ${slug} disabled`));
|
|
7608
|
+
if (opts.json) {
|
|
7609
|
+
console.log(JSON.stringify({ success: true, slug }));
|
|
7610
|
+
}
|
|
7611
|
+
} catch (err) {
|
|
7612
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7613
|
+
spinner.fail("Failed to disable trigger");
|
|
7614
|
+
if (opts.json) {
|
|
7615
|
+
console.log(JSON.stringify({ success: false, error: message }));
|
|
7616
|
+
} else {
|
|
7617
|
+
console.log(chalk20.red("Error:"), message);
|
|
7618
|
+
}
|
|
7619
|
+
process.exit(1);
|
|
7620
|
+
}
|
|
7621
|
+
});
|
|
7622
|
+
|
|
7623
|
+
// src/cli/commands/compile-prompt.ts
|
|
7624
|
+
import { Command as Command19 } from "commander";
|
|
7625
|
+
import chalk21 from "chalk";
|
|
7626
|
+
import ora15 from "ora";
|
|
7627
|
+
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) => {
|
|
6831
7628
|
acc.push(val);
|
|
6832
7629
|
return acc;
|
|
6833
7630
|
}, []).option("--json", "Output full JSON (raw + compiled + context)").option("--raw", "Show raw uncompiled template instead of compiled").action(async (agentSlug, options) => {
|
|
6834
|
-
const spinner =
|
|
7631
|
+
const spinner = ora15();
|
|
6835
7632
|
const cwd = process.cwd();
|
|
6836
7633
|
const nonInteractive = !isInteractive();
|
|
6837
7634
|
const jsonMode = !!options.json;
|
|
@@ -6840,11 +7637,11 @@ var compilePromptCommand = new Command18("compile-prompt").description("Compile
|
|
|
6840
7637
|
if (jsonMode) {
|
|
6841
7638
|
console.log(JSON.stringify({ success: false, error: "No struere.json found" }));
|
|
6842
7639
|
} else {
|
|
6843
|
-
console.log(
|
|
7640
|
+
console.log(chalk21.red("No struere.json found. Run struere init first."));
|
|
6844
7641
|
}
|
|
6845
7642
|
process.exit(1);
|
|
6846
7643
|
}
|
|
6847
|
-
console.log(
|
|
7644
|
+
console.log(chalk21.yellow("No struere.json found - initializing project..."));
|
|
6848
7645
|
console.log();
|
|
6849
7646
|
const success = await runInit(cwd);
|
|
6850
7647
|
if (!success) {
|
|
@@ -6857,7 +7654,7 @@ var compilePromptCommand = new Command18("compile-prompt").description("Compile
|
|
|
6857
7654
|
if (jsonMode) {
|
|
6858
7655
|
console.log(JSON.stringify({ success: false, error: "Failed to load struere.json" }));
|
|
6859
7656
|
} else {
|
|
6860
|
-
console.log(
|
|
7657
|
+
console.log(chalk21.red("Failed to load struere.json"));
|
|
6861
7658
|
}
|
|
6862
7659
|
process.exit(1);
|
|
6863
7660
|
}
|
|
@@ -6868,15 +7665,15 @@ var compilePromptCommand = new Command18("compile-prompt").description("Compile
|
|
|
6868
7665
|
if (jsonMode) {
|
|
6869
7666
|
console.log(JSON.stringify({ success: false, error: "Not authenticated. Set STRUERE_API_KEY or run struere login." }));
|
|
6870
7667
|
} else {
|
|
6871
|
-
console.log(
|
|
7668
|
+
console.log(chalk21.red("Not authenticated. Set STRUERE_API_KEY or run struere login."));
|
|
6872
7669
|
}
|
|
6873
7670
|
process.exit(1);
|
|
6874
7671
|
}
|
|
6875
|
-
console.log(
|
|
7672
|
+
console.log(chalk21.yellow("Not logged in - authenticating..."));
|
|
6876
7673
|
console.log();
|
|
6877
7674
|
credentials = await performLogin();
|
|
6878
7675
|
if (!credentials) {
|
|
6879
|
-
console.log(
|
|
7676
|
+
console.log(chalk21.red("Authentication failed"));
|
|
6880
7677
|
process.exit(1);
|
|
6881
7678
|
}
|
|
6882
7679
|
console.log();
|
|
@@ -6888,7 +7685,7 @@ var compilePromptCommand = new Command18("compile-prompt").description("Compile
|
|
|
6888
7685
|
if (jsonMode) {
|
|
6889
7686
|
console.log(JSON.stringify({ success: false, error: `Invalid param format: ${param}. Use key=value.` }));
|
|
6890
7687
|
} else {
|
|
6891
|
-
console.log(
|
|
7688
|
+
console.log(chalk21.red(`Invalid param format: ${param}. Use key=value.`));
|
|
6892
7689
|
}
|
|
6893
7690
|
process.exit(1);
|
|
6894
7691
|
}
|
|
@@ -6898,7 +7695,7 @@ var compilePromptCommand = new Command18("compile-prompt").description("Compile
|
|
|
6898
7695
|
}
|
|
6899
7696
|
const environment = options.env;
|
|
6900
7697
|
if (!jsonMode) {
|
|
6901
|
-
spinner.start(`Compiling prompt for ${
|
|
7698
|
+
spinner.start(`Compiling prompt for ${chalk21.cyan(agentSlug)} (${environment})`);
|
|
6902
7699
|
}
|
|
6903
7700
|
const doCompile = async () => {
|
|
6904
7701
|
return compilePrompt({
|
|
@@ -6920,7 +7717,7 @@ var compilePromptCommand = new Command18("compile-prompt").description("Compile
|
|
|
6920
7717
|
if (jsonMode) {
|
|
6921
7718
|
console.log(JSON.stringify({ success: false, error: "Authentication failed" }));
|
|
6922
7719
|
} else {
|
|
6923
|
-
console.log(
|
|
7720
|
+
console.log(chalk21.red("Authentication failed"));
|
|
6924
7721
|
}
|
|
6925
7722
|
process.exit(1);
|
|
6926
7723
|
}
|
|
@@ -6935,7 +7732,7 @@ var compilePromptCommand = new Command18("compile-prompt").description("Compile
|
|
|
6935
7732
|
console.log(JSON.stringify({ success: false, error }));
|
|
6936
7733
|
} else {
|
|
6937
7734
|
spinner.fail("Failed to compile prompt");
|
|
6938
|
-
console.log(
|
|
7735
|
+
console.log(chalk21.red("Error:"), error);
|
|
6939
7736
|
}
|
|
6940
7737
|
process.exit(1);
|
|
6941
7738
|
}
|
|
@@ -6958,25 +7755,25 @@ var compilePromptCommand = new Command18("compile-prompt").description("Compile
|
|
|
6958
7755
|
}, null, 2));
|
|
6959
7756
|
} else if (options.raw) {
|
|
6960
7757
|
console.log();
|
|
6961
|
-
console.log(
|
|
6962
|
-
console.log(
|
|
7758
|
+
console.log(chalk21.bold("Raw System Prompt"));
|
|
7759
|
+
console.log(chalk21.gray("\u2500".repeat(60)));
|
|
6963
7760
|
console.log(result.raw);
|
|
6964
|
-
console.log(
|
|
7761
|
+
console.log(chalk21.gray("\u2500".repeat(60)));
|
|
6965
7762
|
} else {
|
|
6966
7763
|
console.log();
|
|
6967
|
-
console.log(
|
|
6968
|
-
console.log(
|
|
7764
|
+
console.log(chalk21.bold("Compiled System Prompt"));
|
|
7765
|
+
console.log(chalk21.gray("\u2500".repeat(60)));
|
|
6969
7766
|
console.log(result.compiled);
|
|
6970
|
-
console.log(
|
|
7767
|
+
console.log(chalk21.gray("\u2500".repeat(60)));
|
|
6971
7768
|
}
|
|
6972
7769
|
});
|
|
6973
7770
|
|
|
6974
7771
|
// src/cli/commands/run-tool.ts
|
|
6975
|
-
import { Command as
|
|
6976
|
-
import
|
|
6977
|
-
import
|
|
6978
|
-
var runToolCommand = new
|
|
6979
|
-
const spinner =
|
|
7772
|
+
import { Command as Command20 } from "commander";
|
|
7773
|
+
import chalk22 from "chalk";
|
|
7774
|
+
import ora16 from "ora";
|
|
7775
|
+
var runToolCommand = new Command20("run-tool").description("Run a tool as it would execute during a real agent conversation").argument("<agent-slug>", "Agent slug").argument("<tool-name>", "Tool name (e.g., entity.query)").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 (agentSlug, toolName, options) => {
|
|
7776
|
+
const spinner = ora16();
|
|
6980
7777
|
const cwd = process.cwd();
|
|
6981
7778
|
const nonInteractive = !isInteractive();
|
|
6982
7779
|
const jsonMode = !!options.json;
|
|
@@ -6985,11 +7782,11 @@ var runToolCommand = new Command19("run-tool").description("Run a tool as it wou
|
|
|
6985
7782
|
if (jsonMode) {
|
|
6986
7783
|
console.log(JSON.stringify({ success: false, error: "No struere.json found" }));
|
|
6987
7784
|
} else {
|
|
6988
|
-
console.log(
|
|
7785
|
+
console.log(chalk22.red("No struere.json found. Run struere init first."));
|
|
6989
7786
|
}
|
|
6990
7787
|
process.exit(1);
|
|
6991
7788
|
}
|
|
6992
|
-
console.log(
|
|
7789
|
+
console.log(chalk22.yellow("No struere.json found - initializing project..."));
|
|
6993
7790
|
console.log();
|
|
6994
7791
|
const success = await runInit(cwd);
|
|
6995
7792
|
if (!success) {
|
|
@@ -7002,7 +7799,7 @@ var runToolCommand = new Command19("run-tool").description("Run a tool as it wou
|
|
|
7002
7799
|
if (jsonMode) {
|
|
7003
7800
|
console.log(JSON.stringify({ success: false, error: "Failed to load struere.json" }));
|
|
7004
7801
|
} else {
|
|
7005
|
-
console.log(
|
|
7802
|
+
console.log(chalk22.red("Failed to load struere.json"));
|
|
7006
7803
|
}
|
|
7007
7804
|
process.exit(1);
|
|
7008
7805
|
}
|
|
@@ -7013,15 +7810,15 @@ var runToolCommand = new Command19("run-tool").description("Run a tool as it wou
|
|
|
7013
7810
|
if (jsonMode) {
|
|
7014
7811
|
console.log(JSON.stringify({ success: false, error: "Not authenticated. Set STRUERE_API_KEY or run struere login." }));
|
|
7015
7812
|
} else {
|
|
7016
|
-
console.log(
|
|
7813
|
+
console.log(chalk22.red("Not authenticated. Set STRUERE_API_KEY or run struere login."));
|
|
7017
7814
|
}
|
|
7018
7815
|
process.exit(1);
|
|
7019
7816
|
}
|
|
7020
|
-
console.log(
|
|
7817
|
+
console.log(chalk22.yellow("Not logged in - authenticating..."));
|
|
7021
7818
|
console.log();
|
|
7022
7819
|
credentials = await performLogin();
|
|
7023
7820
|
if (!credentials) {
|
|
7024
|
-
console.log(
|
|
7821
|
+
console.log(chalk22.red("Authentication failed"));
|
|
7025
7822
|
process.exit(1);
|
|
7026
7823
|
}
|
|
7027
7824
|
console.log();
|
|
@@ -7039,7 +7836,7 @@ var runToolCommand = new Command19("run-tool").description("Run a tool as it wou
|
|
|
7039
7836
|
if (jsonMode) {
|
|
7040
7837
|
console.log(JSON.stringify({ success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` }));
|
|
7041
7838
|
} else {
|
|
7042
|
-
console.log(
|
|
7839
|
+
console.log(chalk22.red(`Invalid JSON: ${err instanceof Error ? err.message : String(err)}`));
|
|
7043
7840
|
}
|
|
7044
7841
|
process.exit(1);
|
|
7045
7842
|
}
|
|
@@ -7048,14 +7845,14 @@ var runToolCommand = new Command19("run-tool").description("Run a tool as it wou
|
|
|
7048
7845
|
const readline = await import("readline");
|
|
7049
7846
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7050
7847
|
await new Promise((resolve) => {
|
|
7051
|
-
rl.question(
|
|
7848
|
+
rl.question(chalk22.yellow(`WARNING: Running tool against PRODUCTION environment.
|
|
7052
7849
|
This will execute real operations with real data.
|
|
7053
7850
|
Press Enter to continue or Ctrl+C to cancel: `), resolve);
|
|
7054
7851
|
});
|
|
7055
7852
|
rl.close();
|
|
7056
7853
|
}
|
|
7057
7854
|
if (!jsonMode) {
|
|
7058
|
-
spinner.start(`Running ${
|
|
7855
|
+
spinner.start(`Running ${chalk22.cyan(toolName)} on ${chalk22.cyan(agentSlug)} (${environment})`);
|
|
7059
7856
|
}
|
|
7060
7857
|
const doRunTool = async () => {
|
|
7061
7858
|
return runTool({
|
|
@@ -7076,7 +7873,7 @@ var runToolCommand = new Command19("run-tool").description("Run a tool as it wou
|
|
|
7076
7873
|
if (jsonMode) {
|
|
7077
7874
|
console.log(JSON.stringify({ success: false, error: "Authentication failed" }));
|
|
7078
7875
|
} else {
|
|
7079
|
-
console.log(
|
|
7876
|
+
console.log(chalk22.red("Authentication failed"));
|
|
7080
7877
|
}
|
|
7081
7878
|
process.exit(1);
|
|
7082
7879
|
}
|
|
@@ -7084,14 +7881,14 @@ var runToolCommand = new Command19("run-tool").description("Run a tool as it wou
|
|
|
7084
7881
|
result = retry.result;
|
|
7085
7882
|
error = retry.error;
|
|
7086
7883
|
if (!jsonMode && !error)
|
|
7087
|
-
spinner.succeed(`Ran ${
|
|
7884
|
+
spinner.succeed(`Ran ${chalk22.cyan(toolName)}`);
|
|
7088
7885
|
}
|
|
7089
7886
|
if (error) {
|
|
7090
7887
|
if (jsonMode) {
|
|
7091
7888
|
console.log(JSON.stringify({ success: false, error }));
|
|
7092
7889
|
} else {
|
|
7093
7890
|
spinner.fail("Failed to run tool");
|
|
7094
|
-
console.log(
|
|
7891
|
+
console.log(chalk22.red("Error:"), error);
|
|
7095
7892
|
}
|
|
7096
7893
|
process.exit(1);
|
|
7097
7894
|
}
|
|
@@ -7107,32 +7904,32 @@ var runToolCommand = new Command19("run-tool").description("Run a tool as it wou
|
|
|
7107
7904
|
if (jsonMode) {
|
|
7108
7905
|
console.log(JSON.stringify({ success: false, error: `${result.errorType}: ${result.message}`, result }));
|
|
7109
7906
|
} else {
|
|
7110
|
-
spinner.fail(
|
|
7907
|
+
spinner.fail(chalk22.red(`${result.errorType}: ${result.message}`));
|
|
7111
7908
|
}
|
|
7112
7909
|
process.exit(1);
|
|
7113
7910
|
}
|
|
7114
7911
|
if (!jsonMode) {
|
|
7115
|
-
spinner.succeed(`Ran ${
|
|
7912
|
+
spinner.succeed(`Ran ${chalk22.cyan(toolName)} on ${chalk22.cyan(result.agent.slug)} (${result.environment}) in ${result.durationMs}ms`);
|
|
7116
7913
|
}
|
|
7117
7914
|
if (jsonMode) {
|
|
7118
7915
|
console.log(JSON.stringify(result, null, 2));
|
|
7119
7916
|
} else {
|
|
7120
7917
|
console.log();
|
|
7121
|
-
console.log(
|
|
7918
|
+
console.log(chalk22.dim("\u2500".repeat(50)));
|
|
7122
7919
|
console.log(JSON.stringify(result.result, null, 2));
|
|
7123
|
-
console.log(
|
|
7920
|
+
console.log(chalk22.dim("\u2500".repeat(50)));
|
|
7124
7921
|
console.log();
|
|
7125
|
-
console.log(
|
|
7922
|
+
console.log(chalk22.dim(`Identity: ${result.identity.actorType} (${result.identity.identityMode} mode)`));
|
|
7126
7923
|
}
|
|
7127
7924
|
});
|
|
7128
7925
|
|
|
7129
7926
|
// src/cli/commands/chat.ts
|
|
7130
|
-
import { Command as
|
|
7131
|
-
import
|
|
7132
|
-
import
|
|
7927
|
+
import { Command as Command21 } from "commander";
|
|
7928
|
+
import chalk23 from "chalk";
|
|
7929
|
+
import ora17 from "ora";
|
|
7133
7930
|
import readline from "readline";
|
|
7134
|
-
var chatCommand = new
|
|
7135
|
-
const spinner =
|
|
7931
|
+
var chatCommand = new Command21("chat").description("Chat with an agent").argument("<agent-slug>", "Agent slug").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 detailed response info").option("--confirm", "Skip production warning prompt").action(async (agentSlug, options) => {
|
|
7932
|
+
const spinner = ora17();
|
|
7136
7933
|
const cwd = process.cwd();
|
|
7137
7934
|
const nonInteractive = !isInteractive();
|
|
7138
7935
|
const jsonMode = !!options.json;
|
|
@@ -7141,11 +7938,11 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7141
7938
|
if (jsonMode) {
|
|
7142
7939
|
console.log(JSON.stringify({ success: false, error: "No struere.json found" }));
|
|
7143
7940
|
} else {
|
|
7144
|
-
console.log(
|
|
7941
|
+
console.log(chalk23.red("No struere.json found. Run struere init first."));
|
|
7145
7942
|
}
|
|
7146
7943
|
process.exit(1);
|
|
7147
7944
|
}
|
|
7148
|
-
console.log(
|
|
7945
|
+
console.log(chalk23.yellow("No struere.json found - initializing project..."));
|
|
7149
7946
|
console.log();
|
|
7150
7947
|
const success = await runInit(cwd);
|
|
7151
7948
|
if (!success) {
|
|
@@ -7158,7 +7955,7 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7158
7955
|
if (jsonMode) {
|
|
7159
7956
|
console.log(JSON.stringify({ success: false, error: "Failed to load struere.json" }));
|
|
7160
7957
|
} else {
|
|
7161
|
-
console.log(
|
|
7958
|
+
console.log(chalk23.red("Failed to load struere.json"));
|
|
7162
7959
|
}
|
|
7163
7960
|
process.exit(1);
|
|
7164
7961
|
}
|
|
@@ -7169,15 +7966,15 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7169
7966
|
if (jsonMode) {
|
|
7170
7967
|
console.log(JSON.stringify({ success: false, error: "Not authenticated. Set STRUERE_API_KEY or run struere login." }));
|
|
7171
7968
|
} else {
|
|
7172
|
-
console.log(
|
|
7969
|
+
console.log(chalk23.red("Not authenticated. Set STRUERE_API_KEY or run struere login."));
|
|
7173
7970
|
}
|
|
7174
7971
|
process.exit(1);
|
|
7175
7972
|
}
|
|
7176
|
-
console.log(
|
|
7973
|
+
console.log(chalk23.yellow("Not logged in - authenticating..."));
|
|
7177
7974
|
console.log();
|
|
7178
7975
|
credentials = await performLogin();
|
|
7179
7976
|
if (!credentials) {
|
|
7180
|
-
console.log(
|
|
7977
|
+
console.log(chalk23.red("Authentication failed"));
|
|
7181
7978
|
process.exit(1);
|
|
7182
7979
|
}
|
|
7183
7980
|
console.log();
|
|
@@ -7186,7 +7983,7 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7186
7983
|
if (environment === "production" && !nonInteractive && !options.confirm) {
|
|
7187
7984
|
const confirmRl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7188
7985
|
await new Promise((resolve) => {
|
|
7189
|
-
confirmRl.question(
|
|
7986
|
+
confirmRl.question(chalk23.yellow(`WARNING: Chatting with agent in PRODUCTION environment.
|
|
7190
7987
|
Press Enter to continue or Ctrl+C to cancel: `), resolve);
|
|
7191
7988
|
});
|
|
7192
7989
|
confirmRl.close();
|
|
@@ -7216,7 +8013,7 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7216
8013
|
if (jsonMode) {
|
|
7217
8014
|
console.log(JSON.stringify({ success: false, error: "Authentication failed" }));
|
|
7218
8015
|
} else {
|
|
7219
|
-
console.log(
|
|
8016
|
+
console.log(chalk23.red("Authentication failed"));
|
|
7220
8017
|
}
|
|
7221
8018
|
process.exit(1);
|
|
7222
8019
|
}
|
|
@@ -7231,7 +8028,7 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7231
8028
|
console.log(JSON.stringify({ success: false, error }));
|
|
7232
8029
|
} else {
|
|
7233
8030
|
spinner.fail("Failed to send message");
|
|
7234
|
-
console.log(
|
|
8031
|
+
console.log(chalk23.red("Error:"), error);
|
|
7235
8032
|
}
|
|
7236
8033
|
process.exit(1);
|
|
7237
8034
|
}
|
|
@@ -7251,30 +8048,30 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7251
8048
|
console.log();
|
|
7252
8049
|
console.log("\u2500".repeat(60));
|
|
7253
8050
|
console.log();
|
|
7254
|
-
console.log(
|
|
8051
|
+
console.log(chalk23.green("Agent:"));
|
|
7255
8052
|
console.log(result.message);
|
|
7256
8053
|
console.log();
|
|
7257
8054
|
if (options.verbose) {
|
|
7258
|
-
console.log(
|
|
7259
|
-
console.log(
|
|
7260
|
-
console.log(
|
|
8055
|
+
console.log(chalk23.dim(`Thread: ${result.threadId}`));
|
|
8056
|
+
console.log(chalk23.dim(`Tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out (${result.usage.totalTokens} total)`));
|
|
8057
|
+
console.log(chalk23.dim("Tool call details available in dashboard"));
|
|
7261
8058
|
} else {
|
|
7262
|
-
console.log(
|
|
8059
|
+
console.log(chalk23.dim(`Thread: ${result.threadId} | Tokens: ${result.usage.totalTokens}`));
|
|
7263
8060
|
}
|
|
7264
8061
|
console.log();
|
|
7265
8062
|
console.log("\u2500".repeat(60));
|
|
7266
8063
|
}
|
|
7267
8064
|
return;
|
|
7268
8065
|
}
|
|
7269
|
-
console.log(
|
|
7270
|
-
console.log(
|
|
8066
|
+
console.log(chalk23.bold(`Chat with ${chalk23.cyan(agentSlug)} (${environment})`));
|
|
8067
|
+
console.log(chalk23.dim("Type 'exit' to quit"));
|
|
7271
8068
|
console.log();
|
|
7272
8069
|
let threadId = options.thread;
|
|
7273
8070
|
let processing = false;
|
|
7274
8071
|
let generation = 0;
|
|
7275
8072
|
let currentAbort = null;
|
|
7276
8073
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7277
|
-
rl.setPrompt(
|
|
8074
|
+
rl.setPrompt(chalk23.cyan("You: "));
|
|
7278
8075
|
rl.prompt();
|
|
7279
8076
|
rl.on("SIGINT", () => {
|
|
7280
8077
|
if (processing) {
|
|
@@ -7286,7 +8083,7 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7286
8083
|
spinner.stop();
|
|
7287
8084
|
processing = false;
|
|
7288
8085
|
console.log();
|
|
7289
|
-
console.log(
|
|
8086
|
+
console.log(chalk23.yellow("Cancelled"));
|
|
7290
8087
|
console.log();
|
|
7291
8088
|
rl.resume();
|
|
7292
8089
|
rl.prompt();
|
|
@@ -7324,7 +8121,7 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7324
8121
|
if (thisGeneration !== generation)
|
|
7325
8122
|
return;
|
|
7326
8123
|
if (!credentials) {
|
|
7327
|
-
console.log(
|
|
8124
|
+
console.log(chalk23.red("Authentication failed"));
|
|
7328
8125
|
rl.close();
|
|
7329
8126
|
return;
|
|
7330
8127
|
}
|
|
@@ -7338,7 +8135,7 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7338
8135
|
}
|
|
7339
8136
|
if (error) {
|
|
7340
8137
|
spinner.fail("");
|
|
7341
|
-
console.log(
|
|
8138
|
+
console.log(chalk23.red("Error:"), error);
|
|
7342
8139
|
processing = false;
|
|
7343
8140
|
currentAbort = null;
|
|
7344
8141
|
rl.resume();
|
|
@@ -7356,15 +8153,15 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7356
8153
|
spinner.stop();
|
|
7357
8154
|
threadId = result.threadId;
|
|
7358
8155
|
console.log();
|
|
7359
|
-
console.log(
|
|
8156
|
+
console.log(chalk23.green("Agent:"));
|
|
7360
8157
|
console.log(result.message);
|
|
7361
8158
|
console.log();
|
|
7362
8159
|
if (options.verbose) {
|
|
7363
|
-
console.log(
|
|
7364
|
-
console.log(
|
|
7365
|
-
console.log(
|
|
8160
|
+
console.log(chalk23.dim(`Thread: ${result.threadId}`));
|
|
8161
|
+
console.log(chalk23.dim(`Tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out (${result.usage.totalTokens} total)`));
|
|
8162
|
+
console.log(chalk23.dim("Tool call details available in dashboard"));
|
|
7366
8163
|
} else {
|
|
7367
|
-
console.log(
|
|
8164
|
+
console.log(chalk23.dim(`Tokens: ${result.usage.totalTokens}`));
|
|
7368
8165
|
}
|
|
7369
8166
|
console.log();
|
|
7370
8167
|
processing = false;
|
|
@@ -7374,14 +8171,14 @@ var chatCommand = new Command20("chat").description("Chat with an agent").argume
|
|
|
7374
8171
|
});
|
|
7375
8172
|
rl.on("close", () => {
|
|
7376
8173
|
console.log();
|
|
7377
|
-
console.log(
|
|
8174
|
+
console.log(chalk23.dim("Goodbye!"));
|
|
7378
8175
|
process.exit(0);
|
|
7379
8176
|
});
|
|
7380
8177
|
});
|
|
7381
8178
|
// package.json
|
|
7382
8179
|
var package_default = {
|
|
7383
8180
|
name: "struere",
|
|
7384
|
-
version: "0.
|
|
8181
|
+
version: "0.11.0",
|
|
7385
8182
|
description: "Build, test, and deploy AI agents",
|
|
7386
8183
|
keywords: [
|
|
7387
8184
|
"ai",
|
|
@@ -7498,6 +8295,7 @@ program.addCommand(docsCommand);
|
|
|
7498
8295
|
program.addCommand(evalCommand);
|
|
7499
8296
|
program.addCommand(templatesCommand);
|
|
7500
8297
|
program.addCommand(integrationCommand);
|
|
8298
|
+
program.addCommand(triggersCommand);
|
|
7501
8299
|
program.addCommand(compilePromptCommand);
|
|
7502
8300
|
program.addCommand(runToolCommand);
|
|
7503
8301
|
program.addCommand(chatCommand);
|