@cursor/july 0.1.2 → 0.1.4

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 (232) hide show
  1. package/AGENTS.md +16 -5
  2. package/README.md +8 -9
  3. package/dist/bin/agent-serve.d.ts +3 -1
  4. package/dist/bin/agent-serve.d.ts.map +1 -1
  5. package/dist/bin/agent-serve.js +416 -155
  6. package/dist/channels/slack/log.d.ts +1 -1
  7. package/dist/channels/slack/log.d.ts.map +1 -1
  8. package/dist/channels/slack/log.js +4 -5
  9. package/dist/channels/slack/setup.js +1 -1
  10. package/dist/channels/slack/socket-mode.d.ts.map +1 -1
  11. package/dist/channels/slack/socket-mode.js +10 -9
  12. package/dist/docs/404.html +2 -2
  13. package/dist/docs/ab.html +3 -3
  14. package/dist/docs/assets/{app.Oje4vhlk.js → app.DF-Yx4OP.js} +1 -1
  15. package/dist/docs/assets/chunks/@localSearchIndexroot.0XrheBv2.js +1 -0
  16. package/dist/docs/assets/chunks/{VPLocalSearchBox.H5XZ2zCB.js → VPLocalSearchBox.DSeJSudL.js} +1 -1
  17. package/dist/docs/assets/chunks/{theme.CTR_TuaE.js → theme.DZVLTXOC.js} +2 -2
  18. package/dist/docs/assets/{index.md.m81y7TY7.js → index.md.Cylk70gg.js} +1 -1
  19. package/dist/docs/assets/{quickstart.md.CfU8_uTC.js → quickstart.md.BU6Iwi_9.js} +18 -6
  20. package/dist/docs/assets/{reference_cli.md.DA730zCu.js → reference_cli.md.Bv6pOxcF.js} +11 -6
  21. package/dist/docs/assets/{reference_cli.md.DA730zCu.lean.js → reference_cli.md.Bv6pOxcF.lean.js} +1 -1
  22. package/dist/docs/building-with-agents.html +3 -3
  23. package/dist/docs/concepts.html +3 -3
  24. package/dist/docs/deployment.html +3 -3
  25. package/dist/docs/evals.html +3 -3
  26. package/dist/docs/guides/agent-to-agent.html +3 -3
  27. package/dist/docs/guides/cloud-runtime.html +3 -3
  28. package/dist/docs/guides/github.html +3 -3
  29. package/dist/docs/guides/human-in-the-loop.html +3 -3
  30. package/dist/docs/guides/slack.html +3 -3
  31. package/dist/docs/guides/webhooks.html +3 -3
  32. package/dist/docs/hashmap.json +1 -1
  33. package/dist/docs/hillclimbing.html +3 -3
  34. package/dist/docs/index.html +5 -5
  35. package/dist/docs/quickstart.html +22 -10
  36. package/dist/docs/reference/agent-config.html +3 -3
  37. package/dist/docs/reference/channels.html +3 -3
  38. package/dist/docs/reference/cli.html +14 -9
  39. package/dist/docs/reference/connections.html +3 -3
  40. package/dist/docs/reference/hooks.html +3 -3
  41. package/dist/docs/reference/http-api.html +3 -3
  42. package/dist/docs/reference/instructions.html +3 -3
  43. package/dist/docs/reference/playground.html +3 -3
  44. package/dist/docs/reference/project-layout.html +3 -3
  45. package/dist/docs/reference/schedules.html +3 -3
  46. package/dist/docs/reference/sessions.html +3 -3
  47. package/dist/docs/reference/skills.html +3 -3
  48. package/dist/docs/reference/subagents.html +3 -3
  49. package/dist/docs/reference/tools.html +3 -3
  50. package/dist/docs/scaffolding-agents.html +3 -3
  51. package/dist/docs/storage.html +3 -3
  52. package/dist/docs/troubleshooting.html +3 -3
  53. package/dist/internal/ab-collector.js +3 -3
  54. package/dist/internal/ab-fold.js +1 -1
  55. package/dist/internal/chat-client.d.ts +29 -3
  56. package/dist/internal/chat-client.d.ts.map +1 -1
  57. package/dist/internal/chat-client.js +180 -27
  58. package/dist/internal/cli-ax.d.ts +83 -2
  59. package/dist/internal/cli-ax.d.ts.map +1 -1
  60. package/dist/internal/cli-ax.js +626 -52
  61. package/dist/internal/cli-cursor.d.ts.map +1 -1
  62. package/dist/internal/cli-cursor.js +8 -36
  63. package/dist/internal/cli-deploy.d.ts +59 -3
  64. package/dist/internal/cli-deploy.d.ts.map +1 -1
  65. package/dist/internal/cli-deploy.js +316 -38
  66. package/dist/internal/cli-github.js +13 -13
  67. package/dist/internal/cursor/account-mcp.js +3 -3
  68. package/dist/internal/cursor/backend-client.js +1 -1
  69. package/dist/internal/cursor/credentials.d.ts +14 -3
  70. package/dist/internal/cursor/credentials.d.ts.map +1 -1
  71. package/dist/internal/cursor/credentials.js +21 -6
  72. package/dist/internal/cursor/github-credentials.js +3 -3
  73. package/dist/internal/cursor-event-relay.js +1 -1
  74. package/dist/internal/cursor-relay-core.d.ts +1 -1
  75. package/dist/internal/cursor-relay-core.d.ts.map +1 -1
  76. package/dist/internal/cursor-relay-core.js +2 -1
  77. package/dist/internal/cursor-slack-relay.js +1 -1
  78. package/dist/internal/deploy-client.d.ts +9 -1
  79. package/dist/internal/deploy-client.d.ts.map +1 -1
  80. package/dist/internal/deploy-client.js +23 -3
  81. package/dist/internal/deploy-source.d.ts +35 -0
  82. package/dist/internal/deploy-source.d.ts.map +1 -0
  83. package/dist/internal/deploy-source.js +118 -0
  84. package/dist/internal/discovery.d.ts +11 -0
  85. package/dist/internal/discovery.d.ts.map +1 -1
  86. package/dist/internal/discovery.js +43 -14
  87. package/dist/internal/distribution.d.ts +7 -0
  88. package/dist/internal/distribution.d.ts.map +1 -1
  89. package/dist/internal/distribution.js +7 -0
  90. package/dist/internal/docs-site.js +3 -3
  91. package/dist/internal/eval-run-store.d.ts.map +1 -1
  92. package/dist/internal/eval-run-store.js +10 -9
  93. package/dist/internal/eval-runner.d.ts +2 -0
  94. package/dist/internal/eval-runner.d.ts.map +1 -1
  95. package/dist/internal/eval-runner.js +2 -0
  96. package/dist/internal/event-mapper.d.ts +54 -1
  97. package/dist/internal/event-mapper.d.ts.map +1 -1
  98. package/dist/internal/event-mapper.js +151 -41
  99. package/dist/internal/github-fanout.js +2 -2
  100. package/dist/internal/host-platforms.js +5 -5
  101. package/dist/internal/init-project.d.ts +88 -1
  102. package/dist/internal/init-project.d.ts.map +1 -1
  103. package/dist/internal/init-project.js +221 -31
  104. package/dist/internal/install-cursor-skills.d.ts +64 -0
  105. package/dist/internal/install-cursor-skills.d.ts.map +1 -0
  106. package/dist/internal/install-cursor-skills.js +274 -0
  107. package/dist/internal/logs-client.d.ts +60 -0
  108. package/dist/internal/logs-client.d.ts.map +1 -0
  109. package/dist/internal/logs-client.js +311 -0
  110. package/dist/internal/mcp-endpoint.d.ts.map +1 -1
  111. package/dist/internal/mcp-endpoint.js +1 -1
  112. package/dist/internal/open-browser.d.ts +5 -0
  113. package/dist/internal/open-browser.d.ts.map +1 -0
  114. package/dist/internal/open-browser.js +34 -0
  115. package/dist/internal/playground/toolchain.d.ts.map +1 -1
  116. package/dist/internal/playground/toolchain.js +19 -14
  117. package/dist/internal/playground-proxy.d.ts +69 -0
  118. package/dist/internal/playground-proxy.d.ts.map +1 -0
  119. package/dist/internal/playground-proxy.js +468 -0
  120. package/dist/internal/prompt-context.d.ts +35 -0
  121. package/dist/internal/prompt-context.d.ts.map +1 -0
  122. package/dist/internal/prompt-context.js +71 -0
  123. package/dist/internal/reminder-runner.d.ts.map +1 -1
  124. package/dist/internal/reminder-runner.js +11 -11
  125. package/dist/internal/request-headers.d.ts +11 -0
  126. package/dist/internal/request-headers.d.ts.map +1 -0
  127. package/dist/internal/request-headers.js +14 -0
  128. package/dist/internal/resolve-prod-target.d.ts +44 -0
  129. package/dist/internal/resolve-prod-target.d.ts.map +1 -0
  130. package/dist/internal/resolve-prod-target.js +134 -0
  131. package/dist/internal/resolved-connections.js +5 -5
  132. package/dist/internal/run-client.d.ts +2 -2
  133. package/dist/internal/run-client.d.ts.map +1 -1
  134. package/dist/internal/run-client.js +38 -23
  135. package/dist/internal/schedule-runner.js +1 -1
  136. package/dist/internal/server.d.ts.map +1 -1
  137. package/dist/internal/server.js +23 -17
  138. package/dist/internal/session-engine.d.ts +1 -1
  139. package/dist/internal/session-engine.d.ts.map +1 -1
  140. package/dist/internal/session-engine.js +34 -19
  141. package/dist/internal/sessions-client.d.ts +34 -0
  142. package/dist/internal/sessions-client.d.ts.map +1 -0
  143. package/dist/internal/sessions-client.js +193 -0
  144. package/dist/internal/storage-coordinator.js +6 -6
  145. package/dist/internal/stream-progress.d.ts.map +1 -1
  146. package/dist/internal/stream-progress.js +31 -3
  147. package/dist/internal/terminal-style.d.ts +22 -0
  148. package/dist/internal/terminal-style.d.ts.map +1 -0
  149. package/dist/internal/terminal-style.js +49 -0
  150. package/dist/internal/trajectory.d.ts +10 -5
  151. package/dist/internal/trajectory.d.ts.map +1 -1
  152. package/dist/internal/trajectory.js +82 -10
  153. package/dist/internal/update-check.d.ts +93 -0
  154. package/dist/internal/update-check.d.ts.map +1 -0
  155. package/dist/internal/update-check.js +431 -0
  156. package/dist/internal/workspace.d.ts +11 -0
  157. package/dist/internal/workspace.d.ts.map +1 -1
  158. package/dist/internal/workspace.js +38 -4
  159. package/dist/playground/assets/index-Ct_Usdm8.css +1 -0
  160. package/dist/playground/assets/index-Dsyb-Vaj.js +319 -0
  161. package/dist/playground/index.html +2 -2
  162. package/dist/types.d.ts +29 -2
  163. package/dist/types.d.ts.map +1 -1
  164. package/docs/README.md +0 -1
  165. package/docs/quickstart.md +22 -7
  166. package/docs/reference/cli.md +51 -3
  167. package/package.json +4 -1
  168. package/skills/ab/SKILL.md +8 -8
  169. package/skills/create-agent/SKILL.md +28 -22
  170. package/skills/debug/SKILL.md +11 -11
  171. package/skills/evals/SKILL.md +16 -16
  172. package/skills/framework-map/SKILL.md +6 -6
  173. package/skills/github/SKILL.md +13 -13
  174. package/skills/hillclimb/SKILL.md +10 -10
  175. package/skills/setup-slack/SKILL.md +14 -14
  176. package/src/bin/agent-serve.ts +451 -191
  177. package/src/channels/slack/log.ts +5 -5
  178. package/src/channels/slack/setup.ts +1 -1
  179. package/src/channels/slack/socket-mode.ts +11 -9
  180. package/src/internal/ab-collector.ts +3 -3
  181. package/src/internal/ab-fold.ts +1 -1
  182. package/src/internal/chat-client.ts +252 -37
  183. package/src/internal/cli-ax.ts +761 -72
  184. package/src/internal/cli-cursor.ts +14 -42
  185. package/src/internal/cli-deploy.ts +428 -49
  186. package/src/internal/cli-github.ts +13 -15
  187. package/src/internal/cursor/account-mcp.ts +3 -3
  188. package/src/internal/cursor/backend-client.ts +1 -1
  189. package/src/internal/cursor/credentials.ts +26 -7
  190. package/src/internal/cursor/github-credentials.ts +3 -3
  191. package/src/internal/cursor-event-relay.ts +1 -1
  192. package/src/internal/cursor-relay-core.ts +4 -2
  193. package/src/internal/cursor-slack-relay.ts +1 -1
  194. package/src/internal/deploy-client.ts +45 -4
  195. package/src/internal/deploy-source.ts +133 -0
  196. package/src/internal/discovery.ts +53 -16
  197. package/src/internal/distribution.ts +8 -0
  198. package/src/internal/docs-site.ts +3 -3
  199. package/src/internal/eval-run-store.ts +10 -11
  200. package/src/internal/eval-runner.ts +5 -0
  201. package/src/internal/event-mapper.ts +222 -42
  202. package/src/internal/github-fanout.ts +2 -2
  203. package/src/internal/host-platforms.ts +5 -5
  204. package/src/internal/init-project.ts +333 -51
  205. package/src/internal/install-cursor-skills.ts +327 -0
  206. package/src/internal/logs-client.ts +442 -0
  207. package/src/internal/mcp-endpoint.ts +1 -3
  208. package/src/internal/open-browser.ts +41 -0
  209. package/src/internal/playground/toolchain.ts +18 -16
  210. package/src/internal/playground-proxy.ts +576 -0
  211. package/src/internal/prompt-context.ts +95 -0
  212. package/src/internal/reminder-runner.ts +11 -17
  213. package/src/internal/request-headers.ts +23 -0
  214. package/src/internal/resolve-prod-target.ts +182 -0
  215. package/src/internal/resolved-connections.ts +5 -5
  216. package/src/internal/run-client.ts +39 -36
  217. package/src/internal/schedule-runner.ts +1 -1
  218. package/src/internal/server.ts +25 -16
  219. package/src/internal/session-engine.ts +35 -18
  220. package/src/internal/sessions-client.ts +216 -0
  221. package/src/internal/storage-coordinator.ts +6 -6
  222. package/src/internal/stream-progress.ts +36 -2
  223. package/src/internal/terminal-style.ts +74 -0
  224. package/src/internal/trajectory.ts +91 -13
  225. package/src/internal/update-check.ts +552 -0
  226. package/src/internal/workspace.ts +42 -4
  227. package/src/types.ts +45 -7
  228. package/dist/docs/assets/chunks/@localSearchIndexroot.zwQ9RCQ7.js +0 -1
  229. package/dist/playground/assets/index-B1Qc9h2u.css +0 -1
  230. package/dist/playground/assets/index-CpDYCj8W.js +0 -79
  231. /package/dist/docs/assets/{index.md.m81y7TY7.lean.js → index.md.Cylk70gg.lean.js} +0 -0
  232. /package/dist/docs/assets/{quickstart.md.CfU8_uTC.lean.js → quickstart.md.BU6Iwi_9.lean.js} +0 -0
