@indigoai-us/hq-cli 5.135.0 → 5.137.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/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.137.0] — 2026-09-23
6
+ ### Added
7
+
8
+ - Added `hq channels members <channel>` to print channel members for human and machine-principal sessions, with a `--json` format for scripts.
9
+
10
+ ## [5.136.0] — 2026-09-23
11
+
12
+ ### Added
13
+
14
+ - Your local bots can now do work on a repeating schedule. Ask a company bot for something regular — "check the overnight errors every weekday morning" — and it sets the schedule up itself; you can also see and remove its schedules with `hq bot jobs <name>`. The schedule is kept in the cloud, not on your computer. If the Mac is asleep when a run is due, the run happens as a catch-up when it wakes, as long as that is within about an hour, and the bot's report says it ran late; after a longer outage that run is skipped and the job carries on at its next scheduled time. Personal bots can't schedule work yet.
15
+
5
16
  ## [5.135.0] — 2026-09-23
6
17
 
7
18
  ### Added
@@ -2388,6 +2388,22 @@ export declare const COMMAND_CATALOG: readonly [{
2388
2388
  readonly arguments: readonly [];
2389
2389
  readonly options: readonly [];
2390
2390
  readonly subcommands: readonly [];
2391
+ }, {
2392
+ readonly name: "members";
2393
+ readonly description: "Print the members of one of your DM channels.";
2394
+ readonly aliases: readonly [];
2395
+ readonly hidden: false;
2396
+ readonly usage: "[options] <channel>";
2397
+ readonly arguments: readonly [{
2398
+ readonly name: "channel";
2399
+ readonly required: true;
2400
+ readonly variadic: false;
2401
+ }];
2402
+ readonly options: readonly [{
2403
+ readonly flags: "--json";
2404
+ readonly description: "Output the member array as JSON.";
2405
+ }];
2406
+ readonly subcommands: readonly [];
2391
2407
  }];
2392
2408
  }, {
2393
2409
  readonly name: "onboard";
@@ -7318,6 +7334,37 @@ export declare const COMMAND_CATALOG: readonly [{
7318
7334
  readonly description: "Expected transfer size";
7319
7335
  }];
7320
7336
  readonly subcommands: readonly [];
7337
+ }, {
7338
+ readonly name: "jobs";
7339
+ readonly description: "Show, schedule, or remove a bot's recurring jobs (the schedule runs in the cloud, not on this computer)";
7340
+ readonly aliases: readonly [];
7341
+ readonly hidden: false;
7342
+ readonly usage: "[options] <name>";
7343
+ readonly arguments: readonly [{
7344
+ readonly name: "name";
7345
+ readonly required: true;
7346
+ readonly variadic: false;
7347
+ }];
7348
+ readonly options: readonly [{
7349
+ readonly flags: "--add <what>";
7350
+ readonly description: "Schedule new work, in plain language";
7351
+ }, {
7352
+ readonly flags: "--every <when>";
7353
+ readonly description: "How often, in plain language (e.g. \"every weekday at 9am\")";
7354
+ }, {
7355
+ readonly flags: "--cron <expr>";
7356
+ readonly description: "How often, as a cron expression (e.g. \"0 9 * * 1-5\")";
7357
+ }, {
7358
+ readonly flags: "--tz <zone>";
7359
+ readonly description: "IANA timezone for the schedule (default: this computer's)";
7360
+ }, {
7361
+ readonly flags: "--rm <jobId>";
7362
+ readonly description: "Remove a scheduled job";
7363
+ }, {
7364
+ readonly flags: "--json";
7365
+ readonly description: "Print machine-readable JSON";
7366
+ }];
7367
+ readonly subcommands: readonly [];
7321
7368
  }, {
7322
7369
  readonly name: "promote";
7323
7370
  readonly description: "Move this local bot to cloud compute, preserving its identity and private context";
@@ -3067,6 +3067,27 @@ export const COMMAND_CATALOG = [
3067
3067
  "arguments": [],
3068
3068
  "options": [],
3069
3069
  "subcommands": []
3070
+ },
3071
+ {
3072
+ "name": "members",
3073
+ "description": "Print the members of one of your DM channels.",
3074
+ "aliases": [],
3075
+ "hidden": false,
3076
+ "usage": "[options] <channel>",
3077
+ "arguments": [
3078
+ {
3079
+ "name": "channel",
3080
+ "required": true,
3081
+ "variadic": false
3082
+ }
3083
+ ],
3084
+ "options": [
3085
+ {
3086
+ "flags": "--json",
3087
+ "description": "Output the member array as JSON."
3088
+ }
3089
+ ],
3090
+ "subcommands": []
3070
3091
  }
3071
3092
  ]
