@simonfestl/husky-cli 0.9.6 β 1.0.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 +19 -13
- package/dist/commands/chat.d.ts +2 -0
- package/dist/commands/chat.js +162 -0
- package/dist/commands/completion.js +0 -9
- package/dist/commands/interactive/tasks.js +93 -9
- package/dist/commands/interactive.js +0 -5
- package/dist/commands/llm-context.d.ts +0 -4
- package/dist/commands/llm-context.js +9 -15
- package/dist/commands/task.js +101 -15
- package/dist/index.js +7 -5
- package/dist/lib/project-resolver.d.ts +26 -0
- package/dist/lib/project-resolver.js +111 -0
- package/package.json +1 -1
- package/dist/commands/interactive/jules-sessions.d.ts +0 -1
- package/dist/commands/interactive/jules-sessions.js +0 -460
- package/dist/commands/jules.d.ts +0 -2
- package/dist/commands/jules.js +0 -593
- package/dist/commands/services.d.ts +0 -2
- package/dist/commands/services.js +0 -381
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { getConfig } from "./config.js";
|
|
3
|
-
// Helper: Ensure API is configured
|
|
4
|
-
function ensureConfig() {
|
|
5
|
-
const config = getConfig();
|
|
6
|
-
if (!config.apiUrl) {
|
|
7
|
-
console.error("Error: API URL not configured. Run: husky config set api-url <url>");
|
|
8
|
-
process.exit(1);
|
|
9
|
-
}
|
|
10
|
-
return { apiUrl: config.apiUrl, apiKey: config.apiKey };
|
|
11
|
-
}
|
|
12
|
-
// Helper: Make API request
|
|
13
|
-
async function fetchAPI(apiUrl, apiKey, path, options = {}) {
|
|
14
|
-
const response = await fetch(`${apiUrl}${path}`, {
|
|
15
|
-
...options,
|
|
16
|
-
headers: {
|
|
17
|
-
"Content-Type": "application/json",
|
|
18
|
-
...(apiKey ? { "x-api-key": apiKey } : {}),
|
|
19
|
-
...options.headers,
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
if (!response.ok) {
|
|
23
|
-
const error = await response.text();
|
|
24
|
-
throw new Error(`API Error: ${response.status} - ${error}`);
|
|
25
|
-
}
|
|
26
|
-
return response.json();
|
|
27
|
-
}
|
|
28
|
-
export const servicesCommand = new Command("services")
|
|
29
|
-
.description("Manage Agent Services (Agentic Workflow Platform)");
|
|
30
|
-
// husky services list
|
|
31
|
-
servicesCommand
|
|
32
|
-
.command("list")
|
|
33
|
-
.description("List all agent services")
|
|
34
|
-
.option("--project <id>", "Filter by project ID")
|
|
35
|
-
.option("--json", "Output as JSON")
|
|
36
|
-
.action(async (options) => {
|
|
37
|
-
const config = ensureConfig();
|
|
38
|
-
try {
|
|
39
|
-
const params = new URLSearchParams();
|
|
40
|
-
if (options.project)
|
|
41
|
-
params.set("projectId", options.project);
|
|
42
|
-
const queryString = params.toString();
|
|
43
|
-
const path = queryString ? `/api/services?${queryString}` : "/api/services";
|
|
44
|
-
const services = await fetchAPI(config.apiUrl, config.apiKey, path);
|
|
45
|
-
if (options.json) {
|
|
46
|
-
console.log(JSON.stringify(services, null, 2));
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
if (services.length === 0) {
|
|
50
|
-
console.log("No services found.");
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
console.log("\n Agent Services");
|
|
54
|
-
console.log(" " + "β".repeat(80));
|
|
55
|
-
for (const s of services) {
|
|
56
|
-
const statusIcon = {
|
|
57
|
-
building: "π¨",
|
|
58
|
-
deployed: "π¦",
|
|
59
|
-
running: "β
",
|
|
60
|
-
failed: "β",
|
|
61
|
-
disabled: "βΈοΈ",
|
|
62
|
-
};
|
|
63
|
-
console.log(` ${statusIcon[s.status] || "β"} ${s.name} (${s.type})`);
|
|
64
|
-
console.log(` ID: ${s.id}`);
|
|
65
|
-
console.log(` Status: ${s.status}`);
|
|
66
|
-
if (s.schedule)
|
|
67
|
-
console.log(` Schedule: ${s.schedule}`);
|
|
68
|
-
if (s.cloudRunUrl)
|
|
69
|
-
console.log(` URL: ${s.cloudRunUrl}`);
|
|
70
|
-
console.log(` Runs: ${s.runCount} (${s.successCount} success, ${s.failureCount} failed)`);
|
|
71
|
-
console.log("");
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
// husky services get <id>
|
|
80
|
-
servicesCommand
|
|
81
|
-
.command("get <id>")
|
|
82
|
-
.description("Get service details")
|
|
83
|
-
.option("--json", "Output as JSON")
|
|
84
|
-
.action(async (id, options) => {
|
|
85
|
-
const config = ensureConfig();
|
|
86
|
-
try {
|
|
87
|
-
const service = await fetchAPI(config.apiUrl, config.apiKey, `/api/services/${id}`);
|
|
88
|
-
if (options.json) {
|
|
89
|
-
console.log(JSON.stringify(service, null, 2));
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
console.log(`\n Service: ${service.name}`);
|
|
93
|
-
console.log(" " + "β".repeat(50));
|
|
94
|
-
console.log(` ID: ${service.id}`);
|
|
95
|
-
console.log(` Type: ${service.type}`);
|
|
96
|
-
console.log(` Status: ${service.status}`);
|
|
97
|
-
if (service.description)
|
|
98
|
-
console.log(` Description: ${service.description}`);
|
|
99
|
-
if (service.schedule)
|
|
100
|
-
console.log(` Schedule: ${service.schedule}`);
|
|
101
|
-
if (service.cloudRunUrl)
|
|
102
|
-
console.log(` URL: ${service.cloudRunUrl}`);
|
|
103
|
-
if (service.dockerImage)
|
|
104
|
-
console.log(` Image: ${service.dockerImage}`);
|
|
105
|
-
console.log(` Runs: ${service.runCount} total`);
|
|
106
|
-
console.log(` Success: ${service.successCount}`);
|
|
107
|
-
console.log(` Failures: ${service.failureCount}`);
|
|
108
|
-
if (service.avgDurationMs)
|
|
109
|
-
console.log(` Avg Duration: ${service.avgDurationMs}ms`);
|
|
110
|
-
if (service.lastError)
|
|
111
|
-
console.log(` Last Error: ${service.lastError}`);
|
|
112
|
-
console.log(` Created: ${new Date(service.createdAt).toLocaleString()}`);
|
|
113
|
-
console.log(` Updated: ${new Date(service.updatedAt).toLocaleString()}`);
|
|
114
|
-
console.log("");
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
118
|
-
process.exit(1);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
// husky services create <name>
|
|
122
|
-
servicesCommand
|
|
123
|
-
.command("create <name>")
|
|
124
|
-
.description("Create a new agent service")
|
|
125
|
-
.option("-t, --type <type>", "Service type (cloud-run, cloud-function, scheduled-job)", "cloud-run")
|
|
126
|
-
.option("-d, --description <desc>", "Service description")
|
|
127
|
-
.option("-s, --schedule <cron>", 'Cron schedule (e.g., "0 6 * * *")')
|
|
128
|
-
.option("--project <id>", "Link to project")
|
|
129
|
-
.option("--repo <url>", "Source repository URL")
|
|
130
|
-
.option("--path <path>", "Source path in repository")
|
|
131
|
-
.action(async (name, options) => {
|
|
132
|
-
const config = ensureConfig();
|
|
133
|
-
try {
|
|
134
|
-
const service = await fetchAPI(config.apiUrl, config.apiKey, "/api/services", {
|
|
135
|
-
method: "POST",
|
|
136
|
-
body: JSON.stringify({
|
|
137
|
-
name,
|
|
138
|
-
type: options.type,
|
|
139
|
-
description: options.description,
|
|
140
|
-
schedule: options.schedule,
|
|
141
|
-
projectId: options.project,
|
|
142
|
-
sourceRepo: options.repo,
|
|
143
|
-
sourcePath: options.path,
|
|
144
|
-
}),
|
|
145
|
-
});
|
|
146
|
-
console.log(`β Created service: ${service.name} (${service.id})`);
|
|
147
|
-
console.log(` Type: ${service.type}`);
|
|
148
|
-
console.log(` Status: ${service.status}`);
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
// husky services update <id>
|
|
156
|
-
servicesCommand
|
|
157
|
-
.command("update <id>")
|
|
158
|
-
.description("Update a service")
|
|
159
|
-
.option("-d, --description <desc>", "Update description")
|
|
160
|
-
.option("-s, --schedule <cron>", "Update schedule")
|
|
161
|
-
.option("--status <status>", "Update status")
|
|
162
|
-
.option("--url <url>", "Set Cloud Run URL")
|
|
163
|
-
.option("--image <image>", "Set Docker image")
|
|
164
|
-
.action(async (id, options) => {
|
|
165
|
-
const config = ensureConfig();
|
|
166
|
-
const updates = {};
|
|
167
|
-
if (options.description)
|
|
168
|
-
updates.description = options.description;
|
|
169
|
-
if (options.schedule)
|
|
170
|
-
updates.schedule = options.schedule;
|
|
171
|
-
if (options.status)
|
|
172
|
-
updates.status = options.status;
|
|
173
|
-
if (options.url)
|
|
174
|
-
updates.cloudRunUrl = options.url;
|
|
175
|
-
if (options.image)
|
|
176
|
-
updates.dockerImage = options.image;
|
|
177
|
-
if (Object.keys(updates).length === 0) {
|
|
178
|
-
console.log("No updates specified. Use --help for available options.");
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
try {
|
|
182
|
-
const service = await fetchAPI(config.apiUrl, config.apiKey, `/api/services/${id}`, {
|
|
183
|
-
method: "PATCH",
|
|
184
|
-
body: JSON.stringify(updates),
|
|
185
|
-
});
|
|
186
|
-
console.log(`β Updated service: ${service.name}`);
|
|
187
|
-
const changedFields = Object.keys(updates).join(", ");
|
|
188
|
-
console.log(` Changed: ${changedFields}`);
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
// husky services delete <id>
|
|
196
|
-
servicesCommand
|
|
197
|
-
.command("delete <id>")
|
|
198
|
-
.description("Delete a service")
|
|
199
|
-
.option("-f, --force", "Skip confirmation")
|
|
200
|
-
.action(async (id, options) => {
|
|
201
|
-
const config = ensureConfig();
|
|
202
|
-
if (!options.force) {
|
|
203
|
-
console.log("Use --force to confirm deletion.");
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
try {
|
|
207
|
-
await fetchAPI(config.apiUrl, config.apiKey, `/api/services/${id}`, { method: "DELETE" });
|
|
208
|
-
console.log(`β Deleted service: ${id}`);
|
|
209
|
-
}
|
|
210
|
-
catch (error) {
|
|
211
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
212
|
-
process.exit(1);
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
// husky services health
|
|
216
|
-
servicesCommand
|
|
217
|
-
.command("health")
|
|
218
|
-
.description("Check health of all services")
|
|
219
|
-
.option("--json", "Output as JSON")
|
|
220
|
-
.action(async (options) => {
|
|
221
|
-
const config = ensureConfig();
|
|
222
|
-
try {
|
|
223
|
-
const services = await fetchAPI(config.apiUrl, config.apiKey, "/api/services");
|
|
224
|
-
if (options.json) {
|
|
225
|
-
const healthData = services
|
|
226
|
-
.filter((s) => s.status !== "disabled")
|
|
227
|
-
.map((s) => ({
|
|
228
|
-
id: s.id,
|
|
229
|
-
name: s.name,
|
|
230
|
-
healthStatus: s.healthStatus || "unknown",
|
|
231
|
-
status: s.status,
|
|
232
|
-
lastError: s.lastError,
|
|
233
|
-
}));
|
|
234
|
-
console.log(JSON.stringify(healthData, null, 2));
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
console.log("\n Service Health");
|
|
238
|
-
console.log(" " + "β".repeat(50));
|
|
239
|
-
let healthy = 0;
|
|
240
|
-
let unhealthy = 0;
|
|
241
|
-
let unknown = 0;
|
|
242
|
-
for (const s of services) {
|
|
243
|
-
if (s.status === "disabled")
|
|
244
|
-
continue;
|
|
245
|
-
const icon = s.healthStatus === "healthy"
|
|
246
|
-
? "β
"
|
|
247
|
-
: s.healthStatus === "unhealthy"
|
|
248
|
-
? "β"
|
|
249
|
-
: "β";
|
|
250
|
-
console.log(` ${icon} ${s.name}: ${s.healthStatus || "unknown"}`);
|
|
251
|
-
if (s.lastError && s.healthStatus === "unhealthy") {
|
|
252
|
-
console.log(` Last Error: ${s.lastError}`);
|
|
253
|
-
}
|
|
254
|
-
if (s.healthStatus === "healthy")
|
|
255
|
-
healthy++;
|
|
256
|
-
else if (s.healthStatus === "unhealthy")
|
|
257
|
-
unhealthy++;
|
|
258
|
-
else
|
|
259
|
-
unknown++;
|
|
260
|
-
}
|
|
261
|
-
console.log("");
|
|
262
|
-
console.log(` Summary: ${healthy} healthy, ${unhealthy} unhealthy, ${unknown} unknown`);
|
|
263
|
-
console.log("");
|
|
264
|
-
}
|
|
265
|
-
catch (error) {
|
|
266
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
267
|
-
process.exit(1);
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
// husky services run <id>
|
|
271
|
-
servicesCommand
|
|
272
|
-
.command("run <id>")
|
|
273
|
-
.description("Trigger a service run")
|
|
274
|
-
.option("--input <json>", "Input data as JSON")
|
|
275
|
-
.option("--json", "Output as JSON")
|
|
276
|
-
.action(async (id, options) => {
|
|
277
|
-
const config = ensureConfig();
|
|
278
|
-
let inputData = {};
|
|
279
|
-
if (options.input) {
|
|
280
|
-
try {
|
|
281
|
-
inputData = JSON.parse(options.input);
|
|
282
|
-
}
|
|
283
|
-
catch {
|
|
284
|
-
console.error("Error: --input must be valid JSON");
|
|
285
|
-
process.exit(1);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
try {
|
|
289
|
-
const result = await fetchAPI(config.apiUrl, config.apiKey, `/api/services/${id}/run`, {
|
|
290
|
-
method: "POST",
|
|
291
|
-
body: JSON.stringify({ input: inputData }),
|
|
292
|
-
});
|
|
293
|
-
if (options.json) {
|
|
294
|
-
console.log(JSON.stringify(result, null, 2));
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
console.log(`β Service run triggered: ${id}`);
|
|
298
|
-
if (result.runId)
|
|
299
|
-
console.log(` Run ID: ${result.runId}`);
|
|
300
|
-
if (result.status)
|
|
301
|
-
console.log(` Status: ${result.status}`);
|
|
302
|
-
}
|
|
303
|
-
catch (error) {
|
|
304
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
305
|
-
process.exit(1);
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
// husky services logs <id>
|
|
309
|
-
servicesCommand
|
|
310
|
-
.command("logs <id>")
|
|
311
|
-
.description("View service logs")
|
|
312
|
-
.option("-n, --lines <num>", "Number of log lines", "50")
|
|
313
|
-
.option("--json", "Output as JSON")
|
|
314
|
-
.action(async (id, options) => {
|
|
315
|
-
const config = ensureConfig();
|
|
316
|
-
try {
|
|
317
|
-
const logs = await fetchAPI(config.apiUrl, config.apiKey, `/api/services/${id}/logs?limit=${options.lines}`);
|
|
318
|
-
if (options.json) {
|
|
319
|
-
console.log(JSON.stringify(logs, null, 2));
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
if (!logs.entries || logs.entries.length === 0) {
|
|
323
|
-
console.log(`No logs found for service ${id}`);
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
console.log(`\n Logs for service: ${id}`);
|
|
327
|
-
console.log(" " + "β".repeat(70));
|
|
328
|
-
for (const entry of logs.entries) {
|
|
329
|
-
const timestamp = new Date(entry.timestamp).toLocaleString();
|
|
330
|
-
const level = entry.level?.toUpperCase() || "INFO";
|
|
331
|
-
console.log(` [${timestamp}] ${level}: ${entry.message}`);
|
|
332
|
-
}
|
|
333
|
-
console.log("");
|
|
334
|
-
}
|
|
335
|
-
catch (error) {
|
|
336
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
337
|
-
process.exit(1);
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
// husky services runs <id>
|
|
341
|
-
servicesCommand
|
|
342
|
-
.command("runs <id>")
|
|
343
|
-
.description("List recent runs for a service")
|
|
344
|
-
.option("-n, --limit <num>", "Number of runs to show", "10")
|
|
345
|
-
.option("--json", "Output as JSON")
|
|
346
|
-
.action(async (id, options) => {
|
|
347
|
-
const config = ensureConfig();
|
|
348
|
-
try {
|
|
349
|
-
const runs = await fetchAPI(config.apiUrl, config.apiKey, `/api/services/${id}/runs?limit=${options.limit}`);
|
|
350
|
-
if (options.json) {
|
|
351
|
-
console.log(JSON.stringify(runs, null, 2));
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
if (!runs || runs.length === 0) {
|
|
355
|
-
console.log(`No runs found for service ${id}`);
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
console.log(`\n Recent Runs for service: ${id}`);
|
|
359
|
-
console.log(" " + "β".repeat(70));
|
|
360
|
-
for (const run of runs) {
|
|
361
|
-
const statusIcon = run.status === "success"
|
|
362
|
-
? "β
"
|
|
363
|
-
: run.status === "failed"
|
|
364
|
-
? "β"
|
|
365
|
-
: run.status === "running"
|
|
366
|
-
? "βΆ"
|
|
367
|
-
: "βΈοΈ";
|
|
368
|
-
const timestamp = new Date(run.startedAt).toLocaleString();
|
|
369
|
-
const duration = run.durationMs ? `${run.durationMs}ms` : "β";
|
|
370
|
-
console.log(` ${statusIcon} ${run.id.slice(0, 12)} β ${timestamp} β ${duration} β ${run.status}`);
|
|
371
|
-
if (run.error) {
|
|
372
|
-
console.log(` Error: ${run.error}`);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
console.log("");
|
|
376
|
-
}
|
|
377
|
-
catch (error) {
|
|
378
|
-
console.error("Error:", error instanceof Error ? error.message : error);
|
|
379
|
-
process.exit(1);
|
|
380
|
-
}
|
|
381
|
-
});
|