@integrity-labs/agt-cli 0.28.220 → 0.28.221

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
@@ -38,7 +38,7 @@ import {
38
38
  success,
39
39
  table,
40
40
  warn
41
- } from "../chunk-QLNXRQAV.js";
41
+ } from "../chunk-SMV5PL54.js";
42
42
  import {
43
43
  CHANNEL_REGISTRY,
44
44
  DEFAULT_FRAMEWORK,
@@ -4826,7 +4826,7 @@ import { execFileSync, execSync } from "child_process";
4826
4826
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4827
4827
  import chalk18 from "chalk";
4828
4828
  import ora16 from "ora";
4829
- var cliVersion = true ? "0.28.220" : "dev";
4829
+ var cliVersion = true ? "0.28.221" : "dev";
4830
4830
  async function fetchLatestVersion() {
4831
4831
  const host2 = getHost();
4832
4832
  if (!host2) return null;
@@ -5840,7 +5840,7 @@ function handleError(err) {
5840
5840
  }
5841
5841
 
5842
5842
  // src/bin/agt.ts
5843
- var cliVersion2 = true ? "0.28.220" : "dev";
5843
+ var cliVersion2 = true ? "0.28.221" : "dev";
5844
5844
  var program = new Command();
5845
5845
  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");
5846
5846
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -5529,7 +5529,7 @@ function requireHost() {
5529
5529
  }
5530
5530
 
5531
5531
  // src/lib/api-client.ts
5532
- var agtCliVersion = true ? "0.28.220" : "dev";
5532
+ var agtCliVersion = true ? "0.28.221" : "dev";
5533
5533
  var lastConfigHash = null;
5534
5534
  function setConfigHash(hash) {
5535
5535
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -7581,4 +7581,4 @@ export {
7581
7581
  managerInstallSystemUnitCommand,
7582
7582
  managerUninstallSystemUnitCommand
7583
7583
  };
7584
- //# sourceMappingURL=chunk-QLNXRQAV.js.map
7584
+ //# sourceMappingURL=chunk-SMV5PL54.js.map
@@ -36,7 +36,7 @@ import {
36
36
  requireHost,
37
37
  safeWriteJsonAtomic,
38
38
  setConfigHash
39
- } from "../chunk-QLNXRQAV.js";
39
+ } from "../chunk-SMV5PL54.js";
40
40
  import {
41
41
  getProjectDir as getProjectDir2,
42
42
  getReadyTasks,
@@ -6224,7 +6224,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6224
6224
  var lastVersionCheckAt = 0;
6225
6225
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6226
6226
  var lastResponsivenessProbeAt = 0;
6227
- var agtCliVersion = true ? "0.28.220" : "dev";
6227
+ var agtCliVersion = true ? "0.28.221" : "dev";
6228
6228
  function resolveBrewPath(execFileSync2) {
6229
6229
  try {
6230
6230
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14303,7 +14303,16 @@ function readLockHolder(path) {
14303
14303
  // src/direct-chat-channel.ts
14304
14304
  import { homedir as homedir2 } from "os";
14305
14305
  import { join as join5 } from "path";
14306
- import { watch, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
14306
+ import { randomUUID } from "crypto";
14307
+ import {
14308
+ watch,
14309
+ mkdirSync as mkdirSync3,
14310
+ writeFileSync as writeFileSync3,
14311
+ readFileSync as readFileSync4,
14312
+ existsSync as existsSync4,
14313
+ renameSync as renameSync3,
14314
+ unlinkSync as unlinkSync2
14315
+ } from "fs";
14307
14316
 
14308
14317
  // src/direct-chat-inbound-attachments.ts
14309
14318
  import { dirname as dirname2, join as join3 } from "path";
@@ -14492,6 +14501,215 @@ function computeStreamSlices(content, config2 = DEFAULT_STREAM_SLICE_CONFIG) {
14492
14501
  return slices;
14493
14502
  }
14494
14503
 
14504
+ // src/channel-progress.ts
14505
+ function channelLiveProgressEnabled() {
14506
+ return resolveHostBooleanFlag({
14507
+ key: "channel-live-progress",
14508
+ envVar: "AGT_CHANNEL_PROGRESS_ENABLED",
14509
+ defaultValue: false
14510
+ });
14511
+ }
14512
+ function decideProgressAction(input) {
14513
+ const { now, heartbeat, target, tracked, freshnessMs, minPendingMs } = input;
14514
+ const fresh = heartbeat != null && now - heartbeat.updatedAtMs <= freshnessMs;
14515
+ const active = target != null && fresh;
14516
+ if (active && input.targetHasCard === true) {
14517
+ if (tracked) {
14518
+ return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
14519
+ }
14520
+ return { type: "none" };
14521
+ }
14522
+ if (!active) {
14523
+ if (tracked) {
14524
+ return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
14525
+ }
14526
+ return { type: "none" };
14527
+ }
14528
+ const t = target;
14529
+ const hb = heartbeat;
14530
+ if (tracked && (tracked.threadTs !== t.threadTs || tracked.channel !== t.channel)) {
14531
+ return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
14532
+ }
14533
+ if (!tracked) {
14534
+ if (now - t.receivedAtMs < minPendingMs) return { type: "none" };
14535
+ return { type: "post", channel: t.channel, threadTs: t.threadTs, step: hb.step };
14536
+ }
14537
+ if (hb.step !== tracked.lastStep) {
14538
+ return { type: "update", channel: t.channel, threadTs: t.threadTs, ts: tracked.ts, step: hb.step };
14539
+ }
14540
+ return { type: "none" };
14541
+ }
14542
+ function progressHeartbeatFreshMs() {
14543
+ const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_FRESH_MS ?? "", 10);
14544
+ return Number.isFinite(raw) && raw > 0 ? raw : 45e3;
14545
+ }
14546
+ function progressMinPendingMs() {
14547
+ const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_MIN_PENDING_MS ?? "", 10);
14548
+ return Number.isFinite(raw) && raw > 0 ? raw : 12e3;
14549
+ }
14550
+ function composeProgressBody(step) {
14551
+ const s = (step ?? "").trim();
14552
+ if (!s) return "Working\u2026";
14553
+ if (/^working/i.test(s)) return s;
14554
+ return `Working\u2026 \xB7 ${s}`;
14555
+ }
14556
+ function parseProgressHeartbeat(raw) {
14557
+ if (!raw) return null;
14558
+ try {
14559
+ const obj = JSON.parse(raw);
14560
+ const step = typeof obj.step === "string" ? obj.step.trim() : "";
14561
+ const updatedAtMs = typeof obj.updated_at_ms === "number" ? obj.updated_at_ms : NaN;
14562
+ if (!step || !Number.isFinite(updatedAtMs)) return null;
14563
+ return { step, updatedAtMs };
14564
+ } catch {
14565
+ return null;
14566
+ }
14567
+ }
14568
+ var SEED_PROGRESS_STEP = "Working\u2026";
14569
+ function serializeProgressHeartbeat(step, nowMs) {
14570
+ return JSON.stringify({ step, updated_at_ms: nowMs });
14571
+ }
14572
+
14573
+ // src/direct-chat-progress.ts
14574
+ async function runDirectChatProgressTick(deps, state) {
14575
+ if (!deps.enabled()) {
14576
+ const t = state.tracked;
14577
+ if (t) {
14578
+ if (await deps.clear(t.channel, t.ts)) state.tracked = null;
14579
+ return { type: "delete", channel: t.channel, threadTs: t.threadTs, ts: t.ts };
14580
+ }
14581
+ return { type: "none" };
14582
+ }
14583
+ const baseInput = {
14584
+ now: deps.now(),
14585
+ heartbeat: deps.readHeartbeat(),
14586
+ target: deps.resolveTarget(),
14587
+ tracked: state.tracked,
14588
+ freshnessMs: deps.freshnessMs,
14589
+ minPendingMs: deps.minPendingMs
14590
+ };
14591
+ let action = decideProgressAction(baseInput);
14592
+ if (deps.isCardActive && baseInput.target && (action.type === "post" || action.type === "update" || action.type === "none" && state.tracked)) {
14593
+ if (await deps.isCardActive(baseInput.target.threadTs)) {
14594
+ action = decideProgressAction({ ...baseInput, targetHasCard: true });
14595
+ }
14596
+ }
14597
+ switch (action.type) {
14598
+ case "post": {
14599
+ const id = await deps.post(action.channel, action.step);
14600
+ if (id) {
14601
+ state.tracked = { channel: action.channel, threadTs: action.threadTs, ts: id, lastStep: action.step };
14602
+ }
14603
+ break;
14604
+ }
14605
+ case "update": {
14606
+ if (await deps.update(action.channel, action.ts, action.step)) {
14607
+ if (state.tracked) state.tracked.lastStep = action.step;
14608
+ }
14609
+ break;
14610
+ }
14611
+ case "delete": {
14612
+ if (await deps.clear(action.channel, action.ts)) state.tracked = null;
14613
+ break;
14614
+ }
14615
+ case "none":
14616
+ break;
14617
+ }
14618
+ return action;
14619
+ }
14620
+ function resolveDirectChatProgressTarget(receivedAt, stillOwed) {
14621
+ let best = null;
14622
+ let bestMs = Infinity;
14623
+ for (const [sessionId, ms] of receivedAt) {
14624
+ if (!stillOwed(sessionId)) {
14625
+ receivedAt.delete(sessionId);
14626
+ continue;
14627
+ }
14628
+ if (ms < bestMs) {
14629
+ bestMs = ms;
14630
+ best = { channel: sessionId, threadTs: sessionId, receivedAtMs: ms };
14631
+ }
14632
+ }
14633
+ return best;
14634
+ }
14635
+
14636
+ // src/kanban-card-active-client.ts
14637
+ var REQUEST_TIMEOUT_MS2 = 8e3;
14638
+ var POSITIVE_TTL_MS = 10 * 6e4;
14639
+ var NEGATIVE_TTL_MS = 15e3;
14640
+ function createKanbanCardActiveClient(args) {
14641
+ if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
14642
+ const fetchImpl = args.fetchImpl ?? fetch;
14643
+ const now = args.now ?? (() => Date.now());
14644
+ const positiveTtlMs = args.positiveTtlMs ?? POSITIVE_TTL_MS;
14645
+ const negativeTtlMs = args.negativeTtlMs ?? NEGATIVE_TTL_MS;
14646
+ const log = args.log ?? (() => {
14647
+ });
14648
+ const base = args.agtHost.replace(/\/+$/, "");
14649
+ const agentId = args.agentId;
14650
+ const apiKey = args.agtApiKey;
14651
+ const cache = /* @__PURE__ */ new Map();
14652
+ let cachedToken = null;
14653
+ let cachedTokenExpiresAt = 0;
14654
+ async function getToken() {
14655
+ if (cachedToken && now() < cachedTokenExpiresAt) return cachedToken;
14656
+ const resp = await fetchImpl(`${base}/host/exchange`, {
14657
+ method: "POST",
14658
+ headers: { "Content-Type": "application/json" },
14659
+ body: JSON.stringify({ host_key: apiKey }),
14660
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
14661
+ });
14662
+ if (!resp.ok) {
14663
+ const body = await resp.text().catch(() => "");
14664
+ throw new Error(`/host/exchange failed (${resp.status}): ${body.slice(0, 200)}`);
14665
+ }
14666
+ const data = await resp.json();
14667
+ cachedToken = data.token;
14668
+ cachedTokenExpiresAt = data.expires_at ? new Date(data.expires_at).getTime() - 12e4 : now() + 55 * 6e4;
14669
+ return cachedToken;
14670
+ }
14671
+ async function queryOnce(sourceIntegration, sourceExternalId) {
14672
+ const token = await getToken();
14673
+ const qs = new URLSearchParams({
14674
+ agent_id: agentId,
14675
+ source_integration: sourceIntegration,
14676
+ source_external_id: sourceExternalId
14677
+ });
14678
+ return fetchImpl(`${base}/host/kanban/progress-card-active?${qs.toString()}`, {
14679
+ method: "GET",
14680
+ headers: { Authorization: `Bearer ${token}` },
14681
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
14682
+ });
14683
+ }
14684
+ async function query(sourceIntegration, sourceExternalId) {
14685
+ let resp = await queryOnce(sourceIntegration, sourceExternalId);
14686
+ if (resp.status === 401) {
14687
+ cachedToken = null;
14688
+ cachedTokenExpiresAt = 0;
14689
+ resp = await queryOnce(sourceIntegration, sourceExternalId);
14690
+ }
14691
+ if (!resp.ok) return false;
14692
+ const data = await resp.json();
14693
+ return data.active === true;
14694
+ }
14695
+ return {
14696
+ async isCardActive(sourceIntegration, sourceExternalId) {
14697
+ const key = `${sourceIntegration}:${sourceExternalId}`;
14698
+ const t = now();
14699
+ const hit = cache.get(key);
14700
+ if (hit && t < hit.expiresAt) return hit.active;
14701
+ try {
14702
+ const active = await query(sourceIntegration, sourceExternalId);
14703
+ cache.set(key, { active, expiresAt: t + (active ? positiveTtlMs : negativeTtlMs) });
14704
+ return active;
14705
+ } catch (err) {
14706
+ log(`kanban-card-active: query threw key=${key}: ${err.message}`);
14707
+ return false;
14708
+ }
14709
+ }
14710
+ };
14711
+ }
14712
+
14495
14713
  // src/maintenance-mode.ts
14496
14714
  var FLAG_KEY = "platform-maintenance-mode";
14497
14715
  var MAINTENANCE_OFFLINE_MESSAGE = "The Augmented Team platform is offline for scheduled maintenance right now, so I can't pick this up \u2014 please try again shortly.";
@@ -14535,6 +14753,117 @@ var INBOUND_ATTACHMENTS_DIR = resolveInboundAttachmentsDir({
14535
14753
  agentId: AGT_AGENT_ID,
14536
14754
  homeDir: homedir2()
14537
14755
  });
14756
+ var AGT_AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME;
14757
+ var PROGRESS_HEARTBEAT_PATH = AGT_AGENT_CODE_NAME ? join5(homedir2(), ".augmented", AGT_AGENT_CODE_NAME, "channel-progress-heartbeat.json") : null;
14758
+ var progressReceivedAt = /* @__PURE__ */ new Map();
14759
+ var directChatProgressState = { tracked: null };
14760
+ var directChatProgressTickRunning = false;
14761
+ var PROGRESS_PREFIX = "\u23F3";
14762
+ var PROGRESS_TICK_MS = (() => {
14763
+ const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_TICK_MS ?? "", 10);
14764
+ return Number.isFinite(raw) && raw > 0 ? raw : 3e3;
14765
+ })();
14766
+ var directChatKanbanCardClient = createKanbanCardActiveClient({
14767
+ agtHost: AGT_HOST ?? null,
14768
+ agtApiKey: AGT_API_KEY ?? null,
14769
+ agentId: AGT_AGENT_ID ?? null,
14770
+ log: (line) => process.stderr.write(`direct-chat-channel: ${line}
14771
+ `)
14772
+ });
14773
+ function readProgressHeartbeat() {
14774
+ if (!PROGRESS_HEARTBEAT_PATH || !existsSync4(PROGRESS_HEARTBEAT_PATH)) return null;
14775
+ try {
14776
+ return parseProgressHeartbeat(readFileSync4(PROGRESS_HEARTBEAT_PATH, "utf-8"));
14777
+ } catch {
14778
+ return null;
14779
+ }
14780
+ }
14781
+ function seedProgressHeartbeat() {
14782
+ if (!PROGRESS_HEARTBEAT_PATH) return;
14783
+ const tmp = `${PROGRESS_HEARTBEAT_PATH}.${process.pid}.tmp`;
14784
+ try {
14785
+ mkdirSync3(join5(homedir2(), ".augmented", AGT_AGENT_CODE_NAME), { recursive: true });
14786
+ writeFileSync3(tmp, serializeProgressHeartbeat(SEED_PROGRESS_STEP, Date.now()), { mode: 384 });
14787
+ renameSync3(tmp, PROGRESS_HEARTBEAT_PATH);
14788
+ } catch {
14789
+ try {
14790
+ unlinkSync2(tmp);
14791
+ } catch {
14792
+ }
14793
+ }
14794
+ }
14795
+ async function postDirectChatProgress(sessionId, step) {
14796
+ const messageId = `progress:${randomUUID()}`;
14797
+ try {
14798
+ const res = await apiPost("/host/direct-chat/progress", {
14799
+ agent_id: AGT_AGENT_ID,
14800
+ session_id: sessionId,
14801
+ message_id: messageId,
14802
+ action: "post",
14803
+ content: `${PROGRESS_PREFIX} ${composeProgressBody(step)}`
14804
+ });
14805
+ if (!res.ok) return null;
14806
+ const data = await res.json().catch(() => ({}));
14807
+ return data.error == null ? messageId : null;
14808
+ } catch {
14809
+ return null;
14810
+ }
14811
+ }
14812
+ async function updateDirectChatProgress(sessionId, messageId, step) {
14813
+ try {
14814
+ const res = await apiPost("/host/direct-chat/progress", {
14815
+ agent_id: AGT_AGENT_ID,
14816
+ session_id: sessionId,
14817
+ message_id: messageId,
14818
+ action: "update",
14819
+ content: `${PROGRESS_PREFIX} ${composeProgressBody(step)}`
14820
+ });
14821
+ if (!res.ok) return false;
14822
+ const data = await res.json().catch(() => ({}));
14823
+ return data.error == null;
14824
+ } catch {
14825
+ return false;
14826
+ }
14827
+ }
14828
+ async function clearDirectChatProgress(sessionId, messageId) {
14829
+ try {
14830
+ const res = await apiPost("/host/direct-chat/progress", {
14831
+ agent_id: AGT_AGENT_ID,
14832
+ session_id: sessionId,
14833
+ message_id: messageId,
14834
+ action: "clear"
14835
+ });
14836
+ if (!res.ok) return false;
14837
+ const data = await res.json().catch(() => ({}));
14838
+ return data.error == null;
14839
+ } catch {
14840
+ return false;
14841
+ }
14842
+ }
14843
+ async function directChatProgressTick() {
14844
+ if (directChatProgressTickRunning) return;
14845
+ directChatProgressTickRunning = true;
14846
+ try {
14847
+ await runDirectChatProgressTick(
14848
+ {
14849
+ enabled: channelLiveProgressEnabled,
14850
+ readHeartbeat: readProgressHeartbeat,
14851
+ resolveTarget: () => resolveDirectChatProgressTarget(progressReceivedAt, (sid) => claimTracker.peek(sid).length > 0),
14852
+ freshnessMs: progressHeartbeatFreshMs(),
14853
+ minPendingMs: progressMinPendingMs(),
14854
+ now: Date.now,
14855
+ post: postDirectChatProgress,
14856
+ update: updateDirectChatProgress,
14857
+ clear: clearDirectChatProgress,
14858
+ ...directChatKanbanCardClient ? { isCardActive: (sid) => directChatKanbanCardClient.isCardActive("direct-chat", sid) } : {}
14859
+ },
14860
+ directChatProgressState
14861
+ );
14862
+ } catch {
14863
+ } finally {
14864
+ directChatProgressTickRunning = false;
14865
+ }
14866
+ }
14538
14867
  var inboundContextClient = createInboundContextClient({
14539
14868
  agtHost: AGT_HOST ?? null,
14540
14869
  agtApiKey: AGT_API_KEY ?? null,
@@ -14891,6 +15220,10 @@ async function pollForMessages(sinceMs) {
14891
15220
  if (!isNotice && !maintenanceActive) {
14892
15221
  markProcessed(msg.id);
14893
15222
  claimTracker.track(msg.session_id, msg.id);
15223
+ if (!progressReceivedAt.has(msg.session_id)) {
15224
+ progressReceivedAt.set(msg.session_id, Date.now());
15225
+ }
15226
+ seedProgressHeartbeat();
14894
15227
  }
14895
15228
  if (maintenanceActive) {
14896
15229
  const throttleKey = `${msg.session_id}|maintenance`;
@@ -15070,6 +15403,13 @@ if (DOORBELL_ENABLED && DIRECT_CHAT_AGENT_DIR) {
15070
15403
  `
15071
15404
  );
15072
15405
  }
15406
+ var progressTickTimer = null;
15407
+ if (PROGRESS_HEARTBEAT_PATH) {
15408
+ progressTickTimer = setInterval(() => {
15409
+ void directChatProgressTick();
15410
+ }, PROGRESS_TICK_MS);
15411
+ progressTickTimer.unref?.();
15412
+ }
15073
15413
  var isShuttingDown = false;
15074
15414
  function shutdown(reason) {
15075
15415
  if (isShuttingDown) return;
@@ -15081,6 +15421,7 @@ function shutdown(reason) {
15081
15421
  } catch {
15082
15422
  }
15083
15423
  if (safetyNetTimer) clearInterval(safetyNetTimer);
15424
+ if (progressTickTimer) clearInterval(progressTickTimer);
15084
15425
  try {
15085
15426
  releaseMcpSpawnLock(acquiredLockPath);
15086
15427
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.220",
3
+ "version": "0.28.221",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {