@integrity-labs/agt-cli 0.28.476 → 0.28.477

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.
@@ -30,7 +30,7 @@ import {
30
30
  resolveConnectivityProbe,
31
31
  worseConnectivityOutcome,
32
32
  wrapScheduledTaskPrompt
33
- } from "./chunk-Q6RVMDAC.js";
33
+ } from "./chunk-6GMNDBOU.js";
34
34
  import {
35
35
  parsePsRows
36
36
  } from "./chunk-XWVM4KPK.js";
@@ -4932,7 +4932,7 @@ function exchangeFailureKind(err) {
4932
4932
  }
4933
4933
 
4934
4934
  // src/lib/api-client.ts
4935
- var agtCliVersion = true ? "0.28.476" : "dev";
4935
+ var agtCliVersion = true ? "0.28.477" : "dev";
4936
4936
  var lastConfigHash = null;
4937
4937
  function setConfigHash(hash) {
4938
4938
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -7661,4 +7661,4 @@ export {
7661
7661
  managerInstallSystemUnitCommand,
7662
7662
  managerUninstallSystemUnitCommand
7663
7663
  };
7664
- //# sourceMappingURL=chunk-IGXBEU55.js.map
7664
+ //# sourceMappingURL=chunk-INPROLVI.js.map
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-QITF76DO.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-3DFUJUF2.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-DYLJU6EV.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-S7CBJ5ML.js.map
@@ -44,7 +44,7 @@ import {
44
44
  resolveEffectivePinRaw,
45
45
  safeWriteJsonAtomic,
46
46
  setConfigHash
47
- } from "../chunk-IGXBEU55.js";
47
+ } from "../chunk-INPROLVI.js";
48
48
  import {
49
49
  getProjectDir as getProjectDir2,
50
50
  getReadyTasks,
@@ -162,7 +162,7 @@ import {
162
162
  toOpencodeModel,
163
163
  transcriptActivityAgeSeconds,
164
164
  writeEgressAllowlist
165
- } from "../chunk-Q6RVMDAC.js";
165
+ } from "../chunk-6GMNDBOU.js";
166
166
  import {
167
167
  reapOrphanChannelMcps
168
168
  } from "../chunk-XWVM4KPK.js";
@@ -10057,7 +10057,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
10057
10057
  var lastVersionCheckAt = 0;
10058
10058
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
10059
10059
  var lastResponsivenessProbeAt = 0;
