@indigoai-us/hq-cli 5.345.198 → 5.345.199

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.
Files changed (102) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/command-catalog.generated.d.ts +106 -6
  3. package/dist/command-catalog.generated.js +130 -6
  4. package/dist/commands/bot-events.d.ts +19 -0
  5. package/dist/commands/bot-events.js +46 -0
  6. package/dist/commands/bot-jobs.d.ts +2 -0
  7. package/dist/commands/bot-jobs.js +43 -2
  8. package/dist/commands/bot.d.ts +5 -0
  9. package/dist/commands/bot.js +33 -1
  10. package/dist/commands/lanes-report.d.ts +2 -1
  11. package/dist/commands/lanes-report.js +44 -1
  12. package/dist/commands/lanes.d.ts +9 -0
  13. package/dist/commands/lanes.js +95 -9
  14. package/dist/commands/meetings.js +1 -21
  15. package/dist/commands/signals-run.d.ts +2 -0
  16. package/dist/commands/signals-run.js +6 -1
  17. package/dist/lanes-drain-hook.js +9 -0
  18. package/dist/lib/bot/api.d.ts +5 -0
  19. package/dist/lib/bot/claude-login.d.ts +31 -0
  20. package/dist/lib/bot/claude-login.js +160 -0
  21. package/dist/lib/bot/events.d.ts +18 -0
  22. package/dist/lib/bot/events.js +160 -0
  23. package/dist/lib/bot/executive-settings.d.ts +10 -0
  24. package/dist/lib/bot/executive-settings.js +43 -0
  25. package/dist/lib/bot/fleet-cron.js +4 -0
  26. package/dist/lib/bot/fleet-local.js +10 -10
  27. package/dist/lib/bot/job-run.js +1 -1
  28. package/dist/lib/bot/jobs/hot-signal-sync.d.ts +8 -0
  29. package/dist/lib/bot/jobs/hot-signal-sync.js +2 -0
  30. package/dist/lib/bot/jobs/meeting-detect.d.ts +28 -0
  31. package/dist/lib/bot/jobs/meeting-detect.js +176 -0
  32. package/dist/lib/bot/jobs/meeting-rider.d.ts +53 -0
  33. package/dist/lib/bot/jobs/meeting-rider.js +284 -0
  34. package/dist/lib/bot/jobs/signal-to-lane.d.ts +32 -0
  35. package/dist/lib/bot/jobs/signal-to-lane.js +169 -0
  36. package/dist/lib/bot/local-jobs.d.ts +15 -2
  37. package/dist/lib/bot/local-jobs.js +24 -7
  38. package/dist/lib/bot/run.d.ts +7 -49
  39. package/dist/lib/bot/run.js +100 -4
  40. package/dist/lib/bot/status.d.ts +21 -0
  41. package/dist/lib/doctor/checks/bots.d.ts +6 -0
  42. package/dist/lib/doctor/checks/bots.js +47 -1
  43. package/dist/lib/hot-channels/adapters/meetings.d.ts +1 -0
  44. package/dist/lib/hot-channels/adapters/meetings.js +3 -1
  45. package/dist/lib/hot-channels/meeting-source-ref.d.ts +3 -0
  46. package/dist/lib/hot-channels/meeting-source-ref.js +7 -0
  47. package/dist/lib/hot-channels/schedule.js +2 -2
  48. package/dist/lib/hot-channels/signals-pass.d.ts +9 -32
  49. package/dist/lib/hot-channels/signals-pass.js +51 -17
  50. package/dist/lib/lanes/admission.d.ts +2 -0
  51. package/dist/lib/lanes/admission.js +4 -0
  52. package/dist/lib/lanes/approval-gate.js +4 -1
  53. package/dist/lib/lanes/links.d.ts +8 -1
  54. package/dist/lib/lanes/links.js +84 -3
  55. package/dist/lib/lanes/outcome.d.ts +154 -0
  56. package/dist/lib/lanes/outcome.js +151 -0
  57. package/dist/lib/lanes/reconcile.js +1 -0
  58. package/dist/lib/lanes/signal-brief-template.d.ts +7 -0
  59. package/dist/lib/lanes/signal-brief-template.js +40 -0
  60. package/dist/lib/lanes/signal-lane.d.ts +24 -0
  61. package/dist/lib/lanes/signal-lane.js +99 -0
  62. package/dist/lib/lanes/source-report.d.ts +37 -0
  63. package/dist/lib/lanes/source-report.js +66 -0
  64. package/dist/lib/lanes/spawn.d.ts +6 -0
  65. package/dist/lib/lanes/spawn.js +21 -0
  66. package/dist/lib/lanes/store.d.ts +3 -0
  67. package/dist/lib/lanes/store.js +64 -0
  68. package/dist/lib/lanes/story-ledger.d.ts +3 -0
  69. package/dist/lib/lanes/story-ledger.js +1 -0
  70. package/dist/lib/lanes/types.d.ts +137 -0
  71. package/dist/lib/lanes/types.js +17 -2
  72. package/dist/lib/lanes/watcher.js +4 -0
  73. package/dist/lib/live-meetings.d.ts +19 -0
  74. package/dist/lib/live-meetings.js +23 -0
  75. package/dist/lib/mesh/live/daemon/doctor.js +6 -7
  76. package/dist/lib/mesh/live/spool.d.ts +8 -0
  77. package/dist/lib/mesh/live/spool.js +59 -40
  78. package/dist/lib/plan-limit-nag.d.ts +30 -4
  79. package/dist/lib/plan-limit-nag.js +68 -17
  80. package/dist/lib/signals/engine.d.ts +4 -0
  81. package/dist/lib/signals/engine.js +25 -5
  82. package/dist/lib/signals/incremental.d.ts +42 -0
  83. package/dist/lib/signals/incremental.js +191 -0
  84. package/dist/lib/signals/prior-signals.d.ts +11 -0
  85. package/dist/lib/signals/prior-signals.js +44 -0
  86. package/dist/lib/signals/reply.js +6 -1
  87. package/dist/lib/signals/settings.d.ts +5 -0
  88. package/dist/lib/signals/settings.js +17 -0
  89. package/dist/lib/signals/steps/extract.d.ts +23 -2
  90. package/dist/lib/signals/steps/extract.js +142 -9
  91. package/dist/lib/signals/steps/types.d.ts +1 -0
  92. package/dist/lib/signals/write-guard.js +7 -0
  93. package/dist/utils/cognito-callback-port.d.ts +15 -0
  94. package/dist/utils/cognito-callback-port.js +51 -0
  95. package/dist/utils/cognito-config.js +2 -3
  96. package/dist/utils/cognito-session.d.ts +7 -6
  97. package/dist/utils/cognito-session.js +14 -14
  98. package/dist/utils/interactive-caller.d.ts +15 -0
  99. package/dist/utils/interactive-caller.js +70 -0
  100. package/dist/utils/login-browser.js +3 -1
  101. package/dist/utils/resident-package-preload.js +4 -0
  102. package/package.json +7 -7