@@ -54,6 +54,7 @@ import { type ABSnapshot, buildABSnapshot } from "./ab-snapshot.js";
54
54
  import { ApprovalGate } from "./approval-gate.js";
55
55
  import { samePrincipal } from "./auth.js";
56
56
  import { mergeCloudOptions, resolveSessionRuntime } from "./cloud-merge.js";
57
+ import { isDevMode } from "./dev-mode.js";
57
58
  import { EventLogStore } from "./event-log.js";
58
59
  import { TurnEventMapper } from "./event-mapper.js";
59
60
  import { createHostPlatforms, type HostPlatforms } from "./host-platforms.js";
@@ -65,6 +66,11 @@ import {
65
66
  } from "./ids.js";
66
67
  import { validateToolInput } from "./json-schema.js";
67
68
  import { McpHost } from "./mcp-host.js";
69
+ import {
70
+ buildIdentitySection,
71
+ buildSessionContextBlock,
72
+ SCHEDULE_CHANNEL_PREFIX,
73
+ } from "./prompt-context.js";
68
74
  import { assertCloudCanHonorAccountServersFilters } from "./resolved-connections.js";
69
75
  import type { AgentRunner } from "./sdk-runner.js";
70
76
  import { SessionStore } from "./session-store.js";
@@ -77,7 +83,7 @@ import {
77
83
  } from "./workspace.js";
