@integrity-labs/agt-cli 0.27.9-test.12 → 0.27.9-test.14

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.
Files changed (35) hide show
  1. package/dist/bin/agt.js +4 -4
  2. package/dist/chunk-354FAVQR.js +173 -0
  3. package/dist/chunk-354FAVQR.js.map +1 -0
  4. package/dist/{chunk-MQJ5DMPT.js → chunk-7GKJZBTB.js} +111 -204
  5. package/dist/chunk-7GKJZBTB.js.map +1 -0
  6. package/dist/{chunk-HR5T2RQF.js → chunk-I3YS5WFV.js} +3 -1
  7. package/dist/chunk-I3YS5WFV.js.map +1 -0
  8. package/dist/{chunk-SXBZDUKN.js → chunk-R7NKCGWN.js} +341 -46
  9. package/dist/chunk-R7NKCGWN.js.map +1 -0
  10. package/dist/{chunk-I2OTQJH3.js → chunk-WOOYOAPG.js} +2644 -2142
  11. package/dist/chunk-WOOYOAPG.js.map +1 -0
  12. package/dist/{claude-pair-runtime-F6USL3EW.js → claude-pair-runtime-GIUCD7IG.js} +2 -2
  13. package/dist/{claude-scheduler-EM24LTGV.js → claude-scheduler-FATCLHDM.js} +2 -2
  14. package/dist/daily-session-PNQX5URX.js +27 -0
  15. package/dist/lib/manager-worker.js +1125 -149
  16. package/dist/lib/manager-worker.js.map +1 -1
  17. package/dist/mcp/augmented-admin.js +21335 -0
  18. package/dist/mcp/index.js +121 -4
  19. package/dist/mcp/slack-channel.js +845 -208
  20. package/dist/mcp/teams-channel.js +73 -29
  21. package/dist/mcp/telegram-channel.js +579 -157
  22. package/dist/{persistent-session-OL5EDYB4.js → persistent-session-35PWSTLO.js} +10 -3
  23. package/dist/persistent-session-35PWSTLO.js.map +1 -0
  24. package/dist/responsiveness-probe-MA4M2QM4.js +158 -0
  25. package/dist/responsiveness-probe-MA4M2QM4.js.map +1 -0
  26. package/package.json +3 -2
  27. package/dist/chunk-HR5T2RQF.js.map +0 -1
  28. package/dist/chunk-I2OTQJH3.js.map +0 -1
  29. package/dist/chunk-MQJ5DMPT.js.map +0 -1
  30. package/dist/chunk-SXBZDUKN.js.map +0 -1
  31. package/dist/responsiveness-probe-B6LJJRUD.js +0 -74
  32. package/dist/responsiveness-probe-B6LJJRUD.js.map +0 -1
  33. /package/dist/{claude-pair-runtime-F6USL3EW.js.map → claude-pair-runtime-GIUCD7IG.js.map} +0 -0
  34. /package/dist/{claude-scheduler-EM24LTGV.js.map → claude-scheduler-FATCLHDM.js.map} +0 -0
  35. /package/dist/{persistent-session-OL5EDYB4.js.map → daily-session-PNQX5URX.js.map} +0 -0
@@ -2,6 +2,7 @@ import {
2
2
  SEND_KEYS_ENTER_DELAY_MS,
3
3
  _internals,
4
4
  collectDiagnostics,
5
+ creditAcpxExecFailureCount,
5
6
  getLastFailureContext,
6
7
  getProjectDir,
7
8
  getSessionState,
@@ -15,20 +16,24 @@ import {
15
16
  resetRestartCount,
16
17
  resolveClaudeBinary,
17
18
  resolveSessionSpawnDecision,
19
+ rotateSessionForWedge,
18
20
  sendToAgent,
19
21
  startPersistentSession,
20
22
  stopAllSessions,
21
23
  stopAllSessionsAndWait,
22
24
  stopPersistentSession,
25
+ takeAcpxExecFailureCount,
23
26
  takeZombieDetection,
24
27
  writePersistentClaudeWrapper
25
- } from "./chunk-MQJ5DMPT.js";
26
- import "./chunk-I2OTQJH3.js";
28
+ } from "./chunk-7GKJZBTB.js";
29
+ import "./chunk-WOOYOAPG.js";
30
+ import "./chunk-354FAVQR.js";
27
31
  import "./chunk-XWVM4KPK.js";
28
32
  export {
29
33
  SEND_KEYS_ENTER_DELAY_MS,
30
34
  _internals,
31
35
  collectDiagnostics,
36
+ creditAcpxExecFailureCount,
32
37
  getLastFailureContext,
33
38
  getProjectDir,
34
39
  getSessionState,
@@ -42,12 +47,14 @@ export {
42
47
  resetRestartCount,
43
48
  resolveClaudeBinary,
44
49
  resolveSessionSpawnDecision,
50
+ rotateSessionForWedge,
45
51
  sendToAgent,
46
52
  startPersistentSession,
47
53
  stopAllSessions,
48
54
  stopAllSessionsAndWait,
49
55
  stopPersistentSession,
56
+ takeAcpxExecFailureCount,
50
57
  takeZombieDetection,
51
58
  writePersistentClaudeWrapper
52
59
  };
53
- //# sourceMappingURL=persistent-session-OL5EDYB4.js.map
60
+ //# sourceMappingURL=persistent-session-35PWSTLO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,158 @@
1
+ import {
2
+ paneLogPath
3
+ } from "./chunk-7GKJZBTB.js";
4
+ import "./chunk-WOOYOAPG.js";
5
+ import "./chunk-354FAVQR.js";
6
+ import "./chunk-XWVM4KPK.js";
7
+
8
+ // src/lib/responsiveness-probe.ts
9
+ import { mkdirSync, readdirSync, readFileSync, renameSync, statSync } from "fs";
10
+ import { dirname, join } from "path";
11
+ var DEFAULT_INTERVAL_MS = 5 * 60 * 1e3;
12
+ function getResponsivenessIntervalMs() {
13
+ const raw = process.env.AUGMENTED_RESPONSIVENESS_INTERVAL_MS;
14
+ if (!raw) return DEFAULT_INTERVAL_MS;
15
+ const parsed = Number.parseInt(raw, 10);
16
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_INTERVAL_MS;
17
+ }
18
+ function oldestPendingInboundMtimeMs(agentHomeDir) {
19
+ let oldest = null;
20
+ let entries;
21
+ try {
22
+ entries = readdirSync(agentHomeDir, { withFileTypes: true });
23
+ } catch {
24
+ return null;
25
+ }
26
+ for (const entry of entries) {
27
+ if (!entry.isDirectory() || !entry.name.endsWith("-pending-inbound")) continue;
28
+ const dir = join(agentHomeDir, entry.name);
29
+ let files;
30
+ try {
31
+ files = readdirSync(dir, { withFileTypes: true });
32
+ } catch {
33
+ continue;
34
+ }
35
+ for (const file of files) {
36
+ if (!file.isFile() || file.name.startsWith(".")) continue;
37
+ try {
38
+ const mtimeMs = statSync(join(dir, file.name)).mtimeMs;
39
+ if (oldest === null || mtimeMs < oldest) oldest = mtimeMs;
40
+ } catch {
41
+ }
42
+ }
43
+ }
44
+ return oldest;
45
+ }
46
+ function isUndeliverableMarker(markerPath) {
47
+ try {
48
+ const parsed = JSON.parse(readFileSync(markerPath, "utf8"));
49
+ return parsed?.undeliverable === true;
50
+ } catch (error) {
51
+ return error.code === "ENOENT" ? null : false;
52
+ }
53
+ }
54
+ function oldestLivePendingInboundMtimeMs(agentHomeDir, opts = {}) {
55
+ const sessionStartMs = opts.sessionStartMs ?? null;
56
+ let oldest = null;
57
+ let entries;
58
+ try {
59
+ entries = readdirSync(agentHomeDir, { withFileTypes: true });
60
+ } catch {
61
+ return null;
62
+ }
63
+ for (const entry of entries) {
64
+ if (!entry.isDirectory() || !entry.name.endsWith("-pending-inbound")) continue;
65
+ const dir = join(agentHomeDir, entry.name);
66
+ let files;
67
+ try {
68
+ files = readdirSync(dir, { withFileTypes: true });
69
+ } catch {
70
+ continue;
71
+ }
72
+ for (const file of files) {
73
+ if (!file.isFile() || file.name.startsWith(".")) continue;
74
+ const full = join(dir, file.name);
75
+ let mtimeMs;
76
+ try {
77
+ mtimeMs = statSync(full).mtimeMs;
78
+ } catch {
79
+ continue;
80
+ }
81
+ if (sessionStartMs !== null && mtimeMs < sessionStartMs) continue;
82
+ const undeliverable = isUndeliverableMarker(full);
83
+ if (undeliverable === null) continue;
84
+ if (undeliverable) continue;
85
+ if (oldest === null || mtimeMs < oldest) oldest = mtimeMs;
86
+ }
87
+ }
88
+ return oldest;
89
+ }
90
+ function livePendingInboundOldestAgeSeconds(codeName, sessionStartMs, now = /* @__PURE__ */ new Date()) {
91
+ const oldest = oldestLivePendingInboundMtimeMs(dirname(paneLogPath(codeName)), { sessionStartMs });
92
+ if (oldest === null) return null;
93
+ return Math.max(0, Math.floor((now.getTime() - oldest) / 1e3));
94
+ }
95
+ function deadLetterPendingInbound(codeName, _now = /* @__PURE__ */ new Date()) {
96
+ const home = dirname(paneLogPath(codeName));
97
+ let moved = 0;
98
+ let entries;
99
+ try {
100
+ entries = readdirSync(home, { withFileTypes: true });
101
+ } catch {
102
+ return 0;
103
+ }
104
+ for (const entry of entries) {
105
+ if (!entry.isDirectory() || !entry.name.endsWith("-pending-inbound")) continue;
106
+ const dir = join(home, entry.name);
107
+ const deadDir = join(home, `${entry.name}-stale`);
108
+ let files;
109
+ try {
110
+ files = readdirSync(dir, { withFileTypes: true });
111
+ } catch {
112
+ continue;
113
+ }
114
+ for (const file of files) {
115
+ if (!file.isFile() || file.name.startsWith(".")) continue;
116
+ try {
117
+ mkdirSync(deadDir, { recursive: true });
118
+ renameSync(join(dir, file.name), join(deadDir, file.name));
119
+ moved++;
120
+ } catch {
121
+ }
122
+ }
123
+ }
124
+ return moved;
125
+ }
126
+ function collectResponsivenessProbes(codeNames, now = /* @__PURE__ */ new Date()) {
127
+ const nowMs = now.getTime();
128
+ const results = [];
129
+ for (const codeName of codeNames) {
130
+ try {
131
+ const panePath = paneLogPath(codeName);
132
+ const mtimeMs = statSync(panePath).mtimeMs;
133
+ const ageSeconds = Math.max(0, Math.floor((nowMs - mtimeMs) / 1e3));
134
+ const result = {
135
+ code_name: codeName,
136
+ pane_activity_age_seconds: ageSeconds
137
+ };
138
+ const oldestMarkerMs = oldestPendingInboundMtimeMs(dirname(panePath));
139
+ if (oldestMarkerMs !== null) {
140
+ result.pending_inbound_oldest_age_seconds = Math.max(
141
+ 0,
142
+ Math.floor((nowMs - oldestMarkerMs) / 1e3)
143
+ );
144
+ }
145
+ results.push(result);
146
+ } catch {
147
+ }
148
+ }
149
+ return results;
150
+ }
151
+ export {
152
+ collectResponsivenessProbes,
153
+ deadLetterPendingInbound,
154
+ getResponsivenessIntervalMs,
155
+ livePendingInboundOldestAgeSeconds,
156
+ oldestLivePendingInboundMtimeMs
157
+ };
158
+ //# sourceMappingURL=responsiveness-probe-MA4M2QM4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/responsiveness-probe.ts"],"sourcesContent":["/**\n * ENG-5399 — Tier 1 responsiveness probe (manager-side).\n *\n * Cheap, fast-cadence canary that catches \"agent went silent\" inside\n * minutes, well before the existing synthetic-probe cron's ~35 min\n * staleness window (`SyntheticReplyAgeSeconds`, ENG-5122).\n *\n * Mechanism: for each managed agent, read the mtime of the agent's\n * `pane.log` and report `now - mtime` as `PaneActivityAgeSeconds` via\n * a new `/host/responsiveness-probe` endpoint. `pane.log` is the\n * tmux pipe-pane sink set up by `setupPaneLog()` — any visible\n * activity (assistant turns, tool calls, in-place progress\n * heartbeats) bumps its mtime. A silent agent has a steadily\n * climbing age that lands in CloudWatch and trips a per-agent alarm.\n *\n * ENG-6017 adds a second per-agent signal on the same cadence:\n * `pending_inbound_oldest_age_seconds` — the age of the oldest marker\n * file across the agent's `*-pending-inbound/` directories (written by\n * the channel MCP servers for inbounds awaiting delivery). This is the\n * one artifact of the \"message typed but never submitted\" failure mode\n * that every other canary is blind to: in the koda incident\n * (2026-06-04) an operator Slack DM sat undelivered for 40+ minutes\n * while pane-activity stayed fresh (health checks), synthetic probes\n * were answered by the one-shot fallback, and heartbeat/session-alive\n * only reflect manager health. The field is OMITTED (not zero) when the\n * agent has no pending-inbound markers — the API treats absent as\n * \"no signal\", never as \"healthy\" (absent-vs-zero matters for\n * mixed-version fleets where old CLIs don't report it at all).\n *\n * Run from `pollCycle()` in `manager-worker.ts` on a configurable\n * interval (default 5 min via `AUGMENTED_RESPONSIVENESS_INTERVAL_MS`).\n */\n\nimport { mkdirSync, readdirSync, readFileSync, renameSync, statSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { paneLogPath } from './persistent-session.js';\n\nexport interface ResponsivenessProbeResult {\n code_name: string;\n pane_activity_age_seconds: number;\n /**\n * ENG-6017: age (s) of the oldest marker file across the agent's\n * `*-pending-inbound/` directories. Omitted when no markers exist —\n * absent means \"no signal\", NOT \"zero / healthy\".\n */\n pending_inbound_oldest_age_seconds?: number;\n}\n\nconst DEFAULT_INTERVAL_MS = 5 * 60 * 1000;\n\nexport function getResponsivenessIntervalMs(): number {\n const raw = process.env.AUGMENTED_RESPONSIVENESS_INTERVAL_MS;\n if (!raw) return DEFAULT_INTERVAL_MS;\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_INTERVAL_MS;\n}\n\n/**\n * ENG-6017: oldest pending-inbound marker mtime (ms epoch) for an agent,\n * or null when the agent has no markers / no pending-inbound dirs.\n *\n * The channel MCP servers (slack-channel, telegram-channel, …) write one\n * marker file per inbound into `~/.augmented/<codeName>/<channel>-pending-\n * inbound/` and clear it when the agent acknowledges the message. The\n * directory layout is the contract here — read-only, no IPC with the MCP\n * (the MCP and CLI release independently; file mtimes need no protocol).\n *\n * ENG-6072: only plain, non-hidden files count as markers. The msteams MCP\n * keeps `.markers/` and `.processed/` housekeeping SUBDIRECTORIES inside its\n * pending-inbound dir; their mtimes never advance, so statting every dirent\n * made the gauge climb forever and fired pending-inbound-stale on agents with\n * zero stranded messages (kylie ~3.4d / scout ~34h false ALARMs the moment\n * ENG-6023 activated the alarm). Dot-entries are skipped wholesale — the\n * hidden namespace is reserved for MCP bookkeeping, never for markers.\n */\nfunction oldestPendingInboundMtimeMs(agentHomeDir: string): number | null {\n let oldest: number | null = null;\n let entries;\n try {\n entries = readdirSync(agentHomeDir, { withFileTypes: true });\n } catch {\n return null; // agent home missing — nothing to report\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith('-pending-inbound')) continue;\n const dir = join(agentHomeDir, entry.name);\n let files;\n try {\n files = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const file of files) {\n if (!file.isFile() || file.name.startsWith('.')) continue;\n try {\n const mtimeMs = statSync(join(dir, file.name)).mtimeMs;\n if (oldest === null || mtimeMs < oldest) oldest = mtimeMs;\n } catch {\n // Marker drained between readdir and stat — that's the happy path.\n }\n }\n }\n return oldest;\n}\n\n/**\n * ENG-6160: classify a marker file for the LIVE-inbound scan.\n * - `true` → flagged `\"undeliverable\": true` (dead-letter, exclude).\n * - `null` → vanished mid-scan (ENOENT) — drained between stat and read, the\n * happy path; exclude it rather than count an already-gone file.\n * - `false` → still present but malformed / unreadable for another reason —\n * treated as LIVE so a corrupt marker can never mask a real wedge.\n */\nfunction isUndeliverableMarker(markerPath: string): boolean | null {\n try {\n const parsed = JSON.parse(readFileSync(markerPath, 'utf8')) as { undeliverable?: unknown };\n return parsed?.undeliverable === true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === 'ENOENT' ? null : false;\n }\n}\n\n/**\n * ENG-6160: oldest *LIVE* pending-inbound marker mtime (ms epoch) for an agent,\n * or null when there is no live marker. \"Live\" excludes:\n *\n * - markers older than `sessionStartMs` — a marker written before the current\n * session started is a leftover from a PREVIOUS session and cannot mean\n * *this* session is failing to drain. This is the load-bearing exclusion:\n * without it, an orphan marker survives a fresh respawn and the wedge\n * detector re-fires forever on a healthy idle agent (the sherlock enforce\n * loop, 2026-06-08: `inboundAge=3389s` on a `● Ready.` session).\n * - markers flagged `undeliverable: true` — already dead-lettered by the channel.\n *\n * Distinct from `oldestPendingInboundMtimeMs` (which counts ALL markers and\n * feeds the ENG-6017 `pending-inbound-stale` CloudWatch alarm — that alarm\n * *wants* to fire on a stuck inbound, so its semantics must NOT change). This\n * variant is wedge-detection-only.\n */\nexport function oldestLivePendingInboundMtimeMs(\n agentHomeDir: string,\n opts: { sessionStartMs?: number | null } = {},\n): number | null {\n const sessionStartMs = opts.sessionStartMs ?? null;\n let oldest: number | null = null;\n let entries;\n try {\n entries = readdirSync(agentHomeDir, { withFileTypes: true });\n } catch {\n return null;\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith('-pending-inbound')) continue;\n const dir = join(agentHomeDir, entry.name);\n let files;\n try {\n files = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const file of files) {\n if (!file.isFile() || file.name.startsWith('.')) continue;\n const full = join(dir, file.name);\n let mtimeMs: number;\n try {\n mtimeMs = statSync(full).mtimeMs;\n } catch {\n continue; // drained between readdir and stat — happy path\n }\n if (sessionStartMs !== null && mtimeMs < sessionStartMs) continue; // pre-session leftover\n const undeliverable = isUndeliverableMarker(full);\n if (undeliverable === null) continue; // vanished between stat and read — drained, exclude\n if (undeliverable) continue; // already dead-lettered\n if (oldest === null || mtimeMs < oldest) oldest = mtimeMs;\n }\n }\n return oldest;\n}\n\n/**\n * ENG-6160: age (s) of the oldest LIVE pending-inbound marker for an agent, or\n * null when none. The wedge detector uses this instead of the alarm-facing\n * `pending_inbound_oldest_age_seconds` so a stale/dead-letter marker can't\n * false-fire a respawn.\n */\nexport function livePendingInboundOldestAgeSeconds(\n codeName: string,\n sessionStartMs: number | null,\n now: Date = new Date(),\n): number | null {\n const oldest = oldestLivePendingInboundMtimeMs(dirname(paneLogPath(codeName)), { sessionStartMs });\n if (oldest === null) return null;\n return Math.max(0, Math.floor((now.getTime() - oldest) / 1000));\n}\n\n/**\n * ENG-6160: move every pending-inbound marker for an agent aside into a sibling\n * `<channel>-pending-inbound-stale/` directory (NOT silently deleted — the\n * payload pointer is preserved for forensics), returning the count moved.\n *\n * Called on a force-fresh wedge respawn: the markers belonged to the wedged\n * session that is being torn down; the fresh session cannot meaningfully\n * process a stale, out-of-context message, and leaving them on disk both keeps\n * the ENG-6017 alarm lit and (pre-ENG-6160) re-fed the wedge loop. The stale\n * dir does not end in `-pending-inbound`, so neither the probe nor this scan\n * re-counts moved markers.\n */\nexport function deadLetterPendingInbound(codeName: string, _now: Date = new Date()): number {\n const home = dirname(paneLogPath(codeName));\n let moved = 0;\n let entries;\n try {\n entries = readdirSync(home, { withFileTypes: true });\n } catch {\n return 0;\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith('-pending-inbound')) continue;\n const dir = join(home, entry.name);\n const deadDir = join(home, `${entry.name}-stale`);\n let files;\n try {\n files = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const file of files) {\n if (!file.isFile() || file.name.startsWith('.')) continue;\n try {\n mkdirSync(deadDir, { recursive: true });\n renameSync(join(dir, file.name), join(deadDir, file.name));\n moved++;\n } catch {\n // best-effort — a marker that vanished or can't move is left as-is\n }\n }\n }\n return moved;\n}\n\n/**\n * Compute the pane.log age for each agent. Missing or unreadable\n * pane.log returns null — the caller should drop those entries\n * rather than fabricate a \"fresh\" or \"ancient\" value. A missing\n * file means the agent has never spawned in this manager generation,\n * which is a separate problem covered by SessionAliveAgeSeconds.\n */\nexport function collectResponsivenessProbes(\n codeNames: string[],\n now: Date = new Date(),\n): ResponsivenessProbeResult[] {\n const nowMs = now.getTime();\n const results: ResponsivenessProbeResult[] = [];\n for (const codeName of codeNames) {\n try {\n const panePath = paneLogPath(codeName);\n const mtimeMs = statSync(panePath).mtimeMs;\n const ageSeconds = Math.max(0, Math.floor((nowMs - mtimeMs) / 1000));\n const result: ResponsivenessProbeResult = {\n code_name: codeName,\n pane_activity_age_seconds: ageSeconds,\n };\n // ENG-6017: piggyback the pending-inbound drain-age scan on the same\n // cadence. Field omitted (not 0) when there are no markers.\n const oldestMarkerMs = oldestPendingInboundMtimeMs(dirname(panePath));\n if (oldestMarkerMs !== null) {\n result.pending_inbound_oldest_age_seconds = Math.max(\n 0,\n Math.floor((nowMs - oldestMarkerMs) / 1000),\n );\n }\n results.push(result);\n } catch {\n // No pane.log yet (fresh agent, never spawned) — skip. The\n // session-alive monitor already covers the \"should be running\n // but isn't\" case.\n }\n }\n return results;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.27.9-test.12",
3
+ "version": "0.27.9-test.14",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsup && npm run build:mcp-assets && npm run build:cli-assets",
26
- "build:mcp-assets": "mkdir -p dist/mcp && cp ../../packages/mcp/dist/index.js dist/mcp/index.js && cp ../../packages/mcp/dist/slack-channel.js dist/mcp/slack-channel.js && cp ../../packages/mcp/dist/direct-chat-channel.js dist/mcp/direct-chat-channel.js && cp ../../packages/mcp/dist/telegram-channel.js dist/mcp/telegram-channel.js && cp ../../packages/mcp/dist/teams-channel.js dist/mcp/teams-channel.js",
26
+ "build:mcp-assets": "mkdir -p dist/mcp && cp ../../packages/mcp/dist/index.js dist/mcp/index.js && cp ../../packages/mcp/dist/slack-channel.js dist/mcp/slack-channel.js && cp ../../packages/mcp/dist/direct-chat-channel.js dist/mcp/direct-chat-channel.js && cp ../../packages/mcp/dist/telegram-channel.js dist/mcp/telegram-channel.js && cp ../../packages/mcp/dist/teams-channel.js dist/mcp/teams-channel.js && cp ../../packages/augmented-admin-mcp/dist/index.js dist/mcp/augmented-admin.js",
27
27
  "build:cli-assets": "mkdir -p dist/assets && cp assets/impersonate-statusline.sh dist/assets/impersonate-statusline.sh && chmod +x dist/assets/impersonate-statusline.sh",
28
28
  "dev": "tsx watch src/bin/agt.ts",
29
29
  "test": "vitest run",
@@ -52,6 +52,7 @@
52
52
  "devDependencies": {
53
53
  "@augmented/core": "workspace:*",
54
54
  "@integrity-labs/augmented-mcp": "workspace:*",
55
+ "@integrity-labs/augmented-admin-mcp": "workspace:*",
55
56
  "@types/node": "22.19.11",
56
57
  "@types/react": "19.2.14",
57
58
  "@types/ws": "8.18.1",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/claude-scheduler.ts"],"sourcesContent":["/**\n * In-process scheduler for Claude Code agents.\n *\n * On each manager poll cycle, checks if any tasks are due and fires them\n * via `claude -p`. State persists to disk so nextFireAt/lastFireAt survive\n * manager restarts.\n */\n\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { Cron } from 'croner';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SchedulerTaskState {\n taskId: string;\n templateId: string;\n name: string;\n agentCodeName: string;\n agentId: string;\n scheduleKind: 'cron' | 'every' | 'at';\n scheduleExpr: string | null;\n scheduleEvery: string | null;\n scheduleAt: string | null;\n timezone: string;\n prompt: string;\n sessionTarget: string;\n deliveryMode: string;\n deliveryChannel: string | null;\n /** ENG-4422 §4: JSONB DeliveryTarget (or null). Legacy string form is gone\n * after the migration; in-memory shape is the structured object. */\n deliveryTo: unknown | null;\n enabled: boolean;\n triggeredAt: number | null; // epoch ms — manual trigger from webapp\n nextFireAt: number | null; // epoch ms, null = completed one-shot\n lastFireAt: number | null;\n lastStatus: 'ok' | 'error' | null;\n firedCount: number;\n}\n\nexport interface SchedulerState {\n version: 1;\n tasks: Record<string, SchedulerTaskState>;\n updatedAt: string;\n}\n\nexport interface SchedulerTaskInput {\n id: string;\n template_id: string;\n name: string;\n schedule_kind: 'cron' | 'every' | 'at';\n schedule_expr: string | null;\n schedule_every: string | null;\n schedule_at: string | null;\n timezone: string;\n prompt: string;\n session_target: string;\n delivery_mode: string;\n delivery_channel: string | null;\n /** ENG-4422 §4: JSONB DeliveryTarget or null (post-migration). */\n delivery_to: unknown | null;\n enabled: boolean;\n triggered_at?: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Interval parsing (reused from Claude Code adapter)\n// ---------------------------------------------------------------------------\n\nfunction parseIntervalMs(scheduleEvery: string | null): number {\n if (!scheduleEvery) return 60 * 60_000; // 1hr default\n const match = scheduleEvery.match(/^(\\d+)\\s*(m|min|h|hr|d)$/i);\n if (!match) return 60 * 60_000;\n const value = parseInt(match[1]!, 10);\n const unit = match[2]!.toLowerCase();\n if (unit === 'h' || unit === 'hr') return value * 60 * 60_000;\n if (unit === 'd') return value * 24 * 60 * 60_000;\n return value * 60_000; // minutes\n}\n\n// ---------------------------------------------------------------------------\n// Next-fire computation\n// ---------------------------------------------------------------------------\n\nexport function computeNextFire(\n kind: 'cron' | 'every' | 'at',\n expr: string | null,\n every: string | null,\n at: string | null,\n timezone: string,\n afterMs?: number,\n): number | null {\n const now = afterMs ?? Date.now();\n\n if (kind === 'cron' && expr) {\n try {\n const cron = new Cron(expr, { timezone: timezone || undefined });\n const next = cron.nextRun(new Date(now));\n return next ? next.getTime() : null;\n } catch {\n return null;\n }\n }\n\n if (kind === 'every') {\n const intervalMs = parseIntervalMs(every);\n return now + intervalMs;\n }\n\n if (kind === 'at' && at) {\n const ts = new Date(at).getTime();\n if (isNaN(ts)) return null;\n // If the 'at' timestamp is in the past and afterMs is set (meaning we already\n // fired), return null to prevent re-firing on state rebuild.\n if (afterMs && ts <= afterMs) return null;\n return ts;\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// State persistence\n// ---------------------------------------------------------------------------\n\nfunction getStateDir(codeName: string): string {\n // ENG-4418: unified agent dir — scheduler state lives at the agent root\n // alongside other runtime state files (plugins.json, schedules.json,\n // registration.json). Legacy ~/.augmented/<codeName>/claudecode/scheduler-state.json\n // is migrated up by claudeCodeAdapter.getAgentDir on first poll.\n return join(homedir(), '.augmented', codeName);\n}\n\nfunction getStatePath(codeName: string): string {\n return join(getStateDir(codeName), 'scheduler-state.json');\n}\n\nexport function loadSchedulerState(codeName: string): SchedulerState {\n const path = getStatePath(codeName);\n if (existsSync(path)) {\n try {\n return JSON.parse(readFileSync(path, 'utf-8'));\n } catch { /* corrupted — start fresh */ }\n }\n return { version: 1, tasks: {}, updatedAt: new Date().toISOString() };\n}\n\nexport function saveSchedulerState(codeName: string, state: SchedulerState): void {\n const dir = getStateDir(codeName);\n mkdirSync(dir, { recursive: true });\n state.updatedAt = new Date().toISOString();\n const path = getStatePath(codeName);\n const tmpPath = path + '.tmp';\n writeFileSync(tmpPath, JSON.stringify(state, null, 2));\n renameSync(tmpPath, path);\n}\n\n// ---------------------------------------------------------------------------\n// Sync API tasks → scheduler state\n// ---------------------------------------------------------------------------\n\nexport function syncTasksToScheduler(\n codeName: string,\n agentId: string,\n tasks: SchedulerTaskInput[],\n): SchedulerState {\n const state = loadSchedulerState(codeName);\n const desiredIds = new Set(tasks.map((t) => t.id));\n\n // Remove tasks no longer in API\n for (const id of Object.keys(state.tasks)) {\n if (!desiredIds.has(id)) {\n delete state.tasks[id];\n }\n }\n\n // Add or update tasks\n for (const t of tasks) {\n const existing = state.tasks[t.id];\n if (existing) {\n // Only recompute nextFireAt if the schedule definition actually changed.\n // Without this guard, every sync cycle resets nextFireAt from \"now\",\n // preventing past-due tasks from ever being detected as ready.\n const scheduleChanged =\n existing.scheduleKind !== t.schedule_kind ||\n existing.scheduleExpr !== t.schedule_expr ||\n existing.scheduleEvery !== t.schedule_every ||\n existing.scheduleAt !== t.schedule_at ||\n existing.timezone !== t.timezone;\n\n // Update mutable fields, preserve fire history\n existing.name = t.name;\n existing.templateId = t.template_id;\n existing.scheduleKind = t.schedule_kind;\n existing.scheduleExpr = t.schedule_expr;\n existing.scheduleEvery = t.schedule_every;\n existing.scheduleAt = t.schedule_at;\n existing.timezone = t.timezone;\n existing.prompt = t.prompt;\n existing.sessionTarget = t.session_target;\n existing.deliveryMode = t.delivery_mode;\n existing.deliveryChannel = t.delivery_channel;\n existing.deliveryTo = t.delivery_to;\n existing.enabled = t.enabled;\n if (t.triggered_at) existing.triggeredAt = new Date(t.triggered_at).getTime();\n if (scheduleChanged) {\n existing.nextFireAt = computeNextFire(\n t.schedule_kind, t.schedule_expr, t.schedule_every, t.schedule_at,\n t.timezone, existing.lastFireAt ?? undefined,\n );\n }\n } else {\n // New task\n state.tasks[t.id] = {\n taskId: t.id,\n templateId: t.template_id,\n name: t.name,\n agentCodeName: codeName,\n agentId,\n scheduleKind: t.schedule_kind,\n scheduleExpr: t.schedule_expr,\n scheduleEvery: t.schedule_every,\n scheduleAt: t.schedule_at,\n timezone: t.timezone,\n prompt: t.prompt,\n sessionTarget: t.session_target,\n deliveryMode: t.delivery_mode,\n deliveryChannel: t.delivery_channel,\n deliveryTo: t.delivery_to,\n enabled: t.enabled,\n triggeredAt: t.triggered_at ? new Date(t.triggered_at).getTime() : null,\n nextFireAt: computeNextFire(\n t.schedule_kind, t.schedule_expr, t.schedule_every, t.schedule_at, t.timezone,\n ),\n lastFireAt: null,\n lastStatus: null,\n firedCount: 0,\n };\n }\n }\n\n saveSchedulerState(codeName, state);\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Ready-task detection\n// ---------------------------------------------------------------------------\n\n// ENG-4675: pass `inFlightTaskIds` so the manager's poll loop doesn't\n// re-detect tasks that already have a `claude -p` subprocess running.\n// Without this, every supervisor tick (~17s) saw the manual trigger as\n// still ready (because lastFireAt is only set on completion, not on\n// fire start), spamming \"N ready task(s)\" + \"Firing task\" log lines that\n// looked like duplicate fires. The in-flight guard at the spawn site\n// prevented actual duplicate subprocesses, but the log was misleading.\nexport function getReadyTasks(\n state: SchedulerState,\n inFlightTaskIds?: ReadonlySet<string>,\n): SchedulerTaskState[] {\n const now = Date.now();\n const ready = Object.values(state.tasks).filter((t) => {\n if (!t.enabled) return false;\n if (inFlightTaskIds?.has(t.taskId)) return false;\n // Manual trigger: triggered_at is set and hasn't been fired yet\n if (t.triggeredAt) {\n const triggerReady = !t.lastFireAt || t.triggeredAt > t.lastFireAt;\n if (triggerReady) return true;\n }\n // Normal schedule\n return t.nextFireAt !== null && t.nextFireAt <= now;\n });\n // Deduplicate by templateId — only fire one task per template per cycle\n const seen = new Set<string>();\n return ready.filter((t) => {\n if (seen.has(t.templateId)) return false;\n seen.add(t.templateId);\n return true;\n });\n}\n\n// ---------------------------------------------------------------------------\n// Post-execution state update\n// ---------------------------------------------------------------------------\n\nexport function markTaskFired(\n codeName: string,\n taskId: string,\n status: 'ok' | 'error',\n): SchedulerState {\n const state = loadSchedulerState(codeName);\n const task = state.tasks[taskId];\n if (!task) return state;\n\n task.lastFireAt = Date.now();\n task.lastStatus = status;\n task.firedCount++;\n\n // Compute next fire\n if (task.scheduleKind === 'at') {\n // One-shot — mark as completed\n task.nextFireAt = null;\n } else {\n task.nextFireAt = computeNextFire(\n task.scheduleKind, task.scheduleExpr, task.scheduleEvery, task.scheduleAt,\n task.timezone, task.lastFireAt,\n );\n }\n\n // Persisting is best-effort: the SchedulerState the caller stores in memory\n // (claudeSchedulerStates) is the running source of truth — getReadyTasks\n // reads it, not the disk file. A disk-write failure (ENOSPC/EACCES) must NOT\n // throw, or the caller's in-memory state would never advance and the task\n // would be treated as ready again next poll (ENG-5599: a duplicate\n // scheduled-task card materialised every tick). The mutated `state` is\n // returned regardless; cross-restart recovery is a separate concern.\n try {\n saveSchedulerState(codeName, state);\n } catch (err) {\n console.error(\n `[claude-scheduler] markTaskFired: failed to persist state for '${codeName}': ${(err as Error).message}`,\n );\n }\n return state;\n}\n\n// ---------------------------------------------------------------------------\n// Find a task by template ID (for work triggers)\n// ---------------------------------------------------------------------------\n\nexport function findTaskByTemplate(state: SchedulerState, templateId: string): SchedulerTaskState | undefined {\n return Object.values(state.tasks).find(\n (t) => t.templateId === templateId && t.enabled,\n );\n}\n\nexport function getProjectDir(codeName: string): string {\n return join(homedir(), '.augmented', codeName, 'project');\n}\n"],"mappings":"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","names":[]}