@simonfestl/husky-cli 1.10.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Husky Biz Skuterzone Command
3
+ *
4
+ * Manages skuterzonepro.com (B2B e-mobility parts supplier) via web scraping
5
+ * WooCommerce platform integration
6
+ * - Parts search and catalog browsing
7
+ * - Order history and details
8
+ * - Invoice download
9
+ */
10
+ import { Command } from "commander";
11
+ import { SkuterzonePlaywrightClient } from "../../lib/biz/skuterzone-playwright.js";
12
+ import { getConfig, saveConfig } from "../config.js";
13
+ import * as path from "path";
14
+ import { homedir } from "os";
15
+ export const skuterzoneCommand = new Command("skuterzone")
16
+ .description("Manage skuterzonepro.com (e-mobility parts supplier - WooCommerce)");
17
+ // ============================================================================
18
+ // husky biz skuterzone login
19
+ // ============================================================================
20
+ skuterzoneCommand
21
+ .command("login")
22
+ .description("Setup Skuterzone credentials")
23
+ .requiredOption("-u, --username <username>", "Login username or email")
24
+ .requiredOption("-p, --password <password>", "Login password")
25
+ .option("--base-url <url>", "Base URL", "https://skuterzonepro.com")
26
+ .action(async (options) => {
27
+ try {
28
+ // Save to config
29
+ const config = getConfig();
30
+ config.skuterzoneUsername = options.username;
31
+ config.skuterzonePassword = options.password;
32
+ if (options.baseUrl) {
33
+ config.skuterzoneBaseUrl = options.baseUrl;
34
+ }
35
+ saveConfig(config);
36
+ console.log("Testing authentication...");
37
+ // Test login
38
+ const client = SkuterzonePlaywrightClient.fromConfig();
39
+ try {
40
+ const result = await client.login();
41
+ if (result.success) {
42
+ console.log("✓ Successfully authenticated with skuterzonepro.com");
43
+ console.log("\nYou can now use:");
44
+ console.log(" husky biz skuterzone orders list");
45
+ console.log(" husky biz skuterzone orders get <id>");
46
+ console.log(" husky biz skuterzone invoice <order-id>");
47
+ console.log(" husky biz skuterzone products <query>");
48
+ }
49
+ else {
50
+ console.error("✗ Login failed:", result.error);
51
+ process.exit(1);
52
+ }
53
+ }
54
+ finally {
55
+ await client.close();
56
+ }
57
+ }
58
+ catch (error) {
59
+ console.error("✗ Login failed:", error.message);
60
+ process.exit(1);
61
+ }
62
+ });
63
+ // ============================================================================
64
+ // husky biz skuterzone orders
65
+ // ============================================================================
66
+ const ordersSubcommand = new Command("orders")
67
+ .description("View supplier orders");
68
+ ordersSubcommand
69
+ .command("list")
70
+ .description("List all orders from Skuterzone")
71
+ .option("--json", "Output as JSON")
72
+ .action(async (options) => {
73
+ const client = SkuterzonePlaywrightClient.fromConfig();
74
+ try {
75
+ const orders = await client.listOrders();
76
+ if (options.json) {
77
+ console.log(JSON.stringify(orders, null, 2));
78
+ return;
79
+ }
80
+ if (orders.length === 0) {
81
+ console.log("\n No orders found.\n");
82
+ return;
83
+ }
84
+ console.log(`\n 📦 Skuterzone Orders (${orders.length} found)\n`);
85
+ // Header
86
+ console.log(` ${"Order #".padEnd(15)} │ ` +
87
+ `${"Date".padEnd(20)} │ ` +
88
+ `${"Status".padEnd(15)} │ ` +
89
+ `${"Total".padEnd(12)}`);
90
+ console.log(" " + "─".repeat(75));
91
+ // Orders
92
+ for (const order of orders) {
93
+ console.log(` ${order.orderNumber.padEnd(15)} │ ` +
94
+ `${order.date.padEnd(20)} │ ` +
95
+ `${order.status.padEnd(15)} │ ` +
96
+ `${order.total}`);
97
+ }
98
+ console.log("");
99
+ }
100
+ catch (error) {
101
+ console.error("Error:", error.message);
102
+ process.exit(1);
103
+ }
104
+ finally {
105
+ await client.close();
106
+ }
107
+ });
108
+ ordersSubcommand
109
+ .command("get <id>")
110
+ .description("Get order details")
111
+ .option("--json", "Output as JSON")
112
+ .action(async (id, options) => {
113
+ const client = SkuterzonePlaywrightClient.fromConfig();
114
+ try {
115
+ const order = await client.getOrder(id);
116
+ if (options.json) {
117
+ console.log(JSON.stringify(order, null, 2));
118
+ return;
119
+ }
120
+ console.log(`\n Order ${order.orderNumber}`);
121
+ console.log(" " + "─".repeat(60));
122
+ console.log(` Status: ${order.status}`);
123
+ console.log(` Date: ${order.date}`);
124
+ console.log(` Total: ${order.total}`);
125
+ if (order.trackingNumber) {
126
+ console.log(` Tracking: ${order.trackingNumber}`);
127
+ }
128
+ if (order.paymentMethod) {
129
+ console.log(` Payment: ${order.paymentMethod}`);
130
+ }
131
+ if (order.customer && order.customer.name) {
132
+ console.log(`\n Shipping To:`);
133
+ console.log(` ${order.customer.name}`);
134
+ if (order.customer.company) {
135
+ console.log(` ${order.customer.company}`);
136
+ }
137
+ if (order.customer.address) {
138
+ console.log(` ${order.customer.address}`);
139
+ }
140
+ if (order.customer.postcode && order.customer.city) {
141
+ console.log(` ${order.customer.postcode} ${order.customer.city}`);
142
+ }
143
+ if (order.customer.email) {
144
+ console.log(` ${order.customer.email}`);
145
+ }
146
+ }
147
+ if (order.items.length > 0) {
148
+ console.log(`\n Items:`);
149
+ for (const item of order.items) {
150
+ const sku = item.sku ? `[${item.sku}]`.padEnd(18) : "".padEnd(18);
151
+ const name = item.name.slice(0, 35).padEnd(35);
152
+ console.log(` ${item.quantity}x ${sku} ${name} (${item.total})`);
153
+ }
154
+ }
155
+ if (order.subtotal || order.shipping || order.tax) {
156
+ console.log(`\n Totals:`);
157
+ if (order.subtotal)
158
+ console.log(` Subtotal: ${order.subtotal}`);
159
+ if (order.shipping)
160
+ console.log(` Shipping: ${order.shipping}`);
161
+ if (order.tax)
162
+ console.log(` Tax: ${order.tax}`);
163
+ console.log(` Total: ${order.total}`);
164
+ }
165
+ if (order.invoiceUrl) {
166
+ console.log(`\n 📄 Invoice available`);
167
+ console.log(` Download with: husky biz skuterzone invoice ${order.id}`);
168
+ }
169
+ console.log("");
170
+ }
171
+ catch (error) {
172
+ console.error("Error:", error.message);
173
+ process.exit(1);
174
+ }
175
+ finally {
176
+ await client.close();
177
+ }
178
+ });
179
+ skuterzoneCommand.addCommand(ordersSubcommand);
180
+ // ============================================================================
181
+ // husky biz skuterzone invoice
182
+ // ============================================================================
183
+ skuterzoneCommand
184
+ .command("invoice <order-id>")
185
+ .description("Download invoice PDF for order")
186
+ .option("-o, --output <path>", "Save path (default: ~/Downloads/skuterzone-invoice-{id}.pdf)")
187
+ .action(async (orderId, options) => {
188
+ const client = SkuterzonePlaywrightClient.fromConfig();
189
+ try {
190
+ const savePath = options.output ||
191
+ path.join(homedir(), 'Downloads', `skuterzone-invoice-${orderId}.pdf`);
192
+ console.log(`Downloading invoice for order #${orderId}...`);
193
+ const success = await client.downloadInvoice(orderId, savePath);
194
+ if (success) {
195
+ console.log(`✓ Invoice saved to: ${savePath}`);
196
+ }
197
+ else {
198
+ console.error("✗ Invoice not available for this order");
199
+ process.exit(1);
200
+ }
201
+ }
202
+ catch (error) {
203
+ console.error("Error:", error.message);
204
+ process.exit(1);
205
+ }
206
+ finally {
207
+ await client.close();
208
+ }
209
+ });
210
+ // ============================================================================
211
+ // husky biz skuterzone products
212
+ // ============================================================================
213
+ skuterzoneCommand
214
+ .command("products <query>")
215
+ .description("Search for parts in catalog")
216
+ .option("--json", "Output as JSON")
217
+ .action(async (query, options) => {
218
+ const client = SkuterzonePlaywrightClient.fromConfig();
219
+ try {
220
+ const products = await client.searchProducts(query);
221
+ if (options.json) {
222
+ console.log(JSON.stringify(products, null, 2));
223
+ return;
224
+ }
225
+ if (products.length === 0) {
226
+ console.log(`\n No products found for: "${query}"\n`);
227
+ return;
228
+ }
229
+ console.log(`\n 🔍 Search results for: "${query}" (${products.length} found)\n`);
230
+ for (const product of products) {
231
+ const sku = product.sku ? `[${product.sku}]` : '';
232
+ const price = product.price || 'Price hidden (login required)';
233
+ const stock = product.stockStatus || '';
234
+ console.log(` ${product.name}`);
235
+ console.log(` ${sku} ${price}${stock ? ' - ' + stock : ''}`);
236
+ console.log(` ${product.url}`);
237
+ console.log("");
238
+ }
239
+ }
240
+ catch (error) {
241
+ console.error("Error:", error.message);
242
+ process.exit(1);
243
+ }
244
+ finally {
245
+ await client.close();
246
+ }
247
+ });
248
+ export default skuterzoneCommand;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Husky Biz Wattiz Command
3
+ *
4
+ * Manages wattiz.fr (B2B e-mobility parts supplier) via web scraping
5
+ * PrestaShop platform integration
6
+ * - Parts search and catalog browsing
7
+ * - Order history and details
8
+ * - Invoice download
9
+ */
10
+ import { Command } from "commander";
11
+ export declare const wattizCommand: Command;
12
+ export default wattizCommand;
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Husky Biz Wattiz Command
3
+ *
4
+ * Manages wattiz.fr (B2B e-mobility parts supplier) via web scraping
5
+ * PrestaShop platform integration
6
+ * - Parts search and catalog browsing
7
+ * - Order history and details
8
+ * - Invoice download
9
+ */
10
+ import { Command } from "commander";
11
+ import { WattizPlaywrightClient } from "../../lib/biz/wattiz-playwright.js";
12
+ import { getConfig, saveConfig } from "../config.js";
13
+ import * as path from "path";
14
+ import { homedir } from "os";
15
+ export const wattizCommand = new Command("wattiz")
16
+ .description("Manage wattiz.fr (e-mobility parts supplier - PrestaShop)");
17
+ // ============================================================================
18
+ // husky biz wattiz login
19
+ // ============================================================================
20
+ wattizCommand
21
+ .command("login")
22
+ .description("Setup Wattiz credentials")
23
+ .requiredOption("-u, --username <username>", "Login username or email")
24
+ .requiredOption("-p, --password <password>", "Login password")
25
+ .option("--base-url <url>", "Base URL", "https://www.wattiz.fr")
26
+ .option("--language <lang>", "Language (gb, fr, de, es)", "gb")
27
+ .action(async (options) => {
28
+ try {
29
+ // Save to config
30
+ const config = getConfig();
31
+ config.wattizUsername = options.username;
32
+ config.wattizPassword = options.password;
33
+ if (options.baseUrl) {
34
+ config.wattizBaseUrl = options.baseUrl;
35
+ }
36
+ if (options.language) {
37
+ config.wattizLanguage = options.language;
38
+ }
39
+ saveConfig(config);
40
+ console.log("Testing authentication...");
41
+ // Test login
42
+ const client = WattizPlaywrightClient.fromConfig();
43
+ try {
44
+ const result = await client.login();
45
+ if (result.success) {
46
+ console.log("✓ Successfully authenticated with wattiz.fr");
47
+ console.log("\nYou can now use:");
48
+ console.log(" husky biz wattiz orders list");
49
+ console.log(" husky biz wattiz orders get <id>");
50
+ console.log(" husky biz wattiz invoice <order-id>");
51
+ console.log(" husky biz wattiz products <query>");
52
+ }
53
+ else {
54
+ console.error("✗ Login failed:", result.error);
55
+ process.exit(1);
56
+ }
57
+ }
58
+ finally {
59
+ await client.close();
60
+ }
61
+ }
62
+ catch (error) {
63
+ console.error("✗ Login failed:", error.message);
64
+ process.exit(1);
65
+ }
66
+ });
67
+ // ============================================================================
68
+ // husky biz wattiz orders
69
+ // ============================================================================
70
+ const ordersSubcommand = new Command("orders")
71
+ .description("View supplier orders");
72
+ ordersSubcommand
73
+ .command("list")
74
+ .description("List all orders from Wattiz")
75
+ .option("--json", "Output as JSON")
76
+ .action(async (options) => {
77
+ const client = WattizPlaywrightClient.fromConfig();
78
+ try {
79
+ const orders = await client.listOrders();
80
+ if (options.json) {
81
+ console.log(JSON.stringify(orders, null, 2));
82
+ return;
83
+ }
84
+ if (orders.length === 0) {
85
+ console.log("\n No orders found.\n");
86
+ return;
87
+ }
88
+ console.log(`\n 📦 Wattiz Orders (${orders.length} found)\n`);
89
+ // Header
90
+ console.log(` ${"Order #".padEnd(15)} │ ` +
91
+ `${"Date".padEnd(20)} │ ` +
92
+ `${"Status".padEnd(15)} │ ` +
93
+ `${"Total".padEnd(12)}`);
94
+ console.log(" " + "─".repeat(75));
95
+ // Orders
96
+ for (const order of orders) {
97
+ console.log(` ${order.orderNumber.padEnd(15)} │ ` +
98
+ `${order.date.padEnd(20)} │ ` +
99
+ `${order.status.padEnd(15)} │ ` +
100
+ `${order.total}`);
101
+ }
102
+ console.log("");
103
+ }
104
+ catch (error) {
105
+ console.error("Error:", error.message);
106
+ process.exit(1);
107
+ }
108
+ finally {
109
+ await client.close();
110
+ }
111
+ });
112
+ ordersSubcommand
113
+ .command("get <id>")
114
+ .description("Get order details")
115
+ .option("--json", "Output as JSON")
116
+ .action(async (id, options) => {
117
+ const client = WattizPlaywrightClient.fromConfig();
118
+ try {
119
+ const order = await client.getOrder(id);
120
+ if (options.json) {
121
+ console.log(JSON.stringify(order, null, 2));
122
+ return;
123
+ }
124
+ console.log(`\n Order ${order.orderNumber}`);
125
+ console.log(" " + "─".repeat(60));
126
+ console.log(` Status: ${order.status}`);
127
+ console.log(` Date: ${order.date}`);
128
+ console.log(` Total: ${order.total}`);
129
+ if (order.trackingNumber) {
130
+ console.log(` Tracking: ${order.trackingNumber}`);
131
+ }
132
+ if (order.paymentMethod) {
133
+ console.log(` Payment: ${order.paymentMethod}`);
134
+ }
135
+ if (order.customer && order.customer.name) {
136
+ console.log(`\n Shipping To:`);
137
+ console.log(` ${order.customer.name}`);
138
+ if (order.customer.company) {
139
+ console.log(` ${order.customer.company}`);
140
+ }
141
+ if (order.customer.address) {
142
+ console.log(` ${order.customer.address}`);
143
+ }
144
+ if (order.customer.postcode && order.customer.city) {
145
+ console.log(` ${order.customer.postcode} ${order.customer.city}`);
146
+ }
147
+ if (order.customer.email) {
148
+ console.log(` ${order.customer.email}`);
149
+ }
150
+ }
151
+ if (order.items.length > 0) {
152
+ console.log(`\n Items:`);
153
+ for (const item of order.items) {
154
+ const sku = item.sku ? `[${item.sku}]`.padEnd(18) : "".padEnd(18);
155
+ const name = item.name.slice(0, 35).padEnd(35);
156
+ console.log(` ${item.quantity}x ${sku} ${name} (${item.total})`);
157
+ }
158
+ }
159
+ if (order.subtotal || order.shipping || order.tax) {
160
+ console.log(`\n Totals:`);
161
+ if (order.subtotal)
162
+ console.log(` Subtotal: ${order.subtotal}`);
163
+ if (order.shipping)
164
+ console.log(` Shipping: ${order.shipping}`);
165
+ if (order.tax)
166
+ console.log(` Tax: ${order.tax}`);
167
+ console.log(` Total: ${order.total}`);
168
+ }
169
+ if (order.invoiceUrl) {
170
+ console.log(`\n 📄 Invoice available`);
171
+ console.log(` Download with: husky biz wattiz invoice ${order.id}`);
172
+ }
173
+ console.log("");
174
+ }
175
+ catch (error) {
176
+ console.error("Error:", error.message);
177
+ process.exit(1);
178
+ }
179
+ finally {
180
+ await client.close();
181
+ }
182
+ });
183
+ wattizCommand.addCommand(ordersSubcommand);
184
+ // ============================================================================
185
+ // husky biz wattiz invoice
186
+ // ============================================================================
187
+ wattizCommand
188
+ .command("invoice <order-id>")
189
+ .description("Download invoice PDF for order")
190
+ .option("-o, --output <path>", "Save path (default: ~/Downloads/wattiz-invoice-{id}.pdf)")
191
+ .action(async (orderId, options) => {
192
+ const client = WattizPlaywrightClient.fromConfig();
193
+ try {
194
+ const savePath = options.output ||
195
+ path.join(homedir(), 'Downloads', `wattiz-invoice-${orderId}.pdf`);
196
+ console.log(`Downloading invoice for order #${orderId}...`);
197
+ const success = await client.downloadInvoice(orderId, savePath);
198
+ if (success) {
199
+ console.log(`✓ Invoice saved to: ${savePath}`);
200
+ }
201
+ else {
202
+ console.error("✗ Invoice not available for this order");
203
+ process.exit(1);
204
+ }
205
+ }
206
+ catch (error) {
207
+ console.error("Error:", error.message);
208
+ process.exit(1);
209
+ }
210
+ finally {
211
+ await client.close();
212
+ }
213
+ });
214
+ // ============================================================================
215
+ // husky biz wattiz products
216
+ // ============================================================================
217
+ wattizCommand
218
+ .command("products <query>")
219
+ .description("Search for parts in catalog")
220
+ .option("--json", "Output as JSON")
221
+ .action(async (query, options) => {
222
+ const client = WattizPlaywrightClient.fromConfig();
223
+ try {
224
+ const products = await client.searchProducts(query);
225
+ if (options.json) {
226
+ console.log(JSON.stringify(products, null, 2));
227
+ return;
228
+ }
229
+ if (products.length === 0) {
230
+ console.log(`\n No products found for: "${query}"\n`);
231
+ return;
232
+ }
233
+ console.log(`\n 🔍 Search results for: "${query}" (${products.length} found)\n`);
234
+ for (const product of products) {
235
+ const sku = product.sku ? `[${product.sku}]` : '';
236
+ const price = product.price || 'Price hidden (login required)';
237
+ const stock = product.stockStatus || '';
238
+ console.log(` ${product.name}`);
239
+ console.log(` ${sku} ${price}${stock ? ' - ' + stock : ''}`);
240
+ console.log(` ${product.url}`);
241
+ console.log("");
242
+ }
243
+ }
244
+ catch (error) {
245
+ console.error("Error:", error.message);
246
+ process.exit(1);
247
+ }
248
+ finally {
249
+ await client.close();
250
+ }
251
+ });
252
+ export default wattizCommand;
@@ -12,6 +12,9 @@ import { customersCommand } from "./biz/customers.js";
12
12
  import { seatableCommand } from "./biz/seatable.js";
