@integrity-labs/agt-cli 0.28.1078 → 0.28.1080

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,12 +40,12 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-R5IN7H32.js";
43
+ } from "../chunk-W4NEUOMU.js";
44
44
  import {
45
45
  getProjectDir,
46
46
  isSessionResumeDisabled,
47
47
  readDirectChatSessionState
48
- } from "../chunk-PJWMW6ET.js";
48
+ } from "../chunk-SREQF7XT.js";
49
49
  import {
50
50
  AnchorSessionClient,
51
51
  CHANNEL_REGISTRY,
@@ -79,7 +79,7 @@ import {
79
79
  serializeManifestForSlackCli,
80
80
  sessionFileExists,
81
81
  sessionTranscriptDir
82
- } from "../chunk-UDJINPUK.js";
82
+ } from "../chunk-7F2UFKYG.js";
83
83
  import "../chunk-OCMJ5E6J.js";
84
84
  import "../chunk-XWVM4KPK.js";
85
85
  import "../chunk-EL5MWGGH.js";
@@ -5474,7 +5474,7 @@ import { execFileSync, execSync } from "child_process";
5474
5474
  import { existsSync as existsSync11, realpathSync as realpathSync2 } from "fs";
5475
5475
  import chalk18 from "chalk";
5476
5476
  import ora16 from "ora";
5477
- var cliVersion = true ? "0.28.1078" : "dev";
5477
+ var cliVersion = true ? "0.28.1080" : "dev";
5478
5478
  async function fetchLatestVersion() {
5479
5479
  const host2 = getHost();
5480
5480
  if (!host2) return null;
@@ -6734,7 +6734,7 @@ function handleError(err) {
6734
6734
  }
6735
6735
 
6736
6736
  // src/bin/agt.ts
6737
- var cliVersion2 = true ? "0.28.1078" : "dev";
6737
+ var cliVersion2 = true ? "0.28.1080" : "dev";
6738
6738
  var program = new Command();
6739
6739
  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");
6740
6740
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -1225,16 +1225,18 @@ var REQUIRE_APPROVAL_HOW = {
1225
1225
  ` with the request_id and act only once it is approved; if it is denied or expires, do`,
1226
1226
  ` not act, and tell the user. Never just say you are waiting for, or cannot reach, your`,
1227
1227
  ` manager without filing the request. If \`request_approval\` fails, say so and leave the`,
1228
- ` action undone. For an email, pass \`detail.email\` = { to, from, subject } so your`,
1229
- ` manager sees who it goes to.`
1228
+ ` action undone.`
1230
1229
  ],
1231
1230
  warn: [
1232
1231
  ` When one of these actions is not clearly justified, ask rather than decline: call`,
1233
1232
  ` \`request_approval\` (it goes to your manager), end your turn, and act only once`,
1234
- ` \`check_approval\` says it is approved. For an email, pass \`detail.email\` =`,
1235
- ` { to, from, subject }.`
1233
+ ` \`check_approval\` says it is approved.`
1236
1234
  ]
1237
1235
  };
1236
+ var REQUIRE_APPROVAL_EMAIL_DETAIL = [
1237
+ ` For an email, pass \`detail.email\` = { to, from, subject } so your manager sees who it`,
1238
+ ` goes to.`
1239
+ ];
1238
1240
  var REQUIRE_APPROVAL_EMAIL_ACTION = "send_email";
1239
1241
  var EMAIL_REQUIRE_APPROVAL_DEF = "email.require_approval";