78
84
 
79
85
  export const HTTP_CHANNEL_ID = "http";
80
- export const SCHEDULE_CHANNEL_PREFIX = "schedule:";
86
+ export { SCHEDULE_CHANNEL_PREFIX } from "./prompt-context.js";
81
87
 
82
88
  export class SessionBusyError extends Error {
83
89
  constructor(sessionId: string) {
@@ -243,7 +249,7 @@ export class SessionEngine {
243
249
  (sessionId) => this.sessions.eventFilePath(sessionId),
244
250
  (sessionId, error) =>
245
251
  this.logger(
246
- `[agent-serve] failed to persist events for ${sessionId}: ${describeError(error)}`
252
+ `[agentkit] failed to persist events for ${sessionId}: ${describeError(error)}`
247
253
  )
248
254
  );
249
255
  this.storage =
@@ -439,7 +445,7 @@ export class SessionEngine {
439
445
  }
440
446
  } catch (error) {
441
447
  this.logger(
442
- `[agent-serve] ab "${experiment.name}" enrollment failed (sticky skip): ${describeError(error)}`
448
+ `[agentkit] ab "${experiment.name}" enrollment failed (sticky skip): ${describeError(error)}`
443
449
  );
444
450
  variant = null;
445
451
  }
@@ -706,7 +712,7 @@ export class SessionEngine {
706
712
  this.queueDispatch(sessionId, event);
707
713
  } catch (error) {
708
714
  this.logger(
709
- `[agent-serve] failed to record event for ${sessionId}: ${describeError(error)}`
715
+ `[agentkit] failed to record event for ${sessionId}: ${describeError(error)}`
710
716
  );
711
717
  }
712
718
  };
