@integrity-labs/agt-cli 0.28.625 → 0.28.626

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/bin/agt.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-WTNH3VCT.js";
43
+ } from "../chunk-4NCEO44Q.js";
44
44
  import {
45
45
  readDirectChatSessionState
46
46
  } from "../chunk-7QNQRV3A.js";
@@ -4909,7 +4909,7 @@ import { execFileSync, execSync } from "child_process";
4909
4909
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4910
4910
  import chalk18 from "chalk";
4911
4911
  import ora16 from "ora";
4912
- var cliVersion = true ? "0.28.625" : "dev";
4912
+ var cliVersion = true ? "0.28.626" : "dev";
4913
4913
  async function fetchLatestVersion() {
4914
4914
  const host2 = getHost();
4915
4915
  if (!host2) return null;
@@ -6089,7 +6089,7 @@ function handleError(err) {
6089
6089
  }
6090
6090
 
6091
6091
  // src/bin/agt.ts
6092
- var cliVersion2 = true ? "0.28.625" : "dev";
6092
+ var cliVersion2 = true ? "0.28.626" : "dev";
6093
6093
  var program = new Command();
6094
6094
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
6095
6095
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -6069,7 +6069,7 @@ function exchangeFailureKind(err) {
6069
6069
  }
6070
6070
 
6071
6071
  // src/lib/api-client.ts
6072
- var agtCliVersion = true ? "0.28.625" : "dev";
6072
+ var agtCliVersion = true ? "0.28.626" : "dev";
6073
6073
  var lastConfigHash = null;
6074
6074
  function setConfigHash(hash) {
6075
6075
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -9589,4 +9589,4 @@ export {
9589
9589
  managerInstallSystemUnitCommand,
9590
9590
  managerUninstallSystemUnitCommand
9591
9591
  };
9592
- //# sourceMappingURL=chunk-WTNH3VCT.js.map
9592
+ //# sourceMappingURL=chunk-4NCEO44Q.js.map
@@ -54,7 +54,7 @@ import {
54
54
  safeWriteJsonAtomic,
55
55
  setConfigHash,
56
56
  tripClass
57
- } from "../chunk-WTNH3VCT.js";
57
+ } from "../chunk-4NCEO44Q.js";
58
58
  import {
59
59
  getProjectDir as getProjectDir2,
60
60
  getReadyTasks,
@@ -12033,7 +12033,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12033
12033
  var lastVersionCheckAt = 0;
12034
12034
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12035
12035
  var lastResponsivenessProbeAt = 0;
12036
- var agtCliVersion = true ? "0.28.625" : "dev";
12036
+ var agtCliVersion = true ? "0.28.626" : "dev";
12037
12037
  function resolveBrewPath(execFileSync3) {
12038
12038
  try {
12039
12039
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -21333,64 +21333,67 @@ var AdminDebugClient = class _AdminDebugClient {
21333
21333
  };
21334
21334
 
21335
21335
  // src/tool-schemas.ts
21336
+ function strictObject(shape) {
21337
+ return external_exports.object(shape).strict();
21338
+ }
21336
21339
  var limitSchema = external_exports.number().int().min(1).max(100).optional().describe("Max rows to return (default 25, server caps at 100).");
21337
- var searchAgentsSchema = external_exports.object({
21340
+ var searchAgentsSchema = strictObject({
21338
21341
  q: external_exports.string().max(128).optional().describe("Case-insensitive substring match on code_name or display_name."),
21339
21342
  status: external_exports.string().max(32).optional().describe("Filter by agent status (draft | active | paused | revoked)."),
21340
21343
  environment: external_exports.string().max(32).optional().describe("Filter by environment (dev | stage | prod)."),
21341
21344
  limit: limitSchema
21342
21345
  });
21343
- var searchOrgsSchema = external_exports.object({
21346
+ var searchOrgsSchema = strictObject({
21344
21347
  q: external_exports.string().max(128).optional().describe("Case-insensitive substring match on organization name or slug."),
21345
21348
  management_mode: external_exports.enum(["fully_managed", "self_managed"]).optional().describe("Filter by management mode (fully_managed | self_managed)."),
21346
21349
  is_internal: external_exports.boolean().optional().describe("Filter to Integrity-Labs-internal orgs (true) or customer orgs (false)."),
21347
21350
  limit: limitSchema
21348
21351
  });
21349
- var getAgentSchema = external_exports.object({
21352
+ var getAgentSchema = strictObject({
21350
21353
  agent_id: external_exports.string().min(1).max(64).describe("The agent UUID to fetch a composite diagnostic for.")
21351
21354
  });
21352
- var getAgentIntegrationsSchema = external_exports.object({
21355
+ var getAgentIntegrationsSchema = strictObject({
21353
21356
  agent_id: external_exports.string().min(1).max(64).describe("The agent UUID whose effective integration set to resolve.")
21354
21357
  });
21355
- var searchHostsSchema = external_exports.object({
21358
+ var searchHostsSchema = strictObject({
21356
21359
  q: external_exports.string().max(128).optional().describe("Case-insensitive substring match on host name."),
21357
21360
  status: external_exports.string().max(32).optional().describe("Filter by host status (active | decommissioned)."),
21358
21361
  limit: limitSchema
21359
21362
  });
21360
- var getHostSchema = external_exports.object({
21363
+ var getHostSchema = strictObject({
21361
21364
  host: external_exports.string().min(1).max(128).describe("The host id (uuid) or its exact, case-insensitive name. Use the id if the name is ambiguous."),
21362
21365
  since_hours: external_exports.number().int().min(1).max(720).optional().describe("Window for the restart-count rollup, in hours. Default 24.")
21363
21366
  });
21364
- var inspectFlagsSchema = external_exports.object({
21367
+ var inspectFlagsSchema = strictObject({
21365
21368
  host: external_exports.string().min(1).max(128).optional().describe("The host id (uuid) or its exact, case-insensitive name. Pass this OR agent_id."),
21366
21369
  agent_id: external_exports.string().min(1).max(64).optional().describe("The agent UUID \u2014 flags are inspected on the agent's current host. Pass this OR host.")
21367
21370
  });
21368
- var evalFailuresSchema = external_exports.object({
21371
+ var evalFailuresSchema = strictObject({
21369
21372
  period: external_exports.enum(["24h", "7d", "30d"]).optional().describe("Window to report over (24h | 7d | 30d). Default 7d."),
21370
21373
  agent_id: external_exports.string().min(1).max(64).optional().describe("Filter to one agent (UUID); omit for a fleet-wide breakdown across your authorized orgs.")
21371
21374
  });
21372
21375
  var alertIdField = external_exports.string().min(1).max(64).describe("The alert id (uuid), from debug_list_alerts.");
21373
21376
  var triageReasonField = external_exports.string().max(2e3).optional().describe("Why \u2014 recorded on the cross-org audit trail. Be specific.");
21374
- var ackAlertSchema = external_exports.object({
21377
+ var ackAlertSchema = strictObject({
21375
21378
  alert_id: alertIdField,
21376
21379
  reason: triageReasonField
21377
21380
  });
21378
- var snoozeAlertSchema = external_exports.object({
21381
+ var snoozeAlertSchema = strictObject({
21379
21382
  alert_id: alertIdField,
21380
21383
  duration: external_exports.enum(["15m", "1h", "4h", "until_tomorrow"]).describe("How long to suppress paging: 15m | 1h | 4h | until_tomorrow (09:00 UTC next day)."),
21381
21384
  reason: triageReasonField
21382
21385
  });
21383
- var closeAlertSchema = external_exports.object({
21386
+ var closeAlertSchema = strictObject({
21384
21387
  alert_id: alertIdField,
21385
21388
  reason: triageReasonField
21386
21389
  });
21387
- var hostVersionsSchema = external_exports.object({
21390
+ var hostVersionsSchema = strictObject({
21388
21391
  q: external_exports.string().max(128).optional().describe("Case-insensitive substring match on host name."),
21389
21392
  status: external_exports.string().max(32).optional().describe("Filter by host status (active | decommissioned)."),
21390
21393
  since_hours: external_exports.number().int().min(1).max(720).optional().describe("Window for the restart count, in hours. Default 24."),
21391
21394
  limit: limitSchema
21392
21395
  });
21393
- var tailLogsSchema = external_exports.object({
21396
+ var tailLogsSchema = strictObject({
21394
21397
  agent_id: external_exports.string().min(1).max(64).describe(
21395
21398
  "UUID of the agent whose host log to tail. Fails closed (uniform not-found) if you are not authorized for its org."
21396
21399
  ),
@@ -21401,7 +21404,7 @@ var tailLogsSchema = external_exports.object({
21401
21404
  "Trailing lines to return (default 200, max 2000). Output is also byte-capped (~20 KB, newest kept) to stay within SSM limits \u2014 `truncated` flags when it clipped."
21402
21405
  )
21403
21406
  });
21404
- var queryLogsSchema = external_exports.object({
21407
+ var queryLogsSchema = strictObject({
21405
21408
  agent_id: external_exports.string().min(1).max(64).describe(
21406
21409
  "UUID of the agent whose host log to query. Fails closed (uniform not-found) if you are not authorized for its org."
21407
21410
  ),
@@ -21418,7 +21421,7 @@ var queryLogsSchema = external_exports.object({
21418
21421
  "Max lines to return (default 1000, max 5000; newest kept). Output is also byte-capped (~20 KB, newest kept) to stay within SSM limits \u2014 `truncated` flags when it clipped. Narrow the window if truncated."
21419
21422
  )
21420
21423
  });
21421
- var probeIntegrationSchema = external_exports.object({
21424
+ var probeIntegrationSchema = strictObject({
21422
21425
  agent_id: external_exports.string().min(1).max(64).describe(
21423
21426
  "UUID of the agent whose integration to probe. Fails closed (uniform not-found) if you are not authorized for its org."
21424
21427
  ),
@@ -21429,12 +21432,12 @@ var probeIntegrationSchema = external_exports.object({
21429
21432
  "The integration slug (its definition code_name, e.g. `gmail`, `slack`, `here-now`) to probe on that agent."
21430
21433
  )
21431
21434
  });
21432
- var inspectDeadLettersSchema = external_exports.object({
21435
+ var inspectDeadLettersSchema = strictObject({
21433
21436
  agent_id: external_exports.string().min(1).max(64).describe(
21434
21437
  "UUID of the agent whose dead-lettered inbound to list. Fails closed (uniform not-found) if you are not authorized for its org."
21435
21438
  )
21436
21439
  });
21437
- var replayDeadLetterSchema = external_exports.object({
21440
+ var replayDeadLetterSchema = strictObject({
21438
21441
  target_agent_id: external_exports.string().min(1).max(64).describe("UUID of the customer agent whose dead letter to replay."),
21439
21442
  channel: external_exports.enum(["slack", "telegram"]).describe("Which inbound channel the dead letter belongs to (from the inspect result)."),
21440
21443
  store: external_exports.string().min(1).max(128).regex(
@@ -21444,39 +21447,39 @@ var replayDeadLetterSchema = external_exports.object({
21444
21447
  marker_name: external_exports.string().trim().min(1).max(256).describe("The exact `marker_name` from the inspect result identifying which parked message to re-inject."),
21445
21448
  reason: external_exports.string().min(1).max(2e3).describe("Why this message should be re-injected \u2014 shown verbatim to the human approver. Be specific.")
21446
21449
  });
21447
- var inspectRestartRequestsSchema = external_exports.object({
21450
+ var inspectRestartRequestsSchema = strictObject({
21448
21451
  agent_id: external_exports.string().min(1).max(64).optional().describe(
21449
21452
  "Optional: narrow to ONE agent's restart request. Omit for a fleet-wide list across every authorized org. Fails closed (empty) for orgs you are not authorized for."
21450
21453
  ),
21451
21454
  limit: limitSchema
21452
21455
  });
21453
- var clearRestartRequestSchema = external_exports.object({
21456
+ var clearRestartRequestSchema = strictObject({
21454
21457
  target_agent_id: external_exports.string().min(1).max(64).describe("UUID of the customer agent whose stuck restart request to clear (from the inspect result)."),
21455
21458
  reason: external_exports.string().min(1).max(2e3).describe("Why this stuck restart request should be cleared \u2014 shown verbatim to the human approver. Be specific.")
21456
21459
  });
21457
- var listAlertsSchema = external_exports.object({
21460
+ var listAlertsSchema = strictObject({
21458
21461
  severity: external_exports.string().max(16).optional().describe("Filter by severity (critical | warning | info)."),
21459
21462
  open: external_exports.boolean().optional().describe("When true, only currently-open (unclosed) alerts."),
21460
21463
  limit: limitSchema
21461
21464
  });
21462
- var requestAccessSchema = external_exports.object({
21465
+ var requestAccessSchema = strictObject({
21463
21466
  target_org_id: external_exports.string().min(1).max(64).describe("UUID of the customer organization to open scoped read access to."),
21464
21467
  reason: external_exports.string().min(1).max(2e3).describe(
21465
21468
  "Why access is needed \u2014 recorded on the customer-visible access log and shown to the org when they review or revoke it. Be specific."
21466
21469
  )
21467
21470
  });
21468
- var requestActionSchema = external_exports.object({
21471
+ var requestActionSchema = strictObject({
21469
21472
  action: external_exports.enum(["restart", "clear_pending_inbound"]).describe(
21470
21473
  "The remedial action. restart = bounce the agent (reversible; backlog replays). clear_pending_inbound = move stuck pending-inbound markers aside (drops queued inbound messages; they are NOT reprocessed)."
21471
21474
  ),
21472
21475
  target_agent_id: external_exports.string().min(1).max(64).describe("UUID of the customer agent to act on."),
21473
21476
  reason: external_exports.string().min(1).max(2e3).describe("Why this action is needed \u2014 shown verbatim to the human approver. Be specific.")
21474
21477
  });
21475
- var restartAgentSchema = external_exports.object({
21478
+ var restartAgentSchema = strictObject({
21476
21479
  target_agent_id: external_exports.string().min(1).max(64).describe("UUID of the customer agent to restart."),
21477
21480
  reason: external_exports.string().min(1).max(2e3).describe("Why the restart is needed \u2014 shown verbatim to the human approver. Be specific.")
21478
21481
  });
21479
- var requestConfigUpdateSchema = external_exports.object({
21482
+ var requestConfigUpdateSchema = strictObject({
21480
21483
  target_agent_id: external_exports.string().min(1).max(64).describe("UUID of the customer agent whose config to change."),
21481
21484
  field: external_exports.enum(["primary_model", "secondary_model", "tertiary_model"]).describe("The agent-config field to change. Only the model tiers are settable."),
21482
21485
  new_value: external_exports.string().min(1).max(128).describe(
@@ -21484,17 +21487,17 @@ var requestConfigUpdateSchema = external_exports.object({
21484
21487
  ),
21485
21488
  reason: external_exports.string().min(1).max(2e3).describe("Why this change is needed \u2014 shown verbatim to the human approver. Be specific.")
21486
21489
  });
21487
- var checkActionStatusSchema = external_exports.object({
21490
+ var checkActionStatusSchema = strictObject({
21488
21491
  request_id: external_exports.string().min(1).max(64).describe("The action request_id returned by request_action, request_config_update, or request_ssm_run.")
21489
21492
  });
21490
- var requestSsmRunSchema = external_exports.object({
21493
+ var requestSsmRunSchema = strictObject({
21491
21494
  target_agent_id: external_exports.string().min(1).max(64).describe("UUID of the customer agent whose host to run the diagnostic on."),
21492
21495
  command: external_exports.enum(["host_health", "manager_status", "manager_journal", "process_list", "agent_dir"]).describe(
21493
21496
  "The allowlisted, READ-ONLY diagnostic to run (closed set \u2014 no free-form shell). host_health = uptime + df -h + free -m (is the box wedged / out of disk / out of memory?); manager_status = systemctl status agt-manager.service (is the manager daemon up?); manager_journal = journalctl -u agt-manager.service -n 200 (recent systemd-captured manager output); process_list = ps (pid/ppid/user/etime/rss/comm, no argv/env) filtered to claude + agt-manager; agent_dir = ls -la ~/.augmented/<code_name>/ (file NAMES only \u2014 stuck markers, state files; never contents). For file CONTENTS use debug_tail_logs (it covers manager.log/pane.log/channel-stderr/manager-state.json)."
21494
21497
  ),
21495
21498
  reason: external_exports.string().min(1).max(2e3).describe("Why this diagnostic is needed \u2014 shown verbatim to the human approver. Be specific.")
21496
21499
  });
21497
- var queryAuditLogSchema = external_exports.object({
21500
+ var queryAuditLogSchema = strictObject({
21498
21501
  agent_id: external_exports.string().min(1).max(64).optional().describe(
21499
21502
  "UUID of ONE agent whose audit events to read (the read is scoped to that agent's org). Omit for a CROSS-AGENT query across all authorized orgs (optionally narrowed with org_id)."
21500
21503
  ),
@@ -21583,10 +21586,9 @@ var client = new AdminDebugClient({
21583
21586
  runId: AGT_RUN_ID || void 0
21584
21587
  });
21585
21588
  var server = new McpServer({ name: "augmented-admin-mcp", version: package_default.version });
21586
- server.tool(
21589
+ server.registerTool(
21587
21590
  "debug_search_agents",
21588
- "Search managed end-user agents across authorized orgs for troubleshooting. Returns a diagnostic projection per agent (code_name, status, environment, risk_tier, org, heartbeat verdict) \u2014 never credentials or transcripts. Authorized = IL-owned + fully-managed orgs (standing) plus any self-managed org you hold an active grant for (see debug_request_access). Filter with { q, status, environment, limit }.",
21589
- searchAgentsSchema.shape,
21591
+ { description: "Search managed end-user agents across authorized orgs for troubleshooting. Returns a diagnostic projection per agent (code_name, status, environment, risk_tier, org, heartbeat verdict) \u2014 never credentials or transcripts. Authorized = IL-owned + fully-managed orgs (standing) plus any self-managed org you hold an active grant for (see debug_request_access). Filter with { q, status, environment, limit }.", inputSchema: searchAgentsSchema },
21590
21592
  async (args) => {
21591
21593
  try {
21592
21594
  const result = await client.searchAgents(args);
@@ -21596,10 +21598,9 @@ server.tool(
21596
21598
  }
21597
21599
  }
21598
21600
  );
21599
- server.tool(
21601
+ server.registerTool(
21600
21602
  "debug_get_agent",
21601
- 'Fetch a composite diagnostic for ONE agent: the agent projection plus its host (heartbeat verdict, framework, EC2/auth status), its integrations, and recent alerts. The primary "why is this agent unhealthy?" read. Never returns credentials. Pass { agent_id }.\n\nThe payload carries TWO integration reads, and confusing them produces wrong root-cause (ENG-8271):\n \u2022 `effective_integrations` \u2014 the COMPLETE set the agent runs with: agent + team + ORG scope, each entry carrying `scope` ("agent" | "team" | "org") and `source_id`. Read THIS to answer "does this agent have integration X?". `effective_count` equals the manager\'s `Integrations provisioned for \'<code_name>\' (N)`, so the two reconcile; `by_scope`, `inherited_definition_ids`, `scopes_skipped`, `excluded_control_plane_only`, `shadowed_by_more_specific` and `duplicate_merge_keys` attribute any row that did not make the count.\n \u2022 `agent_integrations` \u2014 PER-AGENT rows only, kept for compatibility. Team- and org-scoped installs are ABSENT. Do NOT infer "not installed" from an absence here: an org-level install is genuinely missing from this array while being fully present on the agent. Same warning ships in-payload as `agent_integrations_note`.',
21602
- getAgentSchema.shape,
21603
+ { description: 'Fetch a composite diagnostic for ONE agent: the agent projection plus its host (heartbeat verdict, framework, EC2/auth status), its integrations, and recent alerts. The primary "why is this agent unhealthy?" read. Never returns credentials. Pass { agent_id }.\n\nThe payload carries TWO integration reads, and confusing them produces wrong root-cause (ENG-8271):\n \u2022 `effective_integrations` \u2014 the COMPLETE set the agent runs with: agent + team + ORG scope, each entry carrying `scope` ("agent" | "team" | "org") and `source_id`. Read THIS to answer "does this agent have integration X?". `effective_count` equals the manager\'s `Integrations provisioned for \'<code_name>\' (N)`, so the two reconcile; `by_scope`, `inherited_definition_ids`, `scopes_skipped`, `excluded_control_plane_only`, `shadowed_by_more_specific` and `duplicate_merge_keys` attribute any row that did not make the count.\n \u2022 `agent_integrations` \u2014 PER-AGENT rows only, kept for compatibility. Team- and org-scoped installs are ABSENT. Do NOT infer "not installed" from an absence here: an org-level install is genuinely missing from this array while being fully present on the agent. Same warning ships in-payload as `agent_integrations_note`.', inputSchema: getAgentSchema },
21603
21604
  async (args) => {
21604
21605
  try {
21605
21606
  const result = await client.getAgent(args.agent_id);
@@ -21609,10 +21610,9 @@ server.tool(
21609
21610
  }
21610
21611
  }
21611
21612
  );
21612
- server.tool(
21613
+ server.registerTool(
21613
21614
  "debug_get_agent_integrations",
21614
- 'Resolve ONE agent\'s EFFECTIVE integration set \u2014 the focused read for "does this agent have integration X, and where is it installed from?" (ENG-8271). Same resolution as `debug_get_agent`\'s `effective_integrations`, without the host/alerts payload.\n\nReturns { agent_id, code_name, team_id, organization_id, effective_integrations: { effective_count, by_scope, inherited_definition_ids, excluded_control_plane_only, shadowed_by_more_specific, duplicate_merge_keys, scopes_queried, scopes_skipped, integrations[] } } - the same `effective_integrations` object `debug_get_agent` returns, so one shape covers both tools. Each entry: { definition_id, display_name, connection_key, scope ("agent" | "team" | "org"), source_id, status, status_message, auth_type, last_connectivity_check_at, last_connectivity_status, consecutive_connectivity_failures, wired_verdict, last_session_tool_bind_at }. Never credentials.\n\nPrefer this over reading `agent_integrations`: TEAM/ORG-scope installs are invisible to a per-agent read, so absence there is not evidence. `effective_count` reconciles against the manager\'s `Integrations provisioned for \'<code_name>\' (N)` or the tool-bind probe\'s `due=N`; docs/runbooks/admin-debug-dogfood.md lists the benign divergences to rule out before treating a mismatch as a bug. `wired_verdict` is the host\'s last session-tool-bind result (bound | missing | unreachable | unknown), the closest available answer to "is it in the agent\'s .mcp.json right now?"; `null` means never probed, which is NOT "not wired".\n\nFails closed (uniform not-found) for an unauthorized/unknown agent; a failed scope query returns an error rather than a smaller count. Audited as a cross-org access. Pass { agent_id }.',
21615
- getAgentIntegrationsSchema.shape,
21615
+ { description: 'Resolve ONE agent\'s EFFECTIVE integration set \u2014 the focused read for "does this agent have integration X, and where is it installed from?" (ENG-8271). Same resolution as `debug_get_agent`\'s `effective_integrations`, without the host/alerts payload.\n\nReturns { agent_id, code_name, team_id, organization_id, effective_integrations: { effective_count, by_scope, inherited_definition_ids, excluded_control_plane_only, shadowed_by_more_specific, duplicate_merge_keys, scopes_queried, scopes_skipped, integrations[] } } - the same `effective_integrations` object `debug_get_agent` returns, so one shape covers both tools. Each entry: { definition_id, display_name, connection_key, scope ("agent" | "team" | "org"), source_id, status, status_message, auth_type, last_connectivity_check_at, last_connectivity_status, consecutive_connectivity_failures, wired_verdict, last_session_tool_bind_at }. Never credentials.\n\nPrefer this over reading `agent_integrations`: TEAM/ORG-scope installs are invisible to a per-agent read, so absence there is not evidence. `effective_count` reconciles against the manager\'s `Integrations provisioned for \'<code_name>\' (N)` or the tool-bind probe\'s `due=N`; docs/runbooks/admin-debug-dogfood.md lists the benign divergences to rule out before treating a mismatch as a bug. `wired_verdict` is the host\'s last session-tool-bind result (bound | missing | unreachable | unknown), the closest available answer to "is it in the agent\'s .mcp.json right now?"; `null` means never probed, which is NOT "not wired".\n\nFails closed (uniform not-found) for an unauthorized/unknown agent; a failed scope query returns an error rather than a smaller count. Audited as a cross-org access. Pass { agent_id }.', inputSchema: getAgentIntegrationsSchema },
21616
21616
  async (args) => {
21617
21617
  try {
21618
21618
  const result = await client.getAgentIntegrations(args.agent_id);
@@ -21622,10 +21622,9 @@ server.tool(
21622
21622
  }
21623
21623
  }
21624
21624
  );
21625
- server.tool(
21625
+ server.registerTool(
21626
21626
  "debug_search_hosts",
21627
- "Search managed hosts across authorized orgs. Returns a projection per host (name, org, status, framework version, last-seen verdict, EC2 + Claude auth status) \u2014 no api-key fingerprints or secrets. Filter with { q, status, limit }.",
21628
- searchHostsSchema.shape,
21627
+ { description: "Search managed hosts across authorized orgs. Returns a projection per host (name, org, status, framework version, last-seen verdict, EC2 + Claude auth status) \u2014 no api-key fingerprints or secrets. Filter with { q, status, limit }.", inputSchema: searchHostsSchema },
21629
21628
  async (args) => {
21630
21629
  try {
21631
21630
  const result = await client.searchHosts(args);
@@ -21635,10 +21634,9 @@ server.tool(
21635
21634
  }
21636
21635
  }
21637
21636
  );
21638
- server.tool(
21637
+ server.registerTool(
21639
21638
  "debug_get_host",
21640
- "Fetch a host-centric composite for ONE host \u2014 the host equivalent of debug_get_agent, and the right entry point for host-WIDE incidents (e.g. an env drift or a bad deploy hitting every agent on a box). One read returns: the host projection (status, framework + CC version, last-seen verdict, EC2 + Claude auth), EVERY agent bound to the host (each with its own heartbeat verdict + org), a rollup of alerts (the host's own infra alerts \u2014 including NULL-team ones like host_down / probe_timeout \u2014 PLUS each bound agent's alerts), and a { agent_count, restart_count, restart_window_hours } rollup. Saves stitching debug_search_hosts + per-agent reads together. Resolve the host by its id (uuid) or its exact, case-insensitive name; an ambiguous name returns a 400 asking for the id. Returns { host: { \u2026, agents[], recent_alerts[], rollup } }. Fails closed (uniform not-found) for an unauthorized or unknown host; every call is audited as a cross-org access. Pass { host, since_hours? } (since_hours sets the restart-count window, default 24).",
21641
- getHostSchema.shape,
21639
+ { description: "Fetch a host-centric composite for ONE host \u2014 the host equivalent of debug_get_agent, and the right entry point for host-WIDE incidents (e.g. an env drift or a bad deploy hitting every agent on a box). One read returns: the host projection (status, framework + CC version, last-seen verdict, EC2 + Claude auth), EVERY agent bound to the host (each with its own heartbeat verdict + org), a rollup of alerts (the host's own infra alerts \u2014 including NULL-team ones like host_down / probe_timeout \u2014 PLUS each bound agent's alerts), and a { agent_count, restart_count, restart_window_hours } rollup. Saves stitching debug_search_hosts + per-agent reads together. Resolve the host by its id (uuid) or its exact, case-insensitive name; an ambiguous name returns a 400 asking for the id. Returns { host: { \u2026, agents[], recent_alerts[], rollup } }. Fails closed (uniform not-found) for an unauthorized or unknown host; every call is audited as a cross-org access. Pass { host, since_hours? } (since_hours sets the restart-count window, default 24).", inputSchema: getHostSchema },
21642
21640
  async (args) => {
21643
21641
  try {
21644
21642
  const result = await client.getHost(args);
@@ -21648,10 +21646,9 @@ server.tool(
21648
21646
  }
21649
21647
  }
21650
21648
  );
21651
- server.tool(
21649
+ server.registerTool(
21652
21650
  "debug_inspect_flags",
21653
- "Inspect an agent/host's EFFECTIVE feature flags WITH source attribution \u2014 the one-call answer to \"is an env override silently masking a flag?\" (the ENG-6478 / koda drift class), instead of grepping manager.log for WARN spam. For each registry flag it returns { effective, source, env_value, env_var, heartbeat_value, central_value, default_value, env_masks_heartbeat, host_stale, sensitive }. `source` mirrors how the host actually resolves a flag: env override > heartbeat-materialized (the value the control plane last sent the host) > compiled default. `env_masks_heartbeat:true` is the smoking gun for ENG-6478 (a host env gate overriding a different DB-resolved value); `host_stale:true` means the host hasn't picked up a central change. Host-side values come from the host's latest config snapshot (so snapshot:null \u21D2 the host hasn't reported one and attribution degrades to default + central). Top-level `drift_keys` lists the flags worth looking at. Pass exactly one of { host } (id or exact name) or { agent_id } (inspects its current host). Read-only; fails closed for an unauthorized/unknown target; audited as a cross-org access.",
21654
- inspectFlagsSchema.shape,
21651
+ { description: "Inspect an agent/host's EFFECTIVE feature flags WITH source attribution \u2014 the one-call answer to \"is an env override silently masking a flag?\" (the ENG-6478 / koda drift class), instead of grepping manager.log for WARN spam. For each registry flag it returns { effective, source, env_value, env_var, heartbeat_value, central_value, default_value, env_masks_heartbeat, host_stale, sensitive }. `source` mirrors how the host actually resolves a flag: env override > heartbeat-materialized (the value the control plane last sent the host) > compiled default. `env_masks_heartbeat:true` is the smoking gun for ENG-6478 (a host env gate overriding a different DB-resolved value); `host_stale:true` means the host hasn't picked up a central change. Host-side values come from the host's latest config snapshot (so snapshot:null \u21D2 the host hasn't reported one and attribution degrades to default + central). Top-level `drift_keys` lists the flags worth looking at. Pass exactly one of { host } (id or exact name) or { agent_id } (inspects its current host). Read-only; fails closed for an unauthorized/unknown target; audited as a cross-org access.", inputSchema: inspectFlagsSchema },
21655
21652
  async (args) => {
21656
21653
  try {
21657
21654
  const hasHost = typeof args.host === "string" && args.host.length > 0;
@@ -21669,10 +21666,9 @@ server.tool(
21669
21666
  }
21670
21667
  }
21671
21668
  );
21672
- server.tool(
21669
+ server.registerTool(
21673
21670
  "debug_list_alerts",
21674
- "List recent platform alerts across authorized orgs (host-down, agent-stale, probe-timeout, auth-failed), including NULL-team host alerts. Returns a projection per alert (kind, severity, message, source, open/closed state). Filter with { severity, open, limit }.",
21675
- listAlertsSchema.shape,
21671
+ { description: "List recent platform alerts across authorized orgs (host-down, agent-stale, probe-timeout, auth-failed), including NULL-team host alerts. Returns a projection per alert (kind, severity, message, source, open/closed state). Filter with { severity, open, limit }.", inputSchema: listAlertsSchema },
21676
21672
  async (args) => {
21677
21673
  try {
21678
21674
  const result = await client.listAlerts(args);
@@ -21682,10 +21678,9 @@ server.tool(
21682
21678
  }
21683
21679
  }
21684
21680
  );
21685
- server.tool(
21681
+ server.registerTool(
21686
21682
  "debug_ack_alert",
21687
- "Acknowledge an open alert \u2014 close the triage loop here instead of bouncing to the webapp. Stops escalation/paging for it without closing it. Unlike the host-affecting remedial actions this is a low-risk, reversible control-plane write (it sets acknowledged_at/by on the alert row), so it applies directly \u2014 gated by the admin-debug write mode and authorized against the alert's org (a NULL-org infra alert is IL-internal-only). Returns { alert_id, action, write_mode, applied, alert }. `applied:false` means write mode is `shadow` (validated, not written). Get the alert id from debug_list_alerts. Pass { alert_id, reason? }. Every call is audited as a cross-org access.",
21688
- ackAlertSchema.shape,
21683
+ { description: "Acknowledge an open alert \u2014 close the triage loop here instead of bouncing to the webapp. Stops escalation/paging for it without closing it. Unlike the host-affecting remedial actions this is a low-risk, reversible control-plane write (it sets acknowledged_at/by on the alert row), so it applies directly \u2014 gated by the admin-debug write mode and authorized against the alert's org (a NULL-org infra alert is IL-internal-only). Returns { alert_id, action, write_mode, applied, alert }. `applied:false` means write mode is `shadow` (validated, not written). Get the alert id from debug_list_alerts. Pass { alert_id, reason? }. Every call is audited as a cross-org access.", inputSchema: ackAlertSchema },
21689
21684
  async (args) => {
21690
21685
  try {
21691
21686
  const result = await client.ackAlert(args);
@@ -21695,10 +21690,9 @@ server.tool(
21695
21690
  }
21696
21691
  }
21697
21692
  );
21698
- server.tool(
21693
+ server.registerTool(
21699
21694
  "debug_snooze_alert",
21700
- "Snooze an open alert \u2014 suppress fresh pages for it until 15m | 1h | 4h | until_tomorrow (09:00 UTC next day), without closing it. Low-risk reversible control-plane write (sets snoozed_until); applies directly under the admin-debug write mode, authorized against the alert's org. Returns { alert_id, action, write_mode, applied, alert }; `applied:false` \u21D2 shadow mode. Pass { alert_id, duration, reason? }. Audited as a cross-org access.",
21701
- snoozeAlertSchema.shape,
21695
+ { description: "Snooze an open alert \u2014 suppress fresh pages for it until 15m | 1h | 4h | until_tomorrow (09:00 UTC next day), without closing it. Low-risk reversible control-plane write (sets snoozed_until); applies directly under the admin-debug write mode, authorized against the alert's org. Returns { alert_id, action, write_mode, applied, alert }; `applied:false` \u21D2 shadow mode. Pass { alert_id, duration, reason? }. Audited as a cross-org access.", inputSchema: snoozeAlertSchema },
21702
21696
  async (args) => {
21703
21697
  try {
21704
21698
  const result = await client.snoozeAlert(args);
@@ -21708,10 +21702,9 @@ server.tool(
21708
21702
  }
21709
21703
  }
21710
21704
  );
21711
- server.tool(
21705
+ server.registerTool(
21712
21706
  "debug_close_alert",
21713
- "Close an open alert (closed_reason=manual) \u2014 resolve it from here when you've confirmed it's handled, instead of the webapp. Low-risk control-plane write (sets closed_at + closed_reason); applies directly under the admin-debug write mode, authorized against the alert's org. Only OPEN alerts can be closed (a 409 means it was already closed). Returns { alert_id, action, write_mode, applied, alert }; `applied:false` \u21D2 shadow mode. Pass { alert_id, reason? }. Audited as a cross-org access.",
21714
- closeAlertSchema.shape,
21707
+ { description: "Close an open alert (closed_reason=manual) \u2014 resolve it from here when you've confirmed it's handled, instead of the webapp. Low-risk control-plane write (sets closed_at + closed_reason); applies directly under the admin-debug write mode, authorized against the alert's org. Only OPEN alerts can be closed (a 409 means it was already closed). Returns { alert_id, action, write_mode, applied, alert }; `applied:false` \u21D2 shadow mode. Pass { alert_id, reason? }. Audited as a cross-org access.", inputSchema: closeAlertSchema },
21715
21708
  async (args) => {
21716
21709
  try {
21717
21710
  const result = await client.closeAlert(args);
@@ -21721,10 +21714,9 @@ server.tool(
21721
21714
  }
21722
21715
  }
21723
21716
  );
21724
- server.tool(
21717
+ server.registerTool(
21725
21718
  "debug_search_orgs",
21726
- `List the ORGANIZATIONS you're authorized to read \u2014 the org-level entry point for triage and access decisions, so you don't have to infer orgs off agent/host rows or probe one org's tier with debug_request_access. Returns a projection per org: { organization_id, organization_slug, display_name, is_internal, management_mode (fully_managed | self_managed), standing_reason (internal | fully_managed | granted \u2014 WHY you can read it), has_active_grant (do you hold a live grant right now), host_count, agent_count, active_agent_count, open_alert_count, created_at }. Use it to (1) decide access in one read \u2014 see a self_managed org and its grant state before deciding to debug_request_access; (2) triage the fleet \u2014 "which orgs have open alerts" (open_alert_count includes stuck-restart alerts) without walking agents; (3) disambiguate a slug \u2192 id \u2192 tier without needing an agent/host to exist. Authorized = IL-owned (is_internal) + fully-managed orgs (standing) plus any self-managed org you hold an active grant for. Filter with { q (slug/name substring), management_mode, is_internal, limit }. Projection only \u2014 no secrets, no transcripts; org-walled in SQL and audited as a cross-org access.`,
21727
- searchOrgsSchema.shape,
21719
+ { description: `List the ORGANIZATIONS you're authorized to read \u2014 the org-level entry point for triage and access decisions, so you don't have to infer orgs off agent/host rows or probe one org's tier with debug_request_access. Returns a projection per org: { organization_id, organization_slug, display_name, is_internal, management_mode (fully_managed | self_managed), standing_reason (internal | fully_managed | granted \u2014 WHY you can read it), has_active_grant (do you hold a live grant right now), host_count, agent_count, active_agent_count, open_alert_count, created_at }. Use it to (1) decide access in one read \u2014 see a self_managed org and its grant state before deciding to debug_request_access; (2) triage the fleet \u2014 "which orgs have open alerts" (open_alert_count includes stuck-restart alerts) without walking agents; (3) disambiguate a slug \u2192 id \u2192 tier without needing an agent/host to exist. Authorized = IL-owned (is_internal) + fully-managed orgs (standing) plus any self-managed org you hold an active grant for. Filter with { q (slug/name substring), management_mode, is_internal, limit }. Projection only \u2014 no secrets, no transcripts; org-walled in SQL and audited as a cross-org access.`, inputSchema: searchOrgsSchema },
21728
21720
  async (args) => {
21729
21721
  try {
21730
21722
  const result = await client.searchOrgs(args);
@@ -21734,10 +21726,9 @@ server.tool(
21734
21726
  }
21735
21727
  }
21736
21728
  );
21737
- server.tool(
21729
+ server.registerTool(
21738
21730
  "debug_host_versions",
21739
- 'Fleet-wide host health snapshot for triaging "which host is unhealthy?". Returns a projection per authorized host: { id, name, org, framework, framework_version (the Claude Code version the host runs), last_seen_verdict, agent_count, restart_count, restart_window_hours }. `restart_count` tallies `agent.restart` audit events across the host\'s agents within the window (default 24h) \u2014 a high count is the tell for a thrashing host. Use it to spot version skew (an old framework_version) or restart storms across the fleet at a glance. Filter with { q, status, since_hours, limit }.',
21740
- hostVersionsSchema.shape,
21731
+ { description: 'Fleet-wide host health snapshot for triaging "which host is unhealthy?". Returns a projection per authorized host: { id, name, org, framework, framework_version (the Claude Code version the host runs), last_seen_verdict, agent_count, restart_count, restart_window_hours }. `restart_count` tallies `agent.restart` audit events across the host\'s agents within the window (default 24h) \u2014 a high count is the tell for a thrashing host. Use it to spot version skew (an old framework_version) or restart storms across the fleet at a glance. Filter with { q, status, since_hours, limit }.', inputSchema: hostVersionsSchema },
21741
21732
  async (args) => {
21742
21733
  try {
21743
21734
  const result = await client.hostVersions(args);
@@ -21747,10 +21738,9 @@ server.tool(
21747
21738
  }
21748
21739
  }
21749
21740
  );
21750
- server.tool(
21741
+ server.registerTool(
21751
21742
  "debug_tail_logs",
21752
- "Live-tail an agent's HOST logs over SSM to ground-truth \"what was it actually doing?\" \u2014 the host-reaching read, used after debug_get_agent points at a sick agent. Resolves the agent's current host and returns the trailing lines of ONE allowlisted operational log: { agent_id, code_name, host, log, content (the tail), log_present, lines_requested, truncated, ssm_status }. Logs: `manager` (manager.log \u2014 respawn/wedge/lifecycle), `pane` (pane.log \u2014 the tmux pane, the agent's visible I/O, e.g. a stuck AskUserQuestion), `slack-stderr`/`telegram-stderr`/`direct-chat-stderr` (a channel MCP's crash output, e.g. attachment-download 400s), `manager-state` (manager-state.json). Fails closed for an unauthorized org. Only operational logs are reachable \u2014 secret files (.mcp.json, .env.integrations) are NOT. Pass { agent_id, log?, lines? } (lines default 200, max 2000; output ~20 KB-capped, newest kept). Every call is audited as a cross-org host access.",
21753
- tailLogsSchema.shape,
21743
+ { description: "Live-tail an agent's HOST logs over SSM to ground-truth \"what was it actually doing?\" \u2014 the host-reaching read, used after debug_get_agent points at a sick agent. Resolves the agent's current host and returns the trailing lines of ONE allowlisted operational log: { agent_id, code_name, host, log, content (the tail), log_present, lines_requested, truncated, ssm_status }. Logs: `manager` (manager.log \u2014 respawn/wedge/lifecycle), `pane` (pane.log \u2014 the tmux pane, the agent's visible I/O, e.g. a stuck AskUserQuestion), `slack-stderr`/`telegram-stderr`/`direct-chat-stderr` (a channel MCP's crash output, e.g. attachment-download 400s), `manager-state` (manager-state.json). Fails closed for an unauthorized org. Only operational logs are reachable \u2014 secret files (.mcp.json, .env.integrations) are NOT. Pass { agent_id, log?, lines? } (lines default 200, max 2000; output ~20 KB-capped, newest kept). Every call is audited as a cross-org host access.", inputSchema: tailLogsSchema },
21754
21744
  async (args) => {
21755
21745
  try {
21756
21746
  const result = await client.tailLogs(args);
@@ -21760,10 +21750,9 @@ server.tool(
21760
21750
  }
21761
21751
  }
21762
21752
  );
21763
- server.tool(
21753
+ server.registerTool(
21764
21754
  "debug_query_logs",
21765
- 'Read an agent\'s HOST logs OVER A TIME WINDOW, spanning rotated files \u2014 the historical counterpart to debug_tail_logs. Where tail only shows the live tail of the current file (minutes, and gone once it rotates), this reads the active log AND its logrotate siblings (manager.log-YYYYMMDD, manager.log-YYYYMMDD.gz, \u2026 7 days kept on-host) and filters lines to [since, until]. Windows older than 7 days return nothing: those rotations have been archived to S3, and hosts are write-only to that bucket by design, so an older window needs an operator S3 fetch rather than this tool (ENG-8330). Seven days is the ONE local-retention window for everything the host archives, Claude session transcripts included. This is the read path for "did it restart at 4pm YESTERDAY?" \u2014 use it when the answer is older than the live tail or spans a rotation. Returns { agent_id, code_name, host, log, since, until, time_filtered, content, log_present, lines_requested, truncated, ssm_status }. Time filtering applies to `manager` (its lines carry an ISO8601 prefix); `pane`/`slack-stderr`/`telegram-stderr`/`direct-chat-stderr`/`manager-state`/`channel-quarantine` return their byte-capped tail unfiltered (time_filtered:false \u2014 the last two are JSON, not line-oriented). Only operational logs are reachable \u2014 secret files (.mcp.json, .env.integrations) are NOT. Pass { agent_id, log?, since?, until?, lines? } (since/until ISO8601 UTC e.g. 2026-06-14T16:00:00Z, default unbounded; lines default 1000, max 5000; output ~20 KB-capped, newest kept \u2014 narrow the window if truncated). Fails closed for an unauthorized org; every call is audited as a cross-org host access.',
21766
- queryLogsSchema.shape,
21755
+ { description: 'Read an agent\'s HOST logs OVER A TIME WINDOW, spanning rotated files \u2014 the historical counterpart to debug_tail_logs. Where tail only shows the live tail of the current file (minutes, and gone once it rotates), this reads the active log AND its logrotate siblings (manager.log-YYYYMMDD, manager.log-YYYYMMDD.gz, \u2026 7 days kept on-host) and filters lines to [since, until]. Windows older than 7 days return nothing: those rotations have been archived to S3, and hosts are write-only to that bucket by design, so an older window needs an operator S3 fetch rather than this tool (ENG-8330). Seven days is the ONE local-retention window for everything the host archives, Claude session transcripts included. This is the read path for "did it restart at 4pm YESTERDAY?" \u2014 use it when the answer is older than the live tail or spans a rotation. Returns { agent_id, code_name, host, log, since, until, time_filtered, content, log_present, lines_requested, truncated, ssm_status }. Time filtering applies to `manager` (its lines carry an ISO8601 prefix); `pane`/`slack-stderr`/`telegram-stderr`/`direct-chat-stderr`/`manager-state`/`channel-quarantine` return their byte-capped tail unfiltered (time_filtered:false \u2014 the last two are JSON, not line-oriented). Only operational logs are reachable \u2014 secret files (.mcp.json, .env.integrations) are NOT. Pass { agent_id, log?, since?, until?, lines? } (since/until ISO8601 UTC e.g. 2026-06-14T16:00:00Z, default unbounded; lines default 1000, max 5000; output ~20 KB-capped, newest kept \u2014 narrow the window if truncated). Fails closed for an unauthorized org; every call is audited as a cross-org host access.', inputSchema: queryLogsSchema },
21767
21756
  async (args) => {
21768
21757
  try {
21769
21758
  const result = await client.queryLogs(args);
@@ -21773,10 +21762,9 @@ server.tool(
21773
21762
  }
21774
21763
  }
21775
21764
  );
21776
- server.tool(
21765
+ server.registerTool(
21777
21766
  "debug_eval_failures",
21778
- 'Report WHY conversations could not be scored by the host-side success evaluator: the failure counterpart to the "conversation success" trend, which only ever shows EVALUATED conversations (so an agent whose conversations all fail to reconstruct silently vanishes from it). Use when conversation scores look thin/absent for an agent, or to audit eval coverage fleet-wide. Returns { scope, period, scanned, truncated, report, recent }. `report` is the aggregate: { total, gaveUp (subset that hit the retry cap, will never be scored), byReason[] (org-wide count + gaveUp per reason), perAgent[] (worst-first standing) }. The three reasons are data-shaped: `no_transcript` (the host had no local transcript at all), `not_reconstructable` (transcripts exist but none carry the conversation\'s channel ref), `empty_transcript` (turns reconstructed but rendered to nothing). `recent` is the newest failing conversations (boundary + reason only, NEVER transcript content). NOTE: transient/misconfigured EVAL BACKEND failures are NOT here; those show on the host (hosts.eval_backend_*), check debug_get_host. Pass { period? (24h|7d|30d, default 7d), agent_id? (omit for fleet-wide) }. Org-walled in SQL; every call is audited as a cross-org access.',
21779
- evalFailuresSchema.shape,
21767
+ { description: 'Report WHY conversations could not be scored by the host-side success evaluator: the failure counterpart to the "conversation success" trend, which only ever shows EVALUATED conversations (so an agent whose conversations all fail to reconstruct silently vanishes from it). Use when conversation scores look thin/absent for an agent, or to audit eval coverage fleet-wide. Returns { scope, period, scanned, truncated, report, recent }. `report` is the aggregate: { total, gaveUp (subset that hit the retry cap, will never be scored), byReason[] (org-wide count + gaveUp per reason), perAgent[] (worst-first standing) }. The three reasons are data-shaped: `no_transcript` (the host had no local transcript at all), `not_reconstructable` (transcripts exist but none carry the conversation\'s channel ref), `empty_transcript` (turns reconstructed but rendered to nothing). `recent` is the newest failing conversations (boundary + reason only, NEVER transcript content). NOTE: transient/misconfigured EVAL BACKEND failures are NOT here; those show on the host (hosts.eval_backend_*), check debug_get_host. Pass { period? (24h|7d|30d, default 7d), agent_id? (omit for fleet-wide) }. Org-walled in SQL; every call is audited as a cross-org access.', inputSchema: evalFailuresSchema },
21780
21768
  async (args) => {
21781
21769
  try {
21782
21770
  const result = await client.evalFailures(args);
@@ -21786,10 +21774,9 @@ server.tool(
21786
21774
  }
21787
21775
  }
21788
21776
  );
21789
- server.tool(
21777
+ server.registerTool(
21790
21778
  "debug_probe_integration",
21791
- "Force a FRESH host-side connectivity probe for ONE of an agent's integrations and return the LIVE verdict \u2014 use when a user reports an integration \"isn't working\" but the console shows it connected, or to confirm a fix landed. Unlike the cached status the dashboard shows, this SSH-less SSM-invokes the agent's host to run the probe against its actual wired `.mcp.json` + credentials, so it can't disagree with reality. Returns { agent_id, code_name, slug, host, verdict, message, probed_at, ssm_status }. `verdict` is the live result: `ok` | `degraded` | `transient_error` (retryable) | `down` | `not_probeable` (no probe wired for this kind) \u2014 or a central degrade: `unreachable` (agent has no host), `not_installed` (integration not on this agent), `host_cli_too_old` (the host predates the probe \u2014 update its agt-cli), `probe_error`. Pass { agent_id, slug } where slug is the integration's definition code_name (e.g. `gmail`, `slack`, `here-now`). Fails closed for an unauthorized org; every call is audited as a cross-org host access.",
21792
- probeIntegrationSchema.shape,
21779
+ { description: "Force a FRESH host-side connectivity probe for ONE of an agent's integrations and return the LIVE verdict \u2014 use when a user reports an integration \"isn't working\" but the console shows it connected, or to confirm a fix landed. Unlike the cached status the dashboard shows, this SSH-less SSM-invokes the agent's host to run the probe against its actual wired `.mcp.json` + credentials, so it can't disagree with reality. Returns { agent_id, code_name, slug, host, verdict, message, probed_at, ssm_status }. `verdict` is the live result: `ok` | `degraded` | `transient_error` (retryable) | `down` | `not_probeable` (no probe wired for this kind) \u2014 or a central degrade: `unreachable` (agent has no host), `not_installed` (integration not on this agent), `host_cli_too_old` (the host predates the probe \u2014 update its agt-cli), `probe_error`. Pass { agent_id, slug } where slug is the integration's definition code_name (e.g. `gmail`, `slack`, `here-now`). Fails closed for an unauthorized org; every call is audited as a cross-org host access.", inputSchema: probeIntegrationSchema },
21793
21780
  async (args) => {
21794
21781
  try {
21795
21782
  const result = await client.probeIntegration(args);
@@ -21799,10 +21786,9 @@ server.tool(
21799
21786
  }
21800
21787
  }
21801
21788
  );
21802
- server.tool(
21789
+ server.registerTool(
21803
21790
  "debug_inspect_dead_letters",
21804
- "List an agent's DEAD-LETTERED / quarantined inbound \u2014 customer messages that were parked on the host instead of delivered (so the agent never saw them), rather than silently lost. Use when a user says \"the agent never replied\" but nothing shows in the normal flow, or to audit what fell into the dead-letter path. Resolves the agent's current host and reads two on-disk stores over SSM: `stale` (markers moved aside on a wedge-respawn because the agent couldn't receive) and `cleared:<stamp>` (markers the clear_pending_inbound remedial action moved aside). Returns { agent_id, code_name, host, markers[], total, ssm_status } where each marker is { index, store, channel (slack|telegram), marker_name, received_at, undeliverable, discretionary, replay_count, conversation, message_ref } \u2014 routing metadata only, NEVER the message body. To re-inject one, pass its exact { channel, store, marker_name } to debug_replay_dead_letter. Fails closed for an unauthorized org; every call is audited as a cross-org host access. Pass { agent_id }.",
21805
- inspectDeadLettersSchema.shape,
21791
+ { description: "List an agent's DEAD-LETTERED / quarantined inbound \u2014 customer messages that were parked on the host instead of delivered (so the agent never saw them), rather than silently lost. Use when a user says \"the agent never replied\" but nothing shows in the normal flow, or to audit what fell into the dead-letter path. Resolves the agent's current host and reads two on-disk stores over SSM: `stale` (markers moved aside on a wedge-respawn because the agent couldn't receive) and `cleared:<stamp>` (markers the clear_pending_inbound remedial action moved aside). Returns { agent_id, code_name, host, markers[], total, ssm_status } where each marker is { index, store, channel (slack|telegram), marker_name, received_at, undeliverable, discretionary, replay_count, conversation, message_ref } \u2014 routing metadata only, NEVER the message body. To re-inject one, pass its exact { channel, store, marker_name } to debug_replay_dead_letter. Fails closed for an unauthorized org; every call is audited as a cross-org host access. Pass { agent_id }.", inputSchema: inspectDeadLettersSchema },
21806
21792
  async (args) => {
21807
21793
  try {
21808
21794
  const result = await client.inspectDeadLetters(args);
@@ -21812,10 +21798,9 @@ server.tool(
21812
21798
  }
21813
21799
  }
21814
21800
  );
21815
- server.tool(
21801
+ server.registerTool(
21816
21802
  "debug_inspect_restart_requests",
21817
- 'List STUCK / pending agent restart requests across authorized orgs \u2014 the agent_restart_stuck class. A restart request is "stuck" when the manager never acked it (e.g. one sat open on an agent for ~27 days). Use this when an agent went quiet and you suspect a restart that never landed, or to audit the fleet for unacked restarts. Returns { requests[], count } where each request is { agent_id, code_name, organization_id, host, restart_requested_at, stuck_seconds, is_stuck, incident, alert } \u2014 `is_stuck` flags age past the alert threshold (15 min); `incident`/`alert` carry the open ledger row + paged alert when the cron has escalated it. Routing metadata only, never message content. To cancel one, pass its agent_id to request_clear_restart_request. Pass { agent_id? (narrow to one), limit? }; fleet-wide when agent_id is omitted. Org-walled in SQL; every call is audited as a cross-org access.',
21818
- inspectRestartRequestsSchema.shape,
21803
+ { description: 'List STUCK / pending agent restart requests across authorized orgs \u2014 the agent_restart_stuck class. A restart request is "stuck" when the manager never acked it (e.g. one sat open on an agent for ~27 days). Use this when an agent went quiet and you suspect a restart that never landed, or to audit the fleet for unacked restarts. Returns { requests[], count } where each request is { agent_id, code_name, organization_id, host, restart_requested_at, stuck_seconds, is_stuck, incident, alert } \u2014 `is_stuck` flags age past the alert threshold (15 min); `incident`/`alert` carry the open ledger row + paged alert when the cron has escalated it. Routing metadata only, never message content. To cancel one, pass its agent_id to request_clear_restart_request. Pass { agent_id? (narrow to one), limit? }; fleet-wide when agent_id is omitted. Org-walled in SQL; every call is audited as a cross-org access.', inputSchema: inspectRestartRequestsSchema },
21819
21804
  async (args) => {
21820
21805
  try {
21821
21806
  const result = await client.inspectRestartRequests(args);
@@ -21825,10 +21810,9 @@ server.tool(
21825
21810
  }
21826
21811
  }
21827
21812
  );
21828
- server.tool(
21813
+ server.registerTool(
21829
21814
  "request_clear_restart_request",
21830
- "Request a HITL-gated CLEAR of a STUCK restart request \u2014 cancel a restart the manager never acked (listed by debug_inspect_restart_requests) and resolve its agent_restart_stuck alert. Use it to clear a restart signal wedged open for hours/days/weeks. This is NOT a restart and NOT a host action: it nulls the agent's `restart_requested_at` signal in the central DB and closes the alert/incident; the agent keeps running as-is, no in-flight work is destroyed. Reversible \u2014 request a fresh restart afterwards if one is still needed. A HUMAN must approve in Slack before anything happens, and only if writes are armed for this stage (shadow mode runs the approval but executes nothing). Async: returns { request_id, status, write_mode, notification_status }; after approval, poll check_action_status (result_payload carries { cleared_bindings, alert_closed }). Pass { target_agent_id, reason }.",
21831
- clearRestartRequestSchema.shape,
21815
+ { description: "Request a HITL-gated CLEAR of a STUCK restart request \u2014 cancel a restart the manager never acked (listed by debug_inspect_restart_requests) and resolve its agent_restart_stuck alert. Use it to clear a restart signal wedged open for hours/days/weeks. This is NOT a restart and NOT a host action: it nulls the agent's `restart_requested_at` signal in the central DB and closes the alert/incident; the agent keeps running as-is, no in-flight work is destroyed. Reversible \u2014 request a fresh restart afterwards if one is still needed. A HUMAN must approve in Slack before anything happens, and only if writes are armed for this stage (shadow mode runs the approval but executes nothing). Async: returns { request_id, status, write_mode, notification_status }; after approval, poll check_action_status (result_payload carries { cleared_bindings, alert_closed }). Pass { target_agent_id, reason }.", inputSchema: clearRestartRequestSchema },
21832
21816
  async (args) => {
21833
21817
  try {
21834
21818
  const result = await client.requestClearRestartRequest({
@@ -21841,10 +21825,9 @@ server.tool(
21841
21825
  }
21842
21826
  }
21843
21827
  );
21844
- server.tool(
21828
+ server.registerTool(
21845
21829
  "debug_query_audit_log",
21846
- 'Read recent audit events to troubleshoot why/when agents bounced \u2014 primarily restart events. Defaults to the "agent.restart" action: each event returns { created_at, source, reason, detail, actor_kind, agent_id, code_name }, where `source` is the restart trigger (agent-self-request, channel-command, maintenance-window, stale-mcp, hot-reload-mcp, mcp-presence-reaper, day-rollover, auth-tuple-change, \u2026) and `reason` is the free-text rationale when one was given (e.g. the agent\'s own words for a request_restart). `detail` (ENG-8293) is the structured "what changed?" payload, null for sources that don\'t emit one. For `auth-tuple-change` it is { auth_tuple: { changed[], unchanged[], components[] } } naming WHICH credential/identity component moved and its before/after fingerprint \u2014 the auth tuple is deliberately NOT keyed on the rotating access token, so an auth-tuple-change is always a genuine credential or identity change, and `detail.auth_tuple.changed` is how you tell which one. Comparing `components[].to` across agents answers whether a restart WAVE was one control-plane push (same new value everywhere) or coincidental per-agent rotations. Two modes: (1) pass { agent_id } to scope to ONE agent (fails closed if you\'re not authorized for its org) \u2014 use when a specific agent went quiet. (2) OMIT agent_id for a CROSS-AGENT sweep across every org you\'re authorized for (optionally narrow with { org_id }) \u2014 use to spot fleet-wide restart storms or compare agents. Filter the action with `action` (pass "all" to drop the action filter and read every event type), and bound with { since_hours?, limit? }. Cross-agent results are org-walled in SQL; unauthorized orgs are invisible.',
21847
- queryAuditLogSchema.shape,
21830
+ { description: 'Read recent audit events to troubleshoot why/when agents bounced \u2014 primarily restart events. Defaults to the "agent.restart" action: each event returns { created_at, source, reason, detail, actor_kind, agent_id, code_name }, where `source` is the restart trigger (agent-self-request, channel-command, maintenance-window, stale-mcp, hot-reload-mcp, mcp-presence-reaper, day-rollover, auth-tuple-change, \u2026) and `reason` is the free-text rationale when one was given (e.g. the agent\'s own words for a request_restart). `detail` (ENG-8293) is the structured "what changed?" payload, null for sources that don\'t emit one. For `auth-tuple-change` it is { auth_tuple: { changed[], unchanged[], components[] } } naming WHICH credential/identity component moved and its before/after fingerprint \u2014 the auth tuple is deliberately NOT keyed on the rotating access token, so an auth-tuple-change is always a genuine credential or identity change, and `detail.auth_tuple.changed` is how you tell which one. Comparing `components[].to` across agents answers whether a restart WAVE was one control-plane push (same new value everywhere) or coincidental per-agent rotations. Two modes: (1) pass { agent_id } to scope to ONE agent (fails closed if you\'re not authorized for its org) \u2014 use when a specific agent went quiet. (2) OMIT agent_id for a CROSS-AGENT sweep across every org you\'re authorized for (optionally narrow with { org_id }) \u2014 use to spot fleet-wide restart storms or compare agents. Filter the action with `action` (pass "all" to drop the action filter and read every event type), and bound with { since_hours?, limit? }. Cross-agent results are org-walled in SQL; unauthorized orgs are invisible.', inputSchema: queryAuditLogSchema },
21848
21831
  async (args) => {
21849
21832
  try {
21850
21833
  const result = await client.queryAuditLog(args);
@@ -21854,10 +21837,9 @@ server.tool(
21854
21837
  }
21855
21838
  }
21856
21839
  );
21857
- server.tool(
21840
+ server.registerTool(
21858
21841
  "debug_request_access",
21859
- "Open scoped READ access to a SELF-MANAGED customer org so the read tools (debug_search_agents / debug_get_agent / debug_search_hosts / debug_list_alerts) can reach it. Use this when a read returns nothing for an org you have a legitimate support reason to troubleshoot. It mints a short-TTL, logged, customer-revocable read grant \u2014 the customer sees the access in their Support-access console and can revoke it, and it auto-expires; it does NOT grant any write/remedial capability. For an already-authorized org (Integrity-Labs-internal or fully-managed) this returns { already_authorized: true } instead of minting a redundant grant \u2014 just use the read tools. Pass { target_org_id, reason }; the reason is recorded verbatim on the customer-visible access log, so be specific.",
21860
- requestAccessSchema.shape,
21842
+ { description: "Open scoped READ access to a SELF-MANAGED customer org so the read tools (debug_search_agents / debug_get_agent / debug_search_hosts / debug_list_alerts) can reach it. Use this when a read returns nothing for an org you have a legitimate support reason to troubleshoot. It mints a short-TTL, logged, customer-revocable read grant \u2014 the customer sees the access in their Support-access console and can revoke it, and it auto-expires; it does NOT grant any write/remedial capability. For an already-authorized org (Integrity-Labs-internal or fully-managed) this returns { already_authorized: true } instead of minting a redundant grant \u2014 just use the read tools. Pass { target_org_id, reason }; the reason is recorded verbatim on the customer-visible access log, so be specific.", inputSchema: requestAccessSchema },
21861
21843
  async (args) => {
21862
21844
  try {
21863
21845
  const result = await client.requestAccess({
@@ -21870,10 +21852,9 @@ server.tool(
21870
21852
  }
21871
21853
  }
21872
21854
  );
21873
- server.tool(
21855
+ server.registerTool(
21874
21856
  "request_action",
21875
- `Request a HITL-gated remedial action on a customer agent: "restart" (bounce the agent \u2014 reversible, backlog replays) or "clear_pending_inbound" (move stuck pending-inbound markers aside \u2014 drops queued inbound messages, NOT reprocessed). A HUMAN must approve in Slack before anything happens, and only if writes are armed for this stage; in shadow mode the approval runs but nothing executes. Returns { request_id, status, write_mode, notification_status }. Surface a brief, jargon-free note to the user (e.g. "I've asked an admin to approve restarting that agent"). Pass { action, target_agent_id, reason }.`,
21876
- requestActionSchema.shape,
21857
+ { description: `Request a HITL-gated remedial action on a customer agent: "restart" (bounce the agent \u2014 reversible, backlog replays) or "clear_pending_inbound" (move stuck pending-inbound markers aside \u2014 drops queued inbound messages, NOT reprocessed). A HUMAN must approve in Slack before anything happens, and only if writes are armed for this stage; in shadow mode the approval runs but nothing executes. Returns { request_id, status, write_mode, notification_status }. Surface a brief, jargon-free note to the user (e.g. "I've asked an admin to approve restarting that agent"). Pass { action, target_agent_id, reason }.`, inputSchema: requestActionSchema },
21877
21858
  async (args) => {
21878
21859
  try {
21879
21860
  const result = await client.requestAction(args.action, {
@@ -21886,10 +21867,9 @@ server.tool(
21886
21867
  }
21887
21868
  }
21888
21869
  );
21889
- server.tool(
21870
+ server.registerTool(
21890
21871
  "debug_restart_agent",
21891
- `Request a HITL-gated RESTART of a customer agent \u2014 bounce its session so the manager respawns it on the next poll (reversible; the inbound backlog replays). Use this to recover a wedged agent or to make it pick up a newly-bound integration/config change. A HUMAN must approve in Slack before anything happens, and only if writes are armed for this stage; in shadow mode the approval runs but nothing executes. Org-agnostic: keyed on the agent's host assignment, so it works cross-org without an active-org dependency. This is the same path as request_action({ action: "restart" }), exposed as a dedicated tool for discoverability. Returns { request_id, status, write_mode, notification_status }. Surface a brief, jargon-free note to the user (e.g. "I've asked an admin to approve restarting that agent"). Pass { target_agent_id, reason }.`,
21892
- restartAgentSchema.shape,
21872
+ { description: `Request a HITL-gated RESTART of a customer agent \u2014 bounce its session so the manager respawns it on the next poll (reversible; the inbound backlog replays). Use this to recover a wedged agent or to make it pick up a newly-bound integration/config change. A HUMAN must approve in Slack before anything happens, and only if writes are armed for this stage; in shadow mode the approval runs but nothing executes. Org-agnostic: keyed on the agent's host assignment, so it works cross-org without an active-org dependency. This is the same path as request_action({ action: "restart" }), exposed as a dedicated tool for discoverability. Returns { request_id, status, write_mode, notification_status }. Surface a brief, jargon-free note to the user (e.g. "I've asked an admin to approve restarting that agent"). Pass { target_agent_id, reason }.`, inputSchema: restartAgentSchema },
21893
21873
  async (args) => {
21894
21874
  try {
21895
21875
  const result = await client.requestAction("restart", {
@@ -21902,10 +21882,9 @@ server.tool(
21902
21882
  }
21903
21883
  }
21904
21884
  );
21905
- server.tool(
21885
+ server.registerTool(
21906
21886
  "request_config_update",
21907
- "Request a HITL-gated change to a customer agent's model config (primary/secondary/tertiary_model). A HUMAN must approve in Slack before anything happens, and only if writes are armed for this stage (shadow mode runs the approval but executes nothing). The change is reversible and applies at the agent's NEXT session launch after /host/refresh \u2014 it does not restart the agent. The new value is validated against the agent before approval is requested: Claude Code (subscription) agents take a family alias (fable/opus/opus[fast]/sonnet/haiku); routed agents take a full stored model id (e.g. openrouter/anthropic/claude-opus-4-6). Use this to fix a misconfigured model (e.g. an agent wedged on a model its auth can't access). Returns { request_id, status, write_mode, notification_status }. Pass { target_agent_id, field, new_value, reason }.",
21908
- requestConfigUpdateSchema.shape,
21887
+ { description: "Request a HITL-gated change to a customer agent's model config (primary/secondary/tertiary_model). A HUMAN must approve in Slack before anything happens, and only if writes are armed for this stage (shadow mode runs the approval but executes nothing). The change is reversible and applies at the agent's NEXT session launch after /host/refresh \u2014 it does not restart the agent. The new value is validated against the agent before approval is requested: Claude Code (subscription) agents take a family alias (fable/opus/opus[fast]/sonnet/haiku); routed agents take a full stored model id (e.g. openrouter/anthropic/claude-opus-4-6). Use this to fix a misconfigured model (e.g. an agent wedged on a model its auth can't access). Returns { request_id, status, write_mode, notification_status }. Pass { target_agent_id, field, new_value, reason }.", inputSchema: requestConfigUpdateSchema },
21909
21888
  async (args) => {
21910
21889
  try {
21911
21890
  const result = await client.requestConfigUpdate({
@@ -21920,10 +21899,9 @@ server.tool(
21920
21899
  }
21921
21900
  }
21922
21901
  );
21923
- server.tool(
21902
+ server.registerTool(
21924
21903
  "request_ssm_run",
21925
- "Request a HITL-gated, ALLOWLISTED read-only DIAGNOSTIC command on a customer agent's host over SSM \u2014 the escape hatch for host/process/service facts the typed read tools (debug_get_agent, debug_tail_logs, debug_host_versions) don't cover. A HUMAN must approve the EXACT command in Slack before it runs, and only if writes are armed (shadow mode runs the approval but executes nothing). This is NOT a shell: `command` is a CLOSED enum \u2014 host_health (uptime/df/free), manager_status (systemctl status agt-manager), manager_journal (journalctl -n 200), process_list (ps comm-only, no argv/env), agent_dir (ls -la ~/.augmented/<code_name>/, names only). No free-form commands, no file-content reads (use debug_tail_logs for log contents). Async: returns { request_id, status, write_mode, command_key, resolved_command, notification_status }; after approval, poll check_action_status to read the command OUTPUT in result_payload. Pass { target_agent_id, command, reason }.",
21926
- requestSsmRunSchema.shape,
21904
+ { description: "Request a HITL-gated, ALLOWLISTED read-only DIAGNOSTIC command on a customer agent's host over SSM \u2014 the escape hatch for host/process/service facts the typed read tools (debug_get_agent, debug_tail_logs, debug_host_versions) don't cover. A HUMAN must approve the EXACT command in Slack before it runs, and only if writes are armed (shadow mode runs the approval but executes nothing). This is NOT a shell: `command` is a CLOSED enum \u2014 host_health (uptime/df/free), manager_status (systemctl status agt-manager), manager_journal (journalctl -n 200), process_list (ps comm-only, no argv/env), agent_dir (ls -la ~/.augmented/<code_name>/, names only). No free-form commands, no file-content reads (use debug_tail_logs for log contents). Async: returns { request_id, status, write_mode, command_key, resolved_command, notification_status }; after approval, poll check_action_status to read the command OUTPUT in result_payload. Pass { target_agent_id, command, reason }.", inputSchema: requestSsmRunSchema },
21927
21905
  async (args) => {
21928
21906
  try {
21929
21907
  const result = await client.requestSsmRun({
@@ -21937,10 +21915,9 @@ server.tool(
21937
21915
  }
21938
21916
  }
21939
21917
  );
21940
- server.tool(
21918
+ server.registerTool(
21941
21919
  "debug_replay_dead_letter",
21942
- "Request a HITL-gated REPLAY of ONE dead-lettered inbound \u2014 re-inject a customer message that was parked on the host (listed by debug_inspect_dead_letters) back into the agent's live inbound so it is reprocessed. This is the inverse of clear_pending_inbound: use it to recover a message a wedged agent missed. A HUMAN must approve in Slack before anything happens, and only if writes are armed (shadow mode runs the approval but executes nothing). The marker is matched on the host by the exact (channel, store, marker_name) you pass \u2014 copy them verbatim from the inspect result \u2014 so a stale or wrong selector safely no-ops (`replayed:false, reason:not_found`) rather than moving the wrong message. Async: returns { request_id, status, write_mode, notification_status }; after approval, poll check_action_status (result_payload carries { replayed, moved_to }). Pass { target_agent_id, channel, store, marker_name, reason }.",
21943
- replayDeadLetterSchema.shape,
21920
+ { description: "Request a HITL-gated REPLAY of ONE dead-lettered inbound \u2014 re-inject a customer message that was parked on the host (listed by debug_inspect_dead_letters) back into the agent's live inbound so it is reprocessed. This is the inverse of clear_pending_inbound: use it to recover a message a wedged agent missed. A HUMAN must approve in Slack before anything happens, and only if writes are armed (shadow mode runs the approval but executes nothing). The marker is matched on the host by the exact (channel, store, marker_name) you pass \u2014 copy them verbatim from the inspect result \u2014 so a stale or wrong selector safely no-ops (`replayed:false, reason:not_found`) rather than moving the wrong message. Async: returns { request_id, status, write_mode, notification_status }; after approval, poll check_action_status (result_payload carries { replayed, moved_to }). Pass { target_agent_id, channel, store, marker_name, reason }.", inputSchema: replayDeadLetterSchema },
21944
21921
  async (args) => {
21945
21922
  try {
21946
21923
  const result = await client.requestReplayDeadLetter({
@@ -21956,10 +21933,9 @@ server.tool(
21956
21933
  }
21957
21934
  }
21958
21935
  );
21959
- server.tool(
21936
+ server.registerTool(
21960
21937
  "check_action_status",
21961
- "Poll the decision on a remedial action you requested (the approval result is also pushed to you via direct-chat). Returns { status, result_payload, denial_reason, resolved_at } \u2014 for an approved request_ssm_run, result_payload carries the command output; for debug_replay_dead_letter, result_payload carries { replayed, moved_to }. Pass { request_id }.",
21962
- checkActionStatusSchema.shape,
21938
+ { description: "Poll the decision on a remedial action you requested (the approval result is also pushed to you via direct-chat). Returns { status, result_payload, denial_reason, resolved_at } \u2014 for an approved request_ssm_run, result_payload carries the command output; for debug_replay_dead_letter, result_payload carries { replayed, moved_to }. Pass { request_id }.", inputSchema: checkActionStatusSchema },
21963
21939
  async (args) => {
21964
21940
  try {
21965
21941
  const result = await client.getActionStatus(args.request_id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.625",
3
+ "version": "0.28.626",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {