@simonfestl/husky-cli 0.3.0 → 0.5.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/README.md +228 -58
- package/dist/commands/changelog.d.ts +2 -0
- package/dist/commands/changelog.js +401 -0
- package/dist/commands/completion.d.ts +2 -0
- package/dist/commands/completion.js +400 -0
- package/dist/commands/config.d.ts +1 -0
- package/dist/commands/config.js +101 -1
- package/dist/commands/department.d.ts +2 -0
- package/dist/commands/department.js +240 -0
- package/dist/commands/explain.d.ts +2 -0
- package/dist/commands/explain.js +411 -0
- package/dist/commands/idea.d.ts +2 -0
- package/dist/commands/idea.js +340 -0
- package/dist/commands/interactive.d.ts +1 -0
- package/dist/commands/interactive.js +1397 -0
- package/dist/commands/jules.d.ts +2 -0
- package/dist/commands/jules.js +593 -0
- package/dist/commands/process.d.ts +2 -0
- package/dist/commands/process.js +289 -0
- package/dist/commands/project.d.ts +2 -0
- package/dist/commands/project.js +473 -0
- package/dist/commands/roadmap.js +318 -0
- package/dist/commands/settings.d.ts +2 -0
- package/dist/commands/settings.js +153 -0
- package/dist/commands/strategy.d.ts +2 -0
- package/dist/commands/strategy.js +706 -0
- package/dist/commands/task.js +244 -1
- package/dist/commands/vm-config.d.ts +2 -0
- package/dist/commands/vm-config.js +318 -0
- package/dist/commands/vm.d.ts +2 -0
- package/dist/commands/vm.js +621 -0
- package/dist/commands/workflow.d.ts +2 -0
- package/dist/commands/workflow.js +545 -0
- package/dist/index.js +35 -2
- package/package.json +8 -2
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { getConfig } from "./config.js";
|
|
3
|
+
export const workflowCommand = new Command("workflow")
|
|
4
|
+
.description("Manage workflows and workflow steps");
|
|
5
|
+
// Helper: Ensure API is configured
|
|
6
|
+
function ensureConfig() {
|
|
7
|
+
const config = getConfig();
|
|
8
|
+
if (!config.apiUrl) {
|
|
9
|
+
console.error("Error: API URL not configured. Run: husky config set api-url <url>");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
return config;
|
|
13
|
+
}
|
|
14
|
+
// husky workflow list
|
|
15
|
+
workflowCommand
|
|
16
|
+
.command("list")
|
|
17
|
+
.description("List all workflows")
|
|
18
|
+
.option("--value-stream <valueStream>", "Filter by value stream")
|
|
19
|
+
.option("--json", "Output as JSON")
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
const config = ensureConfig();
|
|
22
|
+
try {
|
|
23
|
+
const url = new URL("/api/workflows", config.apiUrl);
|
|
24
|
+
if (options.valueStream) {
|
|
25
|
+
url.searchParams.set("valueStream", options.valueStream);
|
|
26
|
+
}
|
|
27
|
+
const res = await fetch(url.toString(), {
|
|
28
|
+
headers: config.apiKey ? { "x-api-key": config.apiKey } : {},
|
|
29
|
+
});
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
throw new Error(`API error: ${res.status}`);
|
|
32
|
+
}
|
|
33
|
+
const workflows = await res.json();
|
|
34
|
+
if (options.json) {
|
|
35
|
+
console.log(JSON.stringify(workflows, null, 2));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
printWorkflows(workflows);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error("Error fetching workflows:", error);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
// husky workflow get <id>
|
|
47
|
+
workflowCommand
|
|
48
|
+
.command("get <id>")
|
|
49
|
+
.description("Get workflow details with steps")
|
|
50
|
+
.option("--json", "Output as JSON")
|
|
51
|
+
.action(async (id, options) => {
|
|
52
|
+
const config = ensureConfig();
|
|
53
|
+
try {
|
|
54
|
+
// Fetch workflow
|
|
55
|
+
const workflowRes = await fetch(`${config.apiUrl}/api/workflows/${id}`, {
|
|
56
|
+
headers: config.apiKey ? { "x-api-key": config.apiKey } : {},
|
|
57
|
+
});
|
|
58
|
+
if (!workflowRes.ok) {
|
|
59
|
+
if (workflowRes.status === 404) {
|
|
60
|
+
console.error(`Error: Workflow ${id} not found`);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.error(`Error: API returned ${workflowRes.status}`);
|
|
64
|
+
}
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const workflow = await workflowRes.json();
|
|
68
|
+
// Fetch steps
|
|
69
|
+
const stepsRes = await fetch(`${config.apiUrl}/api/workflows/${id}/steps`, {
|
|
70
|
+
headers: config.apiKey ? { "x-api-key": config.apiKey } : {},
|
|
71
|
+
});
|
|
72
|
+
let steps = [];
|
|
73
|
+
if (stepsRes.ok) {
|
|
74
|
+
steps = await stepsRes.json();
|
|
75
|
+
}
|
|
76
|
+
const workflowWithSteps = { ...workflow, steps };
|
|
77
|
+
if (options.json) {
|
|
78
|
+
console.log(JSON.stringify(workflowWithSteps, null, 2));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
printWorkflowDetail(workflowWithSteps);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error("Error fetching workflow:", error);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// husky workflow create <name>
|
|
90
|
+
workflowCommand
|
|
91
|
+
.command("create <name>")
|
|
92
|
+
.description("Create a new workflow")
|
|
93
|
+
.option("-d, --description <description>", "Workflow description")
|
|
94
|
+
.option("--value-stream <valueStream>", "Value stream", "general")
|
|
95
|
+
.option("--status <status>", "Workflow status (draft, active, paused, archived)", "draft")
|
|
96
|
+
.option("--action <action>", "Action type (manual, semi_automated, fully_automated)", "manual")
|
|
97
|
+
.option("--json", "Output as JSON")
|
|
98
|
+
.action(async (name, options) => {
|
|
99
|
+
const config = ensureConfig();
|
|
100
|
+
try {
|
|
101
|
+
const res = await fetch(`${config.apiUrl}/api/workflows`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: {
|
|
104
|
+
"Content-Type": "application/json",
|
|
105
|
+
...(config.apiKey ? { "x-api-key": config.apiKey } : {}),
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
name,
|
|
109
|
+
description: options.description || "",
|
|
110
|
+
valueStream: options.valueStream,
|
|
111
|
+
status: options.status,
|
|
112
|
+
action: options.action,
|
|
113
|
+
departmentIds: [],
|
|
114
|
+
autonomyWeight: 0,
|
|
115
|
+
}),
|
|
116
|
+
});
|
|
117
|
+
if (!res.ok) {
|
|
118
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
119
|
+
throw new Error(errorBody.error || `API error: ${res.status}`);
|
|
120
|
+
}
|
|
121
|
+
const workflow = await res.json();
|
|
122
|
+
if (options.json) {
|
|
123
|
+
console.log(JSON.stringify(workflow, null, 2));
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.log(`Created workflow: ${workflow.name}`);
|
|
127
|
+
console.log(` ID: ${workflow.id}`);
|
|
128
|
+
console.log(` Value Stream: ${workflow.valueStream}`);
|
|
129
|
+
console.log(` Status: ${workflow.status}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
console.error("Error creating workflow:", error);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// husky workflow update <id>
|
|
138
|
+
workflowCommand
|
|
139
|
+
.command("update <id>")
|
|
140
|
+
.description("Update a workflow")
|
|
141
|
+
.option("-n, --name <name>", "New name")
|
|
142
|
+
.option("-d, --description <description>", "New description")
|
|
143
|
+
.option("--value-stream <valueStream>", "New value stream")
|
|
144
|
+
.option("--status <status>", "New status (draft, active, paused, archived)")
|
|
145
|
+
.option("--action <action>", "New action type (manual, semi_automated, fully_automated)")
|
|
146
|
+
.option("--json", "Output as JSON")
|
|
147
|
+
.action(async (id, options) => {
|
|
148
|
+
const config = ensureConfig();
|
|
149
|
+
// Build update payload
|
|
150
|
+
const updateData = {};
|
|
151
|
+
if (options.name)
|
|
152
|
+
updateData.name = options.name;
|
|
153
|
+
if (options.description)
|
|
154
|
+
updateData.description = options.description;
|
|
155
|
+
if (options.valueStream)
|
|
156
|
+
updateData.valueStream = options.valueStream;
|
|
157
|
+
if (options.status) {
|
|
158
|
+
const validStatuses = ["draft", "active", "paused", "archived"];
|
|
159
|
+
if (!validStatuses.includes(options.status)) {
|
|
160
|
+
console.error(`Error: Invalid status "${options.status}". Must be one of: ${validStatuses.join(", ")}`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
updateData.status = options.status;
|
|
164
|
+
}
|
|
165
|
+
if (options.action) {
|
|
166
|
+
const validActions = ["manual", "semi_automated", "fully_automated"];
|
|
167
|
+
if (!validActions.includes(options.action)) {
|
|
168
|
+
console.error(`Error: Invalid action "${options.action}". Must be one of: ${validActions.join(", ")}`);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
updateData.action = options.action;
|
|
172
|
+
}
|
|
173
|
+
if (Object.keys(updateData).length === 0) {
|
|
174
|
+
console.error("Error: No update options provided. Use -n, -d, --value-stream, --status, or --action");
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const res = await fetch(`${config.apiUrl}/api/workflows/${id}`, {
|
|
179
|
+
method: "PATCH",
|
|
180
|
+
headers: {
|
|
181
|
+
"Content-Type": "application/json",
|
|
182
|
+
...(config.apiKey ? { "x-api-key": config.apiKey } : {}),
|
|
183
|
+
},
|
|
184
|
+
body: JSON.stringify(updateData),
|
|
185
|
+
});
|
|
186
|
+
if (!res.ok) {
|
|
187
|
+
if (res.status === 404) {
|
|
188
|
+
console.error(`Error: Workflow ${id} not found`);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
192
|
+
console.error(`Error: API returned ${res.status}`, errorBody.error || "");
|
|
193
|
+
}
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
const workflow = await res.json();
|
|
197
|
+
if (options.json) {
|
|
198
|
+
console.log(JSON.stringify(workflow, null, 2));
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
console.log(`Workflow updated successfully`);
|
|
202
|
+
console.log(` Name: ${workflow.name}`);
|
|
203
|
+
console.log(` Status: ${workflow.status}`);
|
|
204
|
+
console.log(` Action: ${workflow.action}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
console.error("Error updating workflow:", error);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
// husky workflow delete <id>
|
|
213
|
+
workflowCommand
|
|
214
|
+
.command("delete <id>")
|
|
215
|
+
.description("Delete a workflow")
|
|
216
|
+
.option("--force", "Skip confirmation")
|
|
217
|
+
.option("--json", "Output as JSON")
|
|
218
|
+
.action(async (id, options) => {
|
|
219
|
+
const config = ensureConfig();
|
|
220
|
+
if (!options.force) {
|
|
221
|
+
console.log("Warning: This will permanently delete the workflow and all its steps.");
|
|
222
|
+
console.log("Use --force to confirm deletion.");
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
const res = await fetch(`${config.apiUrl}/api/workflows/${id}`, {
|
|
227
|
+
method: "DELETE",
|
|
228
|
+
headers: config.apiKey ? { "x-api-key": config.apiKey } : {},
|
|
229
|
+
});
|
|
230
|
+
if (!res.ok) {
|
|
231
|
+
if (res.status === 404) {
|
|
232
|
+
console.error(`Error: Workflow ${id} not found`);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
console.error(`Error: API returned ${res.status}`);
|
|
236
|
+
}
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
if (options.json) {
|
|
240
|
+
console.log(JSON.stringify({ success: true, id }, null, 2));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
console.log(`Workflow deleted`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
console.error("Error deleting workflow:", error);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
// husky workflow add-step <workflowId>
|
|
252
|
+
workflowCommand
|
|
253
|
+
.command("add-step <workflowId>")
|
|
254
|
+
.description("Add a step to a workflow")
|
|
255
|
+
.requiredOption("--name <name>", "Step name")
|
|
256
|
+
.option("--description <description>", "Step description")
|
|
257
|
+
.option("--order <order>", "Step order (0-based)", parseInt)
|
|
258
|
+
.option("--json", "Output as JSON")
|
|
259
|
+
.action(async (workflowId, options) => {
|
|
260
|
+
const config = ensureConfig();
|
|
261
|
+
try {
|
|
262
|
+
const res = await fetch(`${config.apiUrl}/api/workflows/${workflowId}/steps`, {
|
|
263
|
+
method: "POST",
|
|
264
|
+
headers: {
|
|
265
|
+
"Content-Type": "application/json",
|
|
266
|
+
...(config.apiKey ? { "x-api-key": config.apiKey } : {}),
|
|
267
|
+
},
|
|
268
|
+
body: JSON.stringify({
|
|
269
|
+
name: options.name,
|
|
270
|
+
description: options.description || "",
|
|
271
|
+
order: options.order ?? 0,
|
|
272
|
+
}),
|
|
273
|
+
});
|
|
274
|
+
if (!res.ok) {
|
|
275
|
+
if (res.status === 404) {
|
|
276
|
+
console.error(`Error: Workflow ${workflowId} not found`);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
280
|
+
console.error(`Error: API returned ${res.status}`, errorBody.error || "");
|
|
281
|
+
}
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
const step = await res.json();
|
|
285
|
+
if (options.json) {
|
|
286
|
+
console.log(JSON.stringify(step, null, 2));
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
console.log(`Added step to workflow`);
|
|
290
|
+
console.log(` Step ID: ${step.id}`);
|
|
291
|
+
console.log(` Name: ${step.name}`);
|
|
292
|
+
console.log(` Order: ${step.order}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
console.error("Error adding step:", error);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
// husky workflow update-step <workflowId> <stepId>
|
|
301
|
+
workflowCommand
|
|
302
|
+
.command("update-step <workflowId> <stepId>")
|
|
303
|
+
.description("Update a workflow step")
|
|
304
|
+
.option("--name <name>", "New step name")
|
|
305
|
+
.option("--description <description>", "New step description")
|
|
306
|
+
.option("--order <order>", "New step order", parseInt)
|
|
307
|
+
.option("--json", "Output as JSON")
|
|
308
|
+
.action(async (workflowId, stepId, options) => {
|
|
309
|
+
const config = ensureConfig();
|
|
310
|
+
// Build update payload
|
|
311
|
+
const updateData = {};
|
|
312
|
+
if (options.name)
|
|
313
|
+
updateData.name = options.name;
|
|
314
|
+
if (options.description)
|
|
315
|
+
updateData.description = options.description;
|
|
316
|
+
if (options.order !== undefined)
|
|
317
|
+
updateData.order = options.order;
|
|
318
|
+
if (Object.keys(updateData).length === 0) {
|
|
319
|
+
console.error("Error: No update options provided. Use --name, --description, or --order");
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
const res = await fetch(`${config.apiUrl}/api/workflows/${workflowId}/steps/${stepId}`, {
|
|
324
|
+
method: "PATCH",
|
|
325
|
+
headers: {
|
|
326
|
+
"Content-Type": "application/json",
|
|
327
|
+
...(config.apiKey ? { "x-api-key": config.apiKey } : {}),
|
|
328
|
+
},
|
|
329
|
+
body: JSON.stringify(updateData),
|
|
330
|
+
});
|
|
331
|
+
if (!res.ok) {
|
|
332
|
+
if (res.status === 404) {
|
|
333
|
+
console.error(`Error: Step ${stepId} not found`);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
337
|
+
console.error(`Error: API returned ${res.status}`, errorBody.error || "");
|
|
338
|
+
}
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
const step = await res.json();
|
|
342
|
+
if (options.json) {
|
|
343
|
+
console.log(JSON.stringify(step, null, 2));
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
console.log(`Step updated successfully`);
|
|
347
|
+
console.log(` Name: ${step.name}`);
|
|
348
|
+
console.log(` Order: ${step.order}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
catch (error) {
|
|
352
|
+
console.error("Error updating step:", error);
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
// husky workflow delete-step <workflowId> <stepId>
|
|
357
|
+
workflowCommand
|
|
358
|
+
.command("delete-step <workflowId> <stepId>")
|
|
359
|
+
.description("Delete a workflow step")
|
|
360
|
+
.option("--json", "Output as JSON")
|
|
361
|
+
.action(async (workflowId, stepId, options) => {
|
|
362
|
+
const config = ensureConfig();
|
|
363
|
+
try {
|
|
364
|
+
const res = await fetch(`${config.apiUrl}/api/workflows/${workflowId}/steps/${stepId}`, {
|
|
365
|
+
method: "DELETE",
|
|
366
|
+
headers: config.apiKey ? { "x-api-key": config.apiKey } : {},
|
|
367
|
+
});
|
|
368
|
+
if (!res.ok) {
|
|
369
|
+
if (res.status === 404) {
|
|
370
|
+
console.error(`Error: Step ${stepId} not found`);
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
console.error(`Error: API returned ${res.status}`);
|
|
374
|
+
}
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
if (options.json) {
|
|
378
|
+
console.log(JSON.stringify({ success: true, id: stepId }, null, 2));
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
console.log(`Step deleted`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
console.error("Error deleting step:", error);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
// husky workflow generate-steps <workflowId>
|
|
390
|
+
workflowCommand
|
|
391
|
+
.command("generate-steps <workflowId>")
|
|
392
|
+
.description("AI-generate steps from an SOP document")
|
|
393
|
+
.requiredOption("--sop <document>", "SOP document text")
|
|
394
|
+
.option("--json", "Output as JSON")
|
|
395
|
+
.action(async (workflowId, options) => {
|
|
396
|
+
const config = ensureConfig();
|
|
397
|
+
console.log("Generating workflow steps with AI...");
|
|
398
|
+
console.log("This may take a moment...\n");
|
|
399
|
+
try {
|
|
400
|
+
const res = await fetch(`${config.apiUrl}/api/workflows/${workflowId}/generate-steps`, {
|
|
401
|
+
method: "POST",
|
|
402
|
+
headers: {
|
|
403
|
+
"Content-Type": "application/json",
|
|
404
|
+
...(config.apiKey ? { "x-api-key": config.apiKey } : {}),
|
|
405
|
+
},
|
|
406
|
+
body: JSON.stringify({
|
|
407
|
+
sopDocument: options.sop,
|
|
408
|
+
}),
|
|
409
|
+
});
|
|
410
|
+
if (!res.ok) {
|
|
411
|
+
if (res.status === 404) {
|
|
412
|
+
console.error(`Error: Workflow ${workflowId} not found`);
|
|
413
|
+
}
|
|
414
|
+
else if (res.status === 503) {
|
|
415
|
+
console.error("Error: AI generation not available - ANTHROPIC_API_KEY not configured on server");
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
const errorBody = await res.json().catch(() => ({}));
|
|
419
|
+
console.error(`Error: ${errorBody.error || `API returned ${res.status}`}`);
|
|
420
|
+
}
|
|
421
|
+
process.exit(1);
|
|
422
|
+
}
|
|
423
|
+
const result = await res.json();
|
|
424
|
+
if (options.json) {
|
|
425
|
+
console.log(JSON.stringify(result, null, 2));
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
console.log(`Steps generated successfully!`);
|
|
429
|
+
console.log(` Workflow: ${result.workflowName}`);
|
|
430
|
+
console.log(` Steps Created: ${result.stepsGenerated}`);
|
|
431
|
+
console.log("");
|
|
432
|
+
if (result.steps && result.steps.length > 0) {
|
|
433
|
+
console.log(" GENERATED STEPS");
|
|
434
|
+
console.log(" " + "-".repeat(50));
|
|
435
|
+
for (const step of result.steps) {
|
|
436
|
+
console.log(` ${step.order + 1}. ${step.name}`);
|
|
437
|
+
if (step.description) {
|
|
438
|
+
console.log(` ${step.description}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
console.error("Error generating steps:", error);
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
// husky workflow list-steps <workflowId>
|
|
450
|
+
workflowCommand
|
|
451
|
+
.command("list-steps <workflowId>")
|
|
452
|
+
.description("List all steps in a workflow")
|
|
453
|
+
.option("--json", "Output as JSON")
|
|
454
|
+
.action(async (workflowId, options) => {
|
|
455
|
+
const config = ensureConfig();
|
|
456
|
+
try {
|
|
457
|
+
const res = await fetch(`${config.apiUrl}/api/workflows/${workflowId}/steps`, {
|
|
458
|
+
headers: config.apiKey ? { "x-api-key": config.apiKey } : {},
|
|
459
|
+
});
|
|
460
|
+
if (!res.ok) {
|
|
461
|
+
if (res.status === 404) {
|
|
462
|
+
console.error(`Error: Workflow ${workflowId} not found`);
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
console.error(`Error: API returned ${res.status}`);
|
|
466
|
+
}
|
|
467
|
+
process.exit(1);
|
|
468
|
+
}
|
|
469
|
+
const steps = await res.json();
|
|
470
|
+
if (options.json) {
|
|
471
|
+
console.log(JSON.stringify(steps, null, 2));
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
printSteps(steps);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
catch (error) {
|
|
478
|
+
console.error("Error fetching steps:", error);
|
|
479
|
+
process.exit(1);
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
// Print helpers
|
|
483
|
+
function printWorkflows(workflows) {
|
|
484
|
+
if (workflows.length === 0) {
|
|
485
|
+
console.log("\n No workflows found.");
|
|
486
|
+
console.log(" Create one with: husky workflow create <name>\n");
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
console.log("\n WORKFLOWS");
|
|
490
|
+
console.log(" " + "-".repeat(80));
|
|
491
|
+
console.log(` ${"ID".padEnd(24)} ${"NAME".padEnd(25)} ${"VALUE STREAM".padEnd(18)} ${"STATUS".padEnd(10)} ACTION`);
|
|
492
|
+
console.log(" " + "-".repeat(80));
|
|
493
|
+
for (const workflow of workflows) {
|
|
494
|
+
const truncatedName = workflow.name.length > 23 ? workflow.name.substring(0, 20) + "..." : workflow.name;
|
|
495
|
+
const valueStream = workflow.valueStream.replace(/_/g, " ");
|
|
496
|
+
const truncatedStream = valueStream.length > 16 ? valueStream.substring(0, 13) + "..." : valueStream;
|
|
497
|
+
console.log(` ${workflow.id.padEnd(24)} ${truncatedName.padEnd(25)} ${truncatedStream.padEnd(18)} ${workflow.status.padEnd(10)} ${workflow.action}`);
|
|
498
|
+
}
|
|
499
|
+
console.log("");
|
|
500
|
+
}
|
|
501
|
+
function printWorkflowDetail(workflow) {
|
|
502
|
+
console.log(`\n Workflow: ${workflow.name}`);
|
|
503
|
+
console.log(" " + "-".repeat(60));
|
|
504
|
+
console.log(` ID: ${workflow.id}`);
|
|
505
|
+
console.log(` Description: ${workflow.description || "(none)"}`);
|
|
506
|
+
console.log(` Value Stream: ${workflow.valueStream.replace(/_/g, " ")}`);
|
|
507
|
+
console.log(` Status: ${workflow.status}`);
|
|
508
|
+
console.log(` Action: ${workflow.action}`);
|
|
509
|
+
console.log(` Autonomy: ${workflow.autonomyWeight}%`);
|
|
510
|
+
const steps = workflow.steps || [];
|
|
511
|
+
console.log(`\n Steps: ${steps.length}`);
|
|
512
|
+
if (steps.length > 0) {
|
|
513
|
+
console.log(" " + "-".repeat(50));
|
|
514
|
+
const sortedSteps = [...steps].sort((a, b) => a.order - b.order);
|
|
515
|
+
for (const step of sortedSteps) {
|
|
516
|
+
console.log(` ${step.order + 1}. ${step.name}`);
|
|
517
|
+
if (step.description) {
|
|
518
|
+
console.log(` ${step.description}`);
|
|
519
|
+
}
|
|
520
|
+
console.log(` ID: ${step.id}`);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
console.log("");
|
|
524
|
+
}
|
|
525
|
+
function printSteps(steps) {
|
|
526
|
+
if (steps.length === 0) {
|
|
527
|
+
console.log("\n No steps found.");
|
|
528
|
+
console.log(" Add one with: husky workflow add-step <workflowId> --name <name>\n");
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
console.log("\n WORKFLOW STEPS");
|
|
532
|
+
console.log(" " + "-".repeat(70));
|
|
533
|
+
console.log(` ${"#".padEnd(4)} ${"ID".padEnd(24)} ${"NAME".padEnd(35)}`);
|
|
534
|
+
console.log(" " + "-".repeat(70));
|
|
535
|
+
const sortedSteps = [...steps].sort((a, b) => a.order - b.order);
|
|
536
|
+
for (const step of sortedSteps) {
|
|
537
|
+
const truncatedName = step.name.length > 33 ? step.name.substring(0, 30) + "..." : step.name;
|
|
538
|
+
console.log(` ${String(step.order + 1).padEnd(4)} ${step.id.padEnd(24)} ${truncatedName.padEnd(35)}`);
|
|
539
|
+
if (step.description) {
|
|
540
|
+
const truncatedDesc = step.description.length > 60 ? step.description.substring(0, 57) + "..." : step.description;
|
|
541
|
+
console.log(` ${truncatedDesc}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
console.log("");
|
|
545
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -4,13 +4,46 @@ import { taskCommand } from "./commands/task.js";
|
|
|
4
4
|
import { configCommand } from "./commands/config.js";
|
|
5
5
|
import { agentCommand } from "./commands/agent.js";
|
|
6
6
|
import { roadmapCommand } from "./commands/roadmap.js";
|
|
7
|
+
import { changelogCommand } from "./commands/changelog.js";
|
|
8
|
+
import { explainCommand } from "./commands/explain.js";
|
|
9
|
+
import { projectCommand } from "./commands/project.js";
|
|
10
|
+
import { ideaCommand } from "./commands/idea.js";
|
|
11
|
+
import { departmentCommand } from "./commands/department.js";
|
|
12
|
+
import { workflowCommand } from "./commands/workflow.js";
|
|
13
|
+
import { julesCommand } from "./commands/jules.js";
|
|
14
|
+
import { vmCommand } from "./commands/vm.js";
|
|
15
|
+
import { vmConfigCommand } from "./commands/vm-config.js";
|
|
16
|
+
import { processCommand } from "./commands/process.js";
|
|
17
|
+
import { settingsCommand } from "./commands/settings.js";
|
|
18
|
+
import { strategyCommand } from "./commands/strategy.js";
|
|
19
|
+
import { completionCommand } from "./commands/completion.js";
|
|
20
|
+
import { runInteractiveMode } from "./commands/interactive.js";
|
|
7
21
|
const program = new Command();
|
|
8
22
|
program
|
|
9
23
|
.name("husky")
|
|
10
24
|
.description("CLI for Huskyv0 Task Orchestration with Claude Agent")
|
|
11
|
-
.version("0.
|
|
25
|
+
.version("0.5.1");
|
|
12
26
|
program.addCommand(taskCommand);
|
|
13
27
|
program.addCommand(configCommand);
|
|
14
28
|
program.addCommand(agentCommand);
|
|
15
29
|
program.addCommand(roadmapCommand);
|
|
16
|
-
program.
|
|
30
|
+
program.addCommand(changelogCommand);
|
|
31
|
+
program.addCommand(explainCommand);
|
|
32
|
+
program.addCommand(projectCommand);
|
|
33
|
+
program.addCommand(ideaCommand);
|
|
34
|
+
program.addCommand(departmentCommand);
|
|
35
|
+
program.addCommand(workflowCommand);
|
|
36
|
+
program.addCommand(julesCommand);
|
|
37
|
+
program.addCommand(vmCommand);
|
|
38
|
+
program.addCommand(vmConfigCommand);
|
|
39
|
+
program.addCommand(processCommand);
|
|
40
|
+
program.addCommand(settingsCommand);
|
|
41
|
+
program.addCommand(strategyCommand);
|
|
42
|
+
program.addCommand(completionCommand);
|
|
43
|
+
// Check if no command was provided - run interactive mode
|
|
44
|
+
if (process.argv.length <= 2) {
|
|
45
|
+
runInteractiveMode();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
program.parse();
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simonfestl/husky-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "CLI for Huskyv0 Task Orchestration with Claude Agent SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@anthropic-ai/claude-code": "^1.0.0",
|
|
17
|
+
"@inquirer/prompts": "^8.1.0",
|
|
17
18
|
"commander": "^12.1.0"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
@@ -25,6 +26,11 @@
|
|
|
25
26
|
],
|
|
26
27
|
"repository": {
|
|
27
28
|
"type": "git",
|
|
28
|
-
"url": "https://github.com/simon-sfxecom/
|
|
29
|
+
"url": "https://github.com/simon-sfxecom/huskyv0.git",
|
|
30
|
+
"directory": "packages/cli"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/simon-sfxecom/huskyv0/tree/main/packages/cli#readme",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/simon-sfxecom/huskyv0/issues"
|
|
29
35
|
}
|
|
30
36
|
}
|