@@ -744,7 +750,10 @@ export class SessionEngine {
744
750
  // events while sibling parallel tools are still executing.
745
751
  if (
746
752
  update.type === "tool-call-started" ||
747
- update.type === "tool-call-completed"
753
+ update.type === "tool-call-completed" ||
754
+ // Nested subagent progress (newer SDKs); string check keeps
755
+ // typecheck green against older published `@cursor/sdk` pins.
756
+ (update as { type: string }).type === "tool-call-delta"
748
757
  ) {
749
758
  await yieldEventLoop();
750
759
  }
@@ -847,14 +856,24 @@ export class SessionEngine {
847
856
  })
848
857
  : undefined;
849
858
  let turnPrompt = prompt;
859
+ if (isFirstTurn) {
860
+ const contextBlock = buildSessionContextBlock({
861
+ sessionId: record.sessionId,
862
+ channelId: record.channelId,
863
+ channelKind: this.channelsById.get(record.channelId)?.meta?.kind,
864
+ environment: isDevMode() ? "local dev server" : "hosted deployment",
865
+ });
866
+ turnPrompt = `${contextBlock}\n\n${prompt}`;
867
+ }
850
868
  if (runtime === "cloud" && isFirstTurn) {
851
869
  const preamble = [
852
870
  agent.instructions?.trim() ?? "",
871
+ buildIdentitySection(agent),
853
872
  buildAgentToolsCatalog(agent.tools, { includeScripts: true }),
854
873
  ]
855
874
  .filter((part) => part !== "")
856
875
  .join("\n\n");
857
- turnPrompt = preamble === "" ? prompt : `${preamble}\n\n${prompt}`;
876
+ turnPrompt = `${preamble}\n\n${turnPrompt}`;
858
877
  }
859
878
  return {
860
879
  sessionId: record.sessionId,
@@ -1382,7 +1401,7 @@ export class SessionEngine {
1382
1401
  .then(() => this.dispatchEvent(sessionId, event))
1383
1402
  .catch((error) => {
1384
1403
  this.logger(
1385
- `[agent-serve] event dispatch failed for ${sessionId}: ${describeError(error)}`
1404
+ `[agentkit] event dispatch failed for ${sessionId}: ${describeError(error)}`
1386
1405
  );
1387
1406
  })
1388
1407
  .then(() => {
@@ -1427,7 +1446,7 @@ export class SessionEngine {
1427
1446
  await handler(event, channelCtx, sessionCtx);
1428
1447
  } catch (error) {
1429
1448
  this.logger(
1430
- `[agent-serve] channel "${record.channelId}" handler for ${event.type} threw: ${describeError(error)}`
1449
+ `[agentkit] channel "${record.channelId}" handler for ${event.type} threw: ${describeError(error)}`
1431
1450
  );
1432
1451
  }
1433
1452
  }
@@ -1455,7 +1474,7 @@ export class SessionEngine {
1455
1474
  });
1456
1475
  } catch (error) {
1457
1476
  this.logger(
1458
- `[agent-serve] hook "${hook.name}" handler for ${event.type} threw: ${describeError(error)}`
1477
+ `[agentkit] hook "${hook.name}" handler for ${event.type} threw: ${describeError(error)}`
1459
1478
  );
1460
1479
  }
1461
1480
  }
