@simonfestl/husky-cli 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -116
- package/dist/commands/biz/customers.d.ts +8 -0
- package/dist/commands/biz/customers.js +181 -0
- package/dist/commands/biz/orders.d.ts +8 -0
- package/dist/commands/biz/orders.js +226 -0
- package/dist/commands/biz/products.d.ts +8 -0
- package/dist/commands/biz/products.js +255 -0
- package/dist/commands/biz/qdrant.d.ts +8 -0
- package/dist/commands/biz/qdrant.js +170 -0
- package/dist/commands/biz/seatable.d.ts +8 -0
- package/dist/commands/biz/seatable.js +449 -0
- package/dist/commands/biz/tickets.d.ts +8 -0
- package/dist/commands/biz/tickets.js +600 -0
- package/dist/commands/biz.d.ts +9 -0
- package/dist/commands/biz.js +22 -0
- package/dist/commands/config.d.ts +13 -0
- package/dist/commands/config.js +43 -16
- package/dist/commands/explain.js +12 -595
- package/dist/commands/idea.js +2 -50
- package/dist/commands/project.js +2 -47
- package/dist/commands/roadmap.js +0 -107
- package/dist/commands/task.js +11 -17
- package/dist/commands/vm.js +0 -225
- package/dist/commands/workflow.js +4 -60
- package/dist/index.js +5 -1
- package/dist/lib/biz/billbee-types.d.ts +259 -0
- package/dist/lib/biz/billbee-types.js +41 -0
- package/dist/lib/biz/billbee.d.ts +37 -0
- package/dist/lib/biz/billbee.js +165 -0
- package/dist/lib/biz/embeddings.d.ts +45 -0
- package/dist/lib/biz/embeddings.js +115 -0
- package/dist/lib/biz/index.d.ts +13 -0
- package/dist/lib/biz/index.js +11 -0
- package/dist/lib/biz/qdrant.d.ts +52 -0
- package/dist/lib/biz/qdrant.js +158 -0
- package/dist/lib/biz/seatable-types.d.ts +115 -0
- package/dist/lib/biz/seatable-types.js +27 -0
- package/dist/lib/biz/seatable.d.ts +49 -0
- package/dist/lib/biz/seatable.js +210 -0
- package/dist/lib/biz/zendesk-types.d.ts +136 -0
- package/dist/lib/biz/zendesk-types.js +28 -0
- package/dist/lib/biz/zendesk.d.ts +45 -0
- package/dist/lib/biz/zendesk.js +206 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# Husky CLI
|
|
2
2
|
|
|
3
|
-
[](https://github.com/simon-sfxecom/huskyv0/actions/workflows/cli-tests.yml)
|
|
4
|
-
[](https://codecov.io/gh/simon-sfxecom/huskyv0)
|
|
5
|
-
|
|
6
3
|
CLI for Huskyv0 Task Orchestration with Claude Agent SDK integration.
|
|
7
4
|
|
|
8
5
|
**Part of the [huskyv0 monorepo](https://github.com/simon-sfxecom/huskyv0)**
|
|
@@ -42,8 +39,6 @@ husky
|
|
|
42
39
|
husky task list # List all tasks
|
|
43
40
|
husky task list --status in_progress # Filter by status
|
|
44
41
|
husky task list --json # JSON output
|
|
45
|
-
husky task list -i # Interactive pagination
|
|
46
|
-
husky task list --per-page 10 --page 2 # Paginated output
|
|
47
42
|
husky task create "Fix login bug" --priority high
|
|
48
43
|
husky task get <task-id>
|
|
49
44
|
husky task start <task-id>
|
|
@@ -55,9 +50,7 @@ husky task delete <task-id>
|
|
|
55
50
|
### Project Management
|
|
56
51
|
|
|
57
52
|
```bash
|
|
58
|
-
husky project list
|
|
59
|
-
husky project list -i # Interactive pagination
|
|
60
|
-
husky project list --per-page 5 --page 1 # Paginated output
|
|
53
|
+
husky project list
|
|
61
54
|
husky project create "New Project" --description "..."
|
|
62
55
|
husky project get <project-id>
|
|
63
56
|
husky project update <project-id> --status active
|
|
@@ -70,9 +63,7 @@ husky project delete-knowledge <project-id> <knowledge-id>
|
|
|
70
63
|
### Workflow Management
|
|
71
64
|
|
|
72
65
|
```bash
|
|
73
|
-
husky workflow list
|
|
74
|
-
husky workflow list -i # Interactive pagination
|
|
75
|
-
husky workflow list --per-page 5 # Paginated output
|
|
66
|
+
husky workflow list
|
|
76
67
|
husky workflow create "Onboarding" --department <id>
|
|
77
68
|
husky workflow get <workflow-id>
|
|
78
69
|
husky workflow update <workflow-id> --name "Updated"
|
|
@@ -87,9 +78,7 @@ husky workflow generate-mermaid <workflow-id> # Mermaid diagram
|
|
|
87
78
|
### Idea Management
|
|
88
79
|
|
|
89
80
|
```bash
|
|
90
|
-
husky idea list
|
|
91
|
-
husky idea list -i # Interactive pagination
|
|
92
|
-
husky idea list --per-page 10 # Paginated output
|
|
81
|
+
husky idea list
|
|
93
82
|
husky idea create "New feature idea" --category feature
|
|
94
83
|
husky idea get <idea-id>
|
|
95
84
|
husky idea update <idea-id> --status approved
|
|
@@ -171,8 +160,6 @@ husky roadmap create "Q1 2025" --description "..."
|
|
|
171
160
|
husky roadmap update <roadmap-id> --name "Updated"
|
|
172
161
|
husky roadmap delete <roadmap-id>
|
|
173
162
|
husky roadmap add-phase <roadmap-id> --name "Phase 1"
|
|
174
|
-
husky roadmap update-phase <roadmap-id> <phase-id> --name "Updated"
|
|
175
|
-
husky roadmap delete-phase <roadmap-id> <phase-id> --force
|
|
176
163
|
husky roadmap add-feature <roadmap-id> --phase <id> --title "Feature"
|
|
177
164
|
husky roadmap list-features <roadmap-id>
|
|
178
165
|
husky roadmap update-feature <roadmap-id> <feature-id> --status done
|
|
@@ -200,20 +187,6 @@ husky vm-config update <config-id> --machine-type e2-standard-2
|
|
|
200
187
|
husky vm-config delete <config-id>
|
|
201
188
|
```
|
|
202
189
|
|
|
203
|
-
### Git Worktree Management
|
|
204
|
-
|
|
205
|
-
```bash
|
|
206
|
-
husky worktree list # List all worktrees
|
|
207
|
-
husky worktree create <session-name> # Create worktree
|
|
208
|
-
husky worktree info <session-name> # Show details
|
|
209
|
-
husky worktree status [session-name] # Show status
|
|
210
|
-
husky worktree cd <session-name> # Print path
|
|
211
|
-
husky worktree merge <session-name> # Merge to base
|
|
212
|
-
husky worktree remove <session-name> # Remove worktree
|
|
213
|
-
husky worktree branches # List husky/* branches
|
|
214
|
-
husky worktree cleanup # Clean stale worktrees
|
|
215
|
-
```
|
|
216
|
-
|
|
217
190
|
### Settings
|
|
218
191
|
|
|
219
192
|
```bash
|
|
@@ -248,35 +221,6 @@ husky completion zsh >> ~/.zshrc
|
|
|
248
221
|
husky completion fish > ~/.config/fish/completions/husky.fish
|
|
249
222
|
```
|
|
250
223
|
|
|
251
|
-
## Pagination
|
|
252
|
-
|
|
253
|
-
List commands support pagination with two modes:
|
|
254
|
-
|
|
255
|
-
### Interactive Pagination (`-i`)
|
|
256
|
-
|
|
257
|
-
Navigate through results using arrow keys:
|
|
258
|
-
|
|
259
|
-
```bash
|
|
260
|
-
husky task list -i # Interactive mode with arrow key navigation
|
|
261
|
-
husky project list -i # Works for projects, ideas, workflows
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
Features:
|
|
265
|
-
- Use `↑`/`↓` to navigate items
|
|
266
|
-
- `←` Previous page / `→` Next page
|
|
267
|
-
- Press `Enter` to select and view details
|
|
268
|
-
- Press `Esc` or select "Exit" to return
|
|
269
|
-
|
|
270
|
-
### Static Pagination (`--page`, `--per-page`)
|
|
271
|
-
|
|
272
|
-
For scripting or quick page views:
|
|
273
|
-
|
|
274
|
-
```bash
|
|
275
|
-
husky task list --per-page 10 # Show first 10 items
|
|
276
|
-
husky task list --per-page 10 --page 2 # Show items 11-20
|
|
277
|
-
husky idea list -n 5 -p 3 # Short form: 5 items, page 3
|
|
278
|
-
```
|
|
279
|
-
|
|
280
224
|
## Environment Variables
|
|
281
225
|
|
|
282
226
|
| Variable | Description |
|
|
@@ -339,22 +283,6 @@ husky --version
|
|
|
339
283
|
|
|
340
284
|
## Changelog
|
|
341
285
|
|
|
342
|
-
### v0.6.2 (2026-01-06)
|
|
343
|
-
- Added: Interactive pagination for list commands (`-i` flag)
|
|
344
|
-
- Added: Static pagination (`--page`, `--per-page` flags)
|
|
345
|
-
- Improved: Tasks, projects, ideas, workflows now support pagination
|
|
346
|
-
|
|
347
|
-
### v0.6.1 (2026-01-06)
|
|
348
|
-
- Added: Roadmap phase management (`update-phase`, `delete-phase`)
|
|
349
|
-
- Fixed: Various bug fixes
|
|
350
|
-
|
|
351
|
-
### v0.6.0 (2026-01-06)
|
|
352
|
-
- Added: Git Worktree support for multi-agent isolation
|
|
353
|
-
- Added: `husky worktree` commands (create, list, merge, remove, etc.)
|
|
354
|
-
- Added: MergeLock mechanism for safe concurrent operations
|
|
355
|
-
- Refactored: Interactive mode into modular components
|
|
356
|
-
- Improved: Based on Auto-Claude's worktree architecture
|
|
357
|
-
|
|
358
286
|
### v0.5.0 (2026-01-06)
|
|
359
287
|
- Full Dashboard feature parity (69 new commands)
|
|
360
288
|
- Added: project, workflow, idea, department, vm, jules, process, strategy, settings, vm-config commands
|
|
@@ -381,47 +309,6 @@ husky --version
|
|
|
381
309
|
- Configuration management
|
|
382
310
|
- API key authentication
|
|
383
311
|
|
|
384
|
-
## Development
|
|
385
|
-
|
|
386
|
-
### Testing
|
|
387
|
-
|
|
388
|
-
The CLI has comprehensive test coverage using Vitest:
|
|
389
|
-
|
|
390
|
-
```bash
|
|
391
|
-
# Run all tests
|
|
392
|
-
npm test
|
|
393
|
-
|
|
394
|
-
# Run tests in watch mode
|
|
395
|
-
npm run test:watch
|
|
396
|
-
|
|
397
|
-
# Run with coverage
|
|
398
|
-
npm run test:coverage
|
|
399
|
-
|
|
400
|
-
# Run specific test file
|
|
401
|
-
npm test tests/unit/commands/config.test.ts
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
**Test Structure:**
|
|
405
|
-
- `tests/setup.ts` - Global test configuration (MSW, memfs, mocks)
|
|
406
|
-
- `tests/unit/` - Unit tests for individual modules
|
|
407
|
-
- `tests/integration/` - Integration tests for workflows
|
|
408
|
-
- `tests/helpers/` - Reusable mocking utilities
|
|
409
|
-
|
|
410
|
-
**Current Coverage:**
|
|
411
|
-
- Config Command: ~29% lines, 60% functions
|
|
412
|
-
- Worktree Library: ~55% lines, 70% branches, 65% functions
|
|
413
|
-
- Total: 29 tests across 4 test files
|
|
414
|
-
|
|
415
|
-
### Building
|
|
416
|
-
|
|
417
|
-
```bash
|
|
418
|
-
# Build TypeScript
|
|
419
|
-
npm run build
|
|
420
|
-
|
|
421
|
-
# Watch mode for development
|
|
422
|
-
npm run dev
|
|
423
|
-
```
|
|
424
|
-
|
|
425
312
|
## License
|
|
426
313
|
|
|
427
314
|
MIT
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Husky Biz Customers Command
|
|
3
|
+
*
|
|
4
|
+
* Access customer profiles via Billbee (from order data)
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import { BillbeeClient } from "../../lib/biz/index.js";
|
|
8
|
+
export const customersCommand = new Command("customers")
|
|
9
|
+
.description("Access customer profiles (Billbee)");
|
|
10
|
+
// husky biz customers search <email>
|
|
11
|
+
customersCommand
|
|
12
|
+
.command("search <email>")
|
|
13
|
+
.description("Search customers by email")
|
|
14
|
+
.option("--json", "Output as JSON")
|
|
15
|
+
.action(async (email, options) => {
|
|
16
|
+
try {
|
|
17
|
+
const client = BillbeeClient.fromConfig();
|
|
18
|
+
const result = await client.findCustomerByEmail(email);
|
|
19
|
+
if (!result) {
|
|
20
|
+
console.log(`\n No customer found with email: ${email}\n`);
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
if (options.json) {
|
|
24
|
+
console.log(JSON.stringify(result, null, 2));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
console.log(`\n 👤 Customer: ${email}`);
|
|
28
|
+
console.log(" " + "─".repeat(40));
|
|
29
|
+
const addr = result.address;
|
|
30
|
+
if (addr) {
|
|
31
|
+
console.log(` Name: ${addr.FirstName || ""} ${addr.LastName || ""}`);
|
|
32
|
+
if (addr.Company)
|
|
33
|
+
console.log(` Company: ${addr.Company}`);
|
|
34
|
+
console.log(` Address: ${addr.Street || ""} ${addr.HouseNumber || ""}`);
|
|
35
|
+
console.log(` ${addr.Zip || ""} ${addr.City || ""}`);
|
|
36
|
+
if (addr.Phone)
|
|
37
|
+
console.log(` Phone: ${addr.Phone}`);
|
|
38
|
+
}
|
|
39
|
+
console.log(`\n Orders: ${result.orders.length}`);
|
|
40
|
+
console.log("");
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
console.error("Error:", error.message);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
// husky biz customers history <email>
|
|
48
|
+
customersCommand
|
|
49
|
+
.command("history <email>")
|
|
50
|
+
.description("Get order history for customer by email")
|
|
51
|
+
.option("-l, --limit <num>", "Max orders to show", "10")
|
|
52
|
+
.option("--json", "Output as JSON")
|
|
53
|
+
.action(async (email, options) => {
|
|
54
|
+
try {
|
|
55
|
+
const client = BillbeeClient.fromConfig();
|
|
56
|
+
const result = await client.findCustomerByEmail(email);
|
|
57
|
+
if (!result) {
|
|
58
|
+
console.log(`\n No customer found with email: ${email}\n`);
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
61
|
+
const orders = result.orders.slice(0, parseInt(options.limit, 10));
|
|
62
|
+
if (options.json) {
|
|
63
|
+
console.log(JSON.stringify(orders, null, 2));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const addr = result.address;
|
|
67
|
+
const name = addr ? `${addr.FirstName || ""} ${addr.LastName || ""}`.trim() : email;
|
|
68
|
+
console.log(`\n 📋 Order History for ${name} (${email})`);
|
|
69
|
+
console.log(" " + "─".repeat(60));
|
|
70
|
+
console.log(`\n ${result.orders.length} total orders\n`);
|
|
71
|
+
if (orders.length === 0) {
|
|
72
|
+
console.log(" No orders found.");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
for (const order of orders) {
|
|
76
|
+
const date = order.CreatedAt ? new Date(order.CreatedAt).toLocaleDateString("de-DE") : "?";
|
|
77
|
+
const total = order.TotalCost?.toFixed(2) || "0.00";
|
|
78
|
+
console.log(` #${(order.OrderNumber || "?").padEnd(12)} │ ${date} │ €${total}`);
|
|
79
|
+
}
|
|
80
|
+
console.log("");
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error("Error:", error.message);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// ============================================================================
|
|
88
|
+
// PREBUILD COMMANDS
|
|
89
|
+
// ============================================================================
|
|
90
|
+
import { ZendeskClient } from "../../lib/biz/index.js";
|
|
91
|
+
// husky biz customers 360 <email>
|
|
92
|
+
customersCommand
|
|
93
|
+
.command("360 <email>")
|
|
94
|
+
.alias("full")
|
|
95
|
+
.description("[PREBUILD] Full customer view (Billbee orders + Zendesk tickets)")
|
|
96
|
+
.option("--json", "Output as JSON")
|
|
97
|
+
.action(async (email, options) => {
|
|
98
|
+
try {
|
|
99
|
+
const billbee = BillbeeClient.fromConfig();
|
|
100
|
+
const zendesk = ZendeskClient.fromConfig();
|
|
101
|
+
// Parallel fetch from both systems
|
|
102
|
+
console.log(` Fetching customer data for ${email}...`);
|
|
103
|
+
const [customerResult, tickets] = await Promise.all([
|
|
104
|
+
billbee.findCustomerByEmail(email).catch(() => null),
|
|
105
|
+
zendesk.searchTickets(`requester:${email}`).catch(() => []),
|
|
106
|
+
]);
|
|
107
|
+
const result = {
|
|
108
|
+
email,
|
|
109
|
+
billbee: customerResult ? {
|
|
110
|
+
name: customerResult.address
|
|
111
|
+
? `${customerResult.address.FirstName || ''} ${customerResult.address.LastName || ''}`.trim()
|
|
112
|
+
: null,
|
|
113
|
+
company: customerResult.address?.Company || null,
|
|
114
|
+
phone: customerResult.address?.Phone || null,
|
|
115
|
+
orders: customerResult.orders.slice(0, 5),
|
|
116
|
+
totalOrders: customerResult.orders.length,
|
|
117
|
+
totalSpent: customerResult.orders.reduce((sum, o) => sum + (o.TotalCost || 0), 0),
|
|
118
|
+
} : null,
|
|
119
|
+
zendesk: {
|
|
120
|
+
tickets: tickets.slice(0, 5),
|
|
121
|
+
totalTickets: tickets.length,
|
|
122
|
+
openTickets: tickets.filter(t => ['new', 'open', 'pending'].includes(String(t.status))).length,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
if (options.json) {
|
|
126
|
+
console.log(JSON.stringify(result, null, 2));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
console.log(`\n 👤 Customer 360: ${email}`);
|
|
130
|
+
console.log(" " + "═".repeat(60));
|
|
131
|
+
// Billbee section
|
|
132
|
+
if (result.billbee) {
|
|
133
|
+
console.log(`\n 📦 ORDERS (Billbee)`);
|
|
134
|
+
console.log(" " + "─".repeat(40));
|
|
135
|
+
if (result.billbee.name)
|
|
136
|
+
console.log(` Name: ${result.billbee.name}`);
|
|
137
|
+
if (result.billbee.company)
|
|
138
|
+
console.log(` Company: ${result.billbee.company}`);
|
|
139
|
+
if (result.billbee.phone)
|
|
140
|
+
console.log(` Phone: ${result.billbee.phone}`);
|
|
141
|
+
console.log(` Total: ${result.billbee.totalOrders} orders | €${result.billbee.totalSpent.toFixed(2)}`);
|
|
142
|
+
if (result.billbee.orders.length > 0) {
|
|
143
|
+
console.log(`\n Recent orders:`);
|
|
144
|
+
for (const order of result.billbee.orders) {
|
|
145
|
+
const date = order.CreatedAt ? new Date(order.CreatedAt).toLocaleDateString("de-DE") : "?";
|
|
146
|
+
console.log(` #${(order.OrderNumber || "?").padEnd(12)} │ ${date} │ €${(order.TotalCost || 0).toFixed(2)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.log(`\n 📦 ORDERS: No Billbee data found`);
|
|
152
|
+
}
|
|
153
|
+
// Zendesk section
|
|
154
|
+
console.log(`\n 🎫 TICKETS (Zendesk)`);
|
|
155
|
+
console.log(" " + "─".repeat(40));
|
|
156
|
+
console.log(` Total: ${result.zendesk.totalTickets} tickets | ${result.zendesk.openTickets} open`);
|
|
157
|
+
if (result.zendesk.tickets.length > 0) {
|
|
158
|
+
console.log(`\n Recent tickets:`);
|
|
159
|
+
for (const ticket of result.zendesk.tickets) {
|
|
160
|
+
const statusIcon = getStatusIcon(String(ticket.status));
|
|
161
|
+
console.log(` ${statusIcon} #${String(ticket.id).padEnd(8)} │ ${String(ticket.status).padEnd(8)} │ ${String(ticket.subject).slice(0, 35)}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
console.log("");
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.error("Error:", error.message);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
function getStatusIcon(status) {
|
|
172
|
+
switch (status) {
|
|
173
|
+
case "new": return "🆕";
|
|
174
|
+
case "open": return "📬";
|
|
175
|
+
case "pending": return "⏳";
|
|
176
|
+
case "solved": return "✅";
|
|
177
|
+
case "closed": return "🔒";
|
|
178
|
+
default: return "○";
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
export default customersCommand;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Husky Biz Orders Command
|
|
3
|
+
*
|
|
4
|
+
* Manages orders via Billbee API
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import { BillbeeClient, OrderStateLabels } from "../../lib/biz/index.js";
|
|
8
|
+
export const ordersCommand = new Command("orders")
|
|
9
|
+
.description("Manage orders (Billbee)");
|
|
10
|
+
// husky biz orders list
|
|
11
|
+
ordersCommand
|
|
12
|
+
.command("list")
|
|
13
|
+
.description("List orders")
|
|
14
|
+
.option("-s, --status <status>", "Filter by status (ordered, paid, shipped, completed, etc.)")
|
|
15
|
+
.option("-l, --limit <num>", "Number of orders to show", "20")
|
|
16
|
+
.option("-p, --page <num>", "Page number", "1")
|
|
17
|
+
.option("--json", "Output as JSON")
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
try {
|
|
20
|
+
const client = BillbeeClient.fromConfig();
|
|
21
|
+
// Map status string to state ID
|
|
22
|
+
let orderStateId;
|
|
23
|
+
if (options.status) {
|
|
24
|
+
const statusLower = options.status.toLowerCase();
|
|
25
|
+
const stateEntry = Object.entries(OrderStateLabels).find(([, label]) => label === statusLower);
|
|
26
|
+
if (stateEntry) {
|
|
27
|
+
orderStateId = [parseInt(stateEntry[0], 10)];
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.error(`Unknown status: ${options.status}`);
|
|
31
|
+
console.error("Available: ordered, paid, shipped, completed, cancelled, return, packing, ready");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const response = await client.listOrders({
|
|
36
|
+
page: parseInt(options.page, 10),
|
|
37
|
+
pageSize: parseInt(options.limit, 10),
|
|
38
|
+
orderStateId,
|
|
39
|
+
includePositions: true,
|
|
40
|
+
});
|
|
41
|
+
if (options.json) {
|
|
42
|
+
console.log(JSON.stringify(response, null, 2));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
console.log(`\n 📦 Orders (${response.Paging.TotalRows} total)\n`);
|
|
46
|
+
if (response.Data.length === 0) {
|
|
47
|
+
console.log(" No orders found.");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
for (const order of response.Data) {
|
|
51
|
+
const stateLabel = OrderStateLabels[order.State || 0] || "unknown";
|
|
52
|
+
const date = order.CreatedAt ? new Date(order.CreatedAt).toLocaleDateString("de-DE") : "?";
|
|
53
|
+
const customer = order.InvoiceAddress?.LastName || order.Buyer?.Email || "Unknown";
|
|
54
|
+
const total = order.TotalCost?.toFixed(2) || "0.00";
|
|
55
|
+
console.log(` #${order.OrderNumber?.padEnd(12)} │ ${stateLabel.padEnd(10)} │ ${date} │ ${customer.slice(0, 20).padEnd(20)} │ €${total}`);
|
|
56
|
+
}
|
|
57
|
+
console.log(`\n Page ${response.Paging.Page} of ${response.Paging.TotalPages}\n`);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error("Error:", error.message);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// husky biz orders get <id>
|
|
65
|
+
ordersCommand
|
|
66
|
+
.command("get <id>")
|
|
67
|
+
.description("Get order details")
|
|
68
|
+
.option("--json", "Output as JSON")
|
|
69
|
+
.action(async (id, options) => {
|
|
70
|
+
try {
|
|
71
|
+
const client = BillbeeClient.fromConfig();
|
|
72
|
+
const response = await client.getOrder(id);
|
|
73
|
+
const order = response.Data;
|
|
74
|
+
if (options.json) {
|
|
75
|
+
console.log(JSON.stringify(order, null, 2));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const stateLabel = OrderStateLabels[order.State || 0] || "unknown";
|
|
79
|
+
console.log(`\n Order #${order.OrderNumber}`);
|
|
80
|
+
console.log(" " + "─".repeat(50));
|
|
81
|
+
console.log(` Billbee ID: ${order.BillbeeId || order.Id}`);
|
|
82
|
+
console.log(` Status: ${stateLabel}`);
|
|
83
|
+
console.log(` Created: ${order.CreatedAt ? new Date(order.CreatedAt).toLocaleString("de-DE") : "?"}`);
|
|
84
|
+
console.log(` Total: €${order.TotalCost?.toFixed(2) || "0.00"}`);
|
|
85
|
+
console.log(` Shipping: €${order.ShippingCost?.toFixed(2) || "0.00"}`);
|
|
86
|
+
if (order.InvoiceNumber) {
|
|
87
|
+
console.log(` Invoice: ${order.InvoiceNumber}`);
|
|
88
|
+
}
|
|
89
|
+
// Customer
|
|
90
|
+
const addr = order.InvoiceAddress;
|
|
91
|
+
if (addr) {
|
|
92
|
+
console.log(`\n Customer:`);
|
|
93
|
+
console.log(` ${addr.FirstName || ""} ${addr.LastName || ""}`);
|
|
94
|
+
if (addr.Company)
|
|
95
|
+
console.log(` ${addr.Company}`);
|
|
96
|
+
console.log(` ${addr.Street || ""} ${addr.HouseNumber || ""}`);
|
|
97
|
+
console.log(` ${addr.Zip || ""} ${addr.City || ""}`);
|
|
98
|
+
if (addr.Email)
|
|
99
|
+
console.log(` ${addr.Email}`);
|
|
100
|
+
}
|
|
101
|
+
// Items
|
|
102
|
+
if (order.OrderItems && order.OrderItems.length > 0) {
|
|
103
|
+
console.log(`\n Items:`);
|
|
104
|
+
for (const item of order.OrderItems) {
|
|
105
|
+
const sku = item.Product?.SKU || "-";
|
|
106
|
+
const title = item.Product?.Title?.slice(0, 35) || "Unknown";
|
|
107
|
+
console.log(` ${item.Quantity}x ${sku.padEnd(15)} ${title} (€${item.TotalPrice.toFixed(2)})`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
console.log("");
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error("Error:", error.message);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
// husky biz orders invoice <id>
|
|
118
|
+
ordersCommand
|
|
119
|
+
.command("invoice <id>")
|
|
120
|
+
.description("Get invoice info for order")
|
|
121
|
+
.action(async (id) => {
|
|
122
|
+
try {
|
|
123
|
+
const client = BillbeeClient.fromConfig();
|
|
124
|
+
const response = await client.getOrder(id);
|
|
125
|
+
const order = response.Data;
|
|
126
|
+
if (order.InvoiceNumber) {
|
|
127
|
+
console.log(`\n Invoice: ${order.InvoiceNumber}`);
|
|
128
|
+
if (order.InvoiceDate) {
|
|
129
|
+
console.log(` Date: ${new Date(order.InvoiceDate).toLocaleDateString("de-DE")}`);
|
|
130
|
+
}
|
|
131
|
+
console.log(` Total: €${order.TotalCost?.toFixed(2) || "0.00"}`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.log("\n No invoice generated for this order.");
|
|
135
|
+
}
|
|
136
|
+
console.log("");
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
console.error("Error:", error.message);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
// husky biz orders update <id>
|
|
144
|
+
ordersCommand
|
|
145
|
+
.command("update <id>")
|
|
146
|
+
.description("Update order properties")
|
|
147
|
+
.option("--state <state>", "New state (paid, shipped, completed, etc.)")
|
|
148
|
+
.option("--comment <text>", "Add seller comment")
|
|
149
|
+
.action(async (id, options) => {
|
|
150
|
+
try {
|
|
151
|
+
const client = BillbeeClient.fromConfig();
|
|
152
|
+
const updates = {};
|
|
153
|
+
if (options.state) {
|
|
154
|
+
const stateEntry = Object.entries(OrderStateLabels).find(([, label]) => label === options.state.toLowerCase());
|
|
155
|
+
if (stateEntry) {
|
|
156
|
+
updates.State = parseInt(stateEntry[0], 10);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
console.error(`Unknown state: ${options.state}`);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (options.comment) {
|
|
164
|
+
updates.SellerComment = options.comment;
|
|
165
|
+
}
|
|
166
|
+
if (Object.keys(updates).length === 0) {
|
|
167
|
+
console.error("Error: Provide --state or --comment");
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
const response = await client.updateOrder(id, updates);
|
|
171
|
+
console.log(`✓ Order #${response.Data.OrderNumber} updated`);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
console.error("Error:", error.message);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
// husky biz orders add-tag <id> <tag>
|
|
179
|
+
ordersCommand
|
|
180
|
+
.command("add-tag <id> <tag>")
|
|
181
|
+
.description("Add a tag to an order")
|
|
182
|
+
.action(async (id, tag) => {
|
|
183
|
+
try {
|
|
184
|
+
const client = BillbeeClient.fromConfig();
|
|
185
|
+
await client.addOrderTags(parseInt(id, 10), [tag]);
|
|
186
|
+
console.log(`✓ Tag "${tag}" added to order #${id}`);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
console.error("Error:", error.message);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
// husky biz orders remove-tag <id> <tag>
|
|
194
|
+
ordersCommand
|
|
195
|
+
.command("remove-tag <id> <tag>")
|
|
196
|
+
.description("Remove a tag from an order")
|
|
197
|
+
.action(async (id, tag) => {
|
|
198
|
+
try {
|
|
199
|
+
const client = BillbeeClient.fromConfig();
|
|
200
|
+
await client.removeOrderTags(parseInt(id, 10), [tag]);
|
|
201
|
+
console.log(`✓ Tag "${tag}" removed from order #${id}`);
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
console.error("Error:", error.message);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
// husky biz orders note <id>
|
|
209
|
+
ordersCommand
|
|
210
|
+
.command("note <id>")
|
|
211
|
+
.description("Add seller comment/note to order")
|
|
212
|
+
.requiredOption("-m, --message <text>", "Note content")
|
|
213
|
+
.action(async (id, options) => {
|
|
214
|
+
try {
|
|
215
|
+
const client = BillbeeClient.fromConfig();
|
|
216
|
+
await client.updateOrder(id, {
|
|
217
|
+
SellerComment: options.message,
|
|
218
|
+
});
|
|
219
|
+
console.log(`✓ Note added to order #${id}`);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
console.error("Error:", error.message);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
export default ordersCommand;
|