@ollie-shop/cli 1.1.0 → 1.2.1

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/index.js CHANGED
@@ -50,6 +50,14 @@ function HelpCommand() {
50
50
  /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "component create|list" }) }),
51
51
  /* @__PURE__ */ jsx(Text, { children: "Create or list components" })
52
52
  ] }),
53
+ /* @__PURE__ */ jsxs(Box, { children: [
54
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "deploy" }) }),
55
+ /* @__PURE__ */ jsx(Text, { children: "Bundle and upload a component/function build" })
56
+ ] }),
57
+ /* @__PURE__ */ jsxs(Box, { children: [
58
+ /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "status" }) }),
59
+ /* @__PURE__ */ jsx(Text, { children: "Check or poll a build status" })
60
+ ] }),
53
61
  /* @__PURE__ */ jsxs(Box, { children: [
54
62
  /* @__PURE__ */ jsx(Box, { width: 24, children: /* @__PURE__ */ jsx(Text, { color: "green", children: "schema" }) }),
55
63
  /* @__PURE__ */ jsx(Text, { children: "Introspect resource schemas (JSON Schema)" })
@@ -112,7 +120,9 @@ function HelpCommand() {
112
120
  "-o json"
113
121
  ] }),
114
122
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop version create --store-id UUID --name v1 --active" }),
115
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop init --store-id UUID --version-id UUID" })
123
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop init --store-id UUID --version-id UUID" }),
124
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop deploy --component-id UUID --name FreeShippingBar --wait" }),
125
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "$ ollieshop status --build-id BUILD_ID --wait -o json" })
116
126
  ] })
117
127
  ] });
118
128
  }
@@ -1174,129 +1184,60 @@ function UnknownCommand({ command }) {
1174
1184
  ] });
1175
1185
  }
1176
1186
 