3072
3093
  },
@@ -9463,6 +9484,47 @@ export const COMMAND_CATALOG = [
9463
9484
  ],
9464
9485
  "subcommands": []
9465
9486
  },
9487
+ {
9488
+ "name": "jobs",
9489
+ "description": "Show, schedule, or remove a bot's recurring jobs (the schedule runs in the cloud, not on this computer)",
9490
+ "aliases": [],
9491
+ "hidden": false,
9492
+ "usage": "[options] <name>",
9493
+ "arguments": [
9494
+ {
9495
+ "name": "name",
9496
+ "required": true,
9497
+ "variadic": false
9498
+ }
9499
+ ],
9500
+ "options": [
9501
+ {
9502
+ "flags": "--add <what>",
9503
+ "description": "Schedule new work, in plain language"
9504
+ },
9505
+ {
9506
+ "flags": "--every <when>",
9507
+ "description": "How often, in plain language (e.g. \"every weekday at 9am\")"
9508
+ },
9509
+ {
9510
+ "flags": "--cron <expr>",
9511
+ "description": "How often, as a cron expression (e.g. \"0 9 * * 1-5\")"
9512
+ },
9513
+ {
9514
+ "flags": "--tz <zone>",
9515
+ "description": "IANA timezone for the schedule (default: this computer's)"
9516
+ },
9517
+ {
9518
+ "flags": "--rm <jobId>",
9519
+ "description": "Remove a scheduled job"
9520
+ },
9521
+ {
9522
+ "flags": "--json",
9523
+ "description": "Print machine-readable JSON"
9524
+ }
9525
+ ],
9526
+ "subcommands": []
9527
+ },
9466
9528
  {
9467
9529
  "name": "promote",
9468
9530
  "description": "Move this local bot to cloud compute, preserving its identity and private context",
@@ -0,0 +1,127 @@
1
+ /**
2
+ * `hq bot jobs` — a local bot's recurring scheduled work.
3
+ *
4
+ * hq bot jobs <botName> list
5
+ * hq bot jobs <botName> --add "<what to do>" --every "<plain english>"
6
+ * hq bot jobs <botName> --add "<what to do>" --cron "0 9 * * 1-5"
7
+ * hq bot jobs <botName> --rm <jobId>
8
+ *
9
+ * The schedule lives in the cloud, never on this computer: hq-pro-agents holds
10
+ * the job and fires it on an EventBridge schedule, and the bot's inbox loop
11
+ * runs the fired run (see lib/bot/job-run.ts). Nothing here writes a crontab,
12
+ * a launchd plist, or a systemd unit — by rule.
13
+ *
14
+ * The routes are self-only per agent, so every call uses the BOT's own machine
15
+ * identity — the same credential path its turns use — not the owner's session.
16
+ */
17
+ import { execFileSync } from "node:child_process";
18
+ import type { Command } from "commander";
19
+ import { BotApi, type BotJobRecord, type CreateJobInput } from "../lib/bot/api.js";
20
+ import { type BotConfig, type BotKind } from "../lib/bot/config.js";
21
+ /** Mirrors hq-pro-agents `MIN_RECURRING_INTERVAL_SECONDS`. */
22
+ export declare const MIN_RECURRING_INTERVAL_SECONDS: number;
23
+ /** Mirrors hq-pro-agents `DEFAULT_MAX_ACTIVE_JOBS_PER_AGENT`. */
24
+ export declare const MAX_ACTIVE_JOBS_PER_AGENT = 25;
25
+ /** Mirrors hq-pro-agents `MAX_PROMPT_BYTES`. */
26
+ export declare const MAX_PROMPT_BYTES: number;
27
+ export declare class BotJobsError extends Error {
28
+ readonly expected: true;
29
+ }
30
+ /** The machine's own IANA zone, so "9am" means 9am where the owner lives. */
31
+ export declare function machineTimezone(): string;
32
+ /**
33
+ * Standard 5-field cron → the EventBridge form the cloud stores.
34
+ *
35
+ * EventBridge cron has SIX fields (a trailing year), numbers its days of week
36
+ * 1–7 with SUNDAY = 1 (standard cron uses 0–6 with SUNDAY = 0), and refuses
37
+ * `*` in BOTH the day-of-month and day-of-week fields — exactly one must be
38
+ * `?`. An expression that is already `cron(...)` or `rate(...)` is passed
39
+ * through untouched.
40
+ */
41
+ export declare function toEventBridgeCron(expr: string): string;
42
+ /**
43
+ * The smallest gap a recurring expression can produce, in seconds, or null
44
+ * when it is not a recognised rate()/cron() form. Mirrors hq-pro-agents
45
+ * `recurringIntervalSeconds` so the CLI can refuse a sub-floor schedule with
46
+ * the server's own reason instead of a round-trip and a raw 400.
47
+ */
48
+ export declare function recurringIntervalSeconds(expr: string): number | null;
49
+ /** Refuse a schedule the cloud would refuse, with the cloud's own reason. */
50
+ export declare function assertScheduleWithinFloor(expr: string): void;
51
+ export interface ParsedSchedule {
52
+ /** Standard 5-field cron, as the HQ helper emits it. */
53
+ cron: string;
54
+ timezone: string;
55
+ /** Plain words for the schedule, when the helper supplied them. */
56
+ human?: string;
57
+ }
58
+ export declare function scheduleHelperPath(hqRoot: string): string;
59
+ /**
60
+ * Plain English → cron, using HQ's OWN helper (`core/scripts/jobs-schedule-parse.sh`)
61
+ * so `hq bot jobs --every` and the `/schedule` command agree on what "every
62
+ * weekday morning" means. When the helper is not in this HQ root, the caller is
63
+ * told to pass `--cron` instead rather than getting a second, divergent parser.
64
+ */
65
+ export declare function parseScheduleText(text: string, opts: {
66
+ hqRoot: string;
67
+ timezone: string;
68
+ exec?: typeof execFileSync;
69
+ exists?: (p: string) => boolean;
70
+ }): ParsedSchedule;
71
+ /** The create body the cloud expects, with the client-side limits enforced first. */
72
+ export declare function buildCreateJobBody(input: {
73
+ prompt: string;
74
+ cron: string;
75
+ timezone: string;
76
+ context?: Record<string, unknown>;
77
+ }): CreateJobInput;
78
+ /** A schedule in plain words, falling back to the raw expression. */
79
+ export declare function describeSchedule(job: BotJobRecord): string;
80
+ /** A small humaniser for the shapes `--every` actually produces. */
81
+ export declare function cronInWords(expr: string): string | null;
82
+ /** "never run yet" / "succeeded 2026-09-15 09:00 UTC". */
83
+ export declare function describeLastRun(job: BotJobRecord): string;
84
+ export declare function formatJobsList(botName: string, jobs: BotJobRecord[]): string;
85
+ /**
86
+ * Turn a jobs-route failure into one plain line.
87
+ *
88
+ * Personal bots are refused by the cloud today: their JWT carries the owner's
89
+ * `per_…` company claim and the jobs routes require a `cmp_…`, so the fail-closed
90
+ * guard answers 403 `CROSS_AGENT_JOB` (hq-pro-agents jobs/errors.ts
91
+ * `CrossAgentJobError`). That server fix is a separate change; until it lands the
92
+ * refusal must read as "not available yet for this kind of bot", not as a raw 403.
93
+ * Once the server accepts personal bots the refusal simply stops happening — no
94
+ * client change needed.
95
+ *
96
+ * ONLY that exact code is rewritten. Every other 403, and every 404, keeps its
97
+ * real message: masking them would hide a genuinely missing job or a different
98
+ * permission problem behind copy about the wrong thing.
99
+ */
100
+ export declare function jobsErrorMessage(err: unknown, ctx: {
101
+ botName: string;
102
+ kind: BotKind;
103
+ }): string;
104
+ export interface BotJobsDeps {
105
+ requireBot(name: string): {
106
+ name: string;
107
+ dir: string;
108
+ config: BotConfig;
109
+ };
110
+ botTokenSupplier(dir: string): () => Promise<string>;
111
+ /** Test seam: the jobs client for a bot directory. */
112
+ apiFor?(dir: string): Pick<BotApi, "listJobs" | "createJob" | "cancelJob">;
113
+ parseSchedule?: typeof parseScheduleText;
114
+ timezone?: () => string;
115
+ out?: (line: string) => void;
116
+ }
117
+ export interface BotJobsOptions {
118
+ add?: string;
119
+ every?: string;
120
+ cron?: string;
121
+ tz?: string;
122
+ rm?: string;
123
+ json?: boolean;
124
+ }
125
+ export declare function runBotJobs(nameArg: string, opts: BotJobsOptions, deps: BotJobsDeps): Promise<void>;
126
+ export declare function registerBotJobsCommand(bot: Command, deps: BotJobsDeps): void;
127
+ //# sourceMappingURL=bot-jobs.d.ts.map