@simonfestl/husky-cli 1.37.0 ā 1.38.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/config.d.ts +1 -0
- package/dist/commands/config.js +2 -0
- package/dist/commands/interactive/tasks.js +8 -0
- package/dist/commands/llm-context.js +5 -1
- package/dist/commands/task.js +13 -0
- package/dist/lib/gcp-metadata.d.ts +1 -0
- package/dist/lib/gcp-metadata.js +13 -0
- package/package.json +1 -1
package/dist/commands/config.js
CHANGED
|
@@ -385,6 +385,7 @@ configCommand
|
|
|
385
385
|
"wattiz-password": "wattizPassword",
|
|
386
386
|
"wattiz-base-url": "wattizBaseUrl",
|
|
387
387
|
"wattiz-language": "wattizLanguage",
|
|
388
|
+
"gtasks-subject": "gtasksSubject",
|
|
388
389
|
};
|
|
389
390
|
const configKey = keyMappings[key];
|
|
390
391
|
if (!configKey) {
|
|
@@ -402,6 +403,7 @@ configCommand
|
|
|
402
403
|
console.log(" Skuterzone: skuterzone-username, skuterzone-password, skuterzone-base-url");
|
|
403
404
|
console.log(" Emove: emove-username, emove-password, emove-base-url");
|
|
404
405
|
console.log(" Wattiz: wattiz-username, wattiz-password, wattiz-base-url, wattiz-language");
|
|
406
|
+
console.log(" GTasks: gtasks-subject");
|
|
405
407
|
console.log(" Brain: agent-type");
|
|
406
408
|
console.error("\nš” For configuration help: husky explain config");
|
|
407
409
|
process.exit(1);
|
|
@@ -3,6 +3,7 @@ import { getAuthHeaders } from "../config.js";
|
|
|
3
3
|
import { ensureConfig, pressEnterToContinue, truncate } from "./utils.js";
|
|
4
4
|
import { resolveProject } from "../../lib/project-resolver.js";
|
|
5
5
|
import { requirePermission } from "../../lib/permissions.js";
|
|
6
|
+
import { isRunningOnGcpVm } from "../../lib/gcp-metadata.js";
|
|
6
7
|
export async function tasksMenu() {
|
|
7
8
|
const config = ensureConfig();
|
|
8
9
|
const menuItems = [
|
|
@@ -160,6 +161,12 @@ async function createTask(config) {
|
|
|
160
161
|
],
|
|
161
162
|
default: "medium",
|
|
162
163
|
});
|
|
164
|
+
const runningOnGcp = await isRunningOnGcpVm();
|
|
165
|
+
const queueTask = await confirm({
|
|
166
|
+
message: "Queue task for workers (autoscale)?",
|
|
167
|
+
default: runningOnGcp,
|
|
168
|
+
});
|
|
169
|
+
const skipQueue = !queueTask;
|
|
163
170
|
const projects = await fetchProjects(config);
|
|
164
171
|
let projectId;
|
|
165
172
|
if (projects.length > 0) {
|
|
@@ -224,6 +231,7 @@ async function createTask(config) {
|
|
|
224
231
|
description: description || undefined,
|
|
225
232
|
priority,
|
|
226
233
|
projectId,
|
|
234
|
+
skipQueue,
|
|
227
235
|
}),
|
|
228
236
|
});
|
|
229
237
|
if (!res.ok) {
|
|
@@ -60,7 +60,9 @@ husky task get <id> # Get task details
|
|
|
60
60
|
husky task message <id> "msg" # Post status message
|
|
61
61
|
`;
|
|
62
62
|
if (canCreate) {
|
|
63
|
-
section += `husky task create
|
|
63
|
+
section += `husky task create <title> # Create new task
|
|
64
|
+
husky task create <title> --local # Create locally (skip queue/autoscale)
|
|
65
|
+
husky task create <title> --queue # Force queue/autoscale
|
|
64
66
|
`;
|
|
65
67
|
}
|
|
66
68
|
if (canStart) {
|
|
@@ -72,6 +74,8 @@ husky task message <id> "msg" # Post status message
|
|
|
72
74
|
`;
|
|
73
75
|
}
|
|
74
76
|
section += `\`\`\`
|
|
77
|
+
|
|
78
|
+
Note: On non-GCP machines, \`husky task create\` defaults to \`--local\`. Use \`--queue\` to force autoscaling.
|
|
75
79
|
`;
|
|
76
80
|
return section;
|
|
77
81
|
}
|
package/dist/commands/task.js
CHANGED
|
@@ -11,6 +11,7 @@ import { requirePermission } from "../lib/permissions.js";
|
|
|
11
11
|
import { ErrorHelpers, errorWithHint, ExplainTopic } from "../lib/error-hints.js";
|
|
12
12
|
import { AgentLock, AgentLockError } from "../lib/agent-lock.js";
|
|
13
13
|
import { getApiClient } from "../lib/api-client.js";
|
|
14
|
+
import { isRunningOnGcpVm } from "../lib/gcp-metadata.js";
|
|
14
15
|
export const taskCommand = new Command("task")
|
|
15
16
|
.description("Manage tasks");
|
|
16
17
|
// Helper: Get task ID from --id flag or HUSKY_TASK_ID env var
|
|
@@ -396,6 +397,8 @@ taskCommand
|
|
|
396
397
|
.option("--project <project>", "Project name or ID")
|
|
397
398
|
.option("--path <path>", "Path in project")
|
|
398
399
|
.option("-p, --priority <priority>", "Priority (low, medium, high)", "medium")
|
|
400
|
+
.option("--local", "Create task locally (skip queue/autoscale)")
|
|
401
|
+
.option("--queue", "Force task to be queued (enable autoscale)")
|
|
399
402
|
.action(async (title, options) => {
|
|
400
403
|
const config = getConfig();
|
|
401
404
|
if (!config.apiUrl) {
|
|
@@ -425,6 +428,15 @@ taskCommand
|
|
|
425
428
|
}
|
|
426
429
|
resolvedProjectId = resolved.projectId;
|
|
427
430
|
}
|
|
431
|
+
if (options.local && options.queue) {
|
|
432
|
+
console.error("Error: Use either --local or --queue, not both.");
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
const explicitSkipQueue = options.local ? true : options.queue ? false : undefined;
|
|
436
|
+
const skipQueue = explicitSkipQueue ?? !(await isRunningOnGcpVm());
|
|
437
|
+
if (explicitSkipQueue === undefined && skipQueue) {
|
|
438
|
+
console.log("ā¹ļø Local environment detected; task will not be queued. Use --queue to force autoscaling.");
|
|
439
|
+
}
|
|
428
440
|
try {
|
|
429
441
|
const api = getApiClient();
|
|
430
442
|
const task = await api.post("/api/tasks", {
|
|
@@ -433,6 +445,7 @@ taskCommand
|
|
|
433
445
|
projectId: resolvedProjectId,
|
|
434
446
|
linkedPath: options.path,
|
|
435
447
|
priority: options.priority,
|
|
448
|
+
skipQueue,
|
|
436
449
|
});
|
|
437
450
|
console.log(`ā Created: #${task.id} ${task.title}`);
|
|
438
451
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isRunningOnGcpVm(timeoutMs?: number): Promise<boolean>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export async function isRunningOnGcpVm(timeoutMs = 800) {
|
|
2
|
+
const metadataUrl = "http://metadata.google.internal/computeMetadata/v1/instance/id";
|
|
3
|
+
try {
|
|
4
|
+
const res = await fetch(metadataUrl, {
|
|
5
|
+
headers: { "Metadata-Flavor": "Google" },
|
|
6
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
7
|
+
});
|
|
8
|
+
return res.ok;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|