10060
- var agtCliVersion = true ? "0.28.476" : "dev";
10060
+ var agtCliVersion = true ? "0.28.477" : "dev";
10061
10061
  function resolveBrewPath(execFileSync2) {
10062
10062
  try {
10063
10063
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -11220,7 +11220,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
11220
11220
  if (codeNames.length === 0) return;
11221
11221
  void (async () => {
11222
11222
  try {
11223
- const { collectDiagnostics } = await import("../persistent-session-QITF76DO.js");
11223
+ const { collectDiagnostics } = await import("../persistent-session-3DFUJUF2.js");
11224
11224
  await api.post("/host/heartbeat", {
11225
11225
  host_id: hostId,
11226
11226
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor)
@@ -11327,7 +11327,7 @@ async function pollCycle() {
11327
11327
  }
11328
11328
  try {
11329
11329
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
11330
- const { collectDiagnostics } = await import("../persistent-session-QITF76DO.js");
11330
+ const { collectDiagnostics } = await import("../persistent-session-3DFUJUF2.js");
11331
11331
  const diagCodeNames = [...agentState.persistentSessionAgents];
11332
11332
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor) : void 0;
11333
11333
  let tailscaleHostname;
@@ -11441,7 +11441,7 @@ async function pollCycle() {
11441
11441
  collectResponsivenessProbes,
11442
11442
  collectPanelessActivityProbes,
11443
11443
  getResponsivenessIntervalMs
11444
- } = await import("../responsiveness-probe-BEA4J6IL.js");
11444
+ } = await import("../responsiveness-probe-QBKBBHYD.js");
11445
11445
  const probeIntervalMs = getResponsivenessIntervalMs();
11446
11446
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
11447
11447
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -11505,7 +11505,7 @@ async function pollCycle() {
11505
11505
  collectResponsivenessProbes,
11506
11506
  livePendingInboundOldestAgeSeconds,
11507
11507
  parkPendingInbound
11508
- } = await import("../responsiveness-probe-BEA4J6IL.js");
11508
+ } = await import("../responsiveness-probe-QBKBBHYD.js");
11509
11509
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
11510
11510
  const wedgeNow = /* @__PURE__ */ new Date();
11511
11511
  const liveAgents = agentState.persistentSessionAgents;
@@ -14981,7 +14981,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
14981
14981
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
14982
14982
  void (async () => {
14983
14983
  try {
14984
- const { collectDiagnostics } = await import("../persistent-session-QITF76DO.js");
14984
+ const { collectDiagnostics } = await import("../persistent-session-3DFUJUF2.js");
14985
14985
  await api.post("/host/heartbeat", {
14986
14986
  host_id: hostId,
14987
14987
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15031,7 +15031,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
15031
15031
  }
15032
15032
  try {
15033
15033
  const hostId = await getHostId();
15034
- const { collectDiagnostics } = await import("../persistent-session-QITF76DO.js");
15034
+ const { collectDiagnostics } = await import("../persistent-session-3DFUJUF2.js");
15035
15035
  await api.post("/host/heartbeat", {
15036
15036
  host_id: hostId,
15037
15037
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15489,7 +15489,7 @@ async function processClaudePairSessions(agents) {
15489
15489
  killPairSession,
15490
15490
  pairTmuxSession,
15491
15491
  finalizeClaudePairOnboarding
15492
- } = await import("../claude-pair-runtime-DYLJU6EV.js");
15492
+ } = await import("../claude-pair-runtime-S7CBJ5ML.js");
15493
15493
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
15494
15494
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
15495
15495
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -35287,6 +35287,18 @@ var FLAG_REGISTRY = [
35287
35287
  // the sidebar renders inside the active-org cookie's scope, which is exactly
35288
35288
  // the org whose brand should be shown.
35289
35289
  public: true
35290
+ },
35291
+ {
35292
+ key: "agent-recruit",
35293
+ description: "The `recruit_agent` MCP tool (ENG-8159): lets an ordinary managed agent PROPOSE a new teammate in its own org. The proposal is filed under the `agent.recruit` approval verb and routed to an org owner as a server-rendered card, so this gates the ASK \u2014 nothing is created until a human taps Approve. Deliberately distinct from augmented-support-writes, which gates the concierge's own create_agent surface: the two requesters are separately controllable because an org may well want its support concierge to propose agents without giving every agent in the fleet the same power. Ships dark.",
35294
+ flagType: "boolean",
35295
+ // Declared safe value is `false`. The write is human-gated either way, but an
35296
+ // unbounded ask is still an unbounded demand on an owner's attention, so the
35297
+ // fail-closed direction on a flag-DB fault is "an agent cannot ask".
35298
+ defaultValue: false,
35299
+ // Turning this on lets agents originate proposals that create customer
35300
+ // infrastructure once approved — same posture as augmented-support-writes.
35301
+ sensitive: true
35290
35302
  }
35291
35303
  ];
35292
35304
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
package/dist/mcp/index.js CHANGED
@@ -21357,6 +21357,64 @@ function describeFeatureRequestResult(resp) {
21357
21357
  };
21358
21358
  }
21359
21359
 
21360
+ // src/recruit-agent.ts
21361
+ function describeRecruitAgentResult(resp) {
21362
+ switch (resp.status) {
21363
+ case "proposed": {
21364
+ const name = resp.code_name ? `"${resp.code_name}"` : "the new agent";
21365
+ return {
21366
+ text: `Nothing has been created yet. Your request for ${name} was sent to an organization owner for approval` + (resp.expires_at ? ` and expires at ${resp.expires_at}` : "") + `.
21367
+
21368
+ ` + (resp.request_id ? `Check on it with check_approval using request_id "${resp.request_id}".
21369
+
21370
+ ` : "") + `Do NOT send this request again \u2014 a duplicate just puts a second card in front of the same person. Tell whoever asked that it is waiting on an owner's approval.`,
21371
+ isError: false
21372
+ };
21373
+ }
21374
+ case "feature_disabled":
21375
+ return {
21376
+ text: `${resp.message ?? "Recruiting teammates is not enabled for this organization."} This is a setting, not a fault \u2014 do not retry. Tell your operator what you need and why.`,
21377
+ isError: true
21378
+ };
21379
+ case "agent_limit_reached":
21380
+ return {
21381
+ text: `${resp.message ?? "Your organization's plan agent limit has been reached."} Retrying will not help: someone has to free a slot or upgrade the plan first.`,
21382
+ isError: true
21383
+ };
21384
+ case "name_reserved":
21385
+ return {
21386
+ text: `${resp.message ?? "That display name is reserved."} Pick a different display_name and try once more.`,
21387
+ isError: true
21388
+ };
21389
+ case "no_approver":
21390
+ return {
21391
+ text: `${resp.message ?? "No approval channel is configured for your organization."} Nothing was sent to anyone. Do not retry until an operator has set this up.`,
21392
+ isError: true
21393
+ };
21394
+ case "delivery_failed":
21395
+ return {
21396
+ text: `${resp.message ?? "The approval card could not be delivered."} The request was not left waiting \u2014 it has been closed, so a fresh attempt is needed once the messaging setup is fixed.`,
21397
+ isError: true
21398
+ };
21399
+ case "rate_limited": {
21400
+ const mins = resp.retry_after_seconds ? Math.ceil(resp.retry_after_seconds / 60) : null;
21401
+ return {
21402
+ text: (
21403
+ // Relay the server's own wording like every other branch does; it can
21404
+ // carry a specific quota detail the generic sentence would drop.
21405
+ `${resp.message ?? "Too many pending recruit proposals"}${mins ? ` Try again in about ${mins} minutes.` : ""} This limit exists to protect the person who has to read these \u2014 do not work around it.`
21406
+ ),
21407
+ isError: true
21408
+ };
21409
+ }
21410
+ default:
21411
+ return {
21412
+ text: `Could not request a new teammate${resp.message ? `: ${resp.message}` : ""}. Nothing was created and nobody was asked. Fix what the message describes, or tell your operator \u2014 don't keep retrying.`,
21413
+ isError: true
21414
+ };
21415
+ }
21416
+ }
21417
+
21360
21418
  // src/request-reconnect.ts
21361
21419
  function describeReconnectRequestResult(resp) {
21362
21420
  switch (resp.status) {
@@ -22541,6 +22599,62 @@ server.tool(
22541
22599
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
22542
22600
  }
22543
22601
  );
22602
+ server.tool(
22603
+ "recruit_agent",
22604
+ "Propose a NEW teammate agent for your organization when the work in front of you genuinely needs a different agent \u2014 a distinct role, a separate remit, or capacity you cannot cover yourself. This does NOT create anything: it sends a request to an organization owner, who approves or denies it. Use it sparingly and only when you can say concretely what the new agent is for; do not use it to duplicate yourself, to get around a tool you are missing (use request_feature), or because a single task is large. After calling this, stop and report that it is awaiting approval \u2014 poll with check_approval if you need the outcome.",
22605
+ {
22606
+ code_name: external_exports.string().min(1).max(64).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, "code_name must be kebab-case").describe(
22607
+ 'kebab-case identifier for the proposed agent (lowercase, hyphen-separated), e.g. "invoice-helper". If the name is already taken in your team a numeric suffix is added automatically.'
22608
+ ),
22609
+ display_name: external_exports.string().min(1).max(120).describe('Human-facing name for the proposed agent, e.g. "Invoice Helper".'),
22610
+ description: external_exports.string().min(20).max(2e3).describe(
22611
+ "What this teammate is FOR: its remit, the work it would take on, and why that work needs a separate agent. A human reads this to decide \u2014 be specific and honest. Vague descriptions get denied."
22612
+ ),
22613
+ role: external_exports.string().max(200).optional().describe('Optional short role label for the proposed agent, e.g. "Accounts receivable".'),
22614
+ reason: external_exports.string().max(1e3).optional().describe(
22615
+ "Optional context for the approver: what prompted this now (a spike in volume, a user request, a gap you keep hitting). Shown as context only \u2014 the decision is made on the description above."
22616
+ ),
22617
+ host_id: external_exports.string().uuid().optional().describe(
22618
+ "Optional host (UUID) to place the new agent on. Omit unless you have a specific reason \u2014 it defaults to your own host."
22619
+ )
22620
+ },
22621
+ async (params) => {
22622
+ if (!AGT_AGENT_CODE_NAME) {
22623
+ return {
22624
+ content: [{ type: "text", text: "Error: AGT_AGENT_CODE_NAME not configured." }],
22625
+ isError: true
22626
+ };
22627
+ }
22628
+ let resp;
22629
+ try {
22630
+ resp = await apiPost("/host/recruit-agent", {
22631
+ agent_code_name: AGT_AGENT_CODE_NAME,
22632
+ code_name: params.code_name,
22633
+ display_name: params.display_name,
22634
+ description: params.description,
22635
+ ...params.role ? { role: params.role } : {},
22636
+ ...params.reason ? { reason: params.reason } : {},
22637
+ ...params.host_id ? { host_id: params.host_id } : {}
22638
+ });
22639
+ } catch (err) {
22640
+ process.stderr.write(
22641
+ `recruit_agent: POST /host/recruit-agent failed: ${err instanceof Error ? err.message : String(err)}
22642
+ `
22643
+ );
22644
+ return {
22645
+ content: [
22646
+ {
22647
+ type: "text",
22648
+ text: "Could not reach the recruiting service. It is not known whether the request was filed \u2014 do not send it again; tell your operator to check the logs."
22649
+ }
22650
+ ],
22651
+ isError: true
22652
+ };
22653
+ }
22654
+ const { text, isError } = describeRecruitAgentResult(resp);
22655
+ return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
22656
+ }
22657
+ );
22544
22658
  server.tool(
22545
22659
  "request_reconnect",
22546
22660
  'Ask for one of YOUR OWN integrations to be reconnected when its tools fail with authentication/authorization errors (expired or revoked credentials, "needs re-auth", 401/403 from the provider). This notifies your human manager with a reconnect link \u2014 you cannot re-auth an integration yourself. Use it once per failing integration instead of retrying the failing tool; do NOT use it for tools you never had, for transient errors (timeouts, rate limits), or to request new integrations (use request_feature for that).',
@@ -23916,6 +24030,10 @@ var LOCAL_TOOL_NAMES = /* @__PURE__ */ new Set([
23916
24030
  // ENG-7495: agent-requested integration reconnect (always registered). No
23917
24031
  // API tool shares this name; listed here to keep the lockstep guard green.
23918
24032
  "request_reconnect",
24033
+ // ENG-8159: propose a new teammate (always registered — the gate is the
24034
+ // server-side org-scoped agent-recruit flag, see the registration comment).
24035
+ // No API tool shares this name; listed here to keep the lockstep guard green.
24036
+ "recruit_agent",
23919
24037
  // ENG-6686: self-service identity edit (always registered). Listed here to
23920
24038
  // keep the lockstep guard green; no API tool shares this name.
23921
24039
  "update_identity",
@@ -41234,6 +41234,18 @@ var FLAG_REGISTRY = [
41234
41234
  // the sidebar renders inside the active-org cookie's scope, which is exactly
41235
41235
  // the org whose brand should be shown.
41236
41236
  public: true
41237
+ },
41238
+ {
41239
+ key: "agent-recruit",
41240
+ description: "The `recruit_agent` MCP tool (ENG-8159): lets an ordinary managed agent PROPOSE a new teammate in its own org. The proposal is filed under the `agent.recruit` approval verb and routed to an org owner as a server-rendered card, so this gates the ASK \u2014 nothing is created until a human taps Approve. Deliberately distinct from augmented-support-writes, which gates the concierge's own create_agent surface: the two requesters are separately controllable because an org may well want its support concierge to propose agents without giving every agent in the fleet the same power. Ships dark.",
41241
+ flagType: "boolean",
41242
+ // Declared safe value is `false`. The write is human-gated either way, but an
41243
+ // unbounded ask is still an unbounded demand on an owner's attention, so the
41244
+ // fail-closed direction on a flag-DB fault is "an agent cannot ask".
41245
+ defaultValue: false,
41246
+ // Turning this on lets agents originate proposals that create customer
41247
+ // infrastructure once approved — same posture as augmented-support-writes.
41248
+ sensitive: true
41237
41249
  }
41238
41250
  ];
41239
41251
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -35512,6 +35512,18 @@ var FLAG_REGISTRY = [
35512
35512
  // the sidebar renders inside the active-org cookie's scope, which is exactly
35513
35513
  // the org whose brand should be shown.
35514
35514
  public: true
35515
+ },
35516
+ {
35517
+ key: "agent-recruit",
35518
+ description: "The `recruit_agent` MCP tool (ENG-8159): lets an ordinary managed agent PROPOSE a new teammate in its own org. The proposal is filed under the `agent.recruit` approval verb and routed to an org owner as a server-rendered card, so this gates the ASK \u2014 nothing is created until a human taps Approve. Deliberately distinct from augmented-support-writes, which gates the concierge's own create_agent surface: the two requesters are separately controllable because an org may well want its support concierge to propose agents without giving every agent in the fleet the same power. Ships dark.",
35519
+ flagType: "boolean",
35520
+ // Declared safe value is `false`. The write is human-gated either way, but an
35521
+ // unbounded ask is still an unbounded demand on an owner's attention, so the
35522
+ // fail-closed direction on a flag-DB fault is "an agent cannot ask".
35523
+ defaultValue: false,
35524
+ // Turning this on lets agents originate proposals that create customer
35525
+ // infrastructure once approved — same posture as augmented-support-writes.
35526
+ sensitive: true
35515
35527
  }
35516
35528
  ];
35517
35529
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -35838,6 +35838,18 @@ var FLAG_REGISTRY = [
35838
35838
  // the sidebar renders inside the active-org cookie's scope, which is exactly
35839
35839
  // the org whose brand should be shown.
35840
35840
  public: true
35841
+ },
35842
+ {
35843
+ key: "agent-recruit",
35844
+ description: "The `recruit_agent` MCP tool (ENG-8159): lets an ordinary managed agent PROPOSE a new teammate in its own org. The proposal is filed under the `agent.recruit` approval verb and routed to an org owner as a server-rendered card, so this gates the ASK \u2014 nothing is created until a human taps Approve. Deliberately distinct from augmented-support-writes, which gates the concierge's own create_agent surface: the two requesters are separately controllable because an org may well want its support concierge to propose agents without giving every agent in the fleet the same power. Ships dark.",
35845
+ flagType: "boolean",
35846
+ // Declared safe value is `false`. The write is human-gated either way, but an
35847
+ // unbounded ask is still an unbounded demand on an owner's attention, so the
35848
+ // fail-closed direction on a flag-DB fault is "an agent cannot ask".
35849
+ defaultValue: false,
35850
+ // Turning this on lets agents originate proposals that create customer
35851
+ // infrastructure once approved — same posture as augmented-support-writes.
35852
+ sensitive: true
35841
35853
  }
35842
35854
  ];
35843
35855
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -36,7 +36,7 @@ import {
36
36
  writeDirectChatSessionState,
37
37
  writeEgressAllowlist,
38
38
  writePersistentClaudeWrapper
39
- } from "./chunk-Q6RVMDAC.js";
39
+ } from "./chunk-6GMNDBOU.js";
40
40
  import "./chunk-XWVM4KPK.js";
41
41
  export {
42
42
  EGRESS_BASELINE_DOMAINS,
@@ -77,4 +77,4 @@ export {
77
77
  writeEgressAllowlist,
78
78
  writePersistentClaudeWrapper
79
79
  };
80
- //# sourceMappingURL=persistent-session-QITF76DO.js.map
80
+ //# sourceMappingURL=persistent-session-3DFUJUF2.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-Q6RVMDAC.js";
3
+ } from "./chunk-6GMNDBOU.js";
4
4
  import "./chunk-XWVM4KPK.js";
5
5
 
6
6
  // src/lib/responsiveness-probe.ts
@@ -596,4 +596,4 @@ export {
596
596
  readAndResetSlackReplyBindingClassifications,
597
597
  readAndResetSlackReplyTargetClassifications
598
598
  };
599
- //# sourceMappingURL=responsiveness-probe-BEA4J6IL.js.map
599
+ //# sourceMappingURL=responsiveness-probe-QBKBBHYD.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.476",
3
+ "version": "0.28.477",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {