struere 0.9.6 → 0.9.7

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.
@@ -19710,6 +19710,115 @@ async function getSyncState(organizationId, environment) {
19710
19710
  }
19711
19711
  return { error: `Unexpected response: ${JSON.stringify(result)}` };
19712
19712
  }
19713
+ async function compilePrompt(options) {
19714
+ const credentials = loadCredentials();
19715
+ const apiKey = getApiKey();
19716
+ if (apiKey && !credentials?.token) {
19717
+ const siteUrl = getSiteUrl();
19718
+ try {
19719
+ const response2 = await fetch(`${siteUrl}/v1/compile-prompt`, {
19720
+ method: "POST",
19721
+ headers: {
19722
+ "Content-Type": "application/json",
19723
+ Authorization: `Bearer ${apiKey}`
19724
+ },
19725
+ body: JSON.stringify({
19726
+ slug: options.slug,
19727
+ message: options.message,
19728
+ channel: options.channel,
19729
+ threadMetadata: options.threadMetadata
19730
+ }),
19731
+ signal: AbortSignal.timeout(30000)
19732
+ });
19733
+ const text2 = await response2.text();
19734
+ let json2;
19735
+ try {
19736
+ json2 = JSON.parse(text2);
19737
+ } catch {
19738
+ return { error: text2 || `HTTP ${response2.status}` };
19739
+ }
19740
+ if (!response2.ok) {
19741
+ return { error: json2.error || text2 };
19742
+ }
19743
+ return { result: json2 };
19744
+ } catch (err) {
19745
+ if (err instanceof DOMException && err.name === "TimeoutError") {
19746
+ return { error: "Request timed out after 30s" };
19747
+ }
19748
+ return { error: `Network error: ${err instanceof Error ? err.message : String(err)}` };
19749
+ }
19750
+ }
19751
+ if (credentials?.sessionId) {
19752
+ await refreshToken();
19753
+ }
19754
+ const freshCredentials = loadCredentials();
19755
+ const token = apiKey || freshCredentials?.token;
19756
+ if (!token) {
19757
+ return { error: "Not authenticated" };
19758
+ }
19759
+ const agentResponse = await fetch(`${CONVEX_URL}/api/query`, {
19760
+ method: "POST",
19761
+ headers: {
19762
+ "Content-Type": "application/json",
19763
+ Authorization: `Bearer ${token}`
19764
+ },
19765
+ body: JSON.stringify({
19766
+ path: "agents:getBySlug",
19767
+ args: { slug: options.slug }
19768
+ })
19769
+ });
19770
+ if (!agentResponse.ok) {
19771
+ return { error: await agentResponse.text() };
19772
+ }
19773
+ const agentResult = await agentResponse.json();
19774
+ if (agentResult.status === "error") {
19775
+ return { error: agentResult.errorMessage || "Failed to look up agent" };
19776
+ }
19777
+ if (!agentResult.value) {
19778
+ return { error: `Agent not found: ${options.slug}` };
19779
+ }
19780
+ const response = await fetch(`${CONVEX_URL}/api/action`, {
19781
+ method: "POST",
19782
+ headers: {
19783
+ "Content-Type": "application/json",
19784
+ Authorization: `Bearer ${token}`
19785
+ },
19786
+ body: JSON.stringify({
19787
+ path: "agents:compileSystemPrompt",
19788
+ args: {
19789
+ agentId: agentResult.value._id,
19790
+ environment: options.environment,
19791
+ sampleContext: {
19792
+ message: options.message,
19793
+ channel: options.channel,
19794
+ threadMetadata: options.threadMetadata
19795
+ }
19796
+ }
19797
+ }),
19798
+ signal: AbortSignal.timeout(30000)
19799
+ });
19800
+ const text = await response.text();
19801
+ let json;
19802
+ try {
19803
+ json = JSON.parse(text);
19804
+ } catch {
19805
+ return { error: text || `HTTP ${response.status}` };
19806
+ }
19807
+ if (!response.ok) {
19808
+ const msg = json.errorData?.message || json.errorMessage || text;
19809
+ return { error: msg };
19810
+ }
19811
+ if (json.status === "success" && json.value) {
19812
+ return { result: json.value };
19813
+ }
19814
+ if (json.status === "success" && json.value === null) {
19815
+ return { error: `Agent not found or no config for environment: ${options.environment}` };
19816
+ }
19817
+ if (json.status === "error") {
19818
+ return { error: json.errorData?.message || json.errorMessage || "Unknown error from Convex" };
19819
+ }
19820
+ return { error: `Unexpected response: ${text}` };
19821
+ }
19713
19822
  async function getPullState(organizationId, environment = "development") {
19714
19823
  const credentials = loadCredentials();
19715
19824
  const apiKey = getApiKey();
@@ -19802,6 +19911,7 @@ async function browserLoginInternal(spinner) {
19802
19911
  const authPromise = new Promise((resolve, reject) => {
19803
19912
  const server = Bun.serve({
19804
19913
  port: AUTH_CALLBACK_PORT,
19914
+ hostname: "127.0.0.1",
19805
19915
  async fetch(req) {
19806
19916
  const url = new URL(req.url);
19807
19917
  if (url.pathname === "/callback") {
@@ -20102,9 +20212,9 @@ logs/
20102
20212
  }
20103
20213
  function getEntityTypeTs(name, slug) {
20104
20214
  const displayName = name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
20105
- return `import { defineEntityType } from 'struere'
20215
+ return `import { defineData } from 'struere'
20106
20216
 
20107
- export default defineEntityType({
20217
+ export default defineData({
20108
20218
  name: "${displayName}",
20109
20219
  slug: "${slug}",
20110
20220
  schema: {
@@ -20520,11 +20630,11 @@ function validateObjectProperties(schema, path) {
20520
20630
  }
20521
20631
  }
20522
20632
 
20523
- function defineEntityType(config) {
20524
- if (!config.name) throw new Error('Entity type name is required')
20525
- if (!config.slug) throw new Error('Entity type slug is required')
20526
- if (!config.schema) throw new Error('Entity type schema is required')
20527
- if (config.schema.type !== 'object') throw new Error('Entity type schema must be an object type')
20633
+ function defineData(config) {
20634
+ if (!config.name) throw new Error('Data type name is required')
20635
+ if (!config.slug) throw new Error('Data type slug is required')
20636
+ if (!config.schema) throw new Error('Data type schema is required')
20637
+ if (config.schema.type !== 'object') throw new Error('Data type schema must be an object type')
20528
20638
  if (config.schema.properties) {
20529
20639
  for (const [key, value] of Object.entries(config.schema.properties)) {
20530
20640
  validateObjectProperties(value, key)
@@ -20599,7 +20709,7 @@ function defineConfig(config) {
20599
20709
  }
20600
20710
  }
20601
20711
 
20602
- export { defineAgent, defineRole, defineEntityType, defineTrigger, defineTools, defineConfig }
20712
+ export { defineAgent, defineRole, defineData, defineTrigger, defineTools, defineConfig }
20603
20713
  `;
20604
20714
  function registerStruerePlugin() {
20605
20715
  if (registered)
@@ -20776,7 +20886,7 @@ var TYPE_DECLARATIONS = `declare module 'struere' {
20776
20886
 
20777
20887
  export function defineAgent(config: AgentConfig): AgentConfig
20778
20888
  export function defineRole(config: RoleConfig): RoleConfig
20779
- export function defineEntityType(config: EntityTypeConfig): EntityTypeConfig
20889
+ export function defineData(config: EntityTypeConfig): EntityTypeConfig
20780
20890
  export function defineTrigger(config: TriggerConfig): TriggerConfig
20781
20891
  export function defineTools(tools: ToolDefinition[]): ToolReference[]
20782
20892
  export function defineConfig(config?: Partial<FrameworkConfig>): FrameworkConfig
@@ -20950,7 +21060,7 @@ function buildProjectContext(orgName, resources) {
20950
21060
  }
20951
21061
  if (resources.entityTypes.length > 0) {
20952
21062
  lines.push("");
20953
- lines.push(`### Entity Types (${resources.entityTypes.length})`);
21063
+ lines.push(`### Data Types (${resources.entityTypes.length})`);
20954
21064
  for (const et of resources.entityTypes) {
20955
21065
  const fields = et.schema?.properties ? Object.keys(et.schema.properties).join(", ") : "";
20956
21066
  const fieldStr = fields ? ` \u2014 fields: ${fields}` : "";
@@ -20986,7 +21096,7 @@ function buildDocument(projectContext) {
20986
21096
  const lines = [];
20987
21097
  lines.push(`# Struere Workspace`);
20988
21098
  lines.push("");
20989
- lines.push(`> This is a Struere workspace project. You define agents, entity types, roles, triggers, and custom tools here. The CLI syncs them to the Convex backend.`);
21099
+ lines.push(`> This is a Struere workspace project. You define agents, data types, roles, triggers, and custom tools here. The CLI syncs them to the Convex backend.`);
20990
21100
  lines.push("");
20991
21101
  lines.push(`## Agent Usage`);
20992
21102
  lines.push("");
@@ -21006,7 +21116,7 @@ function buildDocument(projectContext) {
21006
21116
  lines.push("");
21007
21117
  lines.push("**JSON output**: Most commands support `--json` for structured output:");
21008
21118
  lines.push("```bash");
21009
- lines.push("struere entities list <type> --json");
21119
+ lines.push("struere data list <type> --json");
21010
21120
  lines.push("struere status --json");
21011
21121
  lines.push("struere deploy --json --force");
21012
21122
  lines.push("```");
@@ -21023,7 +21133,7 @@ function buildDocument(projectContext) {
21023
21133
  lines.push("");
21024
21134
  lines.push("```");
21025
21135
  lines.push("agents/ # Agent definitions (one file per agent)");
21026
- lines.push("entity-types/ # Entity type schemas (like DB tables)");
21136
+ lines.push("entity-types/ # Data type schemas (like DB tables)");
21027
21137
  lines.push("roles/ # RBAC roles with policies, scope rules, field masks");
21028
21138
  lines.push("triggers/ # Automation rules (react to entity changes)");
21029
21139
  lines.push("tools/index.ts # Custom tools shared by all agents");
@@ -21039,16 +21149,16 @@ function buildDocument(projectContext) {
21039
21149
  lines.push("| `struere sync` | One-shot sync to Convex and exit (agent-friendly) |");
21040
21150
  lines.push("| `struere dev` | Watch files and sync to Convex on save |");
21041
21151
  lines.push("| `struere deploy` | Push development config to production |");
21042
- lines.push("| `struere add agent\\|entity-type\\|role\\|trigger\\|eval\\|fixture <name>` | Scaffold a new resource |");
21152
+ lines.push("| `struere add agent\\|data-type\\|role\\|trigger\\|eval\\|fixture <name>` | Scaffold a new resource |");
21043
21153
  lines.push("| `struere status` | Compare local vs remote state |");
21044
21154
  lines.push("| `struere pull` | Download remote resources to local files |");
21045
- lines.push("| `struere entities types` | List entity types in an environment |");
21046
- lines.push("| `struere entities list <type>` | List entities (supports `--status`, `--limit`, `--json`) |");
21047
- lines.push("| `struere entities get <id>` | Get entity details |");
21048
- lines.push("| `struere entities create <type>` | Create entity (interactive or `--data <json>`) |");
21049
- lines.push("| `struere entities update <id>` | Update entity (`--data <json>`, `--status`) |");
21050
- lines.push("| `struere entities delete <id>` | Delete entity (with confirmation) |");
21051
- lines.push("| `struere entities search <type> <query>` | Search entities by text |");
21155
+ lines.push("| `struere data types` | List data types in an environment |");
21156
+ lines.push("| `struere data list <type>` | List records (supports `--status`, `--limit`, `--json`) |");
21157
+ lines.push("| `struere data get <id>` | Get record details |");
21158
+ lines.push("| `struere data create <type>` | Create record (interactive or `--data <json>`) |");
21159
+ lines.push("| `struere data update <id>` | Update record (`--data <json>`, `--status`) |");
21160
+ lines.push("| `struere data delete <id>` | Delete record (with confirmation) |");
21161
+ lines.push("| `struere data search <type> <query>` | Search records by text |");
21052
21162
  lines.push("| `struere eval run <suite>` | Run an eval suite and write Markdown results |");
21053
21163
  lines.push("| `struere eval run <suite> --case <name>` | Run specific case(s) by name |");
21054
21164
  lines.push("| `struere eval run <suite> --tag <tag>` | Run cases matching a tag |");
@@ -21060,7 +21170,7 @@ function buildDocument(projectContext) {
21060
21170
  lines.push("");
21061
21171
  lines.push(`## Key Patterns`);
21062
21172
  lines.push("");
21063
- lines.push("- **Imports**: `import { defineAgent, defineEntityType, defineRole, defineTrigger, defineTools } from 'struere'`");
21173
+ lines.push("- **Imports**: `import { defineAgent, defineData, defineRole, defineTrigger, defineTools } from 'struere'`");
21064
21174
  lines.push("- **Default model**: `grok-4-1-fast` (provider: `xai`). Also supports `anthropic`, `openai` and `google`");
21065
21175
  lines.push("- **Scope rule values**: `actor.userId`, `actor.entityId`, `actor.organizationId`, `actor.relatedIds:TYPE`, `literal:VALUE`");
21066
21176
  lines.push("- **Policy actions**: `create`, `read`, `update`, `delete`, `list` (deny overrides allow)");
@@ -21157,7 +21267,7 @@ function buildDocument(projectContext) {
21157
21267
  lines.push("### SDK");
21158
21268
  lines.push(`- [SDK Overview](${DOCS_BASE}/sdk/overview.md)`);
21159
21269
  lines.push(`- [defineAgent](${DOCS_BASE}/sdk/define-agent.md)`);
21160
- lines.push(`- [defineEntityType](${DOCS_BASE}/sdk/define-entity-type.md)`);
21270
+ lines.push(`- [defineData](${DOCS_BASE}/sdk/define-data.md)`);
21161
21271
  lines.push(`- [defineRole](${DOCS_BASE}/sdk/define-role.md)`);
21162
21272
  lines.push(`- [defineTrigger](${DOCS_BASE}/sdk/define-trigger.md)`);
21163
21273
  lines.push(`- [defineTools](${DOCS_BASE}/sdk/define-tools.md)`);
@@ -21168,7 +21278,7 @@ function buildDocument(projectContext) {
21168
21278
  lines.push(`- [System Prompt Templates](${DOCS_BASE}/tools/system-prompt-templates.md)`);
21169
21279
  lines.push("");
21170
21280
  lines.push("### Platform");
21171
- lines.push(`- [Entities](${DOCS_BASE}/platform/entities.md)`);
21281
+ lines.push(`- [Data](${DOCS_BASE}/platform/data.md)`);
21172
21282
  lines.push(`- [Permissions](${DOCS_BASE}/platform/permissions.md)`);
21173
21283
  lines.push(`- [Agents](${DOCS_BASE}/platform/agents.md)`);
21174
21284
  lines.push(`- [Events](${DOCS_BASE}/platform/events.md)`);
@@ -21505,7 +21615,7 @@ var initCommand = new Command("init").description("Initialize a new Struere orga
21505
21615
  console.log();
21506
21616
  console.log(source_default.gray("Project structure:"));
21507
21617
  console.log(source_default.gray(" agents/ "), source_default.cyan("Agent definitions"));
21508
- console.log(source_default.gray(" entity-types/ "), source_default.cyan("Entity type schemas"));
21618
+ console.log(source_default.gray(" entity-types/ "), source_default.cyan("Data type schemas"));
21509
21619
  console.log(source_default.gray(" roles/ "), source_default.cyan("Role + permission definitions"));
21510
21620
  console.log(source_default.gray(" tools/ "), source_default.cyan("Shared custom tools"));
21511
21621
  console.log();
@@ -21563,7 +21673,9 @@ var BUILTIN_TOOLS = [
21563
21673
  "airtable.createRecords",
21564
21674
  "airtable.updateRecords",
21565
21675
  "airtable.deleteRecords",
21566
- "email.send"
21676
+ "email.send",
21677
+ "payment.create",
21678
+ "payment.getStatus"
21567
21679
  ];
21568
21680
  function extractSyncPayload(resources) {
21569
21681
  const customToolsMap = new Map;
@@ -21618,7 +21730,9 @@ function extractSyncPayload(resources) {
21618
21730
  userMessage: t.user,
21619
21731
  assertions: t.assertions
21620
21732
  })),
21621
- finalAssertions: c.finalAssertions
21733
+ finalAssertions: c.finalAssertions,
21734
+ channel: c.channel,
21735
+ contextParams: c.contextParams
21622
21736
  }))
21623
21737
  })) : undefined;
21624
21738
  const triggers = resources.triggers.length > 0 ? resources.triggers.map((t) => ({
@@ -21734,7 +21848,9 @@ function getBuiltinToolDescription(name) {
21734
21848
  "airtable.createRecords": "Create up to 10 records in an Airtable table",
21735
21849
  "airtable.updateRecords": "Update up to 10 records in an Airtable table",
21736
21850
  "airtable.deleteRecords": "Delete up to 10 records from an Airtable table",
21737
- "email.send": "Send an email via Resend"
21851
+ "email.send": "Send an email via Resend",
21852
+ "payment.create": "Create a payment link via Flow.cl and return the URL",
21853
+ "payment.getStatus": "Check the current status of a payment"
21738
21854
  };
21739
21855
  return descriptions[name] || name;
21740
21856
  }
@@ -22042,6 +22158,24 @@ function getBuiltinToolParameters(name) {
22042
22158
  replyTo: { type: "string", description: "Reply-to email address" }
22043
22159
  },
22044
22160
  required: ["to", "subject"]
22161
+ },
22162
+ "payment.create": {
22163
+ type: "object",
22164
+ properties: {
22165
+ amount: { type: "number", description: "Payment amount in the smallest currency unit" },
22166
+ description: { type: "string", description: "Description of the payment" },
22167
+ currency: { type: "string", description: "Currency code (defaults to CLP)" },
22168
+ customerEmail: { type: "string", description: "Customer email address" },
22169
+ entityId: { type: "string", description: "Optional entity ID to link the payment to" }
22170
+ },
22171
+ required: ["amount", "description"]
22172
+ },
22173
+ "payment.getStatus": {
22174
+ type: "object",
22175
+ properties: {
22176
+ entityId: { type: "string", description: "Payment entity ID to check status for" }
22177
+ },
22178
+ required: ["entityId"]
22045
22179
  }
22046
22180
  };
22047
22181
  return schemas[name] || { type: "object", properties: {} };
@@ -22118,7 +22252,7 @@ async function checkForDeletions(resources, organizationId, environment) {
22118
22252
  deletions.push({ type: "Agents", remote: remoteState.agents.length, local: payload.agents.length, deleted: deletedAgents });
22119
22253
  const deletedEntityTypes = remoteState.entityTypes.filter((et) => !localSlugs.entityTypes.has(et.slug)).map((et) => et.name);
22120
22254
  if (deletedEntityTypes.length > 0)
22121
- deletions.push({ type: "Entity types", remote: remoteState.entityTypes.length, local: payload.entityTypes.length, deleted: deletedEntityTypes });
22255
+ deletions.push({ type: "Data types", remote: remoteState.entityTypes.length, local: payload.entityTypes.length, deleted: deletedEntityTypes });
22122
22256
  const deletedRoles = remoteState.roles.filter((r) => !localSlugs.roles.has(r.name)).map((r) => r.name);
22123
22257
  if (deletedRoles.length > 0)
22124
22258
  deletions.push({ type: "Roles", remote: remoteState.roles.length, local: payload.roles.length, deleted: deletedRoles });
@@ -22223,7 +22357,7 @@ var syncCommand = new Command("sync").description("Sync resources to Convex and
22223
22357
  process.exit(1);
22224
22358
  }
22225
22359
  if (!jsonMode && !options.dryRun)
22226
- output.succeed(`Loaded ${resources.agents.length} agents, ${resources.entityTypes.length} entity types, ${resources.roles.length} roles`);
22360
+ output.succeed(`Loaded ${resources.agents.length} agents, ${resources.entityTypes.length} data types, ${resources.roles.length} roles`);
22227
22361
  } catch (error) {
22228
22362
  if (jsonMode) {
22229
22363
  console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }));
@@ -22255,7 +22389,7 @@ var syncCommand = new Command("sync").description("Sync resources to Convex and
22255
22389
  console.log(source_default.bold("Dry run \u2014 nothing will be synced"));
22256
22390
  console.log();
22257
22391
  console.log(source_default.gray(" Agents:"), payload.agents.map((a) => a.slug).join(", ") || "none");
22258
- console.log(source_default.gray(" Entity types:"), payload.entityTypes.map((et) => et.slug).join(", ") || "none");
22392
+ console.log(source_default.gray(" Data types:"), payload.entityTypes.map((et) => et.slug).join(", ") || "none");
22259
22393
  console.log(source_default.gray(" Roles:"), payload.roles.map((r) => r.name).join(", ") || "none");
22260
22394
  console.log(source_default.gray(" Triggers:"), (payload.triggers || []).map((t) => t.slug).join(", ") || "none");
22261
22395
  if (deletions.length > 0) {
@@ -22421,7 +22555,7 @@ var devCommand = new Command("dev").description("Watch files and sync to develop
22421
22555
  spinner.start("Loading resources");
22422
22556
  try {
22423
22557
  loadedResources = await loadAllResources(cwd);
22424
- spinner.succeed(`Loaded ${loadedResources.agents.length} agents, ${loadedResources.entityTypes.length} entity types, ${loadedResources.roles.length} roles, ${loadedResources.customTools.length} custom tools, ${loadedResources.evalSuites.length} eval suites, ${loadedResources.triggers.length} triggers, ${loadedResources.fixtures.length} fixtures`);
22558
+ spinner.succeed(`Loaded ${loadedResources.agents.length} agents, ${loadedResources.entityTypes.length} data types, ${loadedResources.roles.length} roles, ${loadedResources.customTools.length} custom tools, ${loadedResources.evalSuites.length} eval suites, ${loadedResources.triggers.length} triggers, ${loadedResources.fixtures.length} fixtures`);
22425
22559
  for (const err of loadedResources.errors) {
22426
22560
  console.log(source_default.red(" \u2716"), err);
22427
22561
  }
@@ -22634,7 +22768,7 @@ var deployCommand = new Command("deploy").description("Deploy all resources to p
22634
22768
  try {
22635
22769
  resources = await loadAllResources(cwd);
22636
22770
  if (!jsonMode)
22637
- spinner.succeed(`Loaded ${resources.agents.length} agents, ${resources.entityTypes.length} entity types, ${resources.roles.length} roles, ${resources.customTools.length} custom tools, ${resources.evalSuites.length} eval suites`);
22771
+ spinner.succeed(`Loaded ${resources.agents.length} agents, ${resources.entityTypes.length} data types, ${resources.roles.length} roles, ${resources.customTools.length} custom tools, ${resources.evalSuites.length} eval suites`);
22638
22772
  for (const err of resources.errors) {
22639
22773
  if (!jsonMode)
22640
22774
  console.log(source_default.red(" \u2716"), err);
@@ -22698,7 +22832,7 @@ var deployCommand = new Command("deploy").description("Deploy all resources to p
22698
22832
  console.log(source_default.gray(" -"), `${source_default.cyan(agent.name)} (${agent.slug}) v${agent.version}`);
22699
22833
  }
22700
22834
  console.log();
22701
- console.log("Entity types:");
22835
+ console.log("Data types:");
22702
22836
  for (const et of resources.entityTypes) {
22703
22837
  console.log(source_default.gray(" -"), source_default.cyan(et.name), `(${et.slug})`);
22704
22838
  }
@@ -22976,7 +23110,7 @@ var whoamiCommand = new Command("whoami").description("Show current logged in us
22976
23110
  });
22977
23111
 
22978
23112
  // src/cli/commands/add.ts
22979
- var addCommand = new Command("add").description("Scaffold a new resource").argument("<type>", "Resource type: agent, entity-type, role, eval, trigger, or fixture").argument("<name>", "Resource name").action(async (type, name) => {
23113
+ var addCommand = new Command("add").description("Scaffold a new resource").argument("<type>", "Resource type: agent, data-type, role, eval, trigger, or fixture").argument("<name>", "Resource name").action(async (type, name) => {
22980
23114
  const cwd = process.cwd();
22981
23115
  console.log();
22982
23116
  if (!hasProject(cwd)) {
@@ -23003,17 +23137,19 @@ var addCommand = new Command("add").description("Scaffold a new resource").argum
23003
23137
  console.log(source_default.yellow("Agent already exists:"), `agents/${slug}.ts`);
23004
23138
  }
23005
23139
  break;
23140
+ case "data-type":
23141
+ case "datatype":
23006
23142
  case "entity-type":
23007
23143
  case "entitytype":
23008
23144
  case "type":
23009
23145
  result = scaffoldEntityType(cwd, displayName, slug);
23010
23146
  if (result.createdFiles.length > 0) {
23011
- console.log(source_default.green("\u2713"), `Created entity type "${displayName}"`);
23147
+ console.log(source_default.green("\u2713"), `Created data type "${displayName}"`);
23012
23148
  for (const file of result.createdFiles) {
23013
23149
  console.log(source_default.gray(" \u2192"), file);
23014
23150
  }
23015
23151
  } else {
23016
- console.log(source_default.yellow("Entity type already exists:"), `entity-types/${slug}.ts`);
23152
+ console.log(source_default.yellow("Data type already exists:"), `entity-types/${slug}.ts`);
23017
23153
  }
23018
23154
  break;
23019
23155
  case "role":
@@ -23070,10 +23206,10 @@ var addCommand = new Command("add").description("Scaffold a new resource").argum
23070
23206
  console.log();
23071
23207
  console.log("Available types:");
23072
23208
  console.log(source_default.gray(" -"), source_default.cyan("agent"), "- Create an AI agent");
23073
- console.log(source_default.gray(" -"), source_default.cyan("entity-type"), "- Create an entity type schema");
23209
+ console.log(source_default.gray(" -"), source_default.cyan("data-type"), "- Create a data type schema");
23074
23210
  console.log(source_default.gray(" -"), source_default.cyan("role"), "- Create a role with permissions");
23075
23211
  console.log(source_default.gray(" -"), source_default.cyan("eval"), "- Create an eval suite (YAML)");
23076
- console.log(source_default.gray(" -"), source_default.cyan("trigger"), "- Create an entity trigger");
23212
+ console.log(source_default.gray(" -"), source_default.cyan("trigger"), "- Create a data trigger");
23077
23213
  console.log(source_default.gray(" -"), source_default.cyan("fixture"), "- Create a test data fixture (YAML)");
23078
23214
  console.log();
23079
23215
  process.exit(1);
@@ -23153,7 +23289,7 @@ var statusCommand = new Command("status").description("Compare local vs remote s
23153
23289
  try {
23154
23290
  localResources = await loadAllResources(cwd);
23155
23291
  if (!jsonMode) {
23156
- spinner.succeed(`Loaded ${localResources.agents.length} agents, ${localResources.entityTypes.length} entity types, ${localResources.roles.length} roles, ${localResources.customTools.length} custom tools, ${localResources.evalSuites.length} eval suites`);
23292
+ spinner.succeed(`Loaded ${localResources.agents.length} agents, ${localResources.entityTypes.length} data types, ${localResources.roles.length} roles, ${localResources.customTools.length} custom tools, ${localResources.evalSuites.length} eval suites`);
23157
23293
  for (const err of localResources.errors) {
23158
23294
  console.log(source_default.red(" \u2716"), err);
23159
23295
  }
@@ -23241,10 +23377,10 @@ var statusCommand = new Command("status").description("Compare local vs remote s
23241
23377
  }
23242
23378
  }
23243
23379
  console.log();
23244
- console.log(source_default.bold("Entity Types"));
23380
+ console.log(source_default.bold("Data Types"));
23245
23381
  console.log(source_default.gray("\u2500".repeat(60)));
23246
23382
  if (localResources.entityTypes.length === 0 && devState.entityTypes.length === 0) {
23247
- console.log(source_default.gray(" No entity types"));
23383
+ console.log(source_default.gray(" No data types"));
23248
23384
  } else {
23249
23385
  for (const et of localResources.entityTypes) {
23250
23386
  const remote = devState.entityTypes.find((r) => r.slug === et.slug);
@@ -23390,9 +23526,9 @@ function generateEntityTypeFile(entityType) {
23390
23526
  if (entityType.displayConfig) {
23391
23527
  parts.push(` displayConfig: ${stringifyValue(entityType.displayConfig, 2)}`);
23392
23528
  }
23393
- return `import { defineEntityType } from 'struere'
23529
+ return `import { defineData } from 'struere'
23394
23530
 
23395
- export default defineEntityType({
23531
+ export default defineData({
23396
23532
  ${parts.join(`,
23397
23533
  `)},
23398
23534
  })
@@ -24001,20 +24137,20 @@ function flattenEntityForTable(entity) {
24001
24137
  status: entity.status
24002
24138
  };
24003
24139
  }
24004
- var entitiesCommand = new Command("entities").description("Manage entity data");
24005
- entitiesCommand.command("types").description("List available entity types").option("--env <environment>", "Environment (development|production)", "development").option("--json", "Output raw JSON").action(async (opts) => {
24140
+ var entitiesCommand = new Command("data").description("Manage data records");
24141
+ entitiesCommand.command("types").description("List available data types").option("--env <environment>", "Environment (development|production)", "development").option("--json", "Output raw JSON").action(async (opts) => {
24006
24142
  await ensureAuth();
24007
24143
  const spinner = ora();
24008
24144
  const env2 = opts.env;
24009
24145
  const orgId = getOrgId();
24010
- spinner.start("Fetching entity types");
24146
+ spinner.start("Fetching data types");
24011
24147
  const { data, error } = await queryEntityTypes(env2, orgId);
24012
24148
  if (error || !data) {
24013
- spinner.fail("Failed to fetch entity types");
24149
+ spinner.fail("Failed to fetch data types");
24014
24150
  console.log(source_default.red("Error:"), error);
24015
24151
  process.exit(1);
24016
24152
  }
24017
- spinner.succeed("Entity types loaded");
24153
+ spinner.succeed("Data types loaded");
24018
24154
  const types = data;
24019
24155
  if (opts.json) {
24020
24156
  console.log(JSON.stringify(types, null, 2));
@@ -24037,12 +24173,12 @@ entitiesCommand.command("types").description("List available entity types").opti
24037
24173
  }));
24038
24174
  console.log();
24039
24175
  });
24040
- entitiesCommand.command("list <type>").description("List entities of a type").option("--env <environment>", "Environment (development|production)", "development").option("--status <status>", "Filter by status").option("--limit <n>", "Maximum results", "50").option("--json", "Output raw JSON").action(async (type, opts) => {
24176
+ entitiesCommand.command("list <type>").description("List records of a type").option("--env <environment>", "Environment (development|production)", "development").option("--status <status>", "Filter by status").option("--limit <n>", "Maximum results", "50").option("--json", "Output raw JSON").action(async (type, opts) => {
24041
24177
  await ensureAuth();
24042
24178
  const spinner = ora();
24043
24179
  const env2 = opts.env;
24044
24180
  const orgId = getOrgId();
24045
- spinner.start(`Fetching ${type} entities`);
24181
+ spinner.start(`Fetching ${type} records`);
24046
24182
  const [entitiesResult, typeResult] = await Promise.all([
24047
24183
  queryEntities(type, env2, {
24048
24184
  status: opts.status,
@@ -24051,12 +24187,12 @@ entitiesCommand.command("list <type>").description("List entities of a type").op
24051
24187
  queryEntityTypeBySlug(type, env2, orgId)
24052
24188
  ]);
24053
24189
  if (entitiesResult.error || !entitiesResult.data) {
24054
- spinner.fail(`Failed to fetch ${type} entities`);
24190
+ spinner.fail(`Failed to fetch ${type} records`);
24055
24191
  console.log(source_default.red("Error:"), entitiesResult.error);
24056
24192
  process.exit(1);
24057
24193
  }
24058
24194
  const entities = entitiesResult.data;
24059
- spinner.succeed(`Found ${entities.length} ${type} entities`);
24195
+ spinner.succeed(`Found ${entities.length} ${type} records`);
24060
24196
  if (opts.json) {
24061
24197
  console.log(JSON.stringify(entities, null, 2));
24062
24198
  return;
@@ -24069,27 +24205,27 @@ entitiesCommand.command("list <type>").description("List entities of a type").op
24069
24205
  renderTable(columns, entities.map(flattenEntityForTable));
24070
24206
  console.log();
24071
24207
  });
24072
- entitiesCommand.command("get <id>").description("Get entity details").option("--env <environment>", "Environment (development|production)", "development").option("--json", "Output raw JSON").action(async (rawId, opts) => {
24208
+ entitiesCommand.command("get <id>").description("Get record details").option("--env <environment>", "Environment (development|production)", "development").option("--json", "Output raw JSON").action(async (rawId, opts) => {
24073
24209
  await ensureAuth();
24074
24210
  const spinner = ora();
24075
24211
  const env2 = opts.env;
24076
24212
  const orgId = getOrgId();
24077
- spinner.start("Resolving entity ID");
24213
+ spinner.start("Resolving record ID");
24078
24214
  const resolved = await resolveEntityId(rawId, env2, orgId);
24079
24215
  if (resolved.error || !resolved.data) {
24080
- spinner.fail("Entity not found");
24081
- console.log(source_default.red("Error:"), resolved.error || `No entity matched "${rawId}"`);
24216
+ spinner.fail("Record not found");
24217
+ console.log(source_default.red("Error:"), resolved.error || `No record matched "${rawId}"`);
24082
24218
  process.exit(1);
24083
24219
  }
24084
24220
  const id = resolved.data;
24085
- spinner.text = "Fetching entity";
24221
+ spinner.text = "Fetching record";
24086
24222
  const { data, error } = await queryEntity(id, env2, orgId);
24087
24223
  if (error || !data) {
24088
- spinner.fail("Failed to fetch entity");
24089
- console.log(source_default.red("Error:"), error || "Entity not found");
24224
+ spinner.fail("Failed to fetch record");
24225
+ console.log(source_default.red("Error:"), error || "Record not found");
24090
24226
  process.exit(1);
24091
24227
  }
24092
- spinner.succeed("Entity loaded");
24228
+ spinner.succeed("Record loaded");
24093
24229
  const result = data;
24094
24230
  if (opts.json) {
24095
24231
  console.log(JSON.stringify(result, null, 2));
@@ -24117,7 +24253,7 @@ entitiesCommand.command("get <id>").description("Get entity details").option("--
24117
24253
  }
24118
24254
  console.log();
24119
24255
  });
24120
- entitiesCommand.command("create <type>").description("Create a new entity").option("--env <environment>", "Environment (development|production)", "development").option("--data <json>", "Entity data as JSON").option("--status <status>", "Initial status").option("--json", "Output raw JSON").action(async (type, opts) => {
24256
+ entitiesCommand.command("create <type>").description("Create a new record").option("--env <environment>", "Environment (development|production)", "development").option("--data <json>", "Record data as JSON").option("--status <status>", "Initial status").option("--json", "Output raw JSON").action(async (type, opts) => {
24121
24257
  await ensureAuth();
24122
24258
  const spinner = ora();
24123
24259
  const env2 = opts.env;
@@ -24137,7 +24273,7 @@ entitiesCommand.command("create <type>").description("Create a new entity").opti
24137
24273
  spinner.start(`Fetching ${type} schema`);
24138
24274
  const { data: typeData, error: error2 } = await queryEntityTypeBySlug(type, env2, orgId);
24139
24275
  if (error2 || !typeData) {
24140
- spinner.fail(`Entity type not found: ${type}`);
24276
+ spinner.fail(`Data type not found: ${type}`);
24141
24277
  console.log(source_default.red("Error:"), error2 || "Not found");
24142
24278
  process.exit(1);
24143
24279
  }
@@ -24146,7 +24282,7 @@ entitiesCommand.command("create <type>").description("Create a new entity").opti
24146
24282
  const entityType = typeData;
24147
24283
  const schema = entityType.schema;
24148
24284
  if (!schema?.properties) {
24149
- console.log(source_default.red("Entity type has no schema properties defined"));
24285
+ console.log(source_default.red("Data type has no schema properties defined"));
24150
24286
  process.exit(1);
24151
24287
  }
24152
24288
  data = {};
@@ -24175,14 +24311,14 @@ entitiesCommand.command("create <type>").description("Create a new entity").opti
24175
24311
  }
24176
24312
  console.log();
24177
24313
  }
24178
- spinner.start(`Creating ${type} entity`);
24314
+ spinner.start(`Creating ${type} record`);
24179
24315
  const { data: result, error } = await createEntity(type, data, env2, opts.status, orgId);
24180
24316
  if (error) {
24181
- spinner.fail("Failed to create entity");
24317
+ spinner.fail("Failed to create record");
24182
24318
  console.log(source_default.red("Error:"), error);
24183
24319
  process.exit(1);
24184
24320
  }
24185
- spinner.succeed(`Entity created`);
24321
+ spinner.succeed(`Record created`);
24186
24322
  if (opts.json) {
24187
24323
  console.log(JSON.stringify({ id: result }, null, 2));
24188
24324
  } else {
@@ -24191,7 +24327,7 @@ entitiesCommand.command("create <type>").description("Create a new entity").opti
24191
24327
  console.log();
24192
24328
  }
24193
24329
  });
24194
- entitiesCommand.command("update <id>").description("Update an entity").option("--env <environment>", "Environment (development|production)", "development").option("--data <json>", "Update data as JSON").option("--status <status>", "New status").option("--json", "Output raw JSON").action(async (rawId, opts) => {
24330
+ entitiesCommand.command("update <id>").description("Update a record").option("--env <environment>", "Environment (development|production)", "development").option("--data <json>", "Update data as JSON").option("--status <status>", "New status").option("--json", "Output raw JSON").action(async (rawId, opts) => {
24195
24331
  await ensureAuth();
24196
24332
  const spinner = ora();
24197
24333
  const env2 = opts.env;
@@ -24209,63 +24345,63 @@ entitiesCommand.command("update <id>").description("Update an entity").option("-
24209
24345
  process.exit(1);
24210
24346
  }
24211
24347
  }
24212
- spinner.start("Resolving entity ID");
24348
+ spinner.start("Resolving record ID");
24213
24349
  const resolved = await resolveEntityId(rawId, env2, orgId);
24214
24350
  if (resolved.error || !resolved.data) {
24215
- spinner.fail("Entity not found");
24216
- console.log(source_default.red("Error:"), resolved.error || `No entity matched "${rawId}"`);
24351
+ spinner.fail("Record not found");
24352
+ console.log(source_default.red("Error:"), resolved.error || `No record matched "${rawId}"`);
24217
24353
  process.exit(1);
24218
24354
  }
24219
24355
  const id = resolved.data;
24220
- spinner.text = "Updating entity";
24356
+ spinner.text = "Updating record";
24221
24357
  const { data: result, error } = await updateEntity(id, data, env2, opts.status, orgId);
24222
24358
  if (error) {
24223
- spinner.fail("Failed to update entity");
24359
+ spinner.fail("Failed to update record");
24224
24360
  console.log(source_default.red("Error:"), error);
24225
24361
  process.exit(1);
24226
24362
  }
24227
- spinner.succeed("Entity updated");
24363
+ spinner.succeed("Record updated");
24228
24364
  if (opts.json) {
24229
24365
  console.log(JSON.stringify(result, null, 2));
24230
24366
  } else {
24231
24367
  console.log();
24232
- console.log(source_default.green(" Entity updated successfully"));
24368
+ console.log(source_default.green(" Record updated successfully"));
24233
24369
  console.log();
24234
24370
  }
24235
24371
  });
24236
- entitiesCommand.command("delete <id>").description("Delete an entity").option("--env <environment>", "Environment (development|production)", "development").option("--yes", "Skip confirmation").option("--json", "Output raw JSON").action(async (rawId, opts) => {
24372
+ entitiesCommand.command("delete <id>").description("Delete a record").option("--env <environment>", "Environment (development|production)", "development").option("--yes", "Skip confirmation").option("--json", "Output raw JSON").action(async (rawId, opts) => {
24237
24373
  await ensureAuth();
24238
24374
  const spinner = ora();
24239
24375
  const env2 = opts.env;
24240
24376
  const orgId = getOrgId();
24241
24377
  const jsonMode = !!opts.json;
24242
24378
  if (!jsonMode)
24243
- spinner.start("Resolving entity ID");
24379
+ spinner.start("Resolving record ID");
24244
24380
  const resolved = await resolveEntityId(rawId, env2, orgId);
24245
24381
  if (resolved.error || !resolved.data) {
24246
24382
  if (jsonMode) {
24247
- console.log(JSON.stringify({ success: false, error: resolved.error || `No entity matched "${rawId}"` }));
24383
+ console.log(JSON.stringify({ success: false, error: resolved.error || `No record matched "${rawId}"` }));
24248
24384
  } else {
24249
- spinner.fail("Entity not found");
24250
- console.log(source_default.red("Error:"), resolved.error || `No entity matched "${rawId}"`);
24385
+ spinner.fail("Record not found");
24386
+ console.log(source_default.red("Error:"), resolved.error || `No record matched "${rawId}"`);
24251
24387
  }
24252
24388
  process.exit(1);
24253
24389
  }
24254
24390
  const id = resolved.data;
24255
24391
  if (!jsonMode)
24256
- spinner.text = "Fetching entity";
24392
+ spinner.text = "Fetching record";
24257
24393
  const { data, error: fetchError } = await queryEntity(id, env2, orgId);
24258
24394
  if (fetchError || !data) {
24259
24395
  if (jsonMode) {
24260
- console.log(JSON.stringify({ success: false, error: fetchError || "Entity not found" }));
24396
+ console.log(JSON.stringify({ success: false, error: fetchError || "Record not found" }));
24261
24397
  } else {
24262
- spinner.fail("Failed to fetch entity");
24263
- console.log(source_default.red("Error:"), fetchError || "Entity not found");
24398
+ spinner.fail("Failed to fetch record");
24399
+ console.log(source_default.red("Error:"), fetchError || "Record not found");
24264
24400
  }
24265
24401
  process.exit(1);
24266
24402
  }
24267
24403
  if (!jsonMode)
24268
- spinner.succeed("Entity loaded");
24404
+ spinner.succeed("Record loaded");
24269
24405
  const result = data;
24270
24406
  const entity = result.entity;
24271
24407
  const entityType = result.entityType;
@@ -24283,7 +24419,7 @@ entitiesCommand.command("delete <id>").description("Delete an entity").option("-
24283
24419
  }
24284
24420
  if (!opts.yes && !jsonMode && isInteractive2()) {
24285
24421
  const confirmed = await esm_default2({
24286
- message: "Are you sure you want to delete this entity?",
24422
+ message: "Are you sure you want to delete this record?",
24287
24423
  default: false
24288
24424
  });
24289
24425
  if (!confirmed) {
@@ -24292,13 +24428,13 @@ entitiesCommand.command("delete <id>").description("Delete an entity").option("-
24292
24428
  }
24293
24429
  }
24294
24430
  if (!jsonMode)
24295
- spinner.start("Deleting entity");
24431
+ spinner.start("Deleting record");
24296
24432
  const { error } = await removeEntity(id, env2, orgId);
24297
24433
  if (error) {
24298
24434
  if (jsonMode) {
24299
24435
  console.log(JSON.stringify({ success: false, error }));
24300
24436
  } else {
24301
- spinner.fail("Failed to delete entity");
24437
+ spinner.fail("Failed to delete record");
24302
24438
  console.log(source_default.red("Error:"), error);
24303
24439
  }
24304
24440
  process.exit(1);
@@ -24306,11 +24442,11 @@ entitiesCommand.command("delete <id>").description("Delete an entity").option("-
24306
24442
  if (jsonMode) {
24307
24443
  console.log(JSON.stringify({ success: true, id }));
24308
24444
  } else {
24309
- spinner.succeed("Entity deleted");
24445
+ spinner.succeed("Record deleted");
24310
24446
  console.log();
24311
24447
  }
24312
24448
  });
24313
- entitiesCommand.command("search <type> <query>").description("Search entities").option("--env <environment>", "Environment (development|production)", "development").option("--limit <n>", "Maximum results", "25").option("--json", "Output raw JSON").action(async (type, query, opts) => {
24449
+ entitiesCommand.command("search <type> <query>").description("Search records").option("--env <environment>", "Environment (development|production)", "development").option("--limit <n>", "Maximum results", "25").option("--json", "Output raw JSON").action(async (type, query, opts) => {
24314
24450
  await ensureAuth();
24315
24451
  const spinner = ora();
24316
24452
  const env2 = opts.env;
@@ -25313,7 +25449,7 @@ async function setIntegrationStatus(provider, env2, status) {
25313
25449
  }
25314
25450
 
25315
25451
  // src/cli/commands/integration.ts
25316
- var VALID_PROVIDERS = ["airtable", "resend"];
25452
+ var VALID_PROVIDERS = ["airtable", "resend", "flow"];
25317
25453
  async function ensureAuth3() {
25318
25454
  const cwd = process.cwd();
25319
25455
  const nonInteractive = !isInteractive2();
@@ -25366,6 +25502,8 @@ function getProviderHelp(provider) {
25366
25502
  return `Usage: struere integration airtable --token <pat> [--base-id <id>] [--test]`;
25367
25503
  case "resend":
25368
25504
  return `Usage: struere integration resend --from-email <email> [--from-name <name>] [--reply-to <email>]`;
25505
+ case "flow":
25506
+ return `Usage: struere integration flow --api-url <url> --api-key <key> --secret-key <secret> [--return-url <url>]`;
25369
25507
  default:
25370
25508
  return "";
25371
25509
  }
@@ -25393,9 +25531,23 @@ function buildConfigFromOpts(provider, opts) {
25393
25531
  return null;
25394
25532
  return config;
25395
25533
  }
25534
+ if (provider === "flow") {
25535
+ const config = {};
25536
+ if (opts.apiUrl)
25537
+ config.apiUrl = opts.apiUrl;
25538
+ if (opts.apiKey)
25539
+ config.apiKey = opts.apiKey;
25540
+ if (opts.secretKey)
25541
+ config.secretKey = opts.secretKey;
25542
+ if (opts.returnUrl)
25543
+ config.returnUrl = opts.returnUrl;
25544
+ if (Object.keys(config).length === 0)
25545
+ return null;
25546
+ return config;
25547
+ }
25396
25548
  return null;
25397
25549
  }
25398
- var integrationCommand = new Command("integration").description("Manage integrations").argument("[provider]", "Integration provider (airtable, resend)").option("--env <environment>", "Environment (development|production)", "development").option("--token <pat>", "Personal access token (airtable)").option("--base-id <id>", "Default base ID (airtable)").option("--from-email <email>", "From email address (resend)").option("--from-name <name>", "From display name (resend)").option("--reply-to <email>", "Reply-to address (resend)").option("--test", "Test the connection after saving").option("--remove", "Remove integration config").option("--enable", "Enable integration").option("--disable", "Disable integration").option("--status", "Show current config status").option("--yes", "Skip confirmation prompts").option("--json", "Output raw JSON").action(async (provider, opts) => {
25550
+ var integrationCommand = new Command("integration").description("Manage integrations").argument("[provider]", "Integration provider (airtable, resend, flow)").option("--env <environment>", "Environment (development|production)", "development").option("--token <pat>", "Personal access token (airtable)").option("--base-id <id>", "Default base ID (airtable)").option("--from-email <email>", "From email address (resend)").option("--from-name <name>", "From display name (resend)").option("--reply-to <email>", "Reply-to address (resend)").option("--api-url <url>", "API URL (flow)").option("--api-key <key>", "API key (flow)").option("--secret-key <secret>", "Secret key (flow)").option("--return-url <url>", "Return URL after payment (flow)").option("--test", "Test the connection after saving").option("--remove", "Remove integration config").option("--enable", "Enable integration").option("--disable", "Disable integration").option("--status", "Show current config status").option("--yes", "Skip confirmation prompts").option("--json", "Output raw JSON").action(async (provider, opts) => {
25399
25551
  await ensureAuth3();
25400
25552
  const env2 = opts.env;
25401
25553
  const out = createOutput();
@@ -25570,10 +25722,154 @@ var integrationCommand = new Command("integration").description("Manage integrat
25570
25722
  }
25571
25723
  console.log();
25572
25724
  });
25725
+
25726
+ // src/cli/commands/compile-prompt.ts
25727
+ var compilePromptCommand = new Command("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) => {
25728
+ acc.push(val);
25729
+ return acc;
25730
+ }, []).option("--json", "Output full JSON (raw + compiled + context)").option("--raw", "Show raw uncompiled template instead of compiled").action(async (agentSlug, options) => {
25731
+ const spinner = ora();
25732
+ const cwd = process.cwd();
25733
+ const nonInteractive = !isInteractive2();
25734
+ const jsonMode = !!options.json;
25735
+ if (!hasProject(cwd)) {
25736
+ if (nonInteractive) {
25737
+ if (jsonMode) {
25738
+ console.log(JSON.stringify({ success: false, error: "No struere.json found" }));
25739
+ } else {
25740
+ console.log(source_default.red("No struere.json found. Run struere init first."));
25741
+ }
25742
+ process.exit(1);
25743
+ }
25744
+ console.log(source_default.yellow("No struere.json found - initializing project..."));
25745
+ console.log();
25746
+ const success = await runInit(cwd);
25747
+ if (!success) {
25748
+ process.exit(1);
25749
+ }
25750
+ console.log();
25751
+ }
25752
+ const project = loadProject(cwd);
25753
+ if (!project) {
25754
+ if (jsonMode) {
25755
+ console.log(JSON.stringify({ success: false, error: "Failed to load struere.json" }));
25756
+ } else {
25757
+ console.log(source_default.red("Failed to load struere.json"));
25758
+ }
25759
+ process.exit(1);
25760
+ }
25761
+ let credentials = loadCredentials();
25762
+ const apiKey = getApiKey();
25763
+ if (!credentials && !apiKey) {
25764
+ if (nonInteractive) {
25765
+ if (jsonMode) {
25766
+ console.log(JSON.stringify({ success: false, error: "Not authenticated. Set STRUERE_API_KEY or run struere login." }));
25767
+ } else {
25768
+ console.log(source_default.red("Not authenticated. Set STRUERE_API_KEY or run struere login."));
25769
+ }
25770
+ process.exit(1);
25771
+ }
25772
+ console.log(source_default.yellow("Not logged in - authenticating..."));
25773
+ console.log();
25774
+ credentials = await performLogin();
25775
+ if (!credentials) {
25776
+ console.log(source_default.red("Authentication failed"));
25777
+ process.exit(1);
25778
+ }
25779
+ console.log();
25780
+ }
25781
+ const threadMetadata = {};
25782
+ for (const param of options.param) {
25783
+ const eqIndex = param.indexOf("=");
25784
+ if (eqIndex === -1) {
25785
+ if (jsonMode) {
25786
+ console.log(JSON.stringify({ success: false, error: `Invalid param format: ${param}. Use key=value.` }));
25787
+ } else {
25788
+ console.log(source_default.red(`Invalid param format: ${param}. Use key=value.`));
25789
+ }
25790
+ process.exit(1);
25791
+ }
25792
+ const key = param.slice(0, eqIndex);
25793
+ const value = param.slice(eqIndex + 1);
25794
+ threadMetadata[key] = value;
25795
+ }
25796
+ const environment = options.env;
25797
+ if (!jsonMode) {
25798
+ spinner.start(`Compiling prompt for ${source_default.cyan(agentSlug)} (${environment})`);
25799
+ }
25800
+ const doCompile = async () => {
25801
+ return compilePrompt({
25802
+ slug: agentSlug,
25803
+ environment,
25804
+ message: options.message,
25805
+ channel: options.channel,
25806
+ threadMetadata: Object.keys(threadMetadata).length > 0 ? threadMetadata : undefined
25807
+ });
25808
+ };
25809
+ let { result, error } = await doCompile();
25810
+ if (error && isAuthError(error) && !nonInteractive) {
25811
+ if (!jsonMode)
25812
+ spinner.fail("Session expired - re-authenticating...");
25813
+ clearCredentials();
25814
+ credentials = await performLogin();
25815
+ if (!credentials) {
25816
+ if (jsonMode) {
25817
+ console.log(JSON.stringify({ success: false, error: "Authentication failed" }));
25818
+ } else {
25819
+ console.log(source_default.red("Authentication failed"));
25820
+ }
25821
+ process.exit(1);
25822
+ }
25823
+ const retry = await doCompile();
25824
+ result = retry.result;
25825
+ error = retry.error;
25826
+ if (!jsonMode && !error)
25827
+ spinner.succeed("Compiled prompt");
25828
+ }
25829
+ if (error) {
25830
+ if (jsonMode) {
25831
+ console.log(JSON.stringify({ success: false, error }));
25832
+ } else {
25833
+ spinner.fail("Failed to compile prompt");
25834
+ console.log(source_default.red("Error:"), error);
25835
+ }
25836
+ process.exit(1);
25837
+ }
25838
+ if (!result) {
25839
+ if (jsonMode) {
25840
+ console.log(JSON.stringify({ success: false, error: "No result returned" }));
25841
+ } else {
25842
+ spinner.fail("No result returned");
25843
+ }
25844
+ process.exit(1);
25845
+ }
25846
+ if (!jsonMode)
25847
+ spinner.succeed("Compiled prompt");
25848
+ if (jsonMode) {
25849
+ console.log(JSON.stringify({
25850
+ success: true,
25851
+ raw: result.raw,
25852
+ compiled: result.compiled,
25853
+ context: result.context
25854
+ }, null, 2));
25855
+ } else if (options.raw) {
25856
+ console.log();
25857
+ console.log(source_default.bold("Raw System Prompt"));
25858
+ console.log(source_default.gray("\u2500".repeat(60)));
25859
+ console.log(result.raw);
25860
+ console.log(source_default.gray("\u2500".repeat(60)));
25861
+ } else {
25862
+ console.log();
25863
+ console.log(source_default.bold("Compiled System Prompt"));
25864
+ console.log(source_default.gray("\u2500".repeat(60)));
25865
+ console.log(result.compiled);
25866
+ console.log(source_default.gray("\u2500".repeat(60)));
25867
+ }
25868
+ });
25573
25869
  // package.json
25574
25870
  var package_default = {
25575
25871
  name: "struere",
25576
- version: "0.9.6",
25872
+ version: "0.9.7",
25577
25873
  description: "Build, test, and deploy AI agents",
25578
25874
  keywords: [
25579
25875
  "ai",
@@ -25688,4 +25984,5 @@ program.addCommand(docsCommand);
25688
25984
  program.addCommand(evalCommand);
25689
25985
  program.addCommand(templatesCommand);
25690
25986
  program.addCommand(integrationCommand);
25987
+ program.addCommand(compilePromptCommand);
25691
25988
  program.parse();