1240
1242
  function liveEmailHoldActions(guardrails) {
@@ -1245,13 +1247,34 @@ function liveEmailHoldActions(guardrails) {
1245
1247
  const covered = Array.isArray(raw) ? raw.filter((a) => typeof a === "string" && a.trim() !== "") : [];
1246
1248
  return covered.length > 0 ? covered : null;
1247
1249
  }
1250
+ function liveDomainHold(guardrails) {
1251
+ const g = guardrails.find((x) => x.definitionId === EMAIL_DOMAIN_RESTRICT_DEF);
1252
+ const config = g?.config ?? {};
1253
+ if (!g || g.enforcement !== "enforce" || config.stage !== "require_approval" || config.approval_live !== true)
1254
+ return null;
1255
+ const raw = config.approval_covered_actions;
1256
+ const covered = Array.isArray(raw) ? raw.filter((a) => typeof a === "string" && a.trim() !== "") : [];
1257
+ return covered.length > 0 ? { covered } : null;
1258
+ }
1259
+ function requireApprovalDomainHoldException(covered) {
1260
+ const tools = ` sent with ${covered.map((a) => `\`${a}\``).join(", ")}`;
1261
+ return [
1262
+ ` Except \`${REQUIRE_APPROVAL_EMAIL_ACTION}\`${tools} to a domain the Email Domain Restriction does not allow:`,
1263
+ ` that restriction holds those sends for a human, so do not call \`request_approval\` and do`,
1264
+ ` not decline on this guardrail's basis. Attempt the send and let that hold decide; asking`,
1265
+ ` first would make your manager approve the same email twice. An email to an allowed domain,`,
1266
+ ` or sent any other way, is not held: ask first with \`request_approval\`, and when you do, pass`,
1267
+ ` \`detail.email\` = { to, from, subject } so your manager sees who it goes to.`
1268
+ ];
1269
+ }
1248
1270
  function requireApprovalEmailException(covered) {
1249
1271
  return [
1250
1272
  ` Except \`${REQUIRE_APPROVAL_EMAIL_ACTION}\` with ${covered.map((a) => `\`${a}\``).join(", ")}: your organization's`,
1251
1273
  ` email approval hold puts every such send in front of a human, so for those do not call`,
1252
1274
  ` \`request_approval\` and do not decline on this guardrail's basis. Attempt the send and let`,
1253
1275
  ` that hold decide; asking first would make your manager approve the same email twice. Any`,
1254
- ` other way of sending email is not held: ask first with \`request_approval\`.`
1276
+ ` other way of sending email is not held: ask first with \`request_approval\`, and when you`,
1277
+ ` do, pass \`detail.email\` = { to, from, subject } so your manager sees who it goes to.`
1255
1278
  ];
1256
1279
  }