1177
- // src/core/schema.ts
1178
- import { z as z2 } from "zod";
1179
- import { zodToJsonSchema } from "zod-to-json-schema";
1180
- var PLATFORM_VENDORS = ["vtex", "shopify", "vnda", "custom"];
1181
- var storeCreateSchema = z2.object({
1182
- name: z2.string().min(1).describe("Store display name"),
1183
- platform: z2.enum(PLATFORM_VENDORS).describe("E-commerce platform vendor"),
1184
- platformStoreId: z2.string().min(1).describe("Platform-specific store identifier (e.g. account name)"),
1185
- logo: z2.string().url().optional().describe("Store logo URL"),
1186
- settings: z2.string().optional().describe("JSON settings string")
1187
- });
1188
- var storeListSchema = z2.object({}).describe("No parameters required");
1189
- var versionCreateSchema = z2.object({
1190
- storeId: z2.string().uuid().describe("Parent store UUID"),
1191
- name: z2.string().min(1).describe("Version name (e.g. v1, main)"),
1192
- active: z2.boolean().default(false).describe("Whether version is active"),
1193
- default: z2.boolean().default(false).describe("Whether this is the default version"),
1194
- template: z2.string().nullable().default(null).describe("Template name or null")
1195
- });
1196
- var versionListSchema = z2.object({
1197
- storeId: z2.string().uuid().describe("Store UUID to list versions for")
1198
- });
1199
- var componentCreateSchema = z2.object({
1200
- versionId: z2.string().uuid().describe("Parent version UUID"),
1201
- name: z2.string().min(1).describe("Component name (e.g. FreeShippingBar)"),
1202
- slot: z2.string().min(1).describe(
1203
- "Target slot (e.g. cart_header_full_page, shipping_address_details_form)"
1204
- ),
1205
- active: z2.boolean().default(true).describe("Whether component is active"),
1206
- props: z2.record(z2.unknown()).nullable().default(null).describe("Default component props as JSON object")
1207
- });
1208
- var componentListSchema = z2.object({
1209
- storeId: z2.string().uuid().describe("Store UUID"),
1210
- versionId: z2.string().uuid().optional().describe("Optional version UUID to filter by")
1211
- });
1212
- var functionCreateSchema = z2.object({
1213
- versionId: z2.string().uuid().describe("Parent version UUID"),
1214
- name: z2.string().min(1).describe("Function name"),
1215
- trigger: z2.string().min(1).describe("Function trigger (e.g. beforePayment, afterShipping)"),
1216
- active: z2.boolean().default(true).describe("Whether function is active")
1217
- });
1218
- var functionListSchema = z2.object({
1219
- versionId: z2.string().uuid().describe("Version UUID to list functions for")
1220
- });
1221
- var schemas = {
1222
- store: {
1223
- create: storeCreateSchema,
1224
- list: storeListSchema
1225
- },
1226
- version: {
1227
- create: versionCreateSchema,
1228
- list: versionListSchema
1229
- },
1230
- component: {
1231
- create: componentCreateSchema,
1232
- list: componentListSchema
1233
- },
1234
- function: {
1235
- create: functionCreateSchema,
1236
- list: functionListSchema
1237
- }
1238
- };
1239
- function getSchemaNames() {
1240
- const names = [];
1241
- for (const [resource, actions] of Object.entries(schemas)) {
1242
- names.push(resource);
1243
- for (const action of Object.keys(actions)) {
1244
- names.push(`${resource}.${action}`);
1245
- }
1187
+ // src/core/business-rule.ts
1188
+ var SELECT_FIELDS = "id, store_id, title, content, previous_content, versions_ids, components_ids, functions_ids, status, code_updated, created_at, updated_at";
1189
+ async function listBusinessRules(client, filters = {}) {
1190
+ let query = client.from("business_rules").select(SELECT_FIELDS).order("created_at", { ascending: false });
1191
+ if (filters.store_id !== void 0) {
1192
+ query = query.eq("store_id", filters.store_id);
1193
+ }
1194
+ if (filters.version_id !== void 0) {
1195
+ query = query.filter(
1196
+ "versions_ids",
1197
+ "cs",
1198
+ JSON.stringify([filters.version_id])
1199
+ );
1246
1200
  }
1247
- return names;
1248
- }
1249
- function getJsonSchema(name) {
1250
- const parts = name.split(".");
1251
- const resource = parts[0];
1252
- const action = parts[1];
1253
- if (!resource || !schemas[resource]) return null;
1254
- if (action) {
1255
- const schema = schemas[resource][action];
1256
- if (!schema) return null;
1257
- return zodToJsonSchema(schema, { name: `${resource}.${action}` });
1201
+ if (filters.code_updated !== void 0) {
1202
+ query = query.eq("code_updated", filters.code_updated);
1258
1203
  }
1259
- const result = {};
1260
- for (const [actionName, schema] of Object.entries(schemas[resource])) {
1261
- result[actionName] = zodToJsonSchema(schema, {
1262
- name: `${resource}.${actionName}`
1263
- });
1204
+ const { data, error } = await query;
1205
+ if (error) {
1206
+ return { error: { message: error.message } };
1264
1207
  }
1265
- return result;
1208
+ return { data };
1266
1209
  }
1267
-
1268
- // src/core/component.ts
1269
- async function createComponent(client, input) {
1270
- const parsed2 = componentCreateSchema.safeParse(input);
1271
- if (!parsed2.success) {
1272
- return {
1273
- error: { message: parsed2.error.issues.map((i) => i.message).join("; ") }
1274
- };
1275
- }
1276
- const { data, error } = await client.from("components").insert({
1277
- name: parsed2.data.name,
1278
- slot: parsed2.data.slot,
1279
- active: parsed2.data.active,
1280
- version_id: parsed2.data.versionId,
1281
- props: parsed2.data.props
1282
- }).select("id").single();
1210
+ async function getBusinessRule(client, id) {
1211
+ const { data, error } = await client.from("business_rules").select(SELECT_FIELDS).eq("id", id).single();
1283
1212
  if (error) {
1284
1213
  return { error: { message: error.message } };
1285
1214
  }
1286
- return { data: { id: data.id } };
1215
+ return { data };
1287
1216
  }
1288
- async function listComponents(client, storeId, versionId) {
1289
- let query = client.from("components").select(
1290
- "id, name, slot, active, version_id, props, created_at, versions!inner(id, name)"
1291
- ).eq("versions.store_id", storeId);
1292
- if (versionId) {
1293
- query = query.eq("versions.id", versionId);
1217
+ async function updateBusinessRule(client, id, input) {
1218
+ const { data: current, error: fetchError } = await client.from("business_rules").select("content").eq("id", id).single();
1219
+ if (fetchError) {
1220
+ return { error: { message: fetchError.message } };
1294
1221
  }
1295
- const { data, error } = await query;
1222
+ const updatePayload = {
1223
+ previous_content: current.content,
1224
+ content: input.content,
1225
+ code_updated: false
1226
+ };
1227
+ if (input.versions_ids !== void 0) {
1228
+ updatePayload.versions_ids = input.versions_ids;
1229
+ }
1230
+ if (input.components_ids !== void 0) {
1231
+ updatePayload.components_ids = input.components_ids;
1232
+ }
1233
+ if (input.functions_ids !== void 0) {
1234
+ updatePayload.functions_ids = input.functions_ids;
1235
+ }
1236
+ const { data, error } = await client.from("business_rules").update(updatePayload).eq("id", id).select("id").single();
1296
1237
  if (error) {
1297
1238
  return { error: { message: error.message } };
1298
1239
  }
1299
- return { data: data ?? [] };
1240
+ return { data: { id: data.id } };
1300
1241
  }
1301
1242
 
1302
1243
  // src/utils/output.ts
@@ -1451,22 +1392,13 @@ function getBoolFlag(flags, ...names) {
1451
1392
 
1452
1393
  // src/utils/supabase.ts
1453
1394
  import { createClient } from "@supabase/supabase-js";
1454
- function requireEnv(name) {
1455
- const value = process.env[name];
1456
- if (!value) {
1457
- throw new Error(
1458
- `Missing required environment variable: ${name}. Set it in your .env file or shell.`
1459
- );
1460
- }
1461
- return value;
1462
- }
1463
1395
  async function getAuthenticatedClient() {
1464
1396
  const credentials = await getCredentials();
1465
1397
  if (!credentials) {
1466
1398
  throw new Error("Not authenticated. Run `ollieshop login` first.");
1467
1399
  }
1468
- const supabaseUrl = requireEnv("OLLIE_SUPABASE_URL");
1469
- const supabaseAnonKey = requireEnv("OLLIE_SUPABASE_ANON_KEY");
1400
+ const supabaseUrl = process.env.OLLIE_SUPABASE_URL || "https://aazahtmqrhjqsyqoqdkm.supabase.co";
1401
+ const supabaseAnonKey = process.env.OLLIE_SUPABASE_ANON_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFhemFodG1xcmhqcXN5cW9xZGttIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDg2MzEwOTcsImV4cCI6MjA2NDIwNzA5N30.VuAbAyjDe0HcL09SZtQ-UmP1o7Z6qwGuOtvfFhnyAcM";
1470
1402
  const client = createClient(supabaseUrl, supabaseAnonKey, {
1471
1403
  auth: {
1472
1404
  autoRefreshToken: false,
@@ -1479,6 +1411,16 @@ async function getAuthenticatedClient() {
1479
1411
  });
1480
1412
  return client;
1481
1413
  }
1414
+ function getBuilderUrl() {
1415
+ return process.env.OLLIE_BUILDER_URL || "";
1416
+ }
1417
+ async function getAuthToken() {
1418
+ const credentials = await getCredentials();
1419
+ if (!credentials) {
1420
+ throw new Error("Not authenticated. Run `ollieshop login` first.");
1421
+ }
1422
+ return credentials.accessToken;
1423
+ }
1482
1424
  async function getOrganizationId(client) {
1483
1425
  const { data: org, error } = await client.from("organizations").select("id").order("created_at", { ascending: true }).limit(1).maybeSingle();
1484
1426
  if (error) {
@@ -1526,6 +1468,250 @@ function validateRequired(value, name) {
1526
1468
  return rejectControlChars(value.trim(), name);
1527
1469
  }
1528
1470
 
1471
+ // src/commands/business-rule-cmd.ts
1472
+ async function businessRuleCommand(parsed2) {
1473
+ const sub = parsed2.subcommand;
1474
+ if (sub === "list" || sub === "ls") return businessRuleListCommand(parsed2);
1475
+ if (sub === "get") return businessRuleGetCommand(parsed2);
1476
+ if (sub === "update") return businessRuleUpdateCommand(parsed2);
1477
+ console.error(
1478
+ `Unknown business-rule subcommand: ${sub}. Use: business-rule list | business-rule get | business-rule update`
1479
+ );
1480
+ process.exit(1);
1481
+ }
1482
+ async function businessRuleListCommand(parsed2) {
1483
+ const format = detectOutputFormat(parsed2.global.output);
1484
+ try {
1485
+ const storeId = getFlag(parsed2.flags, "store-id");
1486
+ const versionId = getFlag(parsed2.flags, "version-id");
1487
+ const codeUpdatedRaw = parsed2.flags["code-updated"];
1488
+ let codeUpdated;
1489
+ if (codeUpdatedRaw === "true" || codeUpdatedRaw === true) {
1490
+ codeUpdated = true;
1491
+ } else if (codeUpdatedRaw === "false") {
1492
+ codeUpdated = false;
1493
+ }
1494
+ if (storeId !== void 0) validateUuid(storeId, "store-id");
1495
+ if (versionId !== void 0) validateUuid(versionId, "version-id");
1496
+ const client = await getAuthenticatedClient();
1497
+ const result = await listBusinessRules(client, {
1498
+ store_id: storeId,
1499
+ version_id: versionId,
1500
+ code_updated: codeUpdated
1501
+ });
1502
+ outputResult(result, format, parsed2.global.fields);
1503
+ if (result.error) process.exit(1);
1504
+ } catch (err) {
1505
+ outputResult(
1506
+ {
1507
+ error: { message: err instanceof Error ? err.message : String(err) }
1508
+ },
1509
+ format
1510
+ );
1511
+ process.exit(1);
1512
+ }
1513
+ }
1514
+ async function businessRuleGetCommand(parsed2) {
1515
+ const format = detectOutputFormat(parsed2.global.output);
1516
+ try {
1517
+ const id = validateUuid(
1518
+ validateRequired(getFlag(parsed2.flags, "id"), "id"),
1519
+ "id"
1520
+ );
1521
+ const client = await getAuthenticatedClient();
1522
+ const result = await getBusinessRule(client, id);
1523
+ outputResult(result, format, parsed2.global.fields);
1524
+ if (result.error) process.exit(1);
1525
+ } catch (err) {
1526
+ outputResult(
1527
+ {
1528
+ error: { message: err instanceof Error ? err.message : String(err) }
1529
+ },
1530
+ format
1531
+ );
1532
+ process.exit(1);
1533
+ }
1534
+ }
1535
+ async function businessRuleUpdateCommand(parsed2) {
1536
+ const format = detectOutputFormat(parsed2.global.output);
1537
+ try {
1538
+ let id;
1539
+ let input;
1540
+ if (parsed2.global.data) {
1541
+ const raw = JSON.parse(parsed2.global.data);
1542
+ id = validateUuid(validateRequired(raw.id, "id"), "id");
1543
+ input = {
1544
+ content: validateRequired(raw.content, "content"),
1545
+ versions_ids: raw.versionsIds ?? void 0,
1546
+ components_ids: raw.componentsIds ?? void 0,
1547
+ functions_ids: raw.functionsIds ?? void 0
1548
+ };
1549
+ } else {
1550
+ id = validateUuid(
1551
+ validateRequired(getFlag(parsed2.flags, "id"), "id"),
1552
+ "id"
1553
+ );
1554
+ const versionsIdsRaw = getFlag(parsed2.flags, "versions-ids");
1555
+ const componentsIdsRaw = getFlag(parsed2.flags, "components-ids");
1556
+ const functionsIdsRaw = getFlag(parsed2.flags, "functions-ids");
1557
+ input = {
1558
+ content: validateRequired(
1559
+ getFlag(parsed2.flags, "content", "c"),
1560
+ "content"
1561
+ ),
1562
+ versions_ids: versionsIdsRaw ? JSON.parse(versionsIdsRaw) : void 0,
1563
+ components_ids: componentsIdsRaw ? JSON.parse(componentsIdsRaw) : void 0,
1564
+ functions_ids: functionsIdsRaw ? JSON.parse(functionsIdsRaw) : void 0
1565
+ };
1566
+ }
1567
+ if (parsed2.global.dryRun) {
1568
+ outputDryRun(
1569
+ "business-rule.update",
1570
+ { id, ...input },
1571
+ format
1572
+ );
1573
+ return;
1574
+ }
1575
+ const client = await getAuthenticatedClient();
1576
+ const result = await updateBusinessRule(client, id, input);
1577
+ outputResult(result, format, parsed2.global.fields);
1578
+ if (result.error) process.exit(1);
1579
+ } catch (err) {
1580
+ outputResult(
1581
+ {
1582
+ error: { message: err instanceof Error ? err.message : String(err) }
1583
+ },
1584
+ format
1585
+ );
1586
+ process.exit(1);
1587
+ }
1588
+ }
1589
+
1590
+ // src/core/schema.ts
1591
+ import { z as z2 } from "zod";
1592
+ import { zodToJsonSchema } from "zod-to-json-schema";
1593
+ var PLATFORM_VENDORS = ["vtex", "shopify", "vnda", "custom"];
1594
+ var storeCreateSchema = z2.object({
1595
+ name: z2.string().min(1).describe("Store display name"),
1596
+ platform: z2.enum(PLATFORM_VENDORS).describe("E-commerce platform vendor"),
1597
+ platformStoreId: z2.string().min(1).describe("Platform-specific store identifier (e.g. account name)"),
1598
+ logo: z2.string().url().optional().describe("Store logo URL"),
1599
+ settings: z2.string().optional().describe("JSON settings string")
1600
+ });
1601
+ var storeListSchema = z2.object({}).describe("No parameters required");
1602
+ var versionCreateSchema = z2.object({
1603
+ storeId: z2.string().uuid().describe("Parent store UUID"),
1604
+ name: z2.string().min(1).describe("Version name (e.g. v1, main)"),
1605
+ active: z2.boolean().default(false).describe("Whether version is active"),
1606
+ default: z2.boolean().default(false).describe("Whether this is the default version"),
1607
+ template: z2.string().nullable().default(null).describe("Template name or null")
1608
+ });
1609
+ var versionListSchema = z2.object({
1610
+ storeId: z2.string().uuid().describe("Store UUID to list versions for")
1611
+ });
1612
+ var componentCreateSchema = z2.object({
1613
+ versionId: z2.string().uuid().describe("Parent version UUID"),
1614
+ name: z2.string().min(1).describe("Component name (e.g. FreeShippingBar)"),
1615
+ slot: z2.string().min(1).describe(
1616
+ "Target slot (e.g. cart_header_full_page, shipping_address_details_form)"
1617
+ ),
1618
+ active: z2.boolean().default(true).describe("Whether component is active"),
1619
+ props: z2.record(z2.unknown()).nullable().default(null).describe("Default component props as JSON object")
1620
+ });
1621
+ var componentListSchema = z2.object({
1622
+ storeId: z2.string().uuid().describe("Store UUID"),
1623
+ versionId: z2.string().uuid().optional().describe("Optional version UUID to filter by")
1624
+ });
1625
+ var functionCreateSchema = z2.object({
1626
+ versionId: z2.string().uuid().describe("Parent version UUID"),
1627
+ name: z2.string().min(1).describe("Function name"),
1628
+ trigger: z2.string().min(1).describe("Function trigger (e.g. beforePayment, afterShipping)"),
1629
+ active: z2.boolean().default(true).describe("Whether function is active")
1630
+ });
1631
+ var functionListSchema = z2.object({
1632
+ versionId: z2.string().uuid().describe("Version UUID to list functions for")
1633
+ });
1634
+ var schemas = {
1635
+ store: {
1636
+ create: storeCreateSchema,
1637
+ list: storeListSchema
1638
+ },
1639
+ version: {
1640
+ create: versionCreateSchema,
1641
+ list: versionListSchema
1642
+ },
1643
+ component: {
1644
+ create: componentCreateSchema,
1645
+ list: componentListSchema
1646
+ },
1647
+ function: {
1648
+ create: functionCreateSchema,
1649
+ list: functionListSchema
1650
+ }
1651
+ };
1652
+ function getSchemaNames() {
1653
+ const names = [];
1654
+ for (const [resource, actions] of Object.entries(schemas)) {
1655
+ names.push(resource);
1656
+ for (const action of Object.keys(actions)) {
1657
+ names.push(`${resource}.${action}`);
1658
+ }
1659
+ }
1660
+ return names;
1661
+ }
1662
+ function getJsonSchema(name) {
1663
+ const parts = name.split(".");
1664
+ const resource = parts[0];
1665
+ const action = parts[1];
1666
+ if (!resource || !schemas[resource]) return null;
1667
+ if (action) {
1668
+ const schema = schemas[resource][action];
1669
+ if (!schema) return null;
1670
+ return zodToJsonSchema(schema, { name: `${resource}.${action}` });
1671
+ }
1672
+ const result = {};
1673
+ for (const [actionName, schema] of Object.entries(schemas[resource])) {
1674
+ result[actionName] = zodToJsonSchema(schema, {
1675
+ name: `${resource}.${actionName}`
1676
+ });
1677
+ }
1678
+ return result;
1679
+ }
1680
+
1681
+ // src/core/component.ts
1682
+ async function createComponent(client, input) {
1683
+ const parsed2 = componentCreateSchema.safeParse(input);
1684
+ if (!parsed2.success) {
1685
+ return {
1686
+ error: { message: parsed2.error.issues.map((i) => i.message).join("; ") }
1687
+ };
1688
+ }
1689
+ const { data, error } = await client.from("components").insert({
1690
+ name: parsed2.data.name,
1691
+ slot: parsed2.data.slot,
1692
+ active: parsed2.data.active,
1693
+ version_id: parsed2.data.versionId,
1694
+ props: parsed2.data.props
1695
+ }).select("id").single();
1696
+ if (error) {
1697
+ return { error: { message: error.message } };
1698
+ }
1699
+ return { data: { id: data.id } };
1700
+ }
1701
+ async function listComponents(client, storeId, versionId) {
1702
+ let query = client.from("components").select(
1703
+ "id, name, slot, active, version_id, props, created_at, versions!inner(id, name)"
1704
+ ).eq("versions.store_id", storeId);
1705
+ if (versionId) {
1706
+ query = query.eq("versions.id", versionId);
1707
+ }
1708
+ const { data, error } = await query;
1709
+ if (error) {
1710
+ return { error: { message: error.message } };
1711
+ }
1712
+ return { data: data ?? [] };
1713
+ }
1714
+
1529
1715
  // src/commands/component-cmd.ts
1530
1716
  async function componentCommand(parsed2) {
1531
1717
  const sub = parsed2.subcommand;
@@ -1607,6 +1793,218 @@ async function componentListCommand(parsed2) {
1607
1793
  }
1608
1794
  }
1609
1795
 
1796
+ // src/core/deploy.ts
1797
+ async function uploadBuild(input) {
1798
+ const builderUrl = getBuilderUrl();
1799
+ const token = await getAuthToken();
1800
+ const formData = new FormData();
1801
+ formData.append(
1802
+ "code",
1803
+ new Blob([input.zipBuffer], { type: "application/zip" }),
1804
+ "code.zip"
1805
+ );
1806
+ formData.append("type", input.type);
1807
+ formData.append("resource_id", input.resourceId);
1808
+ let response;
1809
+ try {
1810
+ response = await fetch(`${builderUrl}/`, {
1811
+ method: "POST",
1812
+ headers: {
1813
+ Authorization: `Bearer ${token}`
1814
+ },
1815
+ body: formData
1816
+ });
1817
+ } catch (err) {
1818
+ return {
1819
+ success: false,
1820
+ error: {
1821
+ message: `Cannot reach builder at ${builderUrl}: ${err instanceof Error ? err.message : String(err)}`
1822
+ }
1823
+ };
1824
+ }
1825
+ const body = await response.json();
1826
+ if (!response.ok || !body.success) {
1827
+ const msg = body.error?.message || body.error?.type || `Builder returned ${response.status}`;
1828
+ return { success: false, error: { message: msg } };
1829
+ }
1830
+ return { success: true, data: body.data };
1831
+ }
1832
+ async function fetchBuildStatus(buildId) {
1833
+ const builderUrl = getBuilderUrl();
1834
+ const token = await getAuthToken();
1835
+ let response;
1836
+ try {
1837
+ response = await fetch(`${builderUrl}/${encodeURIComponent(buildId)}`, {
1838
+ method: "GET",
1839
+ headers: {
1840
+ Authorization: `Bearer ${token}`
1841
+ }
1842
+ });
1843
+ } catch (err) {
1844
+ return {
1845
+ success: false,
1846
+ error: {
1847
+ message: `Cannot reach builder at ${builderUrl}: ${err instanceof Error ? err.message : String(err)}`
1848
+ }
1849
+ };
1850
+ }
1851
+ const body = await response.json();
1852
+ if (!response.ok || !body.success) {
1853
+ const msg = body.error?.message || body.error?.type || `Builder returned ${response.status}`;
1854
+ return { success: false, error: { message: msg } };
1855
+ }
1856
+ return { success: true, data: body.data };
1857
+ }
1858
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
1859
+ "SUCCEEDED",
1860
+ "FAILED",
1861
+ "STOPPED",
1862
+ "TIMED_OUT",
1863
+ "FAULT"
1864
+ ]);
1865
+ function isTerminalStatus(status) {
1866
+ return TERMINAL_STATUSES.has(status);
1867
+ }
1868
+ async function pollBuildStatus(buildId, options = {}) {
1869
+ const { intervalMs = 5e3, timeoutMs = 3e5, onPoll } = options;
1870
+ const deadline = Date.now() + timeoutMs;
1871
+ while (Date.now() < deadline) {
1872
+ const result = await fetchBuildStatus(buildId);
1873
+ if (!result.success) {
1874
+ return result;
1875
+ }
1876
+ if (onPoll) {
1877
+ onPoll(result.data);
1878
+ }
1879
+ if (isTerminalStatus(result.data.status)) {
1880
+ return result;
1881
+ }
1882
+ const remaining = deadline - Date.now();
1883
+ if (remaining <= 0) break;
1884
+ await new Promise(
1885
+ (resolve) => setTimeout(resolve, Math.min(intervalMs, remaining))
1886
+ );
1887
+ }
1888
+ return {
1889
+ success: false,
1890
+ error: { message: `Build ${buildId} timed out after ${timeoutMs / 1e3}s` }
1891
+ };
1892
+ }
1893
+
1894
+ // src/commands/deploy-cmd.ts
1895
+ async function deployCommand(parsed2) {
1896
+ const format = detectOutputFormat(parsed2.global.output);
1897
+ try {
1898
+ let resourceId;
1899
+ let componentName;
1900
+ let resourceType;
1901
+ let wait;
1902
+ let timeout;
1903
+ if (parsed2.global.data) {
1904
+ const raw = JSON.parse(parsed2.global.data);
1905
+ resourceId = validateUuid(
1906
+ raw.componentId || raw.functionId || raw.resourceId,
1907
+ "componentId or functionId"
1908
+ );
1909
+ componentName = validateRequired(raw.name, "name");
1910
+ resourceType = raw.type === "function" ? "function" : "component";
1911
+ wait = raw.wait ?? false;
1912
+ timeout = raw.timeout ?? 300;
1913
+ } else {
1914
+ const compId = getFlag(parsed2.flags, "component-id");
1915
+ const funcId = getFlag(parsed2.flags, "function-id");
1916
+ if (compId && funcId) {
1917
+ throw new Error(
1918
+ "Provide either --component-id or --function-id, not both."
1919
+ );
1920
+ }
1921
+ if (compId) {
1922
+ resourceId = validateUuid(compId, "component-id");
1923
+ resourceType = "component";
1924
+ } else if (funcId) {
1925
+ resourceId = validateUuid(funcId, "function-id");
1926
+ resourceType = "function";
1927
+ } else {
1928
+ throw new Error("Either --component-id or --function-id is required.");
1929
+ }
1930
+ componentName = validateRequired(
1931
+ getFlag(parsed2.flags, "name", "n"),
1932
+ "name"
1933
+ );
1934
+ wait = getBoolFlag(parsed2.flags, "wait");
1935
+ timeout = Number(getFlag(parsed2.flags, "timeout") ?? "300");
1936
+ }
1937
+ const stream = await createComponentBundle({
1938
+ componentName,
1939
+ cwd: process.cwd()
1940
+ });
1941
+ const chunks = [];
1942
+ for await (const chunk of stream) {
1943
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1944
+ }
1945
+ const zipBuffer = Buffer.concat(chunks);
1946
+ if (parsed2.global.dryRun) {
1947
+ outputDryRun(
1948
+ "deploy",
1949
+ {
1950
+ resourceId,
1951
+ resourceType,
1952
+ componentName,
1953
+ bundleSizeBytes: zipBuffer.length,
1954
+ bundleSizeKB: Math.round(zipBuffer.length / 1024),
1955
+ wait,
1956
+ timeout
1957
+ },
1958
+ format
1959
+ );
1960
+ return;
1961
+ }
1962
+ const uploadResult = await uploadBuild({
1963
+ resourceId,
1964
+ type: resourceType,
1965
+ zipBuffer
1966
+ });
1967
+ if (!uploadResult.success) {
1968
+ outputResult(uploadResult, format);
1969
+ process.exit(1);
1970
+ }
1971
+ if (wait) {
1972
+ const isJson = format === "json";
1973
+ if (!isJson) {
1974
+ process.stderr.write(
1975
+ `Build ${uploadResult.data.id} started. Polling...
1976
+ `
1977
+ );
1978
+ }
1979
+ const pollResult = await pollBuildStatus(uploadResult.data.id, {
1980
+ timeoutMs: timeout * 1e3,
1981
+ onPoll: (build) => {
1982
+ if (!isJson) {
1983
+ process.stderr.write(` status: ${build.status}
1984
+ `);
1985
+ }
1986
+ }
1987
+ });
1988
+ outputResult(pollResult, format, parsed2.global.fields);
1989
+ if (!pollResult.success) process.exit(1);
1990
+ if (pollResult.success && isTerminalStatus(pollResult.data.status) && pollResult.data.status !== "SUCCEEDED") {
1991
+ process.exit(1);
1992
+ }
1993
+ } else {
1994
+ outputResult(uploadResult, format, parsed2.global.fields);
1995
+ }
1996
+ } catch (err) {
1997
+ outputResult(
1998
+ {
1999
+ success: false,
2000
+ error: { message: err instanceof Error ? err.message : String(err) }
2001
+ },
2002
+ format
2003
+ );
2004
+ process.exit(1);
2005
+ }
2006
+ }
2007
+
1610
2008
  // src/commands/init-cmd.ts
1611
2009
  async function initCommand(parsed2) {
1612
2010
  const format = detectOutputFormat(parsed2.global.output);
@@ -1678,6 +2076,60 @@ async function schemaCommand(parsed2) {
1678
2076
  `);
1679
2077
  }
1680
2078
 
2079
+ // src/commands/status-cmd.ts
2080
+ async function statusCommand(parsed2) {
2081
+ const format = detectOutputFormat(parsed2.global.output);
2082
+ try {
2083
+ let buildId;
2084
+ let wait;
2085
+ let timeout;
2086
+ if (parsed2.global.data) {
2087
+ const raw = JSON.parse(parsed2.global.data);
2088
+ buildId = validateRequired(raw.buildId, "buildId");
2089
+ wait = raw.wait ?? false;
2090
+ timeout = raw.timeout ?? 300;
2091
+ } else {
2092
+ buildId = validateRequired(getFlag(parsed2.flags, "build-id"), "build-id");
2093
+ wait = getBoolFlag(parsed2.flags, "wait");
2094
+ timeout = Number(getFlag(parsed2.flags, "timeout") ?? "300");
2095
+ }
2096
+ if (wait) {
2097
+ const isJson = format === "json";
2098
+ if (!isJson) {
2099
+ process.stderr.write(`Polling build ${buildId}...
2100
+ `);
2101
+ }
2102
+ const result = await pollBuildStatus(buildId, {
2103
+ timeoutMs: timeout * 1e3,
2104
+ onPoll: (build) => {
2105
+ if (!isJson) {
2106
+ process.stderr.write(` status: ${build.status}
2107
+ `);
2108
+ }
2109
+ }
2110
+ });
2111
+ outputResult(result, format, parsed2.global.fields);
2112
+ if (!result.success) process.exit(1);
2113
+ if (result.success && isTerminalStatus(result.data.status) && result.data.status !== "SUCCEEDED") {
2114
+ process.exit(1);
2115
+ }
2116
+ } else {
2117
+ const result = await fetchBuildStatus(buildId);
2118
+ outputResult(result, format, parsed2.global.fields);
2119
+ if (!result.success) process.exit(1);
2120
+ }
2121
+ } catch (err) {
2122
+ outputResult(
2123
+ {
2124
+ success: false,
2125
+ error: { message: err instanceof Error ? err.message : String(err) }
2126
+ },
2127
+ format
2128
+ );
2129
+ process.exit(1);
2130
+ }
2131
+ }
2132
+
1681
2133
  // src/core/store.ts
1682
2134
  async function createStore(client, input) {
1683
2135
  const parsed2 = storeCreateSchema.safeParse(input);
@@ -1923,8 +2375,11 @@ var AGENT_COMMANDS = {
1923
2375
  store: storeCommand,
1924
2376
  version: versionCommand,
1925
2377
  component: componentCommand,
2378
+ "business-rule": businessRuleCommand,
1926
2379
  schema: schemaCommand,
1927
- init: initCommand
2380
+ init: initCommand,
2381
+ deploy: deployCommand,
2382
+ status: statusCommand
1928
2383
  };
1929
2384
  var parsed = parseArgs(process.argv);
1930
2385
  if (parsed.command in AGENT_COMMANDS) {