@integrity-labs/agt-cli 0.28.249 → 0.28.251

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-JIQM5K3C.js";
41
+ } from "../chunk-2ARDOUIX.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.249" : "dev";
4829
+ var cliVersion = true ? "0.28.251" : "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.249" : "dev";
5843
+ var cliVersion2 = true ? "0.28.251" : "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) => {
@@ -5832,7 +5832,7 @@ function requireHost() {
5832
5832
  }
5833
5833
 
5834
5834
  // src/lib/api-client.ts
5835
- var agtCliVersion = true ? "0.28.249" : "dev";
5835
+ var agtCliVersion = true ? "0.28.251" : "dev";
5836
5836
  var lastConfigHash = null;
5837
5837
  function setConfigHash(hash) {
5838
5838
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8102,4 +8102,4 @@ export {
8102
8102
  managerInstallSystemUnitCommand,
8103
8103
  managerUninstallSystemUnitCommand
8104
8104
  };
8105
- //# sourceMappingURL=chunk-JIQM5K3C.js.map
8105
+ //# sourceMappingURL=chunk-2ARDOUIX.js.map
@@ -37,7 +37,7 @@ import {
37
37
  requireHost,
38
38
  safeWriteJsonAtomic,
39
39
  setConfigHash
40
- } from "../chunk-JIQM5K3C.js";
40
+ } from "../chunk-2ARDOUIX.js";
41
41
  import {
42
42
  getProjectDir as getProjectDir2,
43
43
  getReadyTasks,
@@ -2358,6 +2358,114 @@ function readRecentTurns(dir, nowMs) {
2358
2358
  return turns;
2359
2359
  }
2360
2360
 
2361
+ // src/lib/routine-candidate-extractor.ts
2362
+ var VALID_CADENCE_GUESSES = /* @__PURE__ */ new Set(["daily", "weekdays", "weekly", "unknown"]);
2363
+ var MAX_ASK_CHARS = 400;
2364
+ var MAX_INPUT_CHARS = 6e3;
2365
+ function buildUserAsksInput(turns) {
2366
+ const lines = [];
2367
+ let total = 0;
2368
+ for (const turn of turns) {
2369
+ if (turn.role !== "user") continue;
2370
+ const body = turn.text.length > MAX_ASK_CHARS ? `${turn.text.slice(0, MAX_ASK_CHARS)}\u2026` : turn.text;
2371
+ const line = `User: ${body}`;
2372
+ if (total + line.length > MAX_INPUT_CHARS) break;
2373
+ lines.push(line);
2374
+ total += line.length;
2375
+ }
2376
+ return lines.join("\n");
2377
+ }
2378
+ function buildRoutinePrompt(channel, userAsks) {
2379
+ return `You are looking for a DURABLE RECURRING ASK in the user's messages from one completed ${channel} conversation with an AI agent. A routine candidate is something the user asks for repeatedly or explicitly wants on a schedule ("every morning", "each Friday", "again" for the third time) - not a one-off task.
2380
+
2381
+ User messages (agent replies deliberately omitted):
2382
+ """
2383
+ ${userAsks}
2384
+ """
2385
+
2386
+ Extract 0-2 routine candidates. For each:
2387
+ - description: the recurring ask, self-contained and generic (max 200 chars). No secrets, no personal data beyond what is needed to name the task.
2388
+ - cadence_guess: "daily", "weekdays", "weekly", or "unknown" if the messages imply repetition without a clear cadence
2389
+ - evidence_count: how many of the user messages above support this ask (integer >= 1)
2390
+ - confidence: 0.0-1.0 - how sure you are this is a genuine recurring responsibility
2391
+
2392
+ Most conversations contain NO routine candidate - return an empty array unless the recurrence signal is clear. Do NOT invent candidates.
2393
+
2394
+ Respond with ONLY a JSON array, no other text:
2395
+ [{"description":"...","cadence_guess":"daily","evidence_count":2,"confidence":0.7}]`;
2396
+ }
2397
+ function parseRoutineCandidates(raw) {
2398
+ const match = raw.match(/\[[\s\S]*\]/);
2399
+ if (!match) return null;
2400
+ let arr;
2401
+ try {
2402
+ arr = JSON.parse(match[0]);
2403
+ } catch {
2404
+ return null;
2405
+ }
2406
+ if (!Array.isArray(arr)) return null;
2407
+ const out = [];
2408
+ for (const entry of arr) {
2409
+ if (!entry || typeof entry !== "object") continue;
2410
+ const c = entry;
2411
+ const description = typeof c.description === "string" ? c.description.trim() : "";
2412
+ if (!description) continue;
2413
+ const confidence = typeof c.confidence === "number" && Number.isFinite(c.confidence) ? Math.max(0, Math.min(1, c.confidence)) : 0;
2414
+ if (confidence === 0) continue;
2415
+ const cadence = typeof c.cadence_guess === "string" && VALID_CADENCE_GUESSES.has(c.cadence_guess) ? c.cadence_guess : "unknown";
2416
+ const evidenceRaw = typeof c.evidence_count === "number" && Number.isFinite(c.evidence_count) ? Math.floor(c.evidence_count) : 1;
2417
+ out.push({
2418
+ // Bounded parse only - the FINAL 200-char truncation happens after
2419
+ // scrubbing (maybeEmitRoutineCandidates), because slicing first can
2420
+ // split a secret across the cut so the scrub regex no longer matches
2421
+ // and a fragment leaks onto the wire.
2422
+ description: description.slice(0, 500),
2423
+ cadence_guess: cadence,
2424
+ evidence_count: Math.max(1, Math.min(50, evidenceRaw)),
2425
+ confidence
2426
+ });
2427
+ }
2428
+ return out;
2429
+ }
2430
+ async function maybeEmitRoutineCandidates(args) {
2431
+ const { api: api2, backend, codeName, agentId, conversationId, channel, turns, log: log2 } = args;
2432
+ try {
2433
+ const userAsks = buildUserAsksInput(turns);
2434
+ if (!userAsks.trim()) return;
2435
+ let candidates;
2436
+ try {
2437
+ const out = await backend.run(buildRoutinePrompt(channel, userAsks));
2438
+ candidates = parseRoutineCandidates(out);
2439
+ } catch (err) {
2440
+ log2(`[routine-extract] ${codeName}: extraction failed: ${err.message}`);
2441
+ args.onModelCallError?.(err);
2442
+ return;
2443
+ }
2444
+ if (!candidates || candidates.length === 0) return;
2445
+ const scrubbed = candidates.map((c) => ({
2446
+ ...c,
2447
+ description: scrubSensitive(c.description).slice(0, 200)
2448
+ }));
2449
+ try {
2450
+ const res = await api2.post(
2451
+ "/host/routines/candidates",
2452
+ {
2453
+ agent_id: agentId,
2454
+ conversation_id: conversationId,
2455
+ candidates: scrubbed
2456
+ }
2457
+ );
2458
+ log2(
2459
+ `[routine-extract] ${codeName}: ${conversationId.slice(0, 8)} \u2192 ${scrubbed.length} candidate(s)${res?.discarded ? " (discarded: feature off)" : ""}`
2460
+ );
2461
+ } catch (err) {
2462
+ log2(`[routine-extract] ${codeName}: report failed: ${err.message}`);
2463
+ }
2464
+ } catch (err) {
2465
+ log2(`[routine-extract] ${codeName}: unexpected error: ${err.message}`);
2466
+ }
2467
+ }
2468
+
2361
2469
  // src/lib/memory-extractor.ts
2362
2470
  var MIN_CHECK_INTERVAL_MS5 = 10 * 6e4;
2363
2471
  var WINDOW_PAD_MS2 = 5 * 6e4;
@@ -2503,6 +2611,17 @@ async function maybeExtractMemories(args) {
2503
2611
  } catch (err) {
2504
2612
  log2(`[memory-extract] ${codeName}: report failed: ${err.message}`);
2505
2613
  }
2614
+ await maybeEmitRoutineCandidates({
2615
+ api: api2,
2616
+ backend,
2617
+ codeName,
2618
+ agentId,
2619
+ conversationId: conv.conversation_id,
2620
+ channel: conv.channel,
2621
+ turns,
2622
+ log: log2,
2623
+ onModelCallError: args.onModelCallError
2624
+ });
2506
2625
  }
2507
2626
  }
2508
2627
  async function reportSkip2(api2, agentId, conversationId, log2, codeName) {
@@ -6098,7 +6217,7 @@ function verifyPendingRestarts(now) {
6098
6217
  log(`[restart-verify] '${codeName}' respawned healthy after MCP change \u2014 tools bound (ENG-6174)`);
6099
6218
  finishRestartTiming(codeName, "tools-bound", void 0, log, now);
6100
6219
  if (hostFlagStore().getBoolean("session-tool-probe")) {
6101
- promptBindProbeAgents.add(codeName);
6220
+ promptBindProbeAttempts.set(codeName, PROMPT_BIND_PROBE_ATTEMPTS);
6102
6221
  }
6103
6222
  break;
6104
6223
  case "waiting":
@@ -6278,7 +6397,8 @@ var SESSION_TOOL_REBIND_COOLDOWN_MS = 10 * 60 * 1e3;
6278
6397
  function sessionToolRebindKey(codeName, serverKey) {
6279
6398
  return `${codeName}\0${serverKey}`;
6280
6399
  }
6281
- var promptBindProbeAgents = /* @__PURE__ */ new Set();
6400
+ var promptBindProbeAttempts = /* @__PURE__ */ new Map();
6401
+ var PROMPT_BIND_PROBE_ATTEMPTS = 6;
6282
6402
  async function runAgentSessionToolBindProbes(agent, integrations, projectDir, opts) {
6283
6403
  if (integrations.length === 0) return true;
6284
6404
  const intervalSec = Number(process.env.AGT_CONNECTIVITY_PROBE_INTERVAL_SECONDS) || 3600;
@@ -6519,7 +6639,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6519
6639
  var lastVersionCheckAt = 0;
6520
6640
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6521
6641
  var lastResponsivenessProbeAt = 0;
6522
- var agtCliVersion = true ? "0.28.249" : "dev";
6642
+ var agtCliVersion = true ? "0.28.251" : "dev";
6523
6643
  function resolveBrewPath(execFileSync2) {
6524
6644
  try {
6525
6645
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7928,6 +8048,9 @@ async function pollCycle() {
7928
8048
  if (fastRespawn && restartAcks.has(agent.agent_id) && isSessionHealthy(agent.code_name)) {
7929
8049
  flushRestartedAgentDiagnostics(hostId, [agent.code_name]);
7930
8050
  }
8051
+ if (restartAcks.has(agent.agent_id) && isSessionHealthy(agent.code_name) && hostFlagStore().getBoolean("session-tool-probe")) {
8052
+ promptBindProbeAttempts.set(agent.code_name, PROMPT_BIND_PROBE_ATTEMPTS);
8053
+ }
7931
8054
  }
7932
8055
  void maybeReportActivityCache({ api, log });
7933
8056
  const restartAckStateChanged = applyRestartAcks({
@@ -9089,7 +9212,8 @@ async function processAgent(agent, agentStates) {
9089
9212
  }
9090
9213
  }
9091
9214
  if (hostFlagStore().getBoolean("session-tool-probe")) {
9092
- const forceDue = promptBindProbeAgents.delete(agent.code_name);
9215
+ const attemptsLeft = promptBindProbeAttempts.get(agent.code_name) ?? 0;
9216
+ const forceDue = attemptsLeft > 0;
9093
9217
  let probeRan = false;
9094
9218
  try {
9095
9219
  const probeProjectDir = join16(homedir9(), ".augmented", agent.code_name, "project");
@@ -9097,7 +9221,11 @@ async function processAgent(agent, agentStates) {
9097
9221
  } catch (err) {
9098
9222
  log(`Session-tool-bind probe failed for '${agent.code_name}': ${err.message}`);
9099
9223
  }
9100
- if (forceDue && !probeRan) promptBindProbeAgents.add(agent.code_name);
9224
+ if (forceDue && probeRan) {
9225
+ const left = attemptsLeft - 1;
9226
+ if (left > 0) promptBindProbeAttempts.set(agent.code_name, left);
9227
+ else promptBindProbeAttempts.delete(agent.code_name);
9228
+ }
9101
9229
  }
9102
9230
  if (frameworkAdapter.removeMcpServer && frameworkAdapter.getMcpPath) {
9103
9231
  const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);