@integrity-labs/agt-cli 0.28.220 → 0.28.222

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.
@@ -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 {
@@ -36,7 +36,7 @@ import {
36
36
  writeDirectChatSessionState,
37
37
  writeEgressAllowlist,
38
38
  writePersistentClaudeWrapper
39
- } from "./chunk-M2PGJQP3.js";
39
+ } from "./chunk-B3E4B7JF.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-S2REZDHF.js.map
80
+ //# sourceMappingURL=persistent-session-M4ZTLCDP.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-M2PGJQP3.js";
3
+ } from "./chunk-B3E4B7JF.js";
4
4
  import "./chunk-XWVM4KPK.js";
5
5
 
6
6
  // src/lib/responsiveness-probe.ts
@@ -303,4 +303,4 @@ export {
303
303
  readAndResetChannelDeflections,
304
304
  readAndResetChannelLaneClassifications
305
305
  };
306
- //# sourceMappingURL=responsiveness-probe-BHFLFXY5.js.map
306
+ //# sourceMappingURL=responsiveness-probe-E25HFGJL.js.map
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.222",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {