@songsid/agend 2.1.0-beta.3 → 2.1.0-beta.31

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 (97) hide show
  1. package/README.md +1 -0
  2. package/README.zh-TW.md +2 -1
  3. package/dist/access-path.js +3 -3
  4. package/dist/access-path.js.map +1 -1
  5. package/dist/agent-cli.js +1 -1
  6. package/dist/agent-cli.js.map +1 -1
  7. package/dist/agent-endpoint.d.ts +8 -0
  8. package/dist/agent-endpoint.js +36 -8
  9. package/dist/agent-endpoint.js.map +1 -1
  10. package/dist/backend/antigravity.js +3 -2
  11. package/dist/backend/antigravity.js.map +1 -1
  12. package/dist/backend/claude-code.js +4 -4
  13. package/dist/backend/claude-code.js.map +1 -1
  14. package/dist/backend/factory.js +4 -1
  15. package/dist/backend/factory.js.map +1 -1
  16. package/dist/backend/grok.d.ts +51 -0
  17. package/dist/backend/grok.js +282 -0
  18. package/dist/backend/grok.js.map +1 -0
  19. package/dist/backend/kiro.js +3 -2
  20. package/dist/backend/kiro.js.map +1 -1
  21. package/dist/backend/types.d.ts +12 -2
  22. package/dist/backend/types.js +1 -0
  23. package/dist/backend/types.js.map +1 -1
  24. package/dist/channel/adapters/discord.d.ts +20 -0
  25. package/dist/channel/adapters/discord.js +85 -11
  26. package/dist/channel/adapters/discord.js.map +1 -1
  27. package/dist/channel/adapters/telegram.js +4 -1
  28. package/dist/channel/adapters/telegram.js.map +1 -1
  29. package/dist/channel/mcp-tools.js +17 -1
  30. package/dist/channel/mcp-tools.js.map +1 -1
  31. package/dist/classic-channel-manager.d.ts +14 -1
  32. package/dist/classic-channel-manager.js +65 -4
  33. package/dist/classic-channel-manager.js.map +1 -1
  34. package/dist/cli.js +108 -16
  35. package/dist/cli.js.map +1 -1
  36. package/dist/config-validator.js +68 -1
  37. package/dist/config-validator.js.map +1 -1
  38. package/dist/config.d.ts +3 -1
  39. package/dist/config.js +13 -1
  40. package/dist/config.js.map +1 -1
  41. package/dist/context-guardian.d.ts +2 -0
  42. package/dist/context-guardian.js +10 -2
  43. package/dist/context-guardian.js.map +1 -1
  44. package/dist/daemon-entry.js +2 -1
  45. package/dist/daemon-entry.js.map +1 -1
  46. package/dist/daemon.d.ts +76 -6
  47. package/dist/daemon.js +451 -113
  48. package/dist/daemon.js.map +1 -1
  49. package/dist/fleet-context.d.ts +4 -0
  50. package/dist/fleet-manager.d.ts +88 -7
  51. package/dist/fleet-manager.js +712 -129
  52. package/dist/fleet-manager.js.map +1 -1
  53. package/dist/general-knowledge/skills/fleet-config/SKILL.md +1 -1
  54. package/dist/general-knowledge/skills/model-discovery/SKILL.md +1 -0
  55. package/dist/instance-lifecycle.d.ts +11 -1
  56. package/dist/instance-lifecycle.js +64 -22
  57. package/dist/instance-lifecycle.js.map +1 -1
  58. package/dist/locale.js +26 -2
  59. package/dist/locale.js.map +1 -1
  60. package/dist/logger.d.ts +6 -0
  61. package/dist/logger.js +29 -10
  62. package/dist/logger.js.map +1 -1
  63. package/dist/outbound-handlers.d.ts +3 -0
  64. package/dist/outbound-handlers.js +203 -2
  65. package/dist/outbound-handlers.js.map +1 -1
  66. package/dist/outbound-schemas.d.ts +40 -1
  67. package/dist/outbound-schemas.js +36 -1
  68. package/dist/outbound-schemas.js.map +1 -1
  69. package/dist/pause-marker.d.ts +5 -0
  70. package/dist/pause-marker.js +36 -0
  71. package/dist/pause-marker.js.map +1 -0
  72. package/dist/settings-api.d.ts +20 -2
  73. package/dist/settings-api.js +213 -9
  74. package/dist/settings-api.js.map +1 -1
  75. package/dist/setup-wizard.js +8 -0
  76. package/dist/setup-wizard.js.map +1 -1
  77. package/dist/statusline-watcher.d.ts +1 -1
  78. package/dist/statusline-watcher.js +3 -2
  79. package/dist/statusline-watcher.js.map +1 -1
  80. package/dist/tmux-control.d.ts +7 -0
  81. package/dist/tmux-control.js +22 -1
  82. package/dist/tmux-control.js.map +1 -1
  83. package/dist/tmux-manager.d.ts +1 -1
  84. package/dist/tmux-manager.js.map +1 -1
  85. package/dist/topic-commands.d.ts +19 -1
  86. package/dist/topic-commands.js +132 -23
  87. package/dist/topic-commands.js.map +1 -1
  88. package/dist/transcript-monitor.js +2 -0
  89. package/dist/transcript-monitor.js.map +1 -1
  90. package/dist/types.d.ts +23 -1
  91. package/dist/ui/dashboard.html +2 -2
  92. package/dist/ui/settings.html +453 -74
  93. package/dist/web-api.d.ts +1 -0
  94. package/dist/web-api.js +24 -15
  95. package/dist/web-api.js.map +1 -1
  96. package/dist/workflow-templates/default.md +0 -4
  97. package/package.json +2 -1
package/dist/cli.js CHANGED
@@ -11,6 +11,8 @@ import { homedir, totalmem, freemem } from "node:os";
11
11
  import { fileURLToPath } from "node:url";
12
12
  import { spawn, execSync, execFileSync } from "node:child_process";
13
13
  import { getAgendHome, getTmuxSocketName } from "./paths.js";
14
+ import { readClassicLastActivityAt } from "./classic-channel-manager.js";
15
+ import { hasPausedMarker } from "./pause-marker.js";
14
16
  /** Prefix tmux args with -L when socket isolation is active. */
15
17
  function tmuxArgs(args) {
16
18
  const socket = getTmuxSocketName();
@@ -1889,14 +1891,14 @@ function getTreeRssKb(pid, depth = 0) {
1889
1891
  return total;
1890
1892
  }
1891
1893
  function getInstanceStatusStandalone(name) {
1894
+ if (hasPausedMarker(join(DATA_DIR, "instances", name)))
1895
+ return "paused";
1892
1896
  const pidPath = join(DATA_DIR, "instances", name, "daemon.pid");
1893
1897
  if (!existsSync(pidPath))
1894
1898
  return "stopped";
1895
1899
  const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
1896
1900
  try {
1897
1901
  process.kill(pid, 0);
1898
- if (existsSync(join(DATA_DIR, "instances", name, "paused-state.json")))
1899
- return "paused";
1900
1902
  return "running";
1901
1903
  }
1902
1904
  catch {
@@ -1938,6 +1940,7 @@ function formatTimeSince(isoStr) {
1938
1940
  * kiro classic "8% !>" / TUI "◔ 1%" / bracket "[8%]" / prompt "8% ❯"
1939
1941
  * codex "Context N% left" (remaining → 100-N) or "Context N% used"
1940
1942
  * opencode "1.2K (6%)"
1943
+ * grok "12K / 500K" (used tokens / context window)
1941
1944
  * Duplicated (not imported) so this CLI entry point stays free of the daemon's
1942
1945
  * dependency graph. All returned values are context USED (low % = fresh).
1943
1946
  */
@@ -1948,6 +1951,18 @@ const defaultParser = (output) => {
1948
1951
  const left = line.match(/Context\s+(\d+)%\s+left/i);
1949
1952
  if (left)
1950
1953
  return 100 - parseInt(left[1], 10);
1954
+ const ratio = line.match(/(\d+\.?\d*[KkMm]?)\s*\/\s*(\d+\.?\d*[KkMm]?)/);
1955
+ if (ratio) {
1956
+ const tokenCount = (value) => {
1957
+ const suffix = value.at(-1)?.toLowerCase();
1958
+ const multiplier = suffix === "k" ? 1_000 : suffix === "m" ? 1_000_000 : 1;
1959
+ return parseFloat(value) * multiplier;
1960
+ };
1961
+ const used = tokenCount(ratio[1]);
1962
+ const total = tokenCount(ratio[2]);
1963
+ if (Number.isFinite(used) && Number.isFinite(total) && total > 0)
1964
+ return used / total * 100;
1965
+ }
1951
1966
  const m = line.match(/(\d+)%.*[!❯>]/)
1952
1967
  || line.match(/◔\s*(\d+)%/)
1953
1968
  || line.match(/\[(\d+)%\]/)
@@ -2084,19 +2099,40 @@ async function lsAction(opts) {
2084
2099
  }
2085
2100
  catch { /* ignore */ }
2086
2101
  }
2087
- // Last activity: prefer statusline.json mtime (updated on real agent activity)
2102
+ // Classic activity is channel-driven. Lightweight Classic daemons often
2103
+ // have no statusline/output log, so prefer the persisted inbound timestamp
2104
+ // and fall back to their durable chat-log mtime for pre-migration history.
2088
2105
  let lastActivity = null;
2089
- for (const probe of ["statusline.json", "daemon.log", "output.log"]) {
2090
- const p = join(DATA_DIR, "instances", name, probe);
2106
+ if (isClassic) {
2107
+ let classicActivity = readClassicLastActivityAt(DATA_DIR, name) ?? 0;
2091
2108
  try {
2092
- if (existsSync(p)) {
2093
- lastActivity = formatTimeSince(statSync(p).mtime.toISOString());
2094
- break;
2109
+ const inboundPath = join(DATA_DIR, "instances", name, "last-inbound-at");
2110
+ if (existsSync(inboundPath)) {
2111
+ const inboundAt = Number(readFileSync(inboundPath, "utf-8").trim());
2112
+ if (Number.isFinite(inboundAt) && inboundAt >= 0 && inboundAt <= Date.now()) {
2113
+ classicActivity = Math.max(classicActivity, inboundAt);
2114
+ }
2095
2115
  }
2096
2116
  }
2097
2117
  catch { /* ignore */ }
2118
+ if (classicActivity) {
2119
+ lastActivity = formatTimeSince(new Date(classicActivity).toISOString());
2120
+ }
2121
+ }
2122
+ else {
2123
+ // Fleet activity: prefer statusline.json mtime (updated on real agent activity).
2124
+ for (const probe of ["statusline.json", "daemon.log", "output.log"]) {
2125
+ const p = join(DATA_DIR, "instances", name, probe);
2126
+ try {
2127
+ if (existsSync(p)) {
2128
+ lastActivity = formatTimeSince(statSync(p).mtime.toISOString());
2129
+ break;
2130
+ }
2131
+ }
2132
+ catch { /* ignore */ }
2133
+ }
2098
2134
  }
2099
- return { name, backend, status, teams, source, context, memMb, lastActivity, idle: undefined };
2135
+ return { name, backend, status, teams, source, context, memMb, lastActivity, classic: isClassic, idle: undefined, state: undefined };
2100
2136
  });
2101
2137
  // Enrich with idle state from fleet API (if fleet is running)
2102
2138
  try {
@@ -2104,11 +2140,37 @@ async function lsAction(opts) {
2104
2140
  const resp = await fetch(`http://127.0.0.1:${port}/api/fleet`, { signal: AbortSignal.timeout(2000) });
2105
2141
  const apiData = await resp.json();
2106
2142
  for (const inst of apiData.instances ?? []) {
2107
- const row = rows.find(r => r.name === inst.name);
2143
+ let row = rows.find(r => r.name === inst.name);
2144
+ if (!row && inst.classic) {
2145
+ classicNames.add(inst.name);
2146
+ const channelId = inst.channelId ?? "";
2147
+ row = {
2148
+ name: inst.name,
2149
+ backend: inst.backend ?? "claude-code",
2150
+ status: inst.status ?? "stopped",
2151
+ teams: ["(classic)"],
2152
+ source: inst.adapterId?.toLowerCase().includes("telegram") || channelId.startsWith("-") || (channelId.length > 0 && channelId.length < 17) ? "TG" : "DC",
2153
+ context: null,
2154
+ memMb: null,
2155
+ lastActivity: inst.lastActivity ? formatTimeSince(new Date(inst.lastActivity).toISOString()) : null,
2156
+ classic: true,
2157
+ idle: inst.idle,
2158
+ state: inst.state,
2159
+ };
2160
+ rows.push(row);
2161
+ }
2108
2162
  if (row) {
2109
2163
  row.idle = inst.idle;
2110
2164
  if (inst.status)
2111
2165
  row.status = inst.status;
2166
+ if (inst.backend)
2167
+ row.backend = inst.backend;
2168
+ if (inst.classic)
2169
+ row.classic = true;
2170
+ if (inst.state)
2171
+ row.state = inst.state;
2172
+ if (inst.lastActivity)
2173
+ row.lastActivity = formatTimeSince(new Date(inst.lastActivity).toISOString());
2112
2174
  }
2113
2175
  }
2114
2176
  }
@@ -2117,9 +2179,38 @@ async function lsAction(opts) {
2117
2179
  console.log(JSON.stringify(rows, null, 2));
2118
2180
  return;
2119
2181
  }
2120
- // Status icon
2121
- const statusIcon = (s, idle) => s === "paused" ? "\x1b[33m⏸\x1b[0m" : s === "running" ? (idle === false ? "\x1b[34m●\x1b[0m" : "\x1b[32m●\x1b[0m") : s === "crashed" ? "\x1b[31m●\x1b[0m" : "\x1b[90m○\x1b[0m";
2122
- const statusLabel = (s, idle) => s === "paused" ? "Paused" : s === "running" ? (idle === false ? "Busy" : "Idle") : s === "crashed" ? "Crashed" : "Stopped";
2182
+ // Status icon — prefer tri-state 'state' field, fall back to idle boolean
2183
+ const statusIcon = (s, idle, state) => {
2184
+ if (state === "stuck")
2185
+ return "\x1b[31m●\x1b[0m";
2186
+ if (state === "paused" || s === "paused")
2187
+ return "\x1b[2;33m●\x1b[0m";
2188
+ if (state === "working")
2189
+ return "\x1b[34m●\x1b[0m";
2190
+ if (state === "idle")
2191
+ return "\x1b[32m●\x1b[0m";
2192
+ // Fallback for when API is unreachable
2193
+ if (s === "running")
2194
+ return idle === false ? "\x1b[34m●\x1b[0m" : "\x1b[32m●\x1b[0m";
2195
+ if (s === "crashed")
2196
+ return "\x1b[31m●\x1b[0m";
2197
+ return "\x1b[90m○\x1b[0m";
2198
+ };
2199
+ const statusLabel = (s, idle, state) => {
2200
+ if (state === "stuck")
2201
+ return "Stuck";
2202
+ if (state === "paused" || s === "paused")
2203
+ return "Paused";
2204
+ if (state === "working")
2205
+ return "Working";
2206
+ if (state === "idle")
2207
+ return "Idle";
2208
+ if (s === "running")
2209
+ return idle === false ? "Busy" : "Idle";
2210
+ if (s === "crashed")
2211
+ return "Crashed";
2212
+ return "Stopped";
2213
+ };
2123
2214
  /** Get display width accounting for fullwidth (CJK) characters */
2124
2215
  const displayWidth = (s) => {
2125
2216
  let w = 0;
@@ -2130,7 +2221,8 @@ async function lsAction(opts) {
2130
2221
  return w;
2131
2222
  };
2132
2223
  const padDisplay = (s, width) => s + " ".repeat(Math.max(0, width - displayWidth(s)));
2133
- const nameW = Math.max(20, ...rows.map(r => displayWidth(r.name) + 2));
2224
+ const displayName = (row) => row.classic ? `[C] ${row.name}` : row.name;
2225
+ const nameW = Math.max(20, ...rows.map(r => displayWidth(displayName(r)) + 2));
2134
2226
  const backendW = 14;
2135
2227
  const statusW = 12;
2136
2228
  const teamW = 20;
@@ -2151,9 +2243,9 @@ async function lsAction(opts) {
2151
2243
  const ctxStr = r.context != null ? `${Math.round(r.context)}%` : "-";
2152
2244
  const memStr = r.memMb != null ? `${r.memMb}MB` : "-";
2153
2245
  const actStr = r.lastActivity ?? "-";
2154
- console.log(padDisplay(r.name, nameW) +
2246
+ console.log(padDisplay(displayName(r), nameW) +
2155
2247
  r.backend.padEnd(backendW) +
2156
- statusIcon(r.status, r.idle) + " " + statusLabel(r.status, r.idle).padEnd(statusW - 2) +
2248
+ statusIcon(r.status, r.idle, r.state) + " " + statusLabel(r.status, r.idle, r.state).padEnd(statusW - 2) +
2157
2249
  padDisplay(teamStr, teamW) +
2158
2250
  r.source.padEnd(srcW) +
2159
2251
  ctxStr.padEnd(ctxW) +