@@ -1597,7 +1616,7 @@ export class SessionEngine {
1597
1616
  });
1598
1617
  } catch (error) {
1599
1618
  this.logger(
1600
- `[agent-serve] ab persistSnapshots.save threw: ${describeError(error)}`
1619
+ `[agentkit] ab persistSnapshots.save threw: ${describeError(error)}`
1601
1620
  );
1602
1621
  }
1603
1622
  } else {
@@ -1806,9 +1825,7 @@ export class SessionEngine {
1806
1825
  try {
1807
1826
  await this.runBulkRestore(storage, policy);
1808
1827
  } catch (error) {
1809
- this.logger(
1810
- `[agent-serve] session restore failed: ${describeError(error)}`
1811
- );
1828
+ this.logger(`[agentkit] session restore failed: ${describeError(error)}`);
1812
1829
  }
1813
1830
  }
1814
1831
 
@@ -1865,7 +1882,7 @@ export class SessionEngine {
1865
1882
  return { record, events };
1866
1883
  } catch (error) {
1867
1884
  this.logger(
1868
- `[agent-serve] failed to restore session ${record.sessionId}: ${describeError(error)}`
1885
+ `[agentkit] failed to restore session ${record.sessionId}: ${describeError(error)}`
1869
1886
  );
1870
1887
  return undefined;
1871
1888
  }
@@ -1884,7 +1901,7 @@ export class SessionEngine {
1884
1901
  (ndjson === undefined ? 0 : Buffer.byteLength(ndjson, "utf8"));
1885
1902
  if (bytes > budget) {
1886
1903
  this.logger(
1887
- `[agent-serve] session restore stopped at the ${policy.maxTotalBytes}-byte budget after ${restored} session(s); remaining sessions restore lazily on resume`
1904
+ `[agentkit] session restore stopped at the ${policy.maxTotalBytes}-byte budget after ${restored} session(s); remaining sessions restore lazily on resume`
1888
1905
  );
1889
1906
  break outer;
1890
1907
  }
@@ -1894,13 +1911,13 @@ export class SessionEngine {
1894
1911
  restored += 1;
1895
1912
  } catch (error) {
1896
1913
  this.logger(
1897
- `[agent-serve] failed to restore session ${item.record.sessionId}: ${describeError(error)}`
1914
+ `[agentkit] failed to restore session ${item.record.sessionId}: ${describeError(error)}`
1898
1915
  );
1899
1916
  }
1900
1917
  }
1901
1918
  }
1902
1919
  if (restored > 0) {
1903
- this.logger(`[agent-serve] restored ${restored} session(s) from storage`);
1920
+ this.logger(`[agentkit] restored ${restored} session(s) from storage`);
1904
1921
  }
1905
1922
  }
1906
1923
 
@@ -1956,7 +1973,7 @@ export class SessionEngine {
1956
1973
  const events = await storage.listSessionEvents(record.sessionId);
1957
1974
  await this.materializeSession(record, eventsNdjson(events));
1958
1975
  this.logger(
1959
- `[agent-serve] lazily restored session ${record.sessionId} from storage`
1976
+ `[agentkit] lazily restored session ${record.sessionId} from storage`
1960
1977
  );
1961
1978
  return record;
1962
1979
  }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Session list / event fetch for CLI (`sessions`, `session`, chat reattach).