package/CHANGELOG.md CHANGED
@@ -2,6 +2,51 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.345.199] — 2026-11-04
6
+ - `hq bot status <name>` shows the bot's last reported failure: when, the
7
+ failure class, the plain-language cause and fix the owner was sent, the HQ
8
+ report id, and whether the report was uploaded and the owner DM sent. The
9
+ JSON output carries it as `status.lastFailure`. HQ Fleet Runtime bots write
10
+ it when a turn ends in the canned away line.
11
+ - `hq doctor` checks that a Claude bot on the HQ Fleet Runtime can read a
12
+ Claude Code login the way the runtime reads it (ANTHROPIC_TOKEN,
13
+ CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_API_KEY, the HQ Fleet login file,
14
+ ~/.claude/.credentials.json, then the macOS Keychain item "Claude
15
+ Code-credentials") and fails with the sources it checked and the fix
16
+ (`claude /login`, then `hq bot restart <name>`). It also fails on a bot's
17
+ last reported failure until a later turn works.
18
+ - `hq bot create` with the Claude provider refuses, before creating any
19
+ identity, when no Claude Code login is readable on this computer, naming
20
+ the sources it checked and the fix.
21
+ - The HQ Fleet profile's bootstrap marker records the hq-cli version that
22
+ installed it, so a bot's failure reports name it.
23
+ - `hq bot create` and `hq bot update` now install HQ Fleet Local 0.4.24 on hq-fleet-runtime d257fdd1, the release that uploads failure reports and DMs the owner.
24
+ - Local CLI bots can run jobs when an event arrives with `hq bot jobs --on` and payload filters. Add `hq bot events emit` and `tail`, durable event queues with journal rotation, and a registry for built-in event handlers that run without a model turn.
25
+ - Lane envelopes can include a structured outcome with gathered facts and next steps. Process and subagent lanes retain it, and `hq lanes status <lane-id> --json` exposes it.
26
+ - The Executive can ride an attended meeting in-process, extract signals every 20 seconds, resume after a bot restart, and emit one meeting-ended event after three terminal polls. The rider respects the desktop opt-out setting.
27
+ - The Executive detects attended live meetings every minute while the desktop is closed, using the same meeting rider setting. Bot status now shows the Executive selection, rider preference, and latest detection source and time.
28
+ - Create an Executive lane directly from an action-item signal with `hq lanes create --company <slug> --signal <id>`. Repeating the command returns the existing lane. Generated briefs include your standing rules, and workers report through your conductor's link.
29
+ - Browser sign-in now refuses a callback port that is not registered with
30
+ Cognito (8765, 3000, 53682). A stray `HQ_COGNITO_CALLBACK_PORT` such as
31
+ 57726 opened a sign-in tab that failed with `redirect_mismatch`; the CLI now
32
+ uses 8765 instead and prints a warning on stderr.
33
+ - Background `hq` processes no longer open a browser sign-in tab on their own.
34
+ When a token refresh failed, any caller (daemon, lane, bot, monitor,
35
+ `hq mcp serve`, the sync runner, or a launchd task) fell back to a browser
36
+ sign-in that nobody had started. The implicit sign-in now runs only when
37
+ stdin and stdout are terminals and none of those markers is present; other
38
+ callers get an error that says to run `hq login`. `hq login` is unchanged.
39
+ - The plan-limit warning now says which account it is about ("your personal
40
+ account" or "the <slug> company"), shows storage in GB instead of raw bytes,
41
+ and no longer claims that new files and new secrets are paused. After
42
+ `hq dm --attach` it used to print "storage 47012700666 of 10737418240. New
43
+ files and new secrets are paused." right after the uploads had succeeded.
44
+ - `hq mesh session status` and `hq mesh daemon doctor` no longer crash when a local work-mesh queue file (usually `dead-letter.jsonl`) is larger than 512 MB. Queue counts are now read line by line.
45
+ - The Morning signals job now carries prior signals from the same source into extraction, refreshes longer final-pass bodies in place, and reports new, updated and skipped counts. Live meeting signal IDs and index rows remain stable through the final pass.
46
+ - `hq signals run --company <slug> --source meeting:<id> --incremental` extracts signals while a meeting transcript grows. Landed documents use `<channel>:<file>`. Each source keeps a cursor and prior signal IDs, so unchanged content costs no model turn. Incremental runs default to 12 turns and $0.40, preserve meeting signal references across transcript revisions, and retain signal events for retry.
47
+ - The personal Executive now opens conductor lanes from newly written action-item signals, with one event job per served company and deferred retries when no conductor is linked.
48
+ - `hq lanes report --company <slug> --source <ref>` reports source-linked lane outcomes, pending decisions, progress, and remaining work in text or JSON. Owner wording can be customized in `personal/settings/executive/report.md`.
49
+
5
50
  ## [5.345.198] — 2026-11-04
6
51
  - A personal bot that locked itself to its HQ's only company no longer resumes old conversations under that lock after the HQ gains a second company, loses its only company, or switches to a different one. On restart it archives those conversations and starts fresh, as it already did when a bot's company settings changed. A company bot whose bot.json lists "personal" as well as its company now starts normally after this upgrade, including with unfinished work, instead of stopping with "could not isolate previous company conversations". A personal bot no longer treats an extra top-level manifest key such as `version:` or `deployments:` as a company, and it reads a manifest saved with a UTF-8 byte order mark.
7
52
  - A local bot no longer asks "Which company is this for?" in every channel when its HQ has only one company. A personal bot (including one created before bot kinds existed) with no company in bot.json now locks its sessions to the HQ's only company, scheduled jobs included. A bot with two or more real companies stays unbound and does not guess. A "personal" entry in a company bot's membership list no longer counts as a second company.
@@ -5545,6 +5545,14 @@ export declare const COMMAND_CATALOG: readonly [{
5545
5545
  readonly flags: "--company <slug>";
5546
5546
  readonly description: "Run one company (default: every company listed in the companies manifest)";
5547
5547
  readonly hidden: false;
5548
+ }, {
5549
+ readonly flags: "--source <ref>";
5550
+ readonly description: "Read a growing source: meeting:<id> or <channel>:<file> (needs --incremental and --company)";
5551
+ readonly hidden: false;
5552
+ }, {
5553
+ readonly flags: "--incremental";
5554
+ readonly description: "Extract only new signals from --source, retaining a cursor and prior signal ids";
5555
+ readonly hidden: false;
5548
5556
  }, {
5549
5557
  readonly flags: "--dry-run";
5550
5558
  readonly description: "Print what would run; run no mutating step and write nothing";
@@ -15390,6 +15398,10 @@ export declare const COMMAND_CATALOG: readonly [{
15390
15398
  readonly flags: "--company <slug>";
15391
15399
  readonly description: "Select the company by slug";
15392
15400
  readonly hidden: false;
15401
+ }, {
15402
+ readonly flags: "--source <ref>";
15403
+ readonly description: "Report lanes for a source (requires --company; excludes --since)";
15404
+ readonly hidden: false;
15393
15405
  }, {
15394
15406
  readonly flags: "--since <iso>";
15395
15407
  readonly description: "Report activity from this ISO timestamp";
@@ -15859,7 +15871,23 @@ export declare const COMMAND_CATALOG: readonly [{
15859
15871
  readonly hidden: false;
15860
15872
  }, {
15861
15873
  readonly flags: "--project <slug>";
15862
- readonly description: "HQ project slug";
15874
+ readonly description: "HQ project slug (executive-bot for --signal)";
15875
+ readonly hidden: false;
15876
+ }, {
15877
+ readonly flags: "--signal <id>";
15878
+ readonly description: "Create one lane for a company signal";
15879
+ readonly hidden: false;
15880
+ }, {
15881
+ readonly flags: "--rules-file <path>";
15882
+ readonly description: "Standing rules for a signal lane";
15883
+ readonly hidden: false;
15884
+ }, {
15885
+ readonly flags: "--any-type";
15886
+ readonly description: "Allow signal types other than action_item";
15887
+ readonly hidden: false;
15888
+ }, {
15889
+ readonly flags: "--link <id>";
15890
+ readonly description: "Conductor link for a signal lane";
15863
15891
  readonly hidden: false;
15864
15892
  }, {
15865
15893
  readonly flags: "--story <id>";
@@ -15879,7 +15907,7 @@ export declare const COMMAND_CATALOG: readonly [{
15879
15907
  readonly hidden: false;
15880
15908
  }, {
15881
15909
  readonly flags: "--brief-file <path>";
15882
- readonly description: "Path to the lane brief";
15910
+ readonly description: "Path to the lane brief (generated for --signal)";
15883
15911
  readonly hidden: false;
15884
15912
  }, {
15885
15913
  readonly flags: "--worker <name>";
@@ -16435,17 +16463,22 @@ export declare const COMMAND_CATALOG: readonly [{
16435
16463
  readonly subcommands: readonly [];
16436
16464
  }, {
16437
16465
  readonly name: "status";
16438
- readonly description: "Summarize project stories, lanes, PRs, blockers, and pending questions";
16466
+ readonly description: "Summarize project stories, lanes, PRs, blockers, and pending questions; with a lane id, report that lane's outcome";
16439
16467
  readonly aliases: readonly [];
16440
16468
  readonly hidden: false;
16441
16469
  readonly helpOption: true;
16442
16470
  readonly helpCommand: false;
16443
- readonly usage: "[options]";
16471
+ readonly usage: "[options] [lane-id]";
16444
16472
  readonly helpText: readonly [];
16445
- readonly arguments: readonly [];
16473
+ readonly arguments: readonly [{
16474
+ readonly name: "lane-id";
16475
+ readonly required: false;
16476
+ readonly variadic: false;
16477
+ readonly description: "Report one lane's state and outcome block instead of a project";
16478
+ }];
16446
16479
  readonly options: readonly [{
16447
16480
  readonly flags: "--project <slug>";
16448
- readonly description: "HQ project slug";
16481
+ readonly description: "HQ project slug (required without a lane id)";
16449
16482
  readonly hidden: false;
16450
16483
  }, {
16451
16484
  readonly flags: "--company <slug|uid>";
@@ -19072,6 +19105,15 @@ export declare const COMMAND_CATALOG: readonly [{
19072
19105
  readonly flags: "--cron <expr>";
19073
19106
  readonly description: "How often, as a cron expression (e.g. \"0 9 * * 1-5\")";
19074
19107
  readonly hidden: false;
19108
+ }, {
19109
+ readonly flags: "--on <event>";
19110
+ readonly description: "Run when this event is emitted";
19111
+ readonly hidden: false;
19112
+ }, {
19113
+ readonly flags: "--filter <key=value>";
19114
+ readonly description: "Match an event payload field (repeatable)";
19115
+ readonly hidden: false;
19116
+ readonly defaultValue: readonly [];
19075
19117
  }, {
19076
19118
  readonly flags: "--tz <zone>";
19077
19119
  readonly description: "IANA timezone for the schedule (default: this computer's)";
@@ -19094,6 +19136,64 @@ export declare const COMMAND_CATALOG: readonly [{
19094
19136
  readonly hidden: false;
19095
19137
  }];
19096
19138
  readonly subcommands: readonly [];
19139
+ }, {
19140
+ readonly name: "events";
19141
+ readonly description: "Emit and inspect local bot events";
19142
+ readonly aliases: readonly [];
19143
+ readonly hidden: false;
19144
+ readonly helpOption: true;
19145
+ readonly helpCommand: true;
19146
+ readonly usage: "[options] [command]";
19147
+ readonly helpText: readonly [];
19148
+ readonly arguments: readonly [];
19149
+ readonly options: readonly [];
19150
+ readonly subcommands: readonly [{
19151
+ readonly name: "emit";
19152
+ readonly description: "";
19153
+ readonly aliases: readonly [];
19154
+ readonly hidden: false;
19155
+ readonly helpOption: true;
19156
+ readonly helpCommand: false;
19157
+ readonly usage: "[options] <event>";
19158
+ readonly helpText: readonly [];
19159
+ readonly arguments: readonly [{
19160
+ readonly name: "event";
19161
+ readonly required: true;
19162
+ readonly variadic: false;
19163
+ readonly description: "";
19164
+ }];
19165
+ readonly options: readonly [{
19166
+ readonly flags: "--bot <name>";
19167
+ readonly description: "Bot receiving the event";
19168
+ readonly hidden: false;
19169
+ }, {
19170
+ readonly flags: "--json <payload>";
19171
+ readonly description: "JSON object under 16 KB";
19172
+ readonly hidden: false;
19173
+ }];
19174
+ readonly subcommands: readonly [];
19175
+ }, {
19176
+ readonly name: "tail";
19177
+ readonly description: "";
19178
+ readonly aliases: readonly [];
19179
+ readonly hidden: false;
19180
+ readonly helpOption: true;
19181
+ readonly helpCommand: false;
19182
+ readonly usage: "[options] <name>";
19183
+ readonly helpText: readonly [];
19184
+ readonly arguments: readonly [{
19185
+ readonly name: "name";
19186
+ readonly required: true;
19187
+ readonly variadic: false;
19188
+ readonly description: "";
19189
+ }];
19190
+ readonly options: readonly [{
19191
+ readonly flags: "--json";
19192
+ readonly description: "Print the last 50 events as a JSON array";
19193
+ readonly hidden: false;
19194
+ }];
19195
+ readonly subcommands: readonly [];
19196
+ }];
19097
19197
  }, {
19098
19198
  readonly name: "promote";
19099
19199
  readonly description: "Move this local bot to cloud compute, preserving its identity and private context";
@@ -6723,6 +6723,16 @@ export const COMMAND_CATALOG = [
6723
6723
  "description": "Run one company (default: every company listed in the companies manifest)",
6724
6724
  "hidden": false
6725
6725
  },
6726
+ {
6727
+ "flags": "--source <ref>",
6728
+ "description": "Read a growing source: meeting:<id> or <channel>:<file> (needs --incremental and --company)",
6729
+ "hidden": false
6730
+ },
6731
+ {
6732
+ "flags": "--incremental",
6733
+ "description": "Extract only new signals from --source, retaining a cursor and prior signal ids",
6734
+ "hidden": false
6735
+ },
6726
6736
  {
6727
6737
  "flags": "--dry-run",
6728
6738
  "description": "Print what would run; run no mutating step and write nothing",
@@ -18754,6 +18764,11 @@ export const COMMAND_CATALOG = [
18754
18764
  "description": "Select the company by slug",
18755
18765
  "hidden": false
18756
18766
  },
18767
+ {
18768
+ "flags": "--source <ref>",
18769
+ "description": "Report lanes for a source (requires --company; excludes --since)",
18770
+ "hidden": false
18771
+ },
18757
18772
  {
18758
18773
  "flags": "--since <iso>",
18759
18774
  "description": "Report activity from this ISO timestamp",
@@ -19323,7 +19338,27 @@ export const COMMAND_CATALOG = [
19323
19338
  },
19324
19339
  {
19325
19340
  "flags": "--project <slug>",
19326
- "description": "HQ project slug",
19341
+ "description": "HQ project slug (executive-bot for --signal)",
19342
+ "hidden": false
19343
+ },
19344
+ {
19345
+ "flags": "--signal <id>",
19346
+ "description": "Create one lane for a company signal",
19347
+ "hidden": false
19348
+ },
19349
+ {
19350
+ "flags": "--rules-file <path>",
19351
+ "description": "Standing rules for a signal lane",
19352
+ "hidden": false
19353
+ },
19354
+ {
19355
+ "flags": "--any-type",
19356
+ "description": "Allow signal types other than action_item",
19357
+ "hidden": false
19358
+ },
19359
+ {
19360
+ "flags": "--link <id>",
19361
+ "description": "Conductor link for a signal lane",
19327
19362
  "hidden": false
19328
19363
  },
19329
19364
  {
@@ -19348,7 +19383,7 @@ export const COMMAND_CATALOG = [
19348
19383
  },
19349
19384
  {
19350
19385
  "flags": "--brief-file <path>",
19351
- "description": "Path to the lane brief",
19386
+ "description": "Path to the lane brief (generated for --signal)",
19352
19387
  "hidden": false
19353
19388
  },
19354
19389
  {
@@ -20037,18 +20072,25 @@ export const COMMAND_CATALOG = [
20037
20072
  },
20038
20073
  {
20039
20074
  "name": "status",
20040
- "description": "Summarize project stories, lanes, PRs, blockers, and pending questions",
20075
+ "description": "Summarize project stories, lanes, PRs, blockers, and pending questions; with a lane id, report that lane's outcome",
20041
20076
  "aliases": [],
20042
20077
  "hidden": false,
20043
20078
  "helpOption": true,
20044
20079
  "helpCommand": false,
20045
- "usage": "[options]",
20080
+ "usage": "[options] [lane-id]",
20046
20081
  "helpText": [],
20047
- "arguments": [],
20082
+ "arguments": [
20083
+ {
20084
+ "name": "lane-id",
20085
+ "required": false,
20086
+ "variadic": false,
20087
+ "description": "Report one lane's state and outcome block instead of a project"
20088
+ }
20089
+ ],
20048
20090
  "options": [
20049
20091
  {
20050
20092
  "flags": "--project <slug>",
20051
- "description": "HQ project slug",
20093
+ "description": "HQ project slug (required without a lane id)",
20052
20094
  "hidden": false
20053
20095
  },
20054
20096
  {
@@ -23249,6 +23291,17 @@ export const COMMAND_CATALOG = [
23249
23291
  "description": "How often, as a cron expression (e.g. \"0 9 * * 1-5\")",
23250
23292
  "hidden": false
23251
23293
  },
23294
+ {
23295
+ "flags": "--on <event>",
23296
+ "description": "Run when this event is emitted",
23297
+ "hidden": false
23298
+ },
23299
+ {
23300
+ "flags": "--filter <key=value>",
23301
+ "description": "Match an event payload field (repeatable)",
23302
+ "hidden": false,
23303
+ "defaultValue": []
23304
+ },
23252
23305
  {
23253
23306
  "flags": "--tz <zone>",
23254
23307
  "description": "IANA timezone for the schedule (default: this computer's)",
@@ -23277,6 +23330,77 @@ export const COMMAND_CATALOG = [
23277
23330
  ],
23278
23331
  "subcommands": []
23279
23332
  },
23333
+ {
23334
+ "name": "events",
23335
+ "description": "Emit and inspect local bot events",
23336
+ "aliases": [],
23337
+ "hidden": false,
23338
+ "helpOption": true,
23339
+ "helpCommand": true,
23340
+ "usage": "[options] [command]",
23341
+ "helpText": [],
23342
+ "arguments": [],
23343
+ "options": [],
23344
+ "subcommands": [
23345
+ {
23346
+ "name": "emit",
23347
+ "description": "",
23348
+ "aliases": [],
23349
+ "hidden": false,
23350
+ "helpOption": true,
23351
+ "helpCommand": false,
23352
+ "usage": "[options] <event>",
23353
+ "helpText": [],
23354
+ "arguments": [
23355
+ {
23356
+ "name": "event",
23357
+ "required": true,
23358
+ "variadic": false,
23359
+ "description": ""
23360
+ }
23361
+ ],
23362
+ "options": [
23363
+ {
23364
+ "flags": "--bot <name>",
23365
+ "description": "Bot receiving the event",
23366
+ "hidden": false
23367
+ },
23368
+ {
23369
+ "flags": "--json <payload>",
23370
+ "description": "JSON object under 16 KB",
23371
+ "hidden": false
23372
+ }
23373
+ ],
23374
+ "subcommands": []
23375
+ },
23376
+ {
23377
+ "name": "tail",
23378
+ "description": "",
23379
+ "aliases": [],
23380
+ "hidden": false,
23381
+ "helpOption": true,
23382
+ "helpCommand": false,
23383
+ "usage": "[options] <name>",
23384
+ "helpText": [],
23385
+ "arguments": [
23386
+ {
23387
+ "name": "name",
23388
+ "required": true,
23389
+ "variadic": false,
23390
+ "description": ""
23391
+ }
23392
+ ],
23393
+ "options": [
23394
+ {
23395
+ "flags": "--json",
23396
+ "description": "Print the last 50 events as a JSON array",
23397
+ "hidden": false
23398
+ }
23399
+ ],
23400
+ "subcommands": []
23401
+ }
23402
+ ]
23403
+ },
23280
23404
  {
23281
23405
  "name": "promote",
23282
23406
  "description": "Move this local bot to cloud compute, preserving its identity and private context",
@@ -0,0 +1,19 @@
1
+ import type { Command } from "commander";
2
+ import { type BotConfig } from "../lib/bot/config.js";
3
+ export interface BotEventsDeps {
4
+ requireBot(name: string): {
5
+ name: string;
6
+ dir: string;
7
+ config: BotConfig;
8
+ };
9
+ out?: (line: string) => void;
10
+ }
11
+ export declare function runBotEventEmit(event: string, opts: {
12
+ bot: string;
13
+ json: string;
14
+ }, deps: BotEventsDeps): void;
15
+ export declare function runBotEventsTail(name: string, opts: {
16
+ json?: boolean;
17
+ }, deps: BotEventsDeps): void;
18
+ export declare function registerBotEventsCommand(bot: Command, deps: BotEventsDeps): void;
19
+ //# sourceMappingURL=bot-events.d.ts.map
@@ -0,0 +1,46 @@
1
+ import { emitBotEvent, tailBotEvents } from "../lib/bot/events.js";
2
+ import { HQ_FLEET_RUNTIME_ENGINE_ID } from "../lib/bot/config.js";
3
+ export function runBotEventEmit(event, opts, deps) {
4
+ const { dir, config } = deps.requireBot(opts.bot);
5
+ if (config.engine?.id === HQ_FLEET_RUNTIME_ENGINE_ID)
6
+ throw new Error("Event journals require a local CLI bot; HQ Fleet Runtime does not drain them.");
7
+ let payload;
8
+ try {
9
+ payload = JSON.parse(opts.json);
10
+ }
11
+ catch {
12
+ throw new Error("Event payload must be valid JSON.");
13
+ }
14
+ const record = emitBotEvent(dir, event, payload);
15
+ (deps.out ?? console.log)(JSON.stringify(record));
16
+ }
17
+ export function runBotEventsTail(name, opts, deps) {
18
+ const { dir } = deps.requireBot(name);
19
+ const records = tailBotEvents(dir);
20
+ const out = deps.out ?? console.log;
21
+ if (opts.json)
22
+ out(JSON.stringify(records, null, 2));
23
+ else
24
+ for (const record of records)
25
+ out(`${record.at} ${record.event} ${JSON.stringify(record.payload)}`);
26
+ }
27
+ export function registerBotEventsCommand(bot, deps) {
28
+ const events = bot.command("events").description("Emit and inspect local bot events");
29
+ const action = (fn) => {
30
+ try {
31
+ fn();
32
+ }
33
+ catch (err) {
34
+ console.error(err instanceof Error ? err.message : String(err));
35
+ process.exitCode = 1;
36
+ }
37
+ };
38
+ events.command("emit <event>")
39
+ .requiredOption("--bot <name>", "Bot receiving the event")
40
+ .requiredOption("--json <payload>", "JSON object under 16 KB")
41
+ .action((event, opts) => action(() => runBotEventEmit(event, opts, deps)));
42
+ events.command("tail <name>")
43
+ .option("--json", "Print the last 50 events as a JSON array")
44
+ .action((name, opts) => action(() => runBotEventsTail(name, opts, deps)));
45
+ }
46
+ //# sourceMappingURL=bot-events.js.map
@@ -114,6 +114,8 @@ export interface BotJobsOptions {
114
114
  add?: string;
115
115
  every?: string;
116
116
  cron?: string;
117
+ on?: string;
118
+ filter?: string[];
117
119
  tz?: string;
118
120
  rm?: string;
119
121
  /** Change an existing job's schedule, keeping its id, instruction and history. */
@@ -16,7 +16,7 @@
16
16
  * back when it checks what is due.
17
17
  */
18
18
  import chalk from "chalk";
19
- import { localJobsClient } from "../lib/bot/local-jobs.js";
19
+ import { addLocalJob, localJobsClient, readLocalJobs, toJobRecord } from "../lib/bot/local-jobs.js";
20
20
  import { BotApiError } from "../lib/bot/api.js";
21
21
  import { effectiveBotKind, HQ_FLEET_RUNTIME_ENGINE_ID } from "../lib/bot/config.js";
22
22
  import { fleetCronOps, fleetOwnerOrigin, fleetScheduleFromLegacy } from "../lib/bot/fleet-cron.js";
@@ -318,6 +318,10 @@ export function fleetJobsClient(config, ops, timezone) {
318
318
  // ─── Reading jobs back ───────────────────────────────────────────────────────
319
319
  /** A schedule in plain words, falling back to the raw expression. */
320
320
  export function describeSchedule(job) {
321
+ if (job.trigger) {
322
+ const filters = Object.entries(job.trigger.filter ?? {}).map(([key, value]) => `${key}=${value}`).join(", ");
323
+ return `on ${job.trigger.event}${filters ? ` (${filters})` : ""}`;
324
+ }
321
325
  const schedule = job.schedule;
322
326
  if (!schedule)
323
327
  return "on a schedule";
@@ -391,7 +395,7 @@ export function formatJobsList(botName, jobs, showQuietOption = false) {
391
395
  lines.push(` runs ${describeSchedule(job)}`);
392
396
  if (showQuietOption && isQuietJobContext(job.context))
393
397
  lines.push(" delivery: quiet after successful runs");
394
- lines.push(` next run: ${job.nextRunAt ? `${utcMinute(job.nextRunAt)} UTC` : "not scheduled yet"}`);
398
+ lines.push(` next run: ${job.trigger ? "when a matching event arrives" : job.nextRunAt ? `${utcMinute(job.nextRunAt)} UTC` : "not scheduled yet"}`);
395
399
  lines.push(` last run: ${describeLastRun(job)}`);
396
400
  }
397
401
  return lines.join("\n");
@@ -454,6 +458,11 @@ export async function runBotJobs(nameArg, opts, deps) {
454
458
  if (opts.quiet && opts.add === undefined) {
455
459
  refuse("Use --quiet with --add to set a scheduled job's delivery option.");
456
460
  }
461
+ if (opts.on !== undefined && (opts.add === undefined || opts.every !== undefined || opts.cron !== undefined || opts.tz !== undefined)) {
462
+ refuse("Use --on with --add and without --every, --cron, or --tz.");
463
+ }
464
+ if (opts.filter?.length && opts.on === undefined)
465
+ refuse("Use --filter with --on.");
457
466
  // Shared by --add and --reschedule: one schedule from --every or --cron, in
458
467
  // the stored form, held to the same floor.
459
468
  const scheduleFromOptions = () => {
@@ -516,6 +525,36 @@ export async function runBotJobs(nameArg, opts, deps) {
516
525
  if (opts.quiet && !(await quietOptionEnabled())) {
517
526
  refuse(`--quiet requires the ${BOT_JOB_QUIET_OPTION_FLAG} flag, which is currently disabled.`);
518
527
  }
528
+ if (opts.on !== undefined) {
529
+ if (fleet)
530
+ refuse("Event jobs require a local CLI bot; HQ Fleet Runtime does not drain this event journal.");
531
+ const event = opts.on.trim();
532
+ if (!event || event.length > 256 || /[\r\n]/.test(event))
533
+ refuse("Event name must be 1–256 characters without newlines.");
534
+ const prompt = opts.add.trim();
535
+ if (!prompt || Buffer.byteLength(prompt, "utf8") > MAX_PROMPT_BYTES)
536
+ refuse("Job instruction must be non-empty and at most 16 KB.");
537
+ const filter = Object.create(null);
538
+ for (const entry of opts.filter ?? []) {
539
+ const split = entry.indexOf("=");
540
+ if (split < 1 || !entry.slice(0, split).trim())
541
+ refuse("Each --filter must be key=value.");
542
+ const key = entry.slice(0, split).trim();
543
+ if (Object.hasOwn(filter, key))
544
+ refuse(`Duplicate filter key: ${key}`);
545
+ filter[key] = entry.slice(split + 1);
546
+ }
547
+ if (readLocalJobs(dir).length >= MAX_ACTIVE_JOBS_PER_AGENT)
548
+ refuse(`${name} already has the maximum of ${MAX_ACTIVE_JOBS_PER_AGENT} jobs. Remove one first.`);
549
+ const created = toJobRecord(addLocalJob(dir, {
550
+ prompt,
551
+ timezone: localZone,
552
+ trigger: { kind: "event", event, ...(Object.keys(filter).length ? { filter } : {}) },
553
+ ...(opts.quiet ? { context: { [JOB_RUN_OPTIONS_CONTEXT_KEY]: { quiet: true } } } : {}),
554
+ }));
555
+ out(opts.json ? JSON.stringify({ ok: true, job: created }, null, 2) : `Added ${created.jobId}: ${name} runs it ${describeSchedule(created)}.`);
556
+ return;
557
+ }
519
558
  const schedule = scheduleFromOptions();
520
559
  const body = buildCreateJobBody({ prompt: opts.add, cron: schedule.cron, timezone: schedule.timezone, quiet: opts.quiet });
521
560
  const api = await jobsApi();
@@ -558,6 +597,8 @@ export function registerBotJobsCommand(bot, deps) {
558
597
  .option("--add <what>", "Schedule new work, in plain language")
559
598
  .option("--every <when>", 'How often, in plain language (e.g. "every weekday at 9am")')
560
599
  .option("--cron <expr>", 'How often, as a cron expression (e.g. "0 9 * * 1-5")')
600
+ .option("--on <event>", "Run when this event is emitted")
601
+ .option("--filter <key=value>", "Match an event payload field (repeatable)", (value, values) => [...values, value], [])
561
602
  .option("--tz <zone>", "IANA timezone for the schedule (default: this computer's)")
562
603
  .option("--quiet", "Skip owner DMs after successful runs (requires rollout flag)")
563
604
  .option("--rm <jobId>", "Remove a scheduled job")
@@ -1,5 +1,6 @@
1
1
  import { Command } from "commander";
2
2
  import { type RuntimeSignInCheck, type RuntimeSignInIssue } from "../lib/bot/runtime-sign-in.js";
3
+ import { type ClaudeLoginCheck } from "../lib/bot/claude-login.js";
3
4
  import type { BotStatusFile } from "../lib/bot/status.js";
4
5
  import { probeBotRuntime, type RuntimeProbeResult } from "../lib/bot/probe.js";
5
6
  import { type SpawnInteractive } from "../lib/bot/runtime-auth.js";
@@ -115,6 +116,10 @@ export declare function spawnDetachedRun(name: string, dir: string): number;
115
116
  * "unreadable output: trailing characters").
116
117
  */
117
118
  /** Seams for the self-stop path, replaced in tests. */
119
+ export declare const botCreateSeams: {
120
+ /** The Claude Code login read the way the HQ Fleet Runtime reads it. */
121
+ claudeLogin: () => ClaudeLoginCheck;
122
+ };
118
123
  export declare const botStopSeams: {
119
124
  /** True when this process runs inside the bot process `botPid` (one of its turns). */
120
125
  isInsideBot: (botPid: number) => boolean;