13
13
  import { qdrantCommand } from "./biz/qdrant.js";
14
14
  import { gotessCommand } from "./biz/gotess.js";
15
+ import { skuterzoneCommand } from "./biz/skuterzone.js";
16
+ import { emoveCommand } from "./biz/emove.js";
17
+ import { wattizCommand } from "./biz/wattiz.js";
15
18
  import { guards } from "../lib/permissions.js";
16
19
  export const bizCommand = new Command("biz")
17
20
  .description("Business operations for autonomous agents")
@@ -22,5 +25,8 @@ export const bizCommand = new Command("biz")
22
25
  .addCommand(customersCommand)
23
26
  .addCommand(seatableCommand)
24
27
  .addCommand(qdrantCommand)
25
- .addCommand(gotessCommand);
28
+ .addCommand(gotessCommand)
29
+ .addCommand(skuterzoneCommand)
30
+ .addCommand(emoveCommand)
31
+ .addCommand(wattizCommand);
26
32
  export default bizCommand;
@@ -3,6 +3,10 @@ type AgentRole = "supervisor" | "worker" | "reviewer" | "e2e_agent" | "pr_agent"
3
3
  interface Config {
4
4
  apiUrl?: string;
5
5
  apiKey?: string;
6
+ sessionToken?: string;
7
+ sessionExpiresAt?: string;
8
+ sessionAgent?: string;
9
+ sessionRole?: string;
6
10
  workerId?: string;
7
11
  workerName?: string;
8
12
  role?: AgentRole;
@@ -28,8 +32,19 @@ interface Config {
28
32
  nocodbApiToken?: string;
29
33
  nocodbBaseUrl?: string;
30
34
  nocodbWorkspaceId?: string;
35
+ skuterzoneUsername?: string;
36
+ skuterzonePassword?: string;
37
+ skuterzoneBaseUrl?: string;
38
+ emoveUsername?: string;
39
+ emovePassword?: string;
40
+ emoveBaseUrl?: string;
41
+ wattizUsername?: string;
42
+ wattizPassword?: string;
43
+ wattizBaseUrl?: string;
44
+ wattizLanguage?: string;
31
45
  }
32
46
  export declare function getConfig(): Config;
47
+ export declare function saveConfig(config: Config): void;
33
48
  /**
34
49
  * Fetch role and permissions from /api/auth/whoami
35
50
  * Caches the result in config for 1 hour
@@ -52,5 +67,18 @@ export declare function getRole(): AgentRole | undefined;
52
67
  export declare function clearRoleCache(): void;
53
68
  export declare function setConfig(key: "apiUrl" | "apiKey" | "workerId" | "workerName", value: string): void;
54
69
  export declare function setGotessConfig(token: string, bookId: string): void;
70
+ export declare function setSessionConfig(session: {
71
+ token: string;
72
+ expiresAt: string;
73
+ agent: string;
74
+ role: string;
75
+ }): void;
76
+ export declare function clearSessionConfig(): void;
77
+ export declare function getSessionConfig(): {
78
+ token?: string;
79
+ expiresAt?: string;
80
+ agent?: string;
81
+ role?: string;
82
+ } | null;
55
83
  export declare const configCommand: Command;
56
84
  export {};
@@ -41,7 +41,7 @@ export function getConfig() {
41
41
  return {};
42
42
  }
43
43
  }
44
- function saveConfig(config) {
44
+ export function saveConfig(config) {
45
45
  if (!existsSync(CONFIG_DIR)) {
46
46
  mkdirSync(CONFIG_DIR, { recursive: true });
47
47
  }
@@ -127,6 +127,33 @@ export function setGotessConfig(token, bookId) {
127
127
  config.gotessBookId = bookId;
128
128
  saveConfig(config);
129
129
  }
130
+ export function setSessionConfig(session) {
131
+ const config = getConfig();
132
+ config.sessionToken = session.token;
133
+ config.sessionExpiresAt = session.expiresAt;
134
+ config.sessionAgent = session.agent;
135
+ config.sessionRole = session.role;
136
+ saveConfig(config);
137
+ }
138
+ export function clearSessionConfig() {
139
+ const config = getConfig();
140
+ delete config.sessionToken;
141
+ delete config.sessionExpiresAt;
142
+ delete config.sessionAgent;
143
+ delete config.sessionRole;
144
+ saveConfig(config);
145
+ }
146
+ export function getSessionConfig() {
147
+ const config = getConfig();
148
+ if (!config.sessionToken)
149
+ return null;
150
+ return {
151
+ token: config.sessionToken,
152
+ expiresAt: config.sessionExpiresAt,
153
+ agent: config.sessionAgent,
154
+ role: config.sessionRole,
155
+ };
156
+ }
130
157
  export const configCommand = new Command("config")
131
158
  .description("Manage CLI configuration");
132
159
  // husky config set <key> <value>
@@ -166,6 +193,19 @@ configCommand
166
193
  "nocodb-api-token": "nocodbApiToken",
167
194
  "nocodb-base-url": "nocodbBaseUrl",
168
195
  "nocodb-workspace-id": "nocodbWorkspaceId",
196
+ // Skuterzone
197
+ "skuterzone-username": "skuterzoneUsername",
198
+ "skuterzone-password": "skuterzonePassword",
199
+ "skuterzone-base-url": "skuterzoneBaseUrl",
200
+ // Emove Distribution
201
+ "emove-username": "emoveUsername",
202
+ "emove-password": "emovePassword",
203
+ "emove-base-url": "emoveBaseUrl",
204
+ // Wattiz
205
+ "wattiz-username": "wattizUsername",
206
+ "wattiz-password": "wattizPassword",
207
+ "wattiz-base-url": "wattizBaseUrl",
208
+ "wattiz-language": "wattizLanguage",
169
209
  };
170
210
  const configKey = keyMappings[key];
171
211
  if (!configKey) {
@@ -180,6 +220,9 @@ configCommand
180
220
  console.log(" Gotess: gotess-token, gotess-book-id");
181
221
  console.log(" Gemini: gemini-api-key");
182
222
  console.log(" NocoDB: nocodb-api-token, nocodb-base-url, nocodb-workspace-id");
223
+ console.log(" Skuterzone: skuterzone-username, skuterzone-password, skuterzone-base-url");
224
+ console.log(" Emove: emove-username, emove-password, emove-base-url");
225
+ console.log(" Wattiz: wattiz-username, wattiz-password, wattiz-base-url, wattiz-language");
183
226
  console.log(" Brain: agent-type");
184
227
  console.error("\n💡 For configuration help: husky explain config");
185
228
  process.exit(1);
@@ -201,7 +244,7 @@ configCommand
201
244
  config[configKey] = value;
202
245
  saveConfig(config);
203
246
  // Mask sensitive values in output
204
- const sensitiveKeys = ["api-key", "billbee-api-key", "billbee-password", "zendesk-api-token", "seatable-api-token", "gotess-token", "gemini-api-key", "nocodb-api-token"];
247
+ const sensitiveKeys = ["api-key", "billbee-api-key", "billbee-password", "zendesk-api-token", "seatable-api-token", "gotess-token", "gemini-api-key", "nocodb-api-token", "skuterzone-username", "skuterzone-password", "emove-username", "emove-password", "wattiz-username", "wattiz-password"];
205
248
  const displayValue = sensitiveKeys.includes(key) ? "***" : value;
206
249
  console.log(`✓ Set ${key} = ${displayValue}`);
207
250
  });
@@ -829,12 +829,14 @@ taskCommand
829
829
  throw new Error(`API error: ${res.status}`);
830
830
  }
831
831
  const data = await res.json();
832
- if (data.status === "approved") {
832
+ if (data.approved === true && data.pending === false) {
833
833
  console.log("✓ Plan approved!");
834
834
  process.exit(0);
835
835
  }
836
- else if (data.status === "rejected") {
836
+ else if (data.approved === false && data.rejected === true) {
837
837
  console.log("✗ Plan rejected");
838
+ if (data.reason)
839
+ console.log(`Reason: ${data.reason}`);
838
840
  process.exit(1);
839
841
  }
840
842
  // Still pending, wait and poll again