struere 0.10.2 → 0.10.5
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 +371 -220
- package/dist/cli/commands/chat.d.ts +3 -0
- package/dist/cli/commands/chat.d.ts.map +1 -0
- package/dist/cli/commands/docs.d.ts.map +1 -1
- package/dist/cli/index.js +371 -220
- package/dist/cli/utils/convex.d.ts +22 -0
- package/dist/cli/utils/convex.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/bin/struere.js
CHANGED
|
@@ -540,7 +540,8 @@ async function runTool(options) {
|
|
|
540
540
|
agentId: agentResult.value._id,
|
|
541
541
|
environment: options.environment,
|
|
542
542
|
toolName: options.toolName,
|
|
543
|
-
toolArgs: options.toolArgs
|
|
543
|
+
toolArgs: options.toolArgs,
|
|
544
|
+
organizationId: options.organizationId
|
|
544
545
|
}
|
|
545
546
|
}),
|
|
546
547
|
signal: AbortSignal.timeout(30000)
|
|
@@ -567,6 +568,99 @@ async function runTool(options) {
|
|
|
567
568
|
}
|
|
568
569
|
return { error: `Unexpected response: ${text}` };
|
|
569
570
|
}
|
|
571
|
+
async function chatWithAgent(options) {
|
|
572
|
+
const credentials = loadCredentials();
|
|
573
|
+
const apiKey = getApiKey();
|
|
574
|
+
if (apiKey && !credentials?.token) {
|
|
575
|
+
const siteUrl = getSiteUrl();
|
|
576
|
+
try {
|
|
577
|
+
const response = await fetch(`${siteUrl}/v1/agents/${options.slug}/chat`, {
|
|
578
|
+
method: "POST",
|
|
579
|
+
headers: {
|
|
580
|
+
"Content-Type": "application/json",
|
|
581
|
+
Authorization: `Bearer ${apiKey}`
|
|
582
|
+
},
|
|
583
|
+
body: JSON.stringify({
|
|
584
|
+
message: options.message,
|
|
585
|
+
threadId: options.threadId,
|
|
586
|
+
environment: options.environment,
|
|
587
|
+
channel: options.channel || "api"
|
|
588
|
+
}),
|
|
589
|
+
signal: options.signal || AbortSignal.timeout(120000)
|
|
590
|
+
});
|
|
591
|
+
const text = await response.text();
|
|
592
|
+
let json;
|
|
593
|
+
try {
|
|
594
|
+
json = JSON.parse(text);
|
|
595
|
+
} catch {
|
|
596
|
+
return { error: text || `HTTP ${response.status}` };
|
|
597
|
+
}
|
|
598
|
+
if (!response.ok) {
|
|
599
|
+
return { error: json.error || text };
|
|
600
|
+
}
|
|
601
|
+
return { result: json };
|
|
602
|
+
} catch (err) {
|
|
603
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
604
|
+
return { error: "Request timed out after 120s" };
|
|
605
|
+
}
|
|
606
|
+
return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
if (credentials?.sessionId) {
|
|
610
|
+
await refreshToken();
|
|
611
|
+
}
|
|
612
|
+
const freshCredentials = loadCredentials();
|
|
613
|
+
const token = apiKey || freshCredentials?.token;
|
|
614
|
+
if (!token) {
|
|
615
|
+
return { error: "Not authenticated" };
|
|
616
|
+
}
|
|
617
|
+
try {
|
|
618
|
+
const response = await fetch(`${CONVEX_URL}/api/action`, {
|
|
619
|
+
method: "POST",
|
|
620
|
+
headers: {
|
|
621
|
+
"Content-Type": "application/json",
|
|
622
|
+
Authorization: `Bearer ${token}`
|
|
623
|
+
},
|
|
624
|
+
body: JSON.stringify({
|
|
625
|
+
path: "chat:sendBySlug",
|
|
626
|
+
args: {
|
|
627
|
+
slug: options.slug,
|
|
628
|
+
message: options.message,
|
|
629
|
+
threadId: options.threadId,
|
|
630
|
+
environment: options.environment,
|
|
631
|
+
channel: options.channel || "api"
|
|
632
|
+
}
|
|
633
|
+
}),
|
|
634
|
+
signal: options.signal || AbortSignal.timeout(120000)
|
|
635
|
+
});
|
|
636
|
+
const text = await response.text();
|
|
637
|
+
let json;
|
|
638
|
+
try {
|
|
639
|
+
json = JSON.parse(text);
|
|
640
|
+
} catch {
|
|
641
|
+
return { error: text || `HTTP ${response.status}` };
|
|
642
|
+
}
|
|
643
|
+
if (!response.ok) {
|
|
644
|
+
const msg = json.errorData?.message || json.errorMessage || text;
|
|
645
|
+
return { error: msg };
|
|
646
|
+
}
|
|
647
|
+
if (json.status === "success" && json.value) {
|
|
648
|
+
return { result: json.value };
|
|
649
|
+
}
|
|
650
|
+
if (json.status === "success" && json.value === null) {
|
|
651
|
+
return { error: `Agent not found or no config for environment: ${options.environment}` };
|
|
652
|
+
}
|
|
653
|
+
if (json.status === "error") {
|
|
654
|
+
return { error: json.errorData?.message || json.errorMessage || "Unknown error from Convex" };
|
|
655
|
+
}
|
|
656
|
+
return { error: `Unexpected response: ${text}` };
|
|
657
|
+
} catch (err) {
|
|
658
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
659
|
+
return { error: "Request timed out after 120s" };
|
|
660
|
+
}
|
|
661
|
+
return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
|
|
662
|
+
}
|
|
663
|
+
}
|
|
570
664
|
async function getPullState(organizationId, environment = "development") {
|
|
571
665
|
const credentials = loadCredentials();
|
|
572
666
|
const apiKey = getApiKey();
|
|
@@ -1831,7 +1925,12 @@ function getResourceDirectories(cwd) {
|
|
|
1831
1925
|
}
|
|
1832
1926
|
|
|
1833
1927
|
// src/cli/commands/docs.ts
|
|
1834
|
-
var
|
|
1928
|
+
var TEMPLATE_URL = "https://docs.struere.dev/llms-workspace.txt";
|
|
1929
|
+
var FALLBACK_TEMPLATE = `# Struere Workspace
|
|
1930
|
+
|
|
1931
|
+
> Run \`struere docs\` with internet access to generate full documentation.
|
|
1932
|
+
|
|
1933
|
+
{{PROJECT_CONTEXT}}`;
|
|
1835
1934
|
var ALL_TARGETS = ["claude", "cursor", "copilot"];
|
|
1836
1935
|
var TARGET_FILES = {
|
|
1837
1936
|
claude: "CLAUDE.md",
|
|
@@ -1885,222 +1984,18 @@ function buildProjectContext(orgName, resources) {
|
|
|
1885
1984
|
return lines.join(`
|
|
1886
1985
|
`);
|
|
1887
1986
|
}
|
|
1888
|
-
function
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
lines.push("");
|
|
1900
|
-
lines.push("**Sync**: Use `struere sync` instead of `struere dev` \u2014 it syncs once and exits (no watch loop)");
|
|
1901
|
-
lines.push("```bash");
|
|
1902
|
-
lines.push("struere sync # sync to development + eval, then exit");
|
|
1903
|
-
lines.push("struere sync --json # machine-readable JSON output");
|
|
1904
|
-
lines.push("struere sync --env production # sync to production");
|
|
1905
|
-
lines.push("struere sync --force # skip deletion confirmations");
|
|
1906
|
-
lines.push("```");
|
|
1907
|
-
lines.push("");
|
|
1908
|
-
lines.push("**Deploy**: `struere deploy --force` skips confirmation prompts");
|
|
1909
|
-
lines.push("");
|
|
1910
|
-
lines.push("**JSON output**: Most commands support `--json` for structured output:");
|
|
1911
|
-
lines.push("```bash");
|
|
1912
|
-
lines.push("struere data list <type> --json");
|
|
1913
|
-
lines.push("struere status --json");
|
|
1914
|
-
lines.push("struere deploy --json --force");
|
|
1915
|
-
lines.push("```");
|
|
1916
|
-
lines.push("");
|
|
1917
|
-
lines.push("**Non-interactive mode** is auto-detected when `STRUERE_API_KEY` is set or stdout is not a TTY. In this mode, all confirmation prompts are auto-accepted and spinners are replaced with plain text.");
|
|
1918
|
-
lines.push("");
|
|
1919
|
-
lines.push("**Exit codes**: All commands exit `0` on success, `1` on error. Check `$?` after execution.");
|
|
1920
|
-
lines.push("");
|
|
1921
|
-
if (projectContext) {
|
|
1922
|
-
lines.push(projectContext);
|
|
1923
|
-
lines.push("");
|
|
1987
|
+
async function fetchTemplate() {
|
|
1988
|
+
try {
|
|
1989
|
+
const controller = new AbortController;
|
|
1990
|
+
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
1991
|
+
const response = await fetch(TEMPLATE_URL, { signal: controller.signal });
|
|
1992
|
+
clearTimeout(timeout);
|
|
1993
|
+
if (!response.ok)
|
|
1994
|
+
throw new Error(`HTTP ${response.status}`);
|
|
1995
|
+
return await response.text();
|
|
1996
|
+
} catch {
|
|
1997
|
+
return FALLBACK_TEMPLATE;
|
|
1924
1998
|
}
|
|
1925
|
-
lines.push(`## Project Structure`);
|
|
1926
|
-
lines.push("");
|
|
1927
|
-
lines.push("```");
|
|
1928
|
-
lines.push("agents/ # Agent definitions (one file per agent)");
|
|
1929
|
-
lines.push("entity-types/ # Data type schemas (like DB tables)");
|
|
1930
|
-
lines.push("roles/ # RBAC roles with policies, scope rules, field masks");
|
|
1931
|
-
lines.push("triggers/ # Automation rules (react to entity changes)");
|
|
1932
|
-
lines.push("tools/index.ts # Custom tools shared by all agents");
|
|
1933
|
-
lines.push("evals/*.eval.yaml # Test suites for agent evaluation");
|
|
1934
|
-
lines.push("fixtures/*.fixture.yaml # Test data for eval environment");
|
|
1935
|
-
lines.push("struere.json # Organization config (auto-generated)");
|
|
1936
|
-
lines.push("```");
|
|
1937
|
-
lines.push("");
|
|
1938
|
-
lines.push(`## CLI Commands`);
|
|
1939
|
-
lines.push("");
|
|
1940
|
-
lines.push("| Command | Description |");
|
|
1941
|
-
lines.push("|---------|-------------|");
|
|
1942
|
-
lines.push("| `struere sync` | One-shot sync to Convex and exit (agent-friendly) |");
|
|
1943
|
-
lines.push("| `struere dev` | Watch files and sync to Convex on save |");
|
|
1944
|
-
lines.push("| `struere deploy` | Push development config to production |");
|
|
1945
|
-
lines.push("| `struere add agent\\|data-type\\|role\\|trigger\\|eval\\|fixture <name>` | Scaffold a new resource |");
|
|
1946
|
-
lines.push("| `struere status` | Compare local vs remote state |");
|
|
1947
|
-
lines.push("| `struere pull` | Download remote resources to local files |");
|
|
1948
|
-
lines.push("| `struere data types` | List data types in an environment |");
|
|
1949
|
-
lines.push("| `struere data list <type>` | List records (supports `--status`, `--limit`, `--json`) |");
|
|
1950
|
-
lines.push("| `struere data get <id>` | Get record details |");
|
|
1951
|
-
lines.push("| `struere data create <type>` | Create record (interactive or `--data <json>`) |");
|
|
1952
|
-
lines.push("| `struere data update <id>` | Update record (`--data <json>`, `--status`) |");
|
|
1953
|
-
lines.push("| `struere data delete <id>` | Delete record (with confirmation) |");
|
|
1954
|
-
lines.push("| `struere data search <type> <query>` | Search records by text |");
|
|
1955
|
-
lines.push("| `struere eval run <suite>` | Run an eval suite and write Markdown results |");
|
|
1956
|
-
lines.push("| `struere eval run <suite> --case <name>` | Run specific case(s) by name |");
|
|
1957
|
-
lines.push("| `struere eval run <suite> --tag <tag>` | Run cases matching a tag |");
|
|
1958
|
-
lines.push("| `struere templates list` | List WhatsApp message templates |");
|
|
1959
|
-
lines.push("| `struere templates create <name>` | Create a template (`--components <json>` or `--file <path>`) |");
|
|
1960
|
-
lines.push("| `struere templates delete <name>` | Delete a template (with confirmation) |");
|
|
1961
|
-
lines.push("| `struere templates status <name>` | Check template approval status |");
|
|
1962
|
-
lines.push("| `struere docs` | Regenerate this file |");
|
|
1963
|
-
lines.push("");
|
|
1964
|
-
lines.push(`## Key Patterns`);
|
|
1965
|
-
lines.push("");
|
|
1966
|
-
lines.push("- **Imports**: `import { defineAgent, defineData, defineRole, defineTrigger, defineTools } from 'struere'`");
|
|
1967
|
-
lines.push("- **Default model**: `grok-4-1-fast` (provider: `xai`). Also supports `anthropic`, `openai` and `google`");
|
|
1968
|
-
lines.push("- **Scope rule values**: `actor.userId`, `actor.entityId`, `actor.organizationId`, `actor.relatedIds:TYPE`, `literal:VALUE`");
|
|
1969
|
-
lines.push("- **Policy actions**: `create`, `read`, `update`, `delete`, `list` (deny overrides allow)");
|
|
1970
|
-
lines.push("- **Entity link/unlink params**: `fromId`, `toId`, `relationType`");
|
|
1971
|
-
lines.push("- **Trigger template vars**: `{{trigger.entityId}}`, `{{trigger.data.X}}`, `{{steps.NAME.X}}`");
|
|
1972
|
-
lines.push("");
|
|
1973
|
-
lines.push(`## Dynamic System Prompts`);
|
|
1974
|
-
lines.push("");
|
|
1975
|
-
lines.push("System prompts are **not static strings** \u2014 they are templates evaluated at runtime before every LLM call. This is one of the most powerful features in Struere because it enables completely different agent behavior depending on conditions, live data, and even other agents' responses.");
|
|
1976
|
-
lines.push("");
|
|
1977
|
-
lines.push("### Template Variables");
|
|
1978
|
-
lines.push("Simple variable substitution: `{{agentName}}`, `{{organizationName}}`, `{{currentTime}}`, `{{entityTypes}}`, `{{roles}}`, `{{message}}`, `{{thread.metadata.X}}`");
|
|
1979
|
-
lines.push("");
|
|
1980
|
-
lines.push("### Embedded Queries (Function Calls)");
|
|
1981
|
-
lines.push("Pull live data from the database directly into the system prompt:");
|
|
1982
|
-
lines.push("```");
|
|
1983
|
-
lines.push('{{entity.query({"type": "customer", "limit": 5})}}');
|
|
1984
|
-
lines.push('{{entity.get({"id": "ent_123"})}}');
|
|
1985
|
-
lines.push("```");
|
|
1986
|
-
lines.push("This means the agent always sees the latest data \u2014 no stale context.");
|
|
1987
|
-
lines.push("");
|
|
1988
|
-
lines.push("### Custom Tools in Prompts");
|
|
1989
|
-
lines.push("Since custom tools can run arbitrary logic, you can create tools specifically to generate dynamic prompt sections. A custom tool can fetch external APIs, compute conditions, aggregate data, or format context \u2014 and its output gets embedded into the system prompt at runtime.");
|
|
1990
|
-
lines.push("");
|
|
1991
|
-
lines.push("### Agent-to-Agent in Prompts");
|
|
1992
|
-
lines.push('You can even use `agent.chat` in the template to have another agent\'s response injected into the system prompt. This enables patterns like a "context agent" that summarizes relevant info before the main agent starts reasoning.');
|
|
1993
|
-
lines.push("");
|
|
1994
|
-
lines.push(`For full template syntax: [System Prompt Templates](${DOCS_BASE}/tools/system-prompt-templates.md)`);
|
|
1995
|
-
lines.push("");
|
|
1996
|
-
lines.push(`## WhatsApp Template Management`);
|
|
1997
|
-
lines.push("");
|
|
1998
|
-
lines.push("WhatsApp message templates are required for outbound messages outside the 24-hour messaging window. Struere supports full template lifecycle management.");
|
|
1999
|
-
lines.push("");
|
|
2000
|
-
lines.push("### Template Actions");
|
|
2001
|
-
lines.push("");
|
|
2002
|
-
lines.push("| Action | Description |");
|
|
2003
|
-
lines.push("|--------|-------------|");
|
|
2004
|
-
lines.push("| `whatsappActions.listTemplates` | List all templates for a connection |");
|
|
2005
|
-
lines.push("| `whatsappActions.createTemplate` | Create a new template on Meta |");
|
|
2006
|
-
lines.push("| `whatsappActions.deleteTemplate` | Delete a template from Meta |");
|
|
2007
|
-
lines.push("| `whatsappActions.getTemplateStatus` | Check approval status of a template |");
|
|
2008
|
-
lines.push("");
|
|
2009
|
-
lines.push("### Template Categories");
|
|
2010
|
-
lines.push("");
|
|
2011
|
-
lines.push("- **UTILITY**: transactional updates (order confirmations, reminders)");
|
|
2012
|
-
lines.push("- **MARKETING**: promotional content");
|
|
2013
|
-
lines.push("- **AUTHENTICATION**: OTP/verification codes");
|
|
2014
|
-
lines.push("");
|
|
2015
|
-
lines.push("### Template Components");
|
|
2016
|
-
lines.push("");
|
|
2017
|
-
lines.push("- **HEADER** (optional): TEXT, IMAGE, VIDEO, or DOCUMENT");
|
|
2018
|
-
lines.push("- **BODY** (required): main message text with `{{named_params}}` or `{{1}}` positional");
|
|
2019
|
-
lines.push("- **FOOTER** (optional): short text, no variables");
|
|
2020
|
-
lines.push("- **BUTTONS** (optional): QUICK_REPLY, URL, PHONE_NUMBER (do not interleave QUICK_REPLY with URL/PHONE_NUMBER)");
|
|
2021
|
-
lines.push("");
|
|
2022
|
-
lines.push('Use `parameter_format: "NAMED"` with `{{param_name}}` variables (recommended over positional). Include examples when variables appear in HEADER or BODY.');
|
|
2023
|
-
lines.push("");
|
|
2024
|
-
lines.push("### Status Flow");
|
|
2025
|
-
lines.push("");
|
|
2026
|
-
lines.push("`PENDING` \u2192 `APPROVED` | `REJECTED` | `PAUSED`");
|
|
2027
|
-
lines.push("");
|
|
2028
|
-
lines.push(`For details: [WhatsApp Integration](${DOCS_BASE}/integrations/whatsapp.md)`);
|
|
2029
|
-
lines.push("");
|
|
2030
|
-
lines.push(`## Multi-Agent Communication (agent.chat)`);
|
|
2031
|
-
lines.push("");
|
|
2032
|
-
lines.push("The `agent.chat` tool lets agents delegate work to other agents. This is a core building block for complex systems:");
|
|
2033
|
-
lines.push("");
|
|
2034
|
-
lines.push("- **Orchestrator pattern**: A coordinator agent routes tasks to specialist agents based on the request");
|
|
2035
|
-
lines.push("- **Trigger actions**: Use `agent.chat` inside trigger action pipelines to have an agent reason about entity changes");
|
|
2036
|
-
lines.push("- **Chained delegation**: Agents can call other agents up to 3 levels deep (A\u2192B\u2192C), with cycle detection");
|
|
2037
|
-
lines.push("- **Isolated execution**: Each agent runs its own LLM loop with its own system prompt, tools, and permissions");
|
|
2038
|
-
lines.push("");
|
|
2039
|
-
lines.push("```typescript");
|
|
2040
|
-
lines.push("// Orchestrator that delegates to specialists");
|
|
2041
|
-
lines.push('tools: ["agent.chat", "entity.query"]');
|
|
2042
|
-
lines.push("// In trigger actions:");
|
|
2043
|
-
lines.push('{ tool: "agent.chat", args: { agent: "billing-agent", message: "Process refund for {{trigger.data.orderId}}" } }');
|
|
2044
|
-
lines.push("```");
|
|
2045
|
-
lines.push("");
|
|
2046
|
-
lines.push(`For details: [Agents](${DOCS_BASE}/platform/agents.md)`);
|
|
2047
|
-
lines.push("");
|
|
2048
|
-
lines.push(`## Best Practices`);
|
|
2049
|
-
lines.push("");
|
|
2050
|
-
lines.push("- **Keep tools under 10 per agent.** Agents perform significantly worse when they have too many tools to choose from. If an agent needs more, split it into specialist agents and use `agent.chat` to orchestrate");
|
|
2051
|
-
lines.push("- **Always ask the user before making assumptions.** The user may not be technical \u2014 help them accomplish what they want by asking the right questions and offering clear options");
|
|
2052
|
-
lines.push("- **Always check the documentation before making changes.** Fetch the relevant doc link below to verify the correct API, field names, and patterns. Do not guess \u2014 wrong field names or patterns will cause silent failures");
|
|
2053
|
-
lines.push("- **Use `struere sync` to validate changes.** Run after editing files to sync to Convex. Use `struere dev` for continuous watch mode during manual development");
|
|
2054
|
-
lines.push("- **Test with evals.** Write eval suites to catch regressions in agent behavior (`struere add eval <name>`)");
|
|
2055
|
-
lines.push("");
|
|
2056
|
-
lines.push(`## Documentation`);
|
|
2057
|
-
lines.push("");
|
|
2058
|
-
lines.push(`Fetch these URLs for detailed documentation on each topic:`);
|
|
2059
|
-
lines.push("");
|
|
2060
|
-
lines.push("### SDK");
|
|
2061
|
-
lines.push(`- [SDK Overview](${DOCS_BASE}/sdk/overview.md)`);
|
|
2062
|
-
lines.push(`- [defineAgent](${DOCS_BASE}/sdk/define-agent.md)`);
|
|
2063
|
-
lines.push(`- [defineData](${DOCS_BASE}/sdk/define-data.md)`);
|
|
2064
|
-
lines.push(`- [defineRole](${DOCS_BASE}/sdk/define-role.md)`);
|
|
2065
|
-
lines.push(`- [defineTrigger](${DOCS_BASE}/sdk/define-trigger.md)`);
|
|
2066
|
-
lines.push(`- [defineTools](${DOCS_BASE}/sdk/define-tools.md)`);
|
|
2067
|
-
lines.push("");
|
|
2068
|
-
lines.push("### Tools");
|
|
2069
|
-
lines.push(`- [Built-in Tools](${DOCS_BASE}/tools/built-in-tools.md)`);
|
|
2070
|
-
lines.push(`- [Custom Tools](${DOCS_BASE}/tools/custom-tools.md)`);
|
|
2071
|
-
lines.push(`- [System Prompt Templates](${DOCS_BASE}/tools/system-prompt-templates.md)`);
|
|
2072
|
-
lines.push("");
|
|
2073
|
-
lines.push("### Platform");
|
|
2074
|
-
lines.push(`- [Data](${DOCS_BASE}/platform/data.md)`);
|
|
2075
|
-
lines.push(`- [Permissions](${DOCS_BASE}/platform/permissions.md)`);
|
|
2076
|
-
lines.push(`- [Agents](${DOCS_BASE}/platform/agents.md)`);
|
|
2077
|
-
lines.push(`- [Events](${DOCS_BASE}/platform/events.md)`);
|
|
2078
|
-
lines.push(`- [Triggers](${DOCS_BASE}/platform/triggers.md)`);
|
|
2079
|
-
lines.push(`- [Environment Isolation](${DOCS_BASE}/platform/environment-isolation.md)`);
|
|
2080
|
-
lines.push(`- [Evaluations](${DOCS_BASE}/platform/evals.md)`);
|
|
2081
|
-
lines.push("");
|
|
2082
|
-
lines.push("### CLI");
|
|
2083
|
-
lines.push(`- [CLI Overview](${DOCS_BASE}/cli/overview.md)`);
|
|
2084
|
-
lines.push(`- [struere init](${DOCS_BASE}/cli/init.md)`);
|
|
2085
|
-
lines.push(`- [struere sync](${DOCS_BASE}/cli/sync.md)`);
|
|
2086
|
-
lines.push(`- [struere dev](${DOCS_BASE}/cli/dev.md)`);
|
|
2087
|
-
lines.push(`- [struere add](${DOCS_BASE}/cli/add.md)`);
|
|
2088
|
-
lines.push(`- [struere deploy](${DOCS_BASE}/cli/deploy.md)`);
|
|
2089
|
-
lines.push(`- [struere eval run](${DOCS_BASE}/cli/eval.md)`);
|
|
2090
|
-
lines.push(`- [struere templates](${DOCS_BASE}/cli/templates.md)`);
|
|
2091
|
-
lines.push("");
|
|
2092
|
-
lines.push("### API & Integrations");
|
|
2093
|
-
lines.push(`- [Chat API](${DOCS_BASE}/api/chat.md)`);
|
|
2094
|
-
lines.push(`- [Webhooks](${DOCS_BASE}/api/webhooks.md)`);
|
|
2095
|
-
lines.push(`- [WhatsApp Integration](${DOCS_BASE}/integrations/whatsapp.md)`);
|
|
2096
|
-
lines.push("");
|
|
2097
|
-
lines.push("### Reference");
|
|
2098
|
-
lines.push(`- [Project Structure](${DOCS_BASE}/reference/project-structure.md)`);
|
|
2099
|
-
lines.push(`- [Model Configuration](${DOCS_BASE}/reference/model-configuration.md)`);
|
|
2100
|
-
lines.push("");
|
|
2101
|
-
lines.push(`Full docs: ${DOCS_BASE}/llms-full.txt`);
|
|
2102
|
-
return lines.join(`
|
|
2103
|
-
`);
|
|
2104
1999
|
}
|
|
2105
2000
|
function writeTarget(cwd, target, content) {
|
|
2106
2001
|
const filePath = join6(cwd, TARGET_FILES[target]);
|
|
@@ -2131,7 +2026,8 @@ async function generateDocs(cwd, targets) {
|
|
|
2131
2026
|
});
|
|
2132
2027
|
}
|
|
2133
2028
|
}
|
|
2134
|
-
const
|
|
2029
|
+
const template = await fetchTemplate();
|
|
2030
|
+
const content = template.replace("{{PROJECT_CONTEXT}}", projectContext ?? "");
|
|
2135
2031
|
for (const target of targets) {
|
|
2136
2032
|
writeTarget(cwd, target, content);
|
|
2137
2033
|
generated.push(TARGET_FILES[target]);
|
|
@@ -2825,7 +2721,8 @@ function getBuiltinToolParameters(name) {
|
|
|
2825
2721
|
endTime: { type: "string", description: "Event end time (ISO 8601 datetime)" },
|
|
2826
2722
|
description: { type: "string", description: "Event description" },
|
|
2827
2723
|
attendees: { type: "array", items: { type: "string" }, description: "List of attendee email addresses" },
|
|
2828
|
-
timeZone: { type: "string", description: 'Time zone (e.g., "America/Santiago")' }
|
|
2724
|
+
timeZone: { type: "string", description: 'Time zone (e.g., "America/Santiago")' },
|
|
2725
|
+
addGoogleMeet: { type: "boolean", description: "Set to true to automatically create a Google Meet video conference link for this event" }
|
|
2829
2726
|
},
|
|
2830
2727
|
required: ["userId", "summary", "startTime", "endTime"]
|
|
2831
2728
|
},
|
|
@@ -6956,10 +6853,263 @@ var runToolCommand = new Command18("run-tool").description("Run a tool as it wou
|
|
|
6956
6853
|
console.log(chalk20.dim(`Identity: ${result.identity.actorType} (${result.identity.identityMode} mode)`));
|
|
6957
6854
|
}
|
|
6958
6855
|
});
|
|
6856
|
+
|
|
6857
|
+
// src/cli/commands/chat.ts
|
|
6858
|
+
import { Command as Command19 } from "commander";
|
|
6859
|
+
import chalk21 from "chalk";
|
|
6860
|
+
import ora15 from "ora";
|
|
6861
|
+
import readline from "readline";
|
|
6862
|
+
var chatCommand = new Command19("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) => {
|
|
6863
|
+
const spinner = ora15();
|
|
6864
|
+
const cwd = process.cwd();
|
|
6865
|
+
const nonInteractive = !isInteractive();
|
|
6866
|
+
const jsonMode = !!options.json;
|
|
6867
|
+
if (!hasProject(cwd)) {
|
|
6868
|
+
if (nonInteractive) {
|
|
6869
|
+
if (jsonMode) {
|
|
6870
|
+
console.log(JSON.stringify({ success: false, error: "No struere.json found" }));
|
|
6871
|
+
} else {
|
|
6872
|
+
console.log(chalk21.red("No struere.json found. Run struere init first."));
|
|
6873
|
+
}
|
|
6874
|
+
process.exit(1);
|
|
6875
|
+
}
|
|
6876
|
+
console.log(chalk21.yellow("No struere.json found - initializing project..."));
|
|
6877
|
+
console.log();
|
|
6878
|
+
const success = await runInit(cwd);
|
|
6879
|
+
if (!success) {
|
|
6880
|
+
process.exit(1);
|
|
6881
|
+
}
|
|
6882
|
+
console.log();
|
|
6883
|
+
}
|
|
6884
|
+
const project = loadProject(cwd);
|
|
6885
|
+
if (!project) {
|
|
6886
|
+
if (jsonMode) {
|
|
6887
|
+
console.log(JSON.stringify({ success: false, error: "Failed to load struere.json" }));
|
|
6888
|
+
} else {
|
|
6889
|
+
console.log(chalk21.red("Failed to load struere.json"));
|
|
6890
|
+
}
|
|
6891
|
+
process.exit(1);
|
|
6892
|
+
}
|
|
6893
|
+
let credentials = loadCredentials();
|
|
6894
|
+
const apiKey = getApiKey();
|
|
6895
|
+
if (!credentials && !apiKey) {
|
|
6896
|
+
if (nonInteractive) {
|
|
6897
|
+
if (jsonMode) {
|
|
6898
|
+
console.log(JSON.stringify({ success: false, error: "Not authenticated. Set STRUERE_API_KEY or run struere login." }));
|
|
6899
|
+
} else {
|
|
6900
|
+
console.log(chalk21.red("Not authenticated. Set STRUERE_API_KEY or run struere login."));
|
|
6901
|
+
}
|
|
6902
|
+
process.exit(1);
|
|
6903
|
+
}
|
|
6904
|
+
console.log(chalk21.yellow("Not logged in - authenticating..."));
|
|
6905
|
+
console.log();
|
|
6906
|
+
credentials = await performLogin();
|
|
6907
|
+
if (!credentials) {
|
|
6908
|
+
console.log(chalk21.red("Authentication failed"));
|
|
6909
|
+
process.exit(1);
|
|
6910
|
+
}
|
|
6911
|
+
console.log();
|
|
6912
|
+
}
|
|
6913
|
+
const environment = options.env;
|
|
6914
|
+
if (environment === "production" && !nonInteractive && !options.confirm) {
|
|
6915
|
+
const confirmRl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6916
|
+
await new Promise((resolve) => {
|
|
6917
|
+
confirmRl.question(chalk21.yellow(`WARNING: Chatting with agent in PRODUCTION environment.
|
|
6918
|
+
Press Enter to continue or Ctrl+C to cancel: `), resolve);
|
|
6919
|
+
});
|
|
6920
|
+
confirmRl.close();
|
|
6921
|
+
}
|
|
6922
|
+
const doChat = async (message, threadId2, signal) => {
|
|
6923
|
+
return chatWithAgent({
|
|
6924
|
+
slug: agentSlug,
|
|
6925
|
+
message,
|
|
6926
|
+
threadId: threadId2,
|
|
6927
|
+
environment,
|
|
6928
|
+
organizationId: project?.organization.id,
|
|
6929
|
+
channel: options.channel,
|
|
6930
|
+
signal
|
|
6931
|
+
});
|
|
6932
|
+
};
|
|
6933
|
+
if (options.message) {
|
|
6934
|
+
if (!jsonMode) {
|
|
6935
|
+
spinner.start("Sending message...");
|
|
6936
|
+
}
|
|
6937
|
+
let { result, error } = await doChat(options.message, options.thread);
|
|
6938
|
+
if (error && isAuthError(error) && !nonInteractive) {
|
|
6939
|
+
if (!jsonMode)
|
|
6940
|
+
spinner.fail("Session expired - re-authenticating...");
|
|
6941
|
+
clearCredentials();
|
|
6942
|
+
credentials = await performLogin();
|
|
6943
|
+
if (!credentials) {
|
|
6944
|
+
if (jsonMode) {
|
|
6945
|
+
console.log(JSON.stringify({ success: false, error: "Authentication failed" }));
|
|
6946
|
+
} else {
|
|
6947
|
+
console.log(chalk21.red("Authentication failed"));
|
|
6948
|
+
}
|
|
6949
|
+
process.exit(1);
|
|
6950
|
+
}
|
|
6951
|
+
const retry = await doChat(options.message, options.thread);
|
|
6952
|
+
result = retry.result;
|
|
6953
|
+
error = retry.error;
|
|
6954
|
+
if (!jsonMode && !error)
|
|
6955
|
+
spinner.succeed("Message sent");
|
|
6956
|
+
}
|
|
6957
|
+
if (error) {
|
|
6958
|
+
if (jsonMode) {
|
|
6959
|
+
console.log(JSON.stringify({ success: false, error }));
|
|
6960
|
+
} else {
|
|
6961
|
+
spinner.fail("Failed to send message");
|
|
6962
|
+
console.log(chalk21.red("Error:"), error);
|
|
6963
|
+
}
|
|
6964
|
+
process.exit(1);
|
|
6965
|
+
}
|
|
6966
|
+
if (!result) {
|
|
6967
|
+
if (jsonMode) {
|
|
6968
|
+
console.log(JSON.stringify({ success: false, error: "No result returned" }));
|
|
6969
|
+
} else {
|
|
6970
|
+
spinner.fail("No result returned");
|
|
6971
|
+
}
|
|
6972
|
+
process.exit(1);
|
|
6973
|
+
}
|
|
6974
|
+
if (!jsonMode)
|
|
6975
|
+
spinner.succeed("Message sent");
|
|
6976
|
+
if (jsonMode) {
|
|
6977
|
+
console.log(JSON.stringify({ message: result.message, threadId: result.threadId, usage: result.usage }, null, 2));
|
|
6978
|
+
} else {
|
|
6979
|
+
console.log();
|
|
6980
|
+
console.log("\u2500".repeat(60));
|
|
6981
|
+
console.log();
|
|
6982
|
+
console.log(chalk21.green("Agent:"));
|
|
6983
|
+
console.log(result.message);
|
|
6984
|
+
console.log();
|
|
6985
|
+
if (options.verbose) {
|
|
6986
|
+
console.log(chalk21.dim(`Thread: ${result.threadId}`));
|
|
6987
|
+
console.log(chalk21.dim(`Tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out (${result.usage.totalTokens} total)`));
|
|
6988
|
+
console.log(chalk21.dim("Tool call details available in dashboard"));
|
|
6989
|
+
} else {
|
|
6990
|
+
console.log(chalk21.dim(`Thread: ${result.threadId} | Tokens: ${result.usage.totalTokens}`));
|
|
6991
|
+
}
|
|
6992
|
+
console.log();
|
|
6993
|
+
console.log("\u2500".repeat(60));
|
|
6994
|
+
}
|
|
6995
|
+
return;
|
|
6996
|
+
}
|
|
6997
|
+
console.log(chalk21.bold(`Chat with ${chalk21.cyan(agentSlug)} (${environment})`));
|
|
6998
|
+
console.log(chalk21.dim("Type 'exit' to quit"));
|
|
6999
|
+
console.log();
|
|
7000
|
+
let threadId = options.thread;
|
|
7001
|
+
let processing = false;
|
|
7002
|
+
let generation = 0;
|
|
7003
|
+
let currentAbort = null;
|
|
7004
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7005
|
+
rl.setPrompt(chalk21.cyan("You: "));
|
|
7006
|
+
rl.prompt();
|
|
7007
|
+
rl.on("SIGINT", () => {
|
|
7008
|
+
if (processing) {
|
|
7009
|
+
generation++;
|
|
7010
|
+
if (currentAbort) {
|
|
7011
|
+
currentAbort.abort();
|
|
7012
|
+
currentAbort = null;
|
|
7013
|
+
}
|
|
7014
|
+
spinner.stop();
|
|
7015
|
+
processing = false;
|
|
7016
|
+
console.log();
|
|
7017
|
+
console.log(chalk21.yellow("Cancelled"));
|
|
7018
|
+
console.log();
|
|
7019
|
+
rl.resume();
|
|
7020
|
+
rl.prompt();
|
|
7021
|
+
} else {
|
|
7022
|
+
rl.close();
|
|
7023
|
+
}
|
|
7024
|
+
});
|
|
7025
|
+
rl.on("line", async (input3) => {
|
|
7026
|
+
const trimmed = input3.trim();
|
|
7027
|
+
if (!trimmed) {
|
|
7028
|
+
rl.prompt();
|
|
7029
|
+
return;
|
|
7030
|
+
}
|
|
7031
|
+
if (trimmed === "exit" || trimmed === "quit") {
|
|
7032
|
+
rl.close();
|
|
7033
|
+
return;
|
|
7034
|
+
}
|
|
7035
|
+
if (processing) {
|
|
7036
|
+
return;
|
|
7037
|
+
}
|
|
7038
|
+
generation++;
|
|
7039
|
+
const thisGeneration = generation;
|
|
7040
|
+
processing = true;
|
|
7041
|
+
currentAbort = new AbortController;
|
|
7042
|
+
const signal = AbortSignal.any([currentAbort.signal, AbortSignal.timeout(120000)]);
|
|
7043
|
+
rl.pause();
|
|
7044
|
+
spinner.start("Thinking...");
|
|
7045
|
+
let { result, error } = await doChat(trimmed, threadId, signal);
|
|
7046
|
+
if (thisGeneration !== generation)
|
|
7047
|
+
return;
|
|
7048
|
+
if (error && isAuthError(error) && !nonInteractive) {
|
|
7049
|
+
spinner.fail("Session expired - re-authenticating...");
|
|
7050
|
+
clearCredentials();
|
|
7051
|
+
credentials = await performLogin();
|
|
7052
|
+
if (thisGeneration !== generation)
|
|
7053
|
+
return;
|
|
7054
|
+
if (!credentials) {
|
|
7055
|
+
console.log(chalk21.red("Authentication failed"));
|
|
7056
|
+
rl.close();
|
|
7057
|
+
return;
|
|
7058
|
+
}
|
|
7059
|
+
currentAbort = new AbortController;
|
|
7060
|
+
const retrySignal = AbortSignal.any([currentAbort.signal, AbortSignal.timeout(120000)]);
|
|
7061
|
+
const retry = await doChat(trimmed, threadId, retrySignal);
|
|
7062
|
+
if (thisGeneration !== generation)
|
|
7063
|
+
return;
|
|
7064
|
+
result = retry.result;
|
|
7065
|
+
error = retry.error;
|
|
7066
|
+
}
|
|
7067
|
+
if (error) {
|
|
7068
|
+
spinner.fail("");
|
|
7069
|
+
console.log(chalk21.red("Error:"), error);
|
|
7070
|
+
processing = false;
|
|
7071
|
+
currentAbort = null;
|
|
7072
|
+
rl.resume();
|
|
7073
|
+
rl.prompt();
|
|
7074
|
+
return;
|
|
7075
|
+
}
|
|
7076
|
+
if (!result) {
|
|
7077
|
+
spinner.fail("No result returned");
|
|
7078
|
+
processing = false;
|
|
7079
|
+
currentAbort = null;
|
|
7080
|
+
rl.resume();
|
|
7081
|
+
rl.prompt();
|
|
7082
|
+
return;
|
|
7083
|
+
}
|
|
7084
|
+
spinner.stop();
|
|
7085
|
+
threadId = result.threadId;
|
|
7086
|
+
console.log();
|
|
7087
|
+
console.log(chalk21.green("Agent:"));
|
|
7088
|
+
console.log(result.message);
|
|
7089
|
+
console.log();
|
|
7090
|
+
if (options.verbose) {
|
|
7091
|
+
console.log(chalk21.dim(`Thread: ${result.threadId}`));
|
|
7092
|
+
console.log(chalk21.dim(`Tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out (${result.usage.totalTokens} total)`));
|
|
7093
|
+
console.log(chalk21.dim("Tool call details available in dashboard"));
|
|
7094
|
+
} else {
|
|
7095
|
+
console.log(chalk21.dim(`Tokens: ${result.usage.totalTokens}`));
|
|
7096
|
+
}
|
|
7097
|
+
console.log();
|
|
7098
|
+
processing = false;
|
|
7099
|
+
currentAbort = null;
|
|
7100
|
+
rl.resume();
|
|
7101
|
+
rl.prompt();
|
|
7102
|
+
});
|
|
7103
|
+
rl.on("close", () => {
|
|
7104
|
+
console.log();
|
|
7105
|
+
console.log(chalk21.dim("Goodbye!"));
|
|
7106
|
+
process.exit(0);
|
|
7107
|
+
});
|
|
7108
|
+
});
|
|
6959
7109
|
// package.json
|
|
6960
7110
|
var package_default = {
|
|
6961
7111
|
name: "struere",
|
|
6962
|
-
version: "0.10.
|
|
7112
|
+
version: "0.10.5",
|
|
6963
7113
|
description: "Build, test, and deploy AI agents",
|
|
6964
7114
|
keywords: [
|
|
6965
7115
|
"ai",
|
|
@@ -7077,4 +7227,5 @@ program.addCommand(templatesCommand);
|
|
|
7077
7227
|
program.addCommand(integrationCommand);
|
|
7078
7228
|
program.addCommand(compilePromptCommand);
|
|
7079
7229
|
program.addCommand(runToolCommand);
|
|
7230
|
+
program.addCommand(chatCommand);
|
|
7080
7231
|
program.parse();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWnC,eAAO,MAAM,WAAW,SAyRpB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/docs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/docs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAenC,KAAK,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;AAqF7C,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyBnH;AAED,eAAO,MAAM,WAAW,SAsCpB,CAAA"}
|