3
+ *
4
+ * Customer-facing errors never include hosting URLs or infra jargon.
5
+ */
6
+
7
+ import type { SessionEvent, SessionSummary } from "../types.js";
8
+ import { sanitizeCustomerError } from "./logs-client.js";
9
+ import { mergeRequestHeaders, type RequestAuth } from "./request-headers.js";
10
+
11
+ export async function listSessions(args: {
12
+ baseUrl: string;
13
+ auth?: RequestAuth;
14
+ fetchImpl?: typeof fetch;
15
+ }): Promise<SessionSummary[]> {
16
+ const baseUrl = args.baseUrl.replace(/\/$/, "");
17
+ const fetchImpl = args.fetchImpl ?? fetch;
18
+ let resp: Response;
19
+ try {
20
+ resp = await fetchImpl(`${baseUrl}/v1/sessions`, {
21
+ headers: mergeRequestHeaders(args.auth),
22
+ });
23
+ } catch (error) {
24
+ throw new Error(
25
+ sanitizeCustomerError(
26
+ error instanceof Error ? error.message : "Could not list sessions."
27
+ )
28
+ );
29
+ }
30
+ if (!resp.ok) {
31
+ throw new Error(`Could not list sessions (HTTP ${resp.status}).`);
32
+ }
33
+ const body = (await resp.json()) as { sessions?: unknown };
34
+ if (!Array.isArray(body.sessions)) {
35
+ return [];
36
+ }
37
+ const out: SessionSummary[] = [];
38
+ for (const row of body.sessions) {
39
+ const parsed = parseSessionSummary(row);
40
+ if (parsed !== undefined) {
41
+ out.push(parsed);
42
+ }
43
+ }
44
+ return out;
45
+ }
46
+
47
+ export async function fetchSessionEvents(args: {
48
+ baseUrl: string;
49
+ sessionId: string;
50
+ auth?: RequestAuth;
51
+ fetchImpl?: typeof fetch;
52
+ }): Promise<SessionEvent[]> {
53
+ const baseUrl = args.baseUrl.replace(/\/$/, "");
54
+ const fetchImpl = args.fetchImpl ?? fetch;
55
+ const path = `/v1/session/${encodeURIComponent(args.sessionId)}/events`;
56
+
57
+ try {
58
+ const jsonResp = await fetchImpl(`${baseUrl}${path}?format=json`, {
59
+ headers: mergeRequestHeaders(args.auth),
60
+ });
61
+ if (jsonResp.ok) {
62
+ const body = (await jsonResp.json()) as { events?: unknown };
63
+ if (Array.isArray(body.events)) {
64
+ return body.events as SessionEvent[];
65
+ }
66
+ } else if (jsonResp.status === 404) {
67
+ throw new Error(`Session ${args.sessionId} not found.`);
68
+ } else if (jsonResp.status === 403) {
69
+ throw new Error(
70
+ `Session ${args.sessionId} is not readable by this caller.`
71
+ );
72
+ }
73
+ } catch (error) {
74
+ if (error instanceof Error && error.message.startsWith("Session ")) {
75
+ throw error;
76
+ }
77
+ // Fall through to NDJSON.
78
+ }
79
+
80
+ try {
81
+ const resp = await fetchImpl(`${baseUrl}${path}`, {
82
+ headers: mergeRequestHeaders(args.auth),
83
+ });
84
+ if (resp.status === 404) {
85
+ throw new Error(`Session ${args.sessionId} not found.`);
86
+ }
87
+ if (resp.status === 403) {
88
+ throw new Error(
89
+ `Session ${args.sessionId} is not readable by this caller.`
90
+ );
91
+ }
92
+ if (!resp.ok) {
93
+ throw new Error(`Could not fetch session events (HTTP ${resp.status}).`);
94
+ }
95
+ const text = await resp.text();
96
+ const events: SessionEvent[] = [];
97
+ for (const line of text.split("\n")) {
98
+ if (line.trim() === "") {
99
+ continue;
100
+ }
101
+ try {
102
+ events.push(JSON.parse(line) as SessionEvent);
103
+ } catch {
104
+ // skip malformed lines
105
+ }
106
+ }
107
+ return events;
108
+ } catch (error) {
109
+ if (error instanceof Error && error.message.startsWith("Session ")) {
110
+ throw error;
111
+ }
112
+ if (error instanceof Error && error.message.startsWith("Could not fetch")) {
113
+ throw new Error(sanitizeCustomerError(error.message));
114
+ }
115
+ throw new Error(
116
+ sanitizeCustomerError(
117
+ error instanceof Error
118
+ ? error.message
119
+ : "Could not fetch session events."
120
+ )
121
+ );
122
+ }
123
+ }
124
+
125
+ /** Lenient parse so partial stubs / older servers still list by sessionId. */
126
+ function parseSessionSummary(value: unknown): SessionSummary | undefined {
127
+ if (typeof value !== "object" || value === null) {
128
+ return undefined;
129
+ }
130
+ const row = value as Record<string, unknown>;
131
+ if (typeof row.sessionId !== "string" || row.sessionId === "") {
132
+ return undefined;
133
+ }
134
+ const continuationToken =
135
+ typeof row.continuationToken === "string"
136
+ ? row.continuationToken
137
+ : row.continuationToken === null
138
+ ? null
139
+ : null;
140
+ return {
141
+ sessionId: row.sessionId,
142
+ channelId: typeof row.channelId === "string" ? row.channelId : "",
143
+ mode: row.mode === "task" ? "task" : "chat",
144
+ title: typeof row.title === "string" ? row.title : undefined,
145
+ turnCount: typeof row.turnCount === "number" ? row.turnCount : 0,
146
+ running: row.running === true,
147
+ createdAt: typeof row.createdAt === "string" ? row.createdAt : "",
148
+ updatedAt: typeof row.updatedAt === "string" ? row.updatedAt : "",
149
+ continuationToken,
150
+ externalUrl:
151
+ typeof row.externalUrl === "string" ? row.externalUrl : undefined,
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Pick the previous (most recently updated) followable session for
157
+ * `resume` / `chat --resume` when no session id was passed.
158
+ * Followable = has a non-empty continuation token (task sessions without
159
+ * one are skipped).
160
+ */
161
+ export function pickPreviousSession(
162
+ sessions: readonly SessionSummary[]
163
+ ): SessionSummary | undefined {
164
+ const followable = sessions.filter(
165
+ (s) => typeof s.continuationToken === "string" && s.continuationToken !== ""
166
+ );
167
+ if (followable.length === 0) {
168
+ return undefined;
169
+ }
170
+ return [...followable].sort((a, b) =>
171
+ b.updatedAt.localeCompare(a.updatedAt)
172
+ )[0];
173
+ }
174
+
175
+ /** Look up the most recently updated followable session id. */
176
+ export async function resolvePreviousSessionId(args: {
177
+ baseUrl: string;
178
+ auth?: RequestAuth;
179
+ fetchImpl?: typeof fetch;
180
+ }): Promise<string | undefined> {
181
+ const sessions = await listSessions({
182
+ baseUrl: args.baseUrl,
183
+ auth: args.auth,
184
+ fetchImpl: args.fetchImpl,
185
+ });
186
+ return pickPreviousSession(sessions)?.sessionId;
187
+ }
188
+
189
+ /** Format a sessions table (id, channel, mode, turns, running, updated). */
190
+ export function formatSessionsTable(sessions: SessionSummary[]): string {
191
+ if (sessions.length === 0) {
192
+ return "No sessions.\n";
193
+ }
194
+ const header = ["SESSION", "CHANNEL", "MODE", "TURNS", "RUNNING", "UPDATED"];
195
+ const rows = sessions.map((s) => [
196
+ s.sessionId,
197
+ s.channelId,
198
+ s.mode,
199
+ String(s.turnCount),
200
+ s.running ? "yes" : "no",
201
+ s.updatedAt,
202
+ ]);
203
+ return `${renderTable(header, rows)}\n`;
204
+ }
205
+
206
+ function renderTable(header: string[], rows: string[][]): string {
207
+ const widths = header.map((h, i) =>
208
+ Math.max(h.length, ...rows.map((row) => (row[i] ?? "").length))
209
+ );
210
+ const renderRow = (row: string[]): string =>
211
+ row
212
+ .map((cell, i) => cell.padEnd(widths[i] ?? 0))
213
+ .join(" ")
214
+ .trimEnd();
215
+ return [renderRow(header), ...rows.map(renderRow)].join("\n");
216
+ }
@@ -317,7 +317,7 @@ export class StorageCoordinator {
317
317
  // under at-most-once). The session is unrecoverable; treat as a miss
318
318
  // so the conversation can continue rather than failing forever.
319
319
  this.logger(
320
- `[agent-serve] storage continuation entry points at missing session ${sessionId}; treating as a miss`
320
+ `[agentkit] storage continuation entry points at missing session ${sessionId}; treating as a miss`
321
321
  );
322
322
  return undefined;
323
323
  }
@@ -488,7 +488,7 @@ export class StorageCoordinator {
488
488
  return value == null ? undefined : (value as unknown as ABSnapshot);
489
489
  } catch (error) {
490
490
  this.logger(
491
- `[agent-serve] storage get(ab-snapshot) failed: ${describeError(error)}`
491
+ `[agentkit] storage get(ab-snapshot) failed: ${describeError(error)}`
492
492
  );
493
493
  return undefined;
494
494
  }
@@ -521,7 +521,7 @@ export class StorageCoordinator {
521
521
  clearTimeout(timer);
522
522
  if (!drained) {
523
523
  this.logger(
524
- `[agent-serve] storage shutdown drain timed out after ${CLOSE_DRAIN_TIMEOUT_MS}ms with ${this.pending} write(s) undelivered`
524
+ `[agentkit] storage shutdown drain timed out after ${CLOSE_DRAIN_TIMEOUT_MS}ms with ${this.pending} write(s) undelivered`
525
525
  );
526
526
  }
527
527
  }
@@ -569,7 +569,7 @@ export class StorageCoordinator {
569
569
  return Array.isArray(entries) ? entries : [];
570
570
  } catch (error) {
571
571
  this.logger(
572
- `[agent-serve] storage list(${prefix}) failed: ${describeError(error)}`
572
+ `[agentkit] storage list(${prefix}) failed: ${describeError(error)}`
573
573
  );
574
574
  return [];
575
575
  }
@@ -583,7 +583,7 @@ export class StorageCoordinator {
583
583
  this.dropped += ops.length;
584
584
  if (this.dropped <= ops.length || this.dropped % 1_000 < ops.length) {
585
585
  this.logger(
586
- `[agent-serve] storage queue full (${MAX_PENDING_OPS} pending writes); dropped ${this.dropped} write(s) so far — the sink is too slow for the traffic`
586
+ `[agentkit] storage queue full (${MAX_PENDING_OPS} pending writes); dropped ${this.dropped} write(s) so far — the sink is too slow for the traffic`
587
587
  );
588
588
  }
589
589
  return;
@@ -600,7 +600,7 @@ export class StorageCoordinator {
600
600
  }
601
601
  } catch (error) {
602
602
  this.logger(
603
- `[agent-serve] storage ${op.op}(${op.key}) failed: ${describeError(error)}`
603
+ `[agentkit] storage ${op.op}(${op.key}) failed: ${describeError(error)}`
604
604
  );
605
605
  } finally {
606
606
  this.pending -= 1;
@@ -64,6 +64,9 @@ export function createStreamProgress(options?: {
64
64
  break;
65
65
  }
66
66
  case "reasoning.appended": {
67
+ if (event.data.parentCallId !== undefined) {
68
+ break;
69
+ }
67
70
  if (!thinkingShown) {
68
71
  thinkingShown = true;
69
72
  write(c.dim(" · thinking…\n"));
@@ -71,6 +74,11 @@ export function createStreamProgress(options?: {
71
74
  break;
72
75
  }
73
76
  case "message.appended": {
77
+ // Nested subagent deltas stay inside the task chip/indent, not
78
+ // the parent agent stream.
79
+ if (event.data.parentCallId !== undefined) {
80
+ break;
81
+ }
74
82
  if (!assistantOpen) {
75
83
  write(`${c.green("‹ agent")} `);
76
84
  assistantOpen = true;
@@ -79,6 +87,9 @@ export function createStreamProgress(options?: {
79
87
  break;
80
88
  }
81
89
  case "message.completed": {
90
+ if (event.data.parentCallId !== undefined) {
91
+ break;
92
+ }
82
93
  closeAssistant();
83
94
  break;
84
95
  }
@@ -98,9 +109,18 @@ export function createStreamProgress(options?: {
98
109
  closeAssistant();
99
110
  const now = Date.now();
100
111
  for (const call of event.data.calls) {
112
+ if (call.toolName === "task" && call.parentCallId === undefined) {
113
+ // Covered by subagent.called; avoid a duplicate bare `task` line.
114
+ continue;
115
+ }
101
116
  toolStartedAt.set(call.callId, now);
117
+ const indent =
118
+ call.parentCallId !== undefined ||
119
+ event.data.parentCallId !== undefined
120
+ ? " "
121
+ : " ";
102
122
  write(
103
- ` ${c.magenta("⚙")} ${c.bold(call.toolName)}${c.dim(
123
+ `${indent}${c.magenta("⚙")} ${c.bold(call.toolName)}${c.dim(
104
124
  formatArgs(call.args)
105
125
  )}\n`
106
126
  );
@@ -127,13 +147,21 @@ export function createStreamProgress(options?: {
127
147
  break;
128
148
  }
129
149
  case "action.result": {
150
+ if (
151
+ event.data.toolName === "task" &&
152
+ event.data.parentCallId === undefined
153
+ ) {
154
+ break;
155
+ }
130
156
  const started = toolStartedAt.get(event.data.callId);
131
157
  toolStartedAt.delete(event.data.callId);
132
158
  const dur =
133
159
  started === undefined ? "" : c.dim(` ${elapsed(started)}`);
134
160
  const mark = event.data.isError ? c.red("✗") : c.magenta("✓");
161
+ const indent =
162
+ event.data.parentCallId !== undefined ? " " : " ";
135
163
  write(
136
- ` ${mark} ${c.bold(event.data.toolName)}${dur} ${c.dim(
164
+ `${indent}${mark} ${c.bold(event.data.toolName)}${dur} ${c.dim(
137
165
  truncate(stringify(event.data.output), 90)
138
166
  )}\n`
139
167
  );
@@ -149,6 +177,12 @@ export function createStreamProgress(options?: {
149
177
  );
150
178
  break;
151
179
  }
180
+ case "subagent.completed": {
181
+ write(
182
+ ` ${c.magenta("✓")} ${c.bold(event.data.name ?? "subagent")} ${c.dim("done")}\n`
183
+ );
184
+ break;
185
+ }
152
186
  case "turn.completed": {
153
187
  closeAssistant();
154
188
  const usage = event.data.usage;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Tiny ANSI helpers for CLI progress output. Respects `NO_COLOR` and
3
+ * only enables when the target stream is a TTY.
4
+ */
5
+
6
+ import { clearScreenDown, cursorTo } from "node:readline";
7
+
8
+ export interface TerminalPalette {
9
+ dim: (s: string) => string;
10
+ bold: (s: string) => string;
11
+ cyan: (s: string) => string;
12
+ green: (s: string) => string;
13
+ red: (s: string) => string;
14
+ magenta: (s: string) => string;
15
+ yellow: (s: string) => string;
16
+ }
17
+
18
+ const IDENTITY = (s: string): string => s;
19
+
20
+ const PLAIN: TerminalPalette = {
21
+ dim: IDENTITY,
22
+ bold: IDENTITY,
23
+ cyan: IDENTITY,
24
+ green: IDENTITY,
25
+ red: IDENTITY,
26
+ magenta: IDENTITY,
27
+ yellow: IDENTITY,
28
+ };
29
+
30
+ export function colorEnabledFor(
31
+ stream: NodeJS.WriteStream = process.stdout
32
+ ): boolean {
33
+ return stream.isTTY === true && process.env.NO_COLOR === undefined;
34
+ }
35
+
36
+ export function makePalette(enabled: boolean): TerminalPalette {
37
+ if (!enabled) {
38
+ return PLAIN;
39
+ }
40
+ const wrap =
41
+ (code: string) =>
42
+ (s: string): string =>
43
+ `\u001b[${code}m${s}\u001b[0m`;
44
+ return {
45
+ dim: wrap("2"),
46
+ bold: wrap("1"),
47
+ cyan: wrap("36"),
48
+ green: wrap("32"),
49
+ red: wrap("31"),
50
+ magenta: wrap("35"),
51
+ yellow: wrap("33"),
52
+ };
53
+ }
54
+
55
+ /** Palette for human-facing stdout (init summaries, next steps). */
56
+ export function stdoutPalette(): TerminalPalette {
57
+ return makePalette(colorEnabledFor(process.stdout));
58
+ }
59
+
60
+ /** Palette for human-facing stderr (login progress, warnings). */
61
+ export function stderrPalette(): TerminalPalette {
62
+ return makePalette(colorEnabledFor(process.stderr));
63
+ }
64
+
65
+ /** Wipe the terminal before a `dev` Enter-to-restart cycle. */
66
+ export function clearTerminal(
67
+ stream: NodeJS.WriteStream = process.stdout
68
+ ): void {
69
+ if (stream.isTTY !== true) {
70
+ return;
71
+ }
72
+ cursorTo(stream, 0, 0);
73
+ clearScreenDown(stream);
74
+ }