@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.
@@ -42,6 +42,7 @@ interface Config {
42
42
  wattizPassword?: string;
43
43
  wattizBaseUrl?: string;
44
44
  wattizLanguage?: string;
45
+ gtasksSubject?: string;
45
46
  gcsBucket?: string;
46
47
  shopifyDomain?: string;
47
48
  shopifyToken?: string;
@@ -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 # Create new task
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
  }
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simonfestl/husky-cli",
3
- "version": "1.37.0",
3
+ "version": "1.38.2",
4
4
  "description": "CLI for Huskyv0 Task Orchestration with Claude Agent SDK",
5
5
  "type": "module",
6
6
  "bin": {