@indigoai-us/hq-cli 5.117.3 → 5.118.1
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 +28 -0
- package/dist/command-catalog.generated.d.ts +108 -0
- package/dist/command-catalog.generated.js +136 -0
- package/dist/commands/agent-inbox.d.ts +9 -0
- package/dist/commands/agent-inbox.js +81 -0
- package/dist/commands/agent-kit.js +105 -0
- package/dist/commands/agent-mcp.d.ts +2 -1
- package/dist/commands/agent-mcp.js +4 -3
- package/dist/commands/agent.d.ts +1 -0
- package/dist/commands/agent.js +3 -0
- package/dist/commands/agents.d.ts +1 -1
- package/dist/commands/agents.js +6 -2
- package/dist/lib/agent-kit/inbox-state.d.ts +34 -0
- package/dist/lib/agent-kit/inbox-state.js +86 -0
- package/dist/lib/agent-kit/mcp/tools.d.ts +3 -0
- package/dist/lib/agent-kit/mcp/tools.js +73 -22
- package/dist/lib/agent-kit/run/inbox.d.ts +5 -0
- package/dist/lib/agent-kit/run/inbox.js +21 -0
- package/dist/lib/agent-kit/skills.js +11 -8
- package/dist/lib/agent-kit/wake.d.ts +83 -0
- package/dist/lib/agent-kit/wake.js +236 -0
- package/dist/lib/billing/plan-lock.d.ts +37 -9
- package/dist/lib/billing/plan-lock.js +124 -29
- package/dist/lib/plan-limit-nag.d.ts +8 -0
- package/dist/lib/plan-limit-nag.js +21 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.118.1] — 2026-09-17
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- The locked-workspace notice now names the real reason. A workspace locked
|
|
10
|
+
because of secrets or agents no longer reads "over its 5-member limit"; each
|
|
11
|
+
reason gets its own explanation, its own Starter cap and its own fix, and a
|
|
12
|
+
lock with no recognised reason says only that the workspace is over the
|
|
13
|
+
Starter limits. The plan-limit warning also names the dimension it is quoting
|
|
14
|
+
("users at 9/10 (90%) (members)").
|
|
15
|
+
|
|
16
|
+
- You can now remove an HQ Agents v2 agent from the CLI without bypassing its
|
|
17
|
+
safety check. `hq agents rm` accepts `--confirm-destroy-agents-v2
|
|
18
|
+
<instance-id>` alongside `--yes` and sends only the instance ID you name; HQ
|
|
19
|
+
still refuses an ID that does not match the live box.
|
|
20
|
+
|
|
21
|
+
## [5.118.0] — 2026-09-16
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- External agents can now be woken the moment an HQ message arrives. `hq agent kit wake set-url --stdin` points the kit at a webhook, such as a Grok Bot routine webhook trigger. `hq agent kit wake set-command -- <cmd>` runs a local command for frameworks with a CLI. The kit sends a short notice with no message text when mail is pending, and again every 10 minutes until it is handled. The webhook URL is stored privately and never logged.
|
|
26
|
+
- `hq agent inbox` lists an external agent's pending HQ messages and `hq agent inbox done <id>` marks them handled, so a woken bot never answers the same message twice. The MCP server gains a matching `hq_inbox_done` tool.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- The `hq_inbox_read` MCP tool no longer fails with 403 AGENT_ROUTE_NOT_SUPPORTED. It reads the agent's own inbox instead of the person-only DM inbox, and by default returns only messages not yet handled.
|
|
31
|
+
- The HQ direct-message skill shipped to external agents no longer tells them to use person-only read commands.
|
|
32
|
+
|
|
5
33
|
## [5.117.3] — 2026-09-16
|
|
6
34
|
|
|
7
35
|
### Fixed
|
|
@@ -4023,6 +4023,9 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
4023
4023
|
}, {
|
|
4024
4024
|
readonly flags: "--yes";
|
|
4025
4025
|
readonly description: "Confirm the irreversible teardown (required)";
|
|
4026
|
+
}, {
|
|
4027
|
+
readonly flags: "--confirm-destroy-agents-v2 <instance-id>";
|
|
4028
|
+
readonly description: "Confirm agents-v2 teardown by naming the live EC2 instance ID";
|
|
4026
4029
|
}];
|
|
4027
4030
|
readonly subcommands: readonly [];
|
|
4028
4031
|
}, {
|
|
@@ -4218,6 +4221,83 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
4218
4221
|
readonly description: "Print machine-readable JSON";
|
|
4219
4222
|
}];
|
|
4220
4223
|
readonly subcommands: readonly [];
|
|
4224
|
+
}, {
|
|
4225
|
+
readonly name: "wake";
|
|
4226
|
+
readonly description: "Wake this bot's own framework when HQ messages arrive (webhook URL or local command)";
|
|
4227
|
+
readonly aliases: readonly [];
|
|
4228
|
+
readonly hidden: false;
|
|
4229
|
+
readonly usage: "[options] [command]";
|
|
4230
|
+
readonly arguments: readonly [];
|
|
4231
|
+
readonly options: readonly [];
|
|
4232
|
+
readonly subcommands: readonly [{
|
|
4233
|
+
readonly name: "set-url";
|
|
4234
|
+
readonly description: "POST a notice to a webhook URL (e.g. a Grok Bot routine webhook) when mail is pending. Prefer --stdin so the URL stays out of shell history";
|
|
4235
|
+
readonly aliases: readonly [];
|
|
4236
|
+
readonly hidden: false;
|
|
4237
|
+
readonly usage: "[options] [url]";
|
|
4238
|
+
readonly arguments: readonly [{
|
|
4239
|
+
readonly name: "url";
|
|
4240
|
+
readonly required: false;
|
|
4241
|
+
readonly variadic: false;
|
|
4242
|
+
}];
|
|
4243
|
+
readonly options: readonly [{
|
|
4244
|
+
readonly flags: "--stdin";
|
|
4245
|
+
readonly description: "Read the URL from stdin";
|
|
4246
|
+
}, {
|
|
4247
|
+
readonly flags: "--retry-minutes <n>";
|
|
4248
|
+
readonly description: "Re-wake while items stay pending (default 10, minimum 1)";
|
|
4249
|
+
}];
|
|
4250
|
+
readonly subcommands: readonly [];
|
|
4251
|
+
}, {
|
|
4252
|
+
readonly name: "set-command";
|
|
4253
|
+
readonly description: "Run a local command (no shell) when mail is pending; the notice JSON arrives on stdin. Use -- before the command";
|
|
4254
|
+
readonly aliases: readonly [];
|
|
4255
|
+
readonly hidden: false;
|
|
4256
|
+
readonly usage: "[options] <argv...>";
|
|
4257
|
+
readonly arguments: readonly [{
|
|
4258
|
+
readonly name: "argv";
|
|
4259
|
+
readonly required: true;
|
|
4260
|
+
readonly variadic: true;
|
|
4261
|
+
}];
|
|
4262
|
+
readonly options: readonly [{
|
|
4263
|
+
readonly flags: "--timeout-minutes <n>";
|
|
4264
|
+
readonly description: "Kill a run after this long (default 10)";
|
|
4265
|
+
}, {
|
|
4266
|
+
readonly flags: "--retry-minutes <n>";
|
|
4267
|
+
readonly description: "Re-wake while items stay pending (default 10, minimum 1)";
|
|
4268
|
+
}];
|
|
4269
|
+
readonly subcommands: readonly [];
|
|
4270
|
+
}, {
|
|
4271
|
+
readonly name: "show";
|
|
4272
|
+
readonly description: "Show the configured wake (the URL is masked)";
|
|
4273
|
+
readonly aliases: readonly [];
|
|
4274
|
+
readonly hidden: false;
|
|
4275
|
+
readonly usage: "[options]";
|
|
4276
|
+
readonly arguments: readonly [];
|
|
4277
|
+
readonly options: readonly [{
|
|
4278
|
+
readonly flags: "--json";
|
|
4279
|
+
readonly description: "Print machine-readable JSON";
|
|
4280
|
+
}];
|
|
4281
|
+
readonly subcommands: readonly [];
|
|
4282
|
+
}, {
|
|
4283
|
+
readonly name: "clear";
|
|
4284
|
+
readonly description: "Remove the wake configuration";
|
|
4285
|
+
readonly aliases: readonly [];
|
|
4286
|
+
readonly hidden: false;
|
|
4287
|
+
readonly usage: "[options]";
|
|
4288
|
+
readonly arguments: readonly [];
|
|
4289
|
+
readonly options: readonly [];
|
|
4290
|
+
readonly subcommands: readonly [];
|
|
4291
|
+
}, {
|
|
4292
|
+
readonly name: "test";
|
|
4293
|
+
readonly description: "Fire the wake once now with the current pending count";
|
|
4294
|
+
readonly aliases: readonly [];
|
|
4295
|
+
readonly hidden: false;
|
|
4296
|
+
readonly usage: "[options]";
|
|
4297
|
+
readonly arguments: readonly [];
|
|
4298
|
+
readonly options: readonly [];
|
|
4299
|
+
readonly subcommands: readonly [];
|
|
4300
|
+
}];
|
|
4221
4301
|
}, {
|
|
4222
4302
|
readonly name: "run";
|
|
4223
4303
|
readonly description: "Run one kit service in the foreground (sync|mesh|inbox|heartbeat), or `all` to supervise every service in one process";
|
|
@@ -4253,6 +4333,34 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
4253
4333
|
readonly arguments: readonly [];
|
|
4254
4334
|
readonly options: readonly [];
|
|
4255
4335
|
readonly subcommands: readonly [];
|
|
4336
|
+
}, {
|
|
4337
|
+
readonly name: "inbox";
|
|
4338
|
+
readonly description: "List this agent's pending HQ messages (mirrored by the kit), or mark them handled";
|
|
4339
|
+
readonly aliases: readonly [];
|
|
4340
|
+
readonly hidden: false;
|
|
4341
|
+
readonly usage: "[options] [command]";
|
|
4342
|
+
readonly arguments: readonly [];
|
|
4343
|
+
readonly options: readonly [{
|
|
4344
|
+
readonly flags: "--all";
|
|
4345
|
+
readonly description: "Include items already marked handled";
|
|
4346
|
+
}, {
|
|
4347
|
+
readonly flags: "--json";
|
|
4348
|
+
readonly description: "Print machine-readable JSON";
|
|
4349
|
+
}];
|
|
4350
|
+
readonly subcommands: readonly [{
|
|
4351
|
+
readonly name: "done";
|
|
4352
|
+
readonly description: "Mark inbox items handled and ack them on the server";
|
|
4353
|
+
readonly aliases: readonly [];
|
|
4354
|
+
readonly hidden: false;
|
|
4355
|
+
readonly usage: "[options] <ids...>";
|
|
4356
|
+
readonly arguments: readonly [{
|
|
4357
|
+
readonly name: "ids";
|
|
4358
|
+
readonly required: true;
|
|
4359
|
+
readonly variadic: true;
|
|
4360
|
+
}];
|
|
4361
|
+
readonly options: readonly [];
|
|
4362
|
+
readonly subcommands: readonly [];
|
|
4363
|
+
}];
|
|
4256
4364
|
}];
|
|
4257
4365
|
}, {
|
|
4258
4366
|
readonly name: "outposts";
|
|
@@ -5205,6 +5205,10 @@ export const COMMAND_CATALOG = [
|
|
|
5205
5205
|
{
|
|
5206
5206
|
"flags": "--yes",
|
|
5207
5207
|
"description": "Confirm the irreversible teardown (required)"
|
|
5208
|
+
},
|
|
5209
|
+
{
|
|
5210
|
+
"flags": "--confirm-destroy-agents-v2 <instance-id>",
|
|
5211
|
+
"description": "Confirm agents-v2 teardown by naming the live EC2 instance ID"
|
|
5208
5212
|
}
|
|
5209
5213
|
],
|
|
5210
5214
|
"subcommands": []
|
|
@@ -5457,6 +5461,102 @@ export const COMMAND_CATALOG = [
|
|
|
5457
5461
|
],
|
|
5458
5462
|
"subcommands": []
|
|
5459
5463
|
},
|
|
5464
|
+
{
|
|
5465
|
+
"name": "wake",
|
|
5466
|
+
"description": "Wake this bot's own framework when HQ messages arrive (webhook URL or local command)",
|
|
5467
|
+
"aliases": [],
|
|
5468
|
+
"hidden": false,
|
|
5469
|
+
"usage": "[options] [command]",
|
|
5470
|
+
"arguments": [],
|
|
5471
|
+
"options": [],
|
|
5472
|
+
"subcommands": [
|
|
5473
|
+
{
|
|
5474
|
+
"name": "set-url",
|
|
5475
|
+
"description": "POST a notice to a webhook URL (e.g. a Grok Bot routine webhook) when mail is pending. Prefer --stdin so the URL stays out of shell history",
|
|
5476
|
+
"aliases": [],
|
|
5477
|
+
"hidden": false,
|
|
5478
|
+
"usage": "[options] [url]",
|
|
5479
|
+
"arguments": [
|
|
5480
|
+
{
|
|
5481
|
+
"name": "url",
|
|
5482
|
+
"required": false,
|
|
5483
|
+
"variadic": false
|
|
5484
|
+
}
|
|
5485
|
+
],
|
|
5486
|
+
"options": [
|
|
5487
|
+
{
|
|
5488
|
+
"flags": "--stdin",
|
|
5489
|
+
"description": "Read the URL from stdin"
|
|
5490
|
+
},
|
|
5491
|
+
{
|
|
5492
|
+
"flags": "--retry-minutes <n>",
|
|
5493
|
+
"description": "Re-wake while items stay pending (default 10, minimum 1)"
|
|
5494
|
+
}
|
|
5495
|
+
],
|
|
5496
|
+
"subcommands": []
|
|
5497
|
+
},
|
|
5498
|
+
{
|
|
5499
|
+
"name": "set-command",
|
|
5500
|
+
"description": "Run a local command (no shell) when mail is pending; the notice JSON arrives on stdin. Use -- before the command",
|
|
5501
|
+
"aliases": [],
|
|
5502
|
+
"hidden": false,
|
|
5503
|
+
"usage": "[options] <argv...>",
|
|
5504
|
+
"arguments": [
|
|
5505
|
+
{
|
|
5506
|
+
"name": "argv",
|
|
5507
|
+
"required": true,
|
|
5508
|
+
"variadic": true
|
|
5509
|
+
}
|
|
5510
|
+
],
|
|
5511
|
+
"options": [
|
|
5512
|
+
{
|
|
5513
|
+
"flags": "--timeout-minutes <n>",
|
|
5514
|
+
"description": "Kill a run after this long (default 10)"
|
|
5515
|
+
},
|
|
5516
|
+
{
|
|
5517
|
+
"flags": "--retry-minutes <n>",
|
|
5518
|
+
"description": "Re-wake while items stay pending (default 10, minimum 1)"
|
|
5519
|
+
}
|
|
5520
|
+
],
|
|
5521
|
+
"subcommands": []
|
|
5522
|
+
},
|
|
5523
|
+
{
|
|
5524
|
+
"name": "show",
|
|
5525
|
+
"description": "Show the configured wake (the URL is masked)",
|
|
5526
|
+
"aliases": [],
|
|
5527
|
+
"hidden": false,
|
|
5528
|
+
"usage": "[options]",
|
|
5529
|
+
"arguments": [],
|
|
5530
|
+
"options": [
|
|
5531
|
+
{
|
|
5532
|
+
"flags": "--json",
|
|
5533
|
+
"description": "Print machine-readable JSON"
|
|
5534
|
+
}
|
|
5535
|
+
],
|
|
5536
|
+
"subcommands": []
|
|
5537
|
+
},
|
|
5538
|
+
{
|
|
5539
|
+
"name": "clear",
|
|
5540
|
+
"description": "Remove the wake configuration",
|
|
5541
|
+
"aliases": [],
|
|
5542
|
+
"hidden": false,
|
|
5543
|
+
"usage": "[options]",
|
|
5544
|
+
"arguments": [],
|
|
5545
|
+
"options": [],
|
|
5546
|
+
"subcommands": []
|
|
5547
|
+
},
|
|
5548
|
+
{
|
|
5549
|
+
"name": "test",
|
|
5550
|
+
"description": "Fire the wake once now with the current pending count",
|
|
5551
|
+
"aliases": [],
|
|
5552
|
+
"hidden": false,
|
|
5553
|
+
"usage": "[options]",
|
|
5554
|
+
"arguments": [],
|
|
5555
|
+
"options": [],
|
|
5556
|
+
"subcommands": []
|
|
5557
|
+
}
|
|
5558
|
+
]
|
|
5559
|
+
},
|
|
5460
5560
|
{
|
|
5461
5561
|
"name": "run",
|
|
5462
5562
|
"description": "Run one kit service in the foreground (sync|mesh|inbox|heartbeat), or `all` to supervise every service in one process",
|
|
@@ -5499,6 +5599,42 @@ export const COMMAND_CATALOG = [
|
|
|
5499
5599
|
"arguments": [],
|
|
5500
5600
|
"options": [],
|
|
5501
5601
|
"subcommands": []
|
|
5602
|
+
},
|
|
5603
|
+
{
|
|
5604
|
+
"name": "inbox",
|
|
5605
|
+
"description": "List this agent's pending HQ messages (mirrored by the kit), or mark them handled",
|
|
5606
|
+
"aliases": [],
|
|
5607
|
+
"hidden": false,
|
|
5608
|
+
"usage": "[options] [command]",
|
|
5609
|
+
"arguments": [],
|
|
5610
|
+
"options": [
|
|
5611
|
+
{
|
|
5612
|
+
"flags": "--all",
|
|
5613
|
+
"description": "Include items already marked handled"
|
|
5614
|
+
},
|
|
5615
|
+
{
|
|
5616
|
+
"flags": "--json",
|
|
5617
|
+
"description": "Print machine-readable JSON"
|
|
5618
|
+
}
|
|
5619
|
+
],
|
|
5620
|
+
"subcommands": [
|
|
5621
|
+
{
|
|
5622
|
+
"name": "done",
|
|
5623
|
+
"description": "Mark inbox items handled and ack them on the server",
|
|
5624
|
+
"aliases": [],
|
|
5625
|
+
"hidden": false,
|
|
5626
|
+
"usage": "[options] <ids...>",
|
|
5627
|
+
"arguments": [
|
|
5628
|
+
{
|
|
5629
|
+
"name": "ids",
|
|
5630
|
+
"required": true,
|
|
5631
|
+
"variadic": true
|
|
5632
|
+
}
|
|
5633
|
+
],
|
|
5634
|
+
"options": [],
|
|
5635
|
+
"subcommands": []
|
|
5636
|
+
}
|
|
5637
|
+
]
|
|
5502
5638
|
}
|
|
5503
5639
|
]
|
|
5504
5640
|
},
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hq agent inbox` — what a woken bot runs to see and clear its HQ mail.
|
|
3
|
+
*
|
|
4
|
+
* hq agent inbox [--all] [--json] pending items (oldest first), or all
|
|
5
|
+
* hq agent inbox done <id...> mark handled locally and ack on the server
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
export declare function registerAgentInboxCommand(agent: Command): void;
|
|
9
|
+
//# sourceMappingURL=agent-inbox.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hq agent inbox` — what a woken bot runs to see and clear its HQ mail.
|
|
3
|
+
*
|
|
4
|
+
* hq agent inbox [--all] [--json] pending items (oldest first), or all
|
|
5
|
+
* hq agent inbox done <id...> mark handled locally and ack on the server
|
|
6
|
+
*/
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import { ensureCognitoToken } from "../utils/cognito-session.js";
|
|
10
|
+
import { vaultApiFetch } from "../utils/vault-api.js";
|
|
11
|
+
import { markInboxDone, readDoneIds, readMirroredInbox, summarizeInboxEntry } from "../lib/agent-kit/inbox-state.js";
|
|
12
|
+
import { agentKitPaths } from "../lib/agent-kit/paths.js";
|
|
13
|
+
import { requireExternalCreds } from "./agent-kit.js";
|
|
14
|
+
const ID_RE = /^[A-Za-z0-9._:-]{1,200}$/;
|
|
15
|
+
export function registerAgentInboxCommand(agent) {
|
|
16
|
+
const inbox = agent
|
|
17
|
+
.command("inbox")
|
|
18
|
+
.description("List this agent's pending HQ messages (mirrored by the kit), or mark them handled")
|
|
19
|
+
.option("--all", "Include items already marked handled")
|
|
20
|
+
.option("--json", "Print machine-readable JSON")
|
|
21
|
+
.action((opts) => {
|
|
22
|
+
const paths = agentKitPaths(os.homedir(), process.env);
|
|
23
|
+
const done = readDoneIds(paths);
|
|
24
|
+
const rows = readMirroredInbox(paths)
|
|
25
|
+
.filter((e) => opts.all || !done.has(e.id))
|
|
26
|
+
.map((e) => summarizeInboxEntry(e, done.has(e.id)));
|
|
27
|
+
if (opts.json) {
|
|
28
|
+
console.log(JSON.stringify({ count: rows.length, messages: rows }, null, 2));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (rows.length === 0) {
|
|
32
|
+
console.log(opts.all ? "Inbox is empty." : "No pending messages.");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
for (const r of rows) {
|
|
36
|
+
const state = r.done ? chalk.dim(" (done)") : "";
|
|
37
|
+
console.log(`${chalk.bold(r.id)}${state} ${r.channel ?? "?"} from ${r.from}${r.fromUid ? ` <${r.fromUid}>` : ""} ${r.at ?? ""}`);
|
|
38
|
+
if (r.text)
|
|
39
|
+
console.log(` ${r.text.replace(/\n/g, "\n ")}`);
|
|
40
|
+
}
|
|
41
|
+
if (!opts.all)
|
|
42
|
+
console.log(chalk.dim(`\nReply with hq dm <uid> "…", then: hq agent inbox done <id>`));
|
|
43
|
+
});
|
|
44
|
+
inbox
|
|
45
|
+
.command("done <ids...>")
|
|
46
|
+
.description("Mark inbox items handled and ack them on the server")
|
|
47
|
+
.action(async (ids) => {
|
|
48
|
+
const bad = ids.filter((id) => !ID_RE.test(id));
|
|
49
|
+
if (bad.length) {
|
|
50
|
+
console.error(chalk.red(`Invalid id(s): ${bad.join(", ")}`));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
const paths = agentKitPaths(os.homedir(), process.env);
|
|
54
|
+
const creds = requireExternalCreds(paths);
|
|
55
|
+
const added = markInboxDone(paths, ids);
|
|
56
|
+
process.env.HQ_MACHINE_CREDS_FILE = paths.machineCredsPath;
|
|
57
|
+
process.env.HQ_REQUIRE_MACHINE_IDENTITY = "1";
|
|
58
|
+
process.env.HQ_VAULT_API_URL = creds.apiBaseUrl;
|
|
59
|
+
let acked = 0;
|
|
60
|
+
try {
|
|
61
|
+
const token = await ensureCognitoToken({ tokenSource: "machine", interactive: false });
|
|
62
|
+
for (const id of ids) {
|
|
63
|
+
const res = await vaultApiFetch({
|
|
64
|
+
token,
|
|
65
|
+
baseUrl: creds.apiBaseUrl,
|
|
66
|
+
path: `/v1/agents/${encodeURIComponent(creds.entityUid)}/inbox/${encodeURIComponent(id)}/ack`,
|
|
67
|
+
method: "POST",
|
|
68
|
+
});
|
|
69
|
+
if (res.ok)
|
|
70
|
+
acked += 1;
|
|
71
|
+
else
|
|
72
|
+
console.error(chalk.yellow(`server ack ${id} → ${res.status}`));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error(chalk.yellow(`server ack skipped: ${err instanceof Error ? err.message : String(err)}`));
|
|
77
|
+
}
|
|
78
|
+
console.log(`Marked ${added.length} handled (${ids.length - added.length} already done); server acked ${acked}.`);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=agent-inbox.js.map
|
|
@@ -34,6 +34,8 @@ import { fallbackStatus, rebootCrontabLine, shouldUseFallback, startFallback, st
|
|
|
34
34
|
import { serviceLogPath } from "../lib/agent-kit/paths.js";
|
|
35
35
|
import { spawn } from "node:child_process";
|
|
36
36
|
import { startMeshListener } from "../lib/agent-kit/run/mesh-listener.js";
|
|
37
|
+
import { pendingInbox } from "../lib/agent-kit/inbox-state.js";
|
|
38
|
+
import { buildWakeNotice, clearWakeConfig, currentWakeState, DEFAULT_WAKE_RETRY_MS, describeWake, fireWake, readWakeConfig, validateWakeUrl, writeWakeConfig, } from "../lib/agent-kit/wake.js";
|
|
37
39
|
import { runSyncLoop } from "../lib/agent-kit/run/sync.js";
|
|
38
40
|
import { resolveHqBinary, resolveNodeBinary, } from "../lib/mesh/live/daemon/install.js";
|
|
39
41
|
import { installServices, servicesStatus, uninstallServices, } from "../lib/service-manager/index.js";
|
|
@@ -245,6 +247,14 @@ export function formatFallbackStatus(paths, kill) {
|
|
|
245
247
|
: chalk.yellow(st.pid === null ? "pidfile unreadable" : `not running (stale pid ${st.pid})`);
|
|
246
248
|
return [` mode: fallback supervisor (hq agent kit run all) ${state}${chalk.dim(` ${st.pidFile}`)}`];
|
|
247
249
|
}
|
|
250
|
+
function retryMsFrom(raw) {
|
|
251
|
+
if (raw === undefined)
|
|
252
|
+
return DEFAULT_WAKE_RETRY_MS;
|
|
253
|
+
const n = Number(raw);
|
|
254
|
+
if (!Number.isFinite(n) || n < 1)
|
|
255
|
+
throw new Error("--retry-minutes must be at least 1");
|
|
256
|
+
return n * 60_000;
|
|
257
|
+
}
|
|
248
258
|
function fail(err) {
|
|
249
259
|
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
250
260
|
process.exit(1);
|
|
@@ -341,6 +351,101 @@ export function registerAgentKitCommand(agent) {
|
|
|
341
351
|
fail(err);
|
|
342
352
|
}
|
|
343
353
|
});
|
|
354
|
+
const wake = kit
|
|
355
|
+
.command("wake")
|
|
356
|
+
.description("Wake this bot's own framework when HQ messages arrive (webhook URL or local command)");
|
|
357
|
+
wake
|
|
358
|
+
.command("set-url [url]")
|
|
359
|
+
.description("POST a notice to a webhook URL (e.g. a Grok Bot routine webhook) when mail is pending. Prefer --stdin so the URL stays out of shell history")
|
|
360
|
+
.option("--stdin", "Read the URL from stdin")
|
|
361
|
+
.option("--retry-minutes <n>", "Re-wake while items stay pending (default 10, minimum 1)")
|
|
362
|
+
.action(async (url, opts) => {
|
|
363
|
+
try {
|
|
364
|
+
const paths = agentKitPaths(os.homedir(), process.env);
|
|
365
|
+
requireExternalCreds(paths);
|
|
366
|
+
let raw = url;
|
|
367
|
+
if (opts.stdin) {
|
|
368
|
+
const chunks = [];
|
|
369
|
+
for await (const c of process.stdin)
|
|
370
|
+
chunks.push(c);
|
|
371
|
+
raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
372
|
+
}
|
|
373
|
+
if (!raw)
|
|
374
|
+
throw new Error("Provide the URL as an argument or with --stdin");
|
|
375
|
+
const config = { kind: "url", url: validateWakeUrl(raw), retryMs: retryMsFrom(opts.retryMinutes) };
|
|
376
|
+
writeWakeConfig(paths, config);
|
|
377
|
+
console.log(chalk.green(`Wake set: ${describeWake(config)}`));
|
|
378
|
+
console.log("Test it: hq agent kit wake test");
|
|
379
|
+
}
|
|
380
|
+
catch (err) {
|
|
381
|
+
fail(err);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
wake
|
|
385
|
+
.command("set-command <argv...>")
|
|
386
|
+
.description("Run a local command (no shell) when mail is pending; the notice JSON arrives on stdin. Use -- before the command")
|
|
387
|
+
.option("--timeout-minutes <n>", "Kill a run after this long (default 10)")
|
|
388
|
+
.option("--retry-minutes <n>", "Re-wake while items stay pending (default 10, minimum 1)")
|
|
389
|
+
.action((argv, opts) => {
|
|
390
|
+
try {
|
|
391
|
+
const paths = agentKitPaths(os.homedir(), process.env);
|
|
392
|
+
requireExternalCreds(paths);
|
|
393
|
+
const minutes = opts.timeoutMinutes ? Number(opts.timeoutMinutes) : 10;
|
|
394
|
+
if (!Number.isFinite(minutes) || minutes <= 0)
|
|
395
|
+
throw new Error("--timeout-minutes must be a positive number");
|
|
396
|
+
const config = { kind: "command", command: argv, timeoutMs: minutes * 60_000, retryMs: retryMsFrom(opts.retryMinutes) };
|
|
397
|
+
writeWakeConfig(paths, config);
|
|
398
|
+
console.log(chalk.green(`Wake set: ${describeWake(config)}`));
|
|
399
|
+
console.log("Test it: hq agent kit wake test");
|
|
400
|
+
}
|
|
401
|
+
catch (err) {
|
|
402
|
+
fail(err);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
wake
|
|
406
|
+
.command("show")
|
|
407
|
+
.description("Show the configured wake (the URL is masked)")
|
|
408
|
+
.option("--json", "Print machine-readable JSON")
|
|
409
|
+
.action((opts) => {
|
|
410
|
+
const paths = agentKitPaths(os.homedir(), process.env);
|
|
411
|
+
const config = readWakeConfig(paths);
|
|
412
|
+
const state = currentWakeState(paths);
|
|
413
|
+
if (opts.json) {
|
|
414
|
+
console.log(JSON.stringify({ configured: !!config, wake: describeWake(config), lastWakeAt: state.lastWakeAt ?? null }, null, 2));
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
console.log(` wake: ${describeWake(config)}`);
|
|
418
|
+
console.log(` last wake: ${state.lastWakeAt ?? "never"}`);
|
|
419
|
+
});
|
|
420
|
+
wake
|
|
421
|
+
.command("clear")
|
|
422
|
+
.description("Remove the wake configuration")
|
|
423
|
+
.action(() => {
|
|
424
|
+
const paths = agentKitPaths(os.homedir(), process.env);
|
|
425
|
+
console.log(clearWakeConfig(paths) ? "Wake cleared." : "No wake was configured.");
|
|
426
|
+
});
|
|
427
|
+
wake
|
|
428
|
+
.command("test")
|
|
429
|
+
.description("Fire the wake once now with the current pending count")
|
|
430
|
+
.action(async () => {
|
|
431
|
+
try {
|
|
432
|
+
const paths = agentKitPaths(os.homedir(), process.env);
|
|
433
|
+
const creds = requireExternalCreds(paths);
|
|
434
|
+
ensureKitDirs(paths);
|
|
435
|
+
const config = readWakeConfig(paths);
|
|
436
|
+
if (!config)
|
|
437
|
+
throw new Error("No wake configured. Run hq agent kit wake set-url --stdin (or set-command).");
|
|
438
|
+
const log = createKitLogger(paths, "wake", { echo: false });
|
|
439
|
+
const ids = pendingInbox(paths).map((e) => e.id);
|
|
440
|
+
const result = await fireWake(config, buildWakeNotice(creds.entityUid, "test", ids, new Date()), { paths, agentUid: creds.entityUid, log });
|
|
441
|
+
console.log(result.ok ? chalk.green(result.detail) : chalk.red(result.detail));
|
|
442
|
+
if (!result.ok)
|
|
443
|
+
process.exit(1);
|
|
444
|
+
}
|
|
445
|
+
catch (err) {
|
|
446
|
+
fail(err);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
344
449
|
kit
|
|
345
450
|
.command("run <service>")
|
|
346
451
|
.description(`Run one kit service in the foreground (${KIT_SERVICES.join("|")}), or \`all\` to supervise every service in one process`)
|
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
import { Command } from "commander";
|
|
12
12
|
import { McpServer } from "../lib/agent-kit/mcp/jsonrpc.js";
|
|
13
13
|
import { type HqRunResult, type McpToolClients } from "../lib/agent-kit/mcp/tools.js";
|
|
14
|
+
import { type AgentKitPaths } from "../lib/agent-kit/paths.js";
|
|
14
15
|
import type { ExternalMachineCreds } from "../lib/agent-kit/creds.js";
|
|
15
16
|
export declare const AGENT_MCP_SERVER_NAME = "hq-agent";
|
|
16
17
|
export declare const AGENT_MCP_INSTRUCTIONS: string;
|
|
17
18
|
export declare const HQ_SUBPROCESS_TIMEOUT_MS = 120000;
|
|
18
19
|
export declare function defaultRunHq(nodeBinary: string, hqBinary: string, env: NodeJS.ProcessEnv): (args: string[]) => Promise<HqRunResult>;
|
|
19
|
-
export declare function defaultMcpClients(creds: ExternalMachineCreds, credsPath: string): McpToolClients;
|
|
20
|
+
export declare function defaultMcpClients(creds: ExternalMachineCreds, credsPath: string, paths?: Pick<AgentKitPaths, "inboxDir">): McpToolClients;
|
|
20
21
|
export declare function createAgentMcpServer(clients: McpToolClients): McpServer;
|
|
21
22
|
export declare function registerAgentMcpCommand(agent: Command): void;
|
|
22
23
|
//# sourceMappingURL=agent-mcp.d.ts.map
|
|
@@ -21,7 +21,7 @@ export const AGENT_MCP_SERVER_NAME = "hq-agent";
|
|
|
21
21
|
export const AGENT_MCP_INSTRUCTIONS = "You are acting inside HQ as an enrolled external agent. Tools run as that machine identity: " +
|
|
22
22
|
"hq_whoami (identity), hq_search / hq_files_list / hq_files_read (company vault), " +
|
|
23
23
|
"hq_secrets_list / hq_secrets_exec (secrets by NAME only — values are never returned), " +
|
|
24
|
-
"hq_dm_send /
|
|
24
|
+
"hq_inbox_read / hq_dm_send / hq_inbox_done (read pending HQ messages, reply, then mark each handled), hq_work_mesh_status (what the team is doing). " +
|
|
25
25
|
"Never ask a user for a token or secret value; if a secret is missing, name it and ask an admin to add it.";
|
|
26
26
|
export const HQ_SUBPROCESS_TIMEOUT_MS = 120_000;
|
|
27
27
|
export function defaultRunHq(nodeBinary, hqBinary, env) {
|
|
@@ -45,7 +45,7 @@ export function defaultRunHq(nodeBinary, hqBinary, env) {
|
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
-
export function defaultMcpClients(creds, credsPath) {
|
|
48
|
+
export function defaultMcpClients(creds, credsPath, paths = agentKitPaths(os.homedir(), process.env)) {
|
|
49
49
|
const env = {
|
|
50
50
|
...process.env,
|
|
51
51
|
HQ_MACHINE_CREDS_FILE: credsPath,
|
|
@@ -55,6 +55,7 @@ export function defaultMcpClients(creds, credsPath) {
|
|
|
55
55
|
};
|
|
56
56
|
return {
|
|
57
57
|
creds,
|
|
58
|
+
paths,
|
|
58
59
|
runHq: defaultRunHq(process.execPath, process.argv[1], env),
|
|
59
60
|
getToken: () => ensureCognitoToken({ tokenSource: "machine", interactive: false }),
|
|
60
61
|
apiJson: async (token, path, init) => {
|
|
@@ -96,7 +97,7 @@ export function registerAgentMcpCommand(agent) {
|
|
|
96
97
|
process.env.HQ_MACHINE_CREDS_FILE = paths.machineCredsPath;
|
|
97
98
|
process.env.HQ_REQUIRE_MACHINE_IDENTITY = "1";
|
|
98
99
|
process.env.HQ_VAULT_API_URL = creds.apiBaseUrl;
|
|
99
|
-
const server = createAgentMcpServer(defaultMcpClients(creds, paths.machineCredsPath));
|
|
100
|
+
const server = createAgentMcpServer(defaultMcpClients(creds, paths.machineCredsPath, paths));
|
|
100
101
|
process.stderr.write(`hq agent mcp: serving as ${creds.entityUid} (${creds.companySlug})\n`);
|
|
101
102
|
await server.serve(process.stdin, process.stdout);
|
|
102
103
|
});
|
package/dist/commands/agent.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* hq agent kit install|status|uninstall|run <service>
|
|
7
7
|
* hq agent probe end-to-end membership check
|
|
8
8
|
* hq agent mcp stdio MCP server for the bot framework
|
|
9
|
+
* hq agent inbox [done <id…>] pending HQ messages / mark handled
|
|
9
10
|
*/
|
|
10
11
|
import { Command } from "commander";
|
|
11
12
|
export declare function registerAgentCommand(program: Command): void;
|
package/dist/commands/agent.js
CHANGED
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
* hq agent kit install|status|uninstall|run <service>
|
|
7
7
|
* hq agent probe end-to-end membership check
|
|
8
8
|
* hq agent mcp stdio MCP server for the bot framework
|
|
9
|
+
* hq agent inbox [done <id…>] pending HQ messages / mark handled
|
|
9
10
|
*/
|
|
10
11
|
import { registerAgentEnrollCommand } from "./agent-enroll.js";
|
|
12
|
+
import { registerAgentInboxCommand } from "./agent-inbox.js";
|
|
11
13
|
import { registerAgentKitCommand } from "./agent-kit.js";
|
|
12
14
|
import { registerAgentMcpCommand } from "./agent-mcp.js";
|
|
13
15
|
import { registerAgentProbeCommand } from "./agent-probe.js";
|
|
@@ -19,5 +21,6 @@ export function registerAgentCommand(program) {
|
|
|
19
21
|
registerAgentKitCommand(agent);
|
|
20
22
|
registerAgentProbeCommand(agent);
|
|
21
23
|
registerAgentMcpCommand(agent);
|
|
24
|
+
registerAgentInboxCommand(agent);
|
|
22
25
|
}
|
|
23
26
|
//# sourceMappingURL=agent.js.map
|
|
@@ -258,7 +258,7 @@ export type AgentTerminalResponse = ({
|
|
|
258
258
|
};
|
|
259
259
|
export declare function openAgentTerminal(token: string, agentUid: string, body: Record<string, unknown>): Promise<AgentTerminalResponse>;
|
|
260
260
|
export declare function retryAgent(token: string, agentUid: string): Promise<Record<string, unknown>>;
|
|
261
|
-
export declare function deprovisionAgent(token: string, agentUid: string): Promise<{
|
|
261
|
+
export declare function deprovisionAgent(token: string, agentUid: string, confirmDestroyAgentsV2?: string): Promise<{
|
|
262
262
|
uid: string;
|
|
263
263
|
setupState?: string;
|
|
264
264
|
terminal?: boolean;
|
package/dist/commands/agents.js
CHANGED
|
@@ -564,11 +564,14 @@ export async function retryAgent(token, agentUid) {
|
|
|
564
564
|
method: "POST",
|
|
565
565
|
});
|
|
566
566
|
}
|
|
567
|
-
export async function deprovisionAgent(token, agentUid) {
|
|
567
|
+
export async function deprovisionAgent(token, agentUid, confirmDestroyAgentsV2) {
|
|
568
568
|
return agentsRequest({
|
|
569
569
|
token,
|
|
570
570
|
path: `/v1/agents/${encodeURIComponent(agentUid)}`,
|
|
571
571
|
method: "DELETE",
|
|
572
|
+
body: confirmDestroyAgentsV2 === undefined
|
|
573
|
+
? undefined
|
|
574
|
+
: { confirmDestroyAgentsV2 },
|
|
572
575
|
});
|
|
573
576
|
}
|
|
574
577
|
export async function listAgentJobs(token, agentUid) {
|
|
@@ -1477,6 +1480,7 @@ export function registerAgentsCommand(program) {
|
|
|
1477
1480
|
.description("Deprovision (permanently tear down) an agent")
|
|
1478
1481
|
.option("--company <slug>", "Company slug (resolves to companyUid)")
|
|
1479
1482
|
.option("--yes", "Confirm the irreversible teardown (required)")
|
|
1483
|
+
.option("--confirm-destroy-agents-v2 <instance-id>", "Confirm agents-v2 teardown by naming the live EC2 instance ID")
|
|
1480
1484
|
.action(async function (agentUid, opts) {
|
|
1481
1485
|
if (!opts.yes) {
|
|
1482
1486
|
console.error(chalk.yellow(`This will permanently deprovision agent ${agentUid} and tear down its ` +
|
|
@@ -1486,7 +1490,7 @@ export function registerAgentsCommand(program) {
|
|
|
1486
1490
|
}
|
|
1487
1491
|
try {
|
|
1488
1492
|
const token = (await resolveVaultCredential()).token;
|
|
1489
|
-
const result = await deprovisionAgent(token, agentUid);
|
|
1493
|
+
const result = await deprovisionAgent(token, agentUid, opts.confirmDestroyAgentsV2);
|
|
1490
1494
|
if (result.terminal === false) {
|
|
1491
1495
|
console.log(chalk.yellow(`Deprovision in progress for agent ${agentUid} (not yet fully torn down — re-run to continue).`));
|
|
1492
1496
|
}
|