1257
1280
  function requireApprovalActions(config) {
@@ -1261,14 +1284,19 @@ function requireApprovalActions(config) {
1261
1284
  const actions = raw.filter((a) => typeof a === "string" && a.trim() !== "").map((a) => a.trim());
1262
1285
  return actions.length > 0 ? actions : null;
1263
1286
  }
1264
- function requireApprovalHowLines(g, level, emailHold) {
1287
+ function requireApprovalHowLines(g, level, holds) {
1288
+ const emailHold = holds.requireApproval;
1289
+ const domainHold = emailHold === null ? holds.domain : null;
1265
1290
  const actions = requireApprovalActions(g.config);
1266
1291
  const namesEmail = actions === null || actions.includes(REQUIRE_APPROVAL_EMAIL_ACTION);
1267
1292
  const namesOther = actions === null || actions.some((a) => a !== REQUIRE_APPROVAL_EMAIL_ACTION);
1268
- const ask = namesOther || namesEmail && emailHold === null;
1293
+ const asksAboutEmail = namesEmail && emailHold === null && domainHold === null;
1294
+ const ask = namesOther || asksAboutEmail || namesEmail && domainHold !== null;
1269
1295
  return [
1270
1296
  ...ask ? REQUIRE_APPROVAL_HOW[level] : [],
1271
- ...namesEmail && emailHold !== null ? requireApprovalEmailException(emailHold) : []
1297
+ ...asksAboutEmail ? REQUIRE_APPROVAL_EMAIL_DETAIL : [],
1298
+ ...namesEmail && emailHold !== null ? requireApprovalEmailException(emailHold) : [],
1299
+ ...namesEmail && domainHold !== null ? requireApprovalDomainHoldException(domainHold.covered) : []
1272
1300
  ];
1273
1301
  }
1274
1302
  function renderAdvisoryGuardrailBullet(g, emailHold) {
@@ -1380,7 +1408,7 @@ function buildGuardrailsSection(guardrails) {
1380
1408
  }
1381
1409
  if (advisory.length > 0) {
1382
1410
  blocks.push(``, `### Advisory (policy only \u2014 not enforced by the platform)`, ``, `Follow these as operator instructions, at the level each one states (it`, `replaces the refuse-by-default rule above). No platform control backs them, so`, `never say an action was blocked, held for approval, or audited on their`, `basis \u2014 if you decline, say so and why.`, ``);
1383
- const emailHold = liveEmailHoldActions(active);
1411
+ const emailHold = { requireApproval: liveEmailHoldActions(active), domain: liveDomainHold(guardrails) };
1384
1412
  blocks.push(advisory.map((g) => renderAdvisoryGuardrailBullet(g, emailHold)).join("\n"));
1385
1413
  }
1386
1414
  if (overridden.length > 0) {
@@ -5710,6 +5738,36 @@ var FLAG_REGISTRY = [
5710
5738
  // wearing a precise number, which is the failure this field invites.
5711
5739
  since: "0.28.618"
5712
5740
  },
5741
+ {
5742
+ key: "block-self-serve-org-creation",
5743
+ description: "Invite-only onboarding (ENG-11305): refuse self-serve organization creation. On: the signup trigger and /auth/ensure-person create no organization for a new account, POST /organizations returns 403, and the user is told organizations are by invitation. Still allowed: accepting an invitation, and staff organization creation - NOTHING else. A company-domain signup is no longer auto-joined to any existing organization: no signal available here proves domain ownership (a slug is not a domain, and organization_email_domains.verified_at is self-asserted by any org admin), so an invitation is the only door. Existing organizations are untouched. STAGE-WIDE ONLY: it is read inside Postgres (`self_serve_org_creation_blocked`), which sees only the stage value, never an org override - there is no org yet. Turn it OFF here to reopen self-serve signup.",
5744
+ flagType: "boolean",
5745
+ // Ships ARMED (ENG-11305): the block is the point, and a dark default is a
5746
+ // control that is "Done" and never in force. This literal is duplicated as
5747
+ // the fallback inside self_serve_org_creation_blocked() (SQL cannot see the
5748
+ // registry); eng-11305-self-serve-org-block.test.ts asserts they agree. No
5749
+ // envVar on purpose: TS honours env first and SQL cannot see it, so the two
5750
+ // halves of the gate would disagree on any host that set one.
5751
+ defaultValue: true,
5752
+ // An org override is meaningless here (no org exists when this evaluates)
5753
+ // and is ignored by the SQL half; stop org admins setting one that would
5754
+ // read as if it did something.
5755
+ platformAdminOnly: true,
5756
+ // ADR-0022 §4, CodeRabbit on #6733. `platformAdminOnly` answers WHO may
5757
+ // change this; it does not make changing it deliberate. Turning this flag
5758
+ // OFF reopens self-serve organization creation fleet-wide — every new org
5759
+ // carries the default comp subscription and can provision managed hosts —
5760
+ // and it is a single toggle on a list of toggles, with no org-level blast
5761
+ // radius to make anyone hesitate. `sensitive` is what forces the
5762
+ // confirmation: `isSensitiveFlag` gates the API mutation on an explicit
5763
+ // `confirm: true` (`routes/flags.ts:487`) and on `?confirm=true` for an
5764
+ // override removal (`:360`), and the admin page routes it through a
5765
+ // confirm modal rather than an inline write (`page.tsx:179`).
5766
+ //
5767
+ // This rolls FLAGS_SCHEMA_VERSION, which is expected: `sensitive` is part
5768
+ // of the structural projection (`schema-version.ts:37`).
5769
+ sensitive: true
5770
+ },
5713
5771
  {
5714
5772
  key: "agent-hours-billing-enabled",
5715
5773
  description: "Agent-hours (utilisation) billing (ENG-7910). Per-org gate; ships dark. When on for an org, its closed billing periods are settled into org_agent_hours_settlements from the plan/override agent-hours terms, and the customer billing surface shows used-vs-included hours + projected overage. Off = no settlement written, no charge, surface hidden. Launch prices are seeded in plan_billing_terms; flip on per-org for a controlled rollout.",
@@ -7153,6 +7211,17 @@ var FLAG_REGISTRY = [
7153
7211
  // It widens who may DECIDE an approval, so it is a control, not a display toggle.
7154
7212
  sensitive: true
7155
7213
  },
7214
+ {
7215
+ key: "approval-unified-authority",
7216
+ description: "One authority check for every approval ingress (ENG-11207, ADR-0124 Phase 0b): canDecide() runs inside tryDispatchApprovalCore for console, Slack (channel, alerts, Socket Mode, which also carries Telegram) and Direct Chat taps alike. off = not computed. shadow = compute the verdict and log approval_authority_would_reject (ingress, verb, org, reason) for every tap it would refuse, then decide exactly as today. enforce = reserved for the per-(org, verb) allowlist slice; until that ships it behaves as shadow. Evaluated per-org. Ships dark.",
7217
+ flagType: "enum",
7218
+ allowedValues: ["off", "shadow", "enforce"],
7219
+ // Safe/default value is `off` (no computation, no extra reads on the tap path). A flag-DB read
7220
+ // error degrades to this, so an outage can never change who may decide.
7221
+ defaultValue: "off",
7222
+ // Its enforce value will refuse approvals, so mutating it is worth confirming.
7223
+ sensitive: true
7224
+ },
7156
7225
  {
7157
7226
  key: "slack-reply-binding",
7158
7227
  description: "Slack reply-target binding (ENG-7396 / WS2, cross-thread reply routing): the model names which inbound it answers (inbound_id) and the server resolves the destination from its own verified record. shadow = classify + count only, routing unchanged; warn = same routing plus a tool-result note so the model self-corrects; enforce = route a bound reply to the registry thread and REJECT a reply whose target matches no inbound this process delivered. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_SLACK_REPLY_BINDING spawn env (the operator/canary override, ADR-0022). Ships shadow.",
@@ -13088,6 +13157,11 @@ var QUOTA_EXHAUSTED_ERROR_PATTERNS = [
13088
13157
  "usage limit",
13089
13158
  "daily limit exceeded"
13090
13159
  ];
13160
+ var PROVIDER_ACCESS_BLOCKED_ERROR_PATTERNS = [
13161
+ "api access blocked",
13162
+ "api access has been blocked",
13163
+ "api access is blocked"
13164
+ ];
13091
13165
  function isReadonlyToolDescriptor(t) {
13092
13166
  if (!t?.name)
13093
13167
  return false;
@@ -13180,6 +13254,10 @@ function formatRetryWindow(seconds) {
13180
13254
  return `about ${Math.round(hours * 10) / 10} hours`;
13181
13255
  return `about ${Math.round(hours / 24 * 10) / 10} days`;
13182
13256
  }
13257
+ function isProviderAccessBlockedError(message) {
13258
+ const m = message.toLowerCase();
13259
+ return PROVIDER_ACCESS_BLOCKED_ERROR_PATTERNS.some((p2) => m.includes(p2));
13260
+ }
13183
13261
  function classifyToolCallFailure(text) {
13184
13262
  if (isAccountResolutionError(text))
13185
13263
  return "account";
@@ -13187,6 +13265,8 @@ function classifyToolCallFailure(text) {
13187
13265
  return "quota";
13188
13266
  if (isScopeDeficitError(text))
13189
13267
  return "scope";
13268
+ if (isProviderAccessBlockedError(text))
13269
+ return "blocked";
13190
13270
  if (isUpstreamAuthError(text))
13191
13271
  return "auth";
13192
13272
  if (isSiteResolutionError(text))
@@ -13339,6 +13419,13 @@ async function probeComposioMcpToolCall(config, fetchImpl = fetch) {
13339
13419
  details: { ...baseDetails, reason: "upstream_auth_rejected" }
13340
13420
  };
13341
13421
  }
13422
+ if (kind === "blocked") {
13423
+ return {
13424
+ status: "degraded",
13425
+ message: `Live tool call '${toolName}' reached the provider, which refused API access for this connection's account or app. The credential itself was accepted, so reconnecting alone will not fix it: check that the connecting user still has a role on the account and that the account is not restricted with the provider, then reconnect: ${snippet}`,
13426
+ details: { ...baseDetails, reason: "provider_access_blocked" }
13427
+ };
13428
+ }
13342
13429
  if (kind === "site") {
13343
13430
  return {
13344
13431
  status: "down",
@@ -13346,6 +13433,13 @@ async function probeComposioMcpToolCall(config, fetchImpl = fetch) {
13346
13433
  details: { ...baseDetails, reason: "site_unresolved" }
13347
13434
  };
13348
13435
  }
13436
+ if (resolved.requestedTool && !resolved.fallback && toolName === resolved.requestedTool) {
13437
+ return {
13438
+ status: "degraded",
13439
+ message: `Live tool call '${toolName}' (this integration's connectivity test) failed with an error the probe does not recognise, so the connection cannot be confirmed working: ${snippet}`,
13440
+ details: { ...baseDetails, reason: "connectivity_test_failed", tool_error: snippet }
13441
+ };
13442
+ }
13349
13443
  return {
13350
13444
  status: "ok",
13351
13445
  message: `Live tool call '${toolName}' resolved the account (tool error: ${snippet})`,
@@ -15354,27 +15448,21 @@ function isBareAck(text) {
15354
15448
  }
15355
15449
 
15356
15450
  // ../../packages/core/dist/conversations/metrics.js
15451
+ var DAY_MS2 = 24 * 60 * 60 * 1e3;
15452
+ var ALL_TIME_FLOOR_ISO = "2026-01-01T00:00:00.000Z";
15453
+ var ALL_TIME_FLOOR_MS = Date.parse(ALL_TIME_FLOOR_ISO);
15357
15454
  var PERIOD_CONFIG = {
15358
- "24h": { windowMs: 24 * 60 * 60 * 1e3, bucket: "hour" },
15359
- "7d": { windowMs: 7 * 24 * 60 * 60 * 1e3, bucket: "day" },
15360
- "30d": { windowMs: 30 * 24 * 60 * 60 * 1e3, bucket: "day" }
15455
+ "24h": { windowMs: DAY_MS2, bucket: "hour" },
15456
+ "7d": { windowMs: 7 * DAY_MS2, bucket: "day" },
15457
+ "30d": { windowMs: 30 * DAY_MS2, bucket: "day" },
15458
+ "90d": { windowMs: 90 * DAY_MS2, bucket: "day" },
15459
+ "180d": { windowMs: 180 * DAY_MS2, bucket: "day" },
15460
+ all: { windowMs: null, bucket: "day" }
15361
15461
  };
15362
15462
  var CONVERSATION_METRICS_PERIODS = Object.keys(PERIOD_CONFIG);
15363
15463
 
15364
15464
  // ../../packages/core/dist/conversations/eval-scores.js
15365
15465
  var EVAL_SCORE_MA_WINDOW_MS = 28 * 24 * 60 * 60 * 1e3;
15366
- var PERIOD_CONFIG2 = {
15367
- "24h": { windowMs: 24 * 60 * 60 * 1e3, bucket: "hour" },
15368
- "7d": { windowMs: 7 * 24 * 60 * 60 * 1e3, bucket: "day" },
15369
- "30d": { windowMs: 30 * 24 * 60 * 60 * 1e3, bucket: "day" }
15370
- };
15371
-
15372
- // ../../packages/core/dist/conversations/eval-failures.js
15373
- var PERIOD_WINDOW_MS = {
15374
- "24h": 24 * 60 * 60 * 1e3,
15375
- "7d": 7 * 24 * 60 * 60 * 1e3,
15376
- "30d": 30 * 24 * 60 * 60 * 1e3
15377
- };
15378
15466
 
15379
15467
  // ../../packages/core/dist/conversations/eval-failure-categories.js
15380
15468
  var CONVERSATION_FAILURE_CATEGORIES = [
@@ -15432,19 +15520,9 @@ function buildFailureCategoryPromptLines() {
15432
15520
  function isConversationFailureCategory(v) {
15433
15521
  return typeof v === "string" && CONVERSATION_FAILURE_CATEGORIES.includes(v);
15434
15522
  }
15435
- var PERIOD_WINDOW_MS2 = {
15436
- "24h": 24 * 60 * 60 * 1e3,
15437
- "7d": 7 * 24 * 60 * 60 * 1e3,
15438
- "30d": 30 * 24 * 60 * 60 * 1e3
15439
- };
15440
15523
 
15441
15524
  // ../../packages/core/dist/ratings/kanban-ratings.js
15442
15525
  var RATING_MA_WINDOW_MS = 28 * 24 * 60 * 60 * 1e3;
15443
- var PERIOD_CONFIG3 = {
15444
- "24h": { windowMs: 24 * 60 * 60 * 1e3, bucket: "hour" },
15445
- "7d": { windowMs: 7 * 24 * 60 * 60 * 1e3, bucket: "day" },
15446
- "30d": { windowMs: 30 * 24 * 60 * 60 * 1e3, bucket: "day" }
15447
- };
15448
15526
 
15449
15527
  // ../../packages/core/dist/triggers/registry.js
15450
15528
  var sources = /* @__PURE__ */ new Map();
@@ -16158,4 +16236,4 @@ export {
16158
16236
  peekCurrentSession,
16159
16237
  readDailySessionPin
16160
16238
  };
16161
- //# sourceMappingURL=chunk-UDJINPUK.js.map
16239
+ //# sourceMappingURL=chunk-7F2UFKYG.js.map