@cursor/july 0.1.62 → 0.1.73

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 (286) hide show
  1. package/AGENTS.md +4 -5
  2. package/README.md +23 -11
  3. package/dist/bin/agent-serve.js +11 -2
  4. package/dist/channels/github/api.d.ts +2 -0
  5. package/dist/channels/github/api.d.ts.map +1 -1
  6. package/dist/channels/github/api.js +2 -1
  7. package/dist/channels/github/binding.d.ts +7 -0
  8. package/dist/channels/github/binding.d.ts.map +1 -1
  9. package/dist/channels/github/binding.js +4 -0
  10. package/dist/channels/github/checks.d.ts +99 -0
  11. package/dist/channels/github/checks.d.ts.map +1 -0
  12. package/dist/channels/github/checks.js +108 -0
  13. package/dist/channels/github/cursor-account.d.ts +4 -4
  14. package/dist/channels/github/cursor-account.d.ts.map +1 -1
  15. package/dist/channels/github/cursor-account.js +7 -5
  16. package/dist/channels/github/index.d.ts +1 -0
  17. package/dist/channels/github/index.d.ts.map +1 -1
  18. package/dist/channels/github/index.js +1 -0
  19. package/dist/channels/github/types.d.ts +8 -0
  20. package/dist/channels/github/types.d.ts.map +1 -1
  21. package/dist/channels/slack/channel-watch.d.ts +2 -1
  22. package/dist/channels/slack/channel-watch.d.ts.map +1 -1
  23. package/dist/channels/slack/channel-watch.js +7 -3
  24. package/dist/channels/slack/dispatch.d.ts +9 -0
  25. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  26. package/dist/channels/slack/dispatch.js +41 -21
  27. package/dist/channels/slack/manifest.d.ts +2 -2
  28. package/dist/channels/slack/manifest.d.ts.map +1 -1
  29. package/dist/channels/slack/manifest.js +14 -11
  30. package/dist/channels/slack/nudge-store.d.ts +16 -0
  31. package/dist/channels/slack/nudge-store.d.ts.map +1 -1
  32. package/dist/channels/slack/nudge-store.js +53 -0
  33. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  34. package/dist/channels/slack/slack-channel.js +4 -1
  35. package/dist/channels/slack/types.d.ts +24 -7
  36. package/dist/channels/slack/types.d.ts.map +1 -1
  37. package/dist/connections.d.ts +17 -5
  38. package/dist/connections.d.ts.map +1 -1
  39. package/dist/connections.js +17 -5
  40. package/dist/docs/404.html +2 -2
  41. package/dist/docs/ab.html +3 -3
  42. package/dist/docs/assets/{app.B-biogkN.js → app.CdbcFD8T.js} +1 -1
  43. package/dist/docs/assets/chunks/@localSearchIndexroot.DQad--_z.js +1 -0
  44. package/dist/docs/assets/chunks/{VPLocalSearchBox.DZqKtFZS.js → VPLocalSearchBox.D_NKImM7.js} +1 -1
  45. package/dist/docs/assets/chunks/{theme.BwC5zP2r.js → theme.CMvz7cu9.js} +2 -2
  46. package/dist/docs/assets/{concepts.md.CqOsxbMU.js → concepts.md.BXAm6G-C.js} +1 -1
  47. package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.js → guides_mcp-oauth.md.CzEB6RaG.js} +1 -1
  48. package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.js → reference_agent-config.md.BZnEKfEc.js} +3 -4
  49. package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.lean.js → reference_agent-config.md.BZnEKfEc.lean.js} +1 -1
  50. package/dist/docs/assets/{reference_connections.md.CSQiNzre.js → reference_connections.md.Cu3N-S3Q.js} +26 -9
  51. package/dist/docs/assets/reference_connections.md.Cu3N-S3Q.lean.js +1 -0
  52. package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.js → reference_sessions.md.B0DdlM-K.js} +1 -1
  53. package/dist/docs/assets/{reference_tools.md.kJfJAP2m.js → reference_tools.md.DTg_kEsx.js} +2 -2
  54. package/dist/docs/assets/{reference_tools.md.kJfJAP2m.lean.js → reference_tools.md.DTg_kEsx.lean.js} +1 -1
  55. package/dist/docs/assets/troubleshooting.md.DQ-hYuZT.js +1 -0
  56. package/dist/docs/building-with-agents.html +3 -3
  57. package/dist/docs/concepts.html +5 -5
  58. package/dist/docs/deployment.html +3 -3
  59. package/dist/docs/evals.html +3 -3
  60. package/dist/docs/example-agents/approval-buddy.html +3 -3
  61. package/dist/docs/example-agents/benny.html +3 -3
  62. package/dist/docs/example-agents/bugbot.html +3 -3
  63. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  64. package/dist/docs/example-agents/codeowners-review.html +3 -3
  65. package/dist/docs/example-agents/concierge.html +3 -3
  66. package/dist/docs/example-agents/fsd.html +3 -3
  67. package/dist/docs/example-agents/index.html +3 -3
  68. package/dist/docs/example-agents/knowledge-base.html +3 -3
  69. package/dist/docs/example-agents/oncall.html +3 -3
  70. package/dist/docs/example-agents/security-reviewer.html +3 -3
  71. package/dist/docs/example-agents/slack-agent.html +3 -3
  72. package/dist/docs/example-agents/weather-agent.html +3 -3
  73. package/dist/docs/guides/agent-to-agent.html +3 -3
  74. package/dist/docs/guides/cloud-runtime.html +3 -3
  75. package/dist/docs/guides/convert-automation.html +3 -3
  76. package/dist/docs/guides/github.html +3 -3
  77. package/dist/docs/guides/human-in-the-loop.html +3 -3
  78. package/dist/docs/guides/mcp-oauth.html +5 -5
  79. package/dist/docs/guides/opentelemetry.html +3 -3
  80. package/dist/docs/guides/slack.html +3 -3
  81. package/dist/docs/guides/webhooks.html +3 -3
  82. package/dist/docs/hashmap.json +1 -1
  83. package/dist/docs/hillclimbing.html +3 -3
  84. package/dist/docs/index.html +3 -3
  85. package/dist/docs/quickstart.html +3 -3
  86. package/dist/docs/reference/agent-config.html +5 -6
  87. package/dist/docs/reference/artifacts.html +3 -3
  88. package/dist/docs/reference/channels.html +3 -3
  89. package/dist/docs/reference/cli.html +3 -3
  90. package/dist/docs/reference/connections.html +28 -11
  91. package/dist/docs/reference/hooks.html +3 -3
  92. package/dist/docs/reference/http-api.html +3 -3
  93. package/dist/docs/reference/instructions.html +3 -3
  94. package/dist/docs/reference/playground.html +3 -3
  95. package/dist/docs/reference/project-layout.html +3 -3
  96. package/dist/docs/reference/prompt.html +3 -3
  97. package/dist/docs/reference/schedules.html +3 -3
  98. package/dist/docs/reference/sessions.html +5 -5
  99. package/dist/docs/reference/skills.html +3 -3
  100. package/dist/docs/reference/subagents.html +3 -3
  101. package/dist/docs/reference/tools.html +5 -5
  102. package/dist/docs/scaffolding-agents.html +3 -3
  103. package/dist/docs/storage.html +3 -3
  104. package/dist/docs/templates/agentic-owners.html +3 -3
  105. package/dist/docs/templates/demo.html +3 -3
  106. package/dist/docs/templates/pr-autofixer.html +3 -3
  107. package/dist/docs/templates/security-reviewer.html +3 -3
  108. package/dist/docs/templates/triage.html +3 -3
  109. package/dist/docs/troubleshooting.html +5 -5
  110. package/dist/files-backends/agent-store-presigned-url.js +1 -1
  111. package/dist/index.d.ts +2 -2
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +1 -1
  114. package/dist/internal/advertise-tools.d.ts +79 -0
  115. package/dist/internal/advertise-tools.d.ts.map +1 -0
  116. package/dist/internal/advertise-tools.js +185 -0
  117. package/dist/internal/cli-deploy.d.ts.map +1 -1
  118. package/dist/internal/cli-deploy.js +7 -1
  119. package/dist/internal/cli-manifest.d.ts +19 -0
  120. package/dist/internal/cli-manifest.d.ts.map +1 -0
  121. package/dist/internal/cli-manifest.js +49 -0
  122. package/dist/internal/cli-slack.d.ts.map +1 -1
  123. package/dist/internal/cli-slack.js +9 -1
  124. package/dist/internal/convert-automation/convert-workflow.d.ts.map +1 -1
  125. package/dist/internal/convert-automation/convert-workflow.js +2 -10
  126. package/dist/internal/cursor/account-mcp.d.ts +29 -3
  127. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  128. package/dist/internal/cursor/account-mcp.js +147 -67
  129. package/dist/internal/cursor/backend-client.d.ts +11 -6
  130. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  131. package/dist/internal/cursor/backend-client.js +32 -10
  132. package/dist/internal/cursor-account-mcp-auth.d.ts +11 -0
  133. package/dist/internal/cursor-account-mcp-auth.d.ts.map +1 -1
  134. package/dist/internal/cursor-account-mcp-auth.js +69 -0
  135. package/dist/internal/cursor-agent-template.d.ts +9 -0
  136. package/dist/internal/cursor-agent-template.d.ts.map +1 -0
  137. package/dist/internal/cursor-agent-template.js +37 -0
  138. package/dist/internal/deploy-client.d.ts +1 -0
  139. package/dist/internal/deploy-client.d.ts.map +1 -1
  140. package/dist/internal/deploy-client.js +18 -2
  141. package/dist/internal/deploy-manifest.d.ts +76 -0
  142. package/dist/internal/deploy-manifest.d.ts.map +1 -0
  143. package/dist/internal/deploy-manifest.js +117 -0
  144. package/dist/internal/deployment-scm-event-stream.d.ts +116 -0
  145. package/dist/internal/deployment-scm-event-stream.d.ts.map +1 -0
  146. package/dist/internal/deployment-scm-event-stream.js +474 -0
  147. package/dist/internal/discovery.d.ts.map +1 -1
  148. package/dist/internal/discovery.js +111 -10
  149. package/dist/internal/init-project.d.ts.map +1 -1
  150. package/dist/internal/init-project.js +12 -123
  151. package/dist/internal/init-scaffold.d.ts +8 -0
  152. package/dist/internal/init-scaffold.d.ts.map +1 -0
  153. package/dist/internal/init-scaffold.js +168 -0
  154. package/dist/internal/inline-stdio-mcp.d.ts +2 -0
  155. package/dist/internal/inline-stdio-mcp.d.ts.map +1 -1
  156. package/dist/internal/inline-stdio-mcp.js +10 -8
  157. package/dist/internal/json-schema.d.ts +7 -0
  158. package/dist/internal/json-schema.d.ts.map +1 -1
  159. package/dist/internal/json-schema.js +18 -3
  160. package/dist/internal/mcp-endpoint.js +7 -7
  161. package/dist/internal/mcp-host.d.ts +18 -0
  162. package/dist/internal/mcp-host.d.ts.map +1 -1
  163. package/dist/internal/mcp-host.js +43 -5
  164. package/dist/internal/mcp-oauth.d.ts +22 -0
  165. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  166. package/dist/internal/mcp-oauth.js +40 -1
  167. package/dist/internal/package-inline-stdio.d.ts.map +1 -1
  168. package/dist/internal/package-inline-stdio.js +5 -5
  169. package/dist/internal/review-comments.d.ts +97 -0
  170. package/dist/internal/review-comments.d.ts.map +1 -1
  171. package/dist/internal/review-comments.js +151 -0
  172. package/dist/internal/sanitize-mcp-tool-name.d.ts +20 -0
  173. package/dist/internal/sanitize-mcp-tool-name.d.ts.map +1 -0
  174. package/dist/internal/sanitize-mcp-tool-name.js +30 -0
  175. package/dist/internal/sdk-runner.d.ts +1 -1
  176. package/dist/internal/sdk-runner.d.ts.map +1 -1
  177. package/dist/internal/sdk-runner.js +36 -13
  178. package/dist/internal/server.d.ts.map +1 -1
  179. package/dist/internal/server.js +18 -0
  180. package/dist/internal/session-engine.d.ts +66 -0
  181. package/dist/internal/session-engine.d.ts.map +1 -1
  182. package/dist/internal/session-engine.js +428 -110
  183. package/dist/internal/shallow-clone.d.ts +170 -0
  184. package/dist/internal/shallow-clone.d.ts.map +1 -0
  185. package/dist/internal/shallow-clone.js +412 -0
  186. package/dist/internal/slack-provision-client.d.ts +2 -0
  187. package/dist/internal/slack-provision-client.d.ts.map +1 -1
  188. package/dist/internal/slack-provision-client.js +1 -0
  189. package/dist/internal/terminal-style.d.ts +18 -0
  190. package/dist/internal/terminal-style.d.ts.map +1 -1
  191. package/dist/internal/terminal-style.js +46 -1
  192. package/dist/internal/turn-lease-store.d.ts +44 -0
  193. package/dist/internal/turn-lease-store.d.ts.map +1 -0
  194. package/dist/internal/turn-lease-store.js +139 -0
  195. package/dist/internal/workspace.d.ts +14 -0
  196. package/dist/internal/workspace.d.ts.map +1 -1
  197. package/dist/internal/workspace.js +33 -0
  198. package/dist/playground/assets/index-77uhu5Kr.css +1 -0
  199. package/dist/playground/assets/index-D4buox4m.js +85 -0
  200. package/dist/playground/index.html +2 -2
  201. package/dist/storage-protocol.d.ts +122 -0
  202. package/dist/storage-protocol.d.ts.map +1 -0
  203. package/dist/storage-protocol.js +173 -0
  204. package/dist/storage.d.ts +2 -72
  205. package/dist/storage.d.ts.map +1 -1
  206. package/dist/storage.js +2 -82
  207. package/dist/tools.d.ts +7 -0
  208. package/dist/tools.d.ts.map +1 -1
  209. package/dist/types.d.ts +141 -6
  210. package/dist/types.d.ts.map +1 -1
  211. package/docs/concepts.md +4 -4
  212. package/docs/guides/mcp-oauth.md +3 -1
  213. package/docs/reference/agent-config.md +11 -12
  214. package/docs/reference/connections.md +108 -10
  215. package/docs/reference/sessions.md +2 -2
  216. package/docs/reference/tools.md +14 -0
  217. package/docs/troubleshooting.md +3 -2
  218. package/package.json +7 -2
  219. package/skills/create-agent/SKILL.md +12 -9
  220. package/skills/debug/SKILL.md +2 -1
  221. package/skills/framework-map/SKILL.md +6 -6
  222. package/skills/mcp-auth/SKILL.md +8 -6
  223. package/src/bin/agent-serve.ts +12 -2
  224. package/src/channels/github/api.ts +6 -1
  225. package/src/channels/github/binding.ts +21 -0
  226. package/src/channels/github/checks.ts +179 -0
  227. package/src/channels/github/cursor-account.ts +9 -6
  228. package/src/channels/github/index.ts +1 -0
  229. package/src/channels/github/types.ts +8 -0
  230. package/src/channels/slack/channel-watch.ts +6 -3
  231. package/src/channels/slack/dispatch.ts +40 -3
  232. package/src/channels/slack/manifest.ts +9 -10
  233. package/src/channels/slack/nudge-store.ts +56 -0
  234. package/src/channels/slack/slack-channel.ts +3 -0
  235. package/src/channels/slack/types.ts +24 -7
  236. package/src/connections.ts +17 -5
  237. package/src/index.ts +5 -0
  238. package/src/internal/advertise-tools.ts +278 -0
  239. package/src/internal/cli-deploy.ts +11 -1
  240. package/src/internal/cli-manifest.ts +63 -0
  241. package/src/internal/cli-slack.ts +10 -1
  242. package/src/internal/convert-automation/convert-workflow.ts +2 -11
  243. package/src/internal/cursor/account-mcp.ts +208 -73
  244. package/src/internal/cursor/backend-client.ts +45 -11
  245. package/src/internal/cursor-account-mcp-auth.ts +83 -0
  246. package/src/internal/cursor-agent-template.ts +46 -0
  247. package/src/internal/deploy-client.ts +25 -6
  248. package/src/internal/deploy-manifest.ts +161 -0
  249. package/src/internal/deployment-scm-event-stream.ts +593 -0
  250. package/src/internal/discovery.ts +132 -3
  251. package/src/internal/init-project.ts +18 -153
  252. package/src/internal/init-scaffold.ts +176 -0
  253. package/src/internal/inline-stdio-mcp.ts +13 -0
  254. package/src/internal/json-schema.ts +24 -3
  255. package/src/internal/mcp-endpoint.ts +6 -0
  256. package/src/internal/mcp-host.ts +70 -9
  257. package/src/internal/mcp-oauth.ts +55 -1
  258. package/src/internal/package-inline-stdio.ts +5 -1
  259. package/src/internal/review-comments.ts +245 -0
  260. package/src/internal/sanitize-mcp-tool-name.ts +33 -0
  261. package/src/internal/sdk-runner.ts +50 -11
  262. package/src/internal/server.ts +19 -0
  263. package/src/internal/session-engine.ts +392 -19
  264. package/src/internal/shallow-clone.ts +595 -0
  265. package/src/internal/slack-provision-client.ts +3 -0
  266. package/src/internal/terminal-style.ts +67 -1
  267. package/src/internal/turn-lease-store.ts +147 -0
  268. package/src/internal/workspace.ts +33 -0
  269. package/src/storage-protocol.ts +247 -0
  270. package/src/storage.ts +16 -110
  271. package/src/tools.ts +7 -0
  272. package/src/types.ts +149 -7
  273. package/templates/agentic-owners/agent/agent.ts +3 -0
  274. package/templates/demo/agent/agent.ts +3 -0
  275. package/templates/pr-autofixer/agent/lib/drive-schemas.ts +4 -1
  276. package/templates/security-reviewer/agent/agent.ts +3 -0
  277. package/templates/triage/agent/agent.ts +3 -0
  278. package/dist/docs/assets/chunks/@localSearchIndexroot.5ozYNf74.js +0 -1
  279. package/dist/docs/assets/reference_connections.md.CSQiNzre.lean.js +0 -1
  280. package/dist/docs/assets/troubleshooting.md.CuVztCKs.js +0 -1
  281. package/dist/playground/assets/index-B4rcOgeP.css +0 -1
  282. package/dist/playground/assets/index-DXcY42Jv.js +0 -85
  283. /package/dist/docs/assets/{concepts.md.CqOsxbMU.lean.js → concepts.md.BXAm6G-C.lean.js} +0 -0
  284. /package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.lean.js → guides_mcp-oauth.md.CzEB6RaG.lean.js} +0 -0
  285. /package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.lean.js → reference_sessions.md.B0DdlM-K.lean.js} +0 -0
  286. /package/dist/docs/assets/{troubleshooting.md.CuVztCKs.lean.js → troubleshooting.md.DQ-hYuZT.lean.js} +0 -0
@@ -4,6 +4,11 @@
4
4
  */
5
5
  import { clearScreenDown, cursorTo } from "node:readline";
6
6
  const IDENTITY = (s) => s;
7
+ const ESC = "\u001b";
8
+ const BEL = "\u0007";
9
+ const ANSI_CSI = new RegExp(`${ESC}\\[[0-9;]*m`, "g");
10
+ /** OSC 8 hyperlinks: `ESC ] 8 ; params ; uri BEL` (or ST). */
11
+ const OSC_8 = new RegExp(`${ESC}\\]8;[^${BEL}${ESC}]*(?:${BEL}|${ESC}\\\\)`, "g");
7
12
  const PLAIN = {
8
13
  dim: IDENTITY,
9
14
  bold: IDENTITY,
@@ -22,7 +27,7 @@ export function makePalette(enabled) {
22
27
  }
23
28
  const wrap = (code) => (s) => `\u001b[${code}m${s}\u001b[0m`;
24
29
  return {
25
- dim: wrap("2"),
30
+ dim: (s) => (hasAnsiStyling(s) ? s : wrap("2")(s)),
26
31
  bold: wrap("1"),
27
32
  cyan: wrap("36"),
28
33
  green: wrap("32"),
@@ -39,6 +44,46 @@ export function stdoutPalette() {
39
44
  export function stderrPalette() {
40
45
  return makePalette(colorEnabledFor(process.stderr));
41
46
  }
47
+ /** Visible column count, ignoring CSI color/style and OSC 8 hyperlinks. */
48
+ export function visibleWidth(text) {
49
+ return text.replace(OSC_8, "").replace(ANSI_CSI, "").length;
50
+ }
51
+ /** True when `text` already carries CSI styling or OSC 8 (do not wrap again). */
52
+ export function hasAnsiStyling(text) {
53
+ return text.includes("\u001b[") || text.includes("\u001b]");
54
+ }
55
+ /**
56
+ * Clickable terminal hyperlink (OSC 8). The URI is the click target; `label`
57
+ * is what the user sees. `visibleWidth` ignores the OSC wrapper.
58
+ */
59
+ export function terminalHyperlink(url, label, enabled = colorEnabledFor()) {
60
+ if (!enabled) {
61
+ return label;
62
+ }
63
+ return `\u001b]8;;${url}\u0007\u001b[4m${label}\u001b[24m\u001b]8;;\u0007`;
64
+ }
65
+ /**
66
+ * Unicode box around `lines`. `color` wraps the whole box (borders + body)
67
+ * so a warning panel can be yellow without per-line prefixes.
68
+ */
69
+ export function formatTerminalBox(lines, options) {
70
+ var _a, _b, _c;
71
+ const color = (_a = options === null || options === void 0 ? void 0 : options.color) !== null && _a !== void 0 ? _a : IDENTITY;
72
+ const padding = (_b = options === null || options === void 0 ? void 0 : options.padding) !== null && _b !== void 0 ? _b : 1;
73
+ const contentWidth = Math.max((_c = options === null || options === void 0 ? void 0 : options.minWidth) !== null && _c !== void 0 ? _c : 0, ...lines.map((line) => visibleWidth(line)), 1);
74
+ const inner = contentWidth + padding * 2;
75
+ const padLine = (line) => {
76
+ const extra = contentWidth - visibleWidth(line);
77
+ return `│${" ".repeat(padding)}${line}${" ".repeat(padding + extra)}│`;
78
+ };
79
+ const paint = (line) => color(line);
80
+ const box = [
81
+ paint(`╭${"─".repeat(inner)}╮`),
82
+ ...lines.map((line) => paint(padLine(line))),
83
+ paint(`╰${"─".repeat(inner)}╯`),
84
+ ].join("\n");
85
+ return box;
86
+ }
42
87
  /** Wipe the terminal before a `dev` Enter-to-restart cycle. */
43
88
  export function clearTerminal(stream = process.stdout) {
44
89
  if (stream.isTTY !== true) {
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Durable per-session turn ownership: `activeTurns` is in-memory, so servers
3
+ * sharing a state root would otherwise both run the same session.
4
+ *
5
+ * Exclusion, staleness and liveness refresh come from `proper-lockfile`, which
6
+ * the monorepo already uses for the git cache. Hand-rolling them means
7
+ * inferring that a process died — timeouts, heartbeats, and a takeover path
8
+ * that has to stay atomic while removing another owner's claim. That is where
9
+ * the subtle races live, and none of it is specific to turns.
10
+ *
11
+ * Liveness is lock age, not pid: containers have separate PID namespaces.
12
+ */
13
+ /** A held turn lease. Releasing is idempotent. */
14
+ export interface TurnLease {
15
+ release(): Promise<void>;
16
+ }
17
+ export declare class TurnLeaseStore {
18
+ private readonly dir;
19
+ private readonly staleMs;
20
+ /** Locks this process holds. Their release closures cannot live on disk. */
21
+ private readonly held;
22
+ constructor(dir: string, options?: {
23
+ ttlMs?: number;
24
+ });
25
+ private path;
26
+ /**
27
+ * Undefined when another process holds this session and is still refreshing.
28
+ *
29
+ * `onCompromised` fires when the lock is lost mid-turn — the owner stalled
30
+ * past the stale window and a successor took over. No lease scheme can stop
31
+ * that; the callback is how the displaced turn learns to stand down instead
32
+ * of answering alongside its successor.
33
+ */
34
+ acquire(sessionId: string, onCompromised?: () => void): Promise<TurnLease | undefined>;
35
+ private handle;
36
+ /** Graceful shutdown: drop every claim so a successor need not wait it out. */
37
+ releaseAll(): Promise<void>;
38
+ /**
39
+ * The session is running in another server process. Mirrors the engine's
40
+ * in-memory `isTurnRunning`, which only ever sees this process.
41
+ */
42
+ runningElsewhere(sessionId: string): Promise<boolean>;
43
+ }
44
+ //# sourceMappingURL=turn-lease-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-lease-store.d.ts","sourceRoot":"","sources":["../../src/internal/turn-lease-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,kDAAkD;AAClD,MAAM,WAAW,SAAS;IACxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAmBD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;IAEpD,YAAY,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,EAIxD;IAED,OAAO,CAAC,IAAI;IAIZ;;;;;;;OAOG;IACG,OAAO,CACX,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,IAAI,GACzB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CA6BhC;IAED,OAAO,CAAC,MAAM;IAwBd,+EAA+E;IACzE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAKhC;IAED;;;OAGG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAY1D;CACF"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Durable per-session turn ownership: `activeTurns` is in-memory, so servers
3
+ * sharing a state root would otherwise both run the same session.
4
+ *
5
+ * Exclusion, staleness and liveness refresh come from `proper-lockfile`, which
6
+ * the monorepo already uses for the git cache. Hand-rolling them means
7
+ * inferring that a process died — timeouts, heartbeats, and a takeover path
8
+ * that has to stay atomic while removing another owner's claim. That is where
9
+ * the subtle races live, and none of it is specific to turns.
10
+ *
11
+ * Liveness is lock age, not pid: containers have separate PID namespaces.
12
+ */
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ import { mkdir } from "node:fs/promises";
23
+ import { join } from "node:path";
24
+ import * as lockfile from "proper-lockfile";
25
+ /** Reject path traversal; session ids are opaque strings from the caller. */
26
+ function safeKey(sessionId) {
27
+ const sanitized = sessionId
28
+ .trim()
29
+ .replace(/[^a-zA-Z0-9._-]+/g, "_")
30
+ .replace(/^\.+/, "")
31
+ .replace(/\.+/g, "_")
32
+ .slice(0, 180);
33
+ return sanitized === "" ? "_empty" : sanitized;
34
+ }
35
+ export class TurnLeaseStore {
36
+ constructor(dir, options = {}) {
37
+ var _a;
38
+ /** Locks this process holds. Their release closures cannot live on disk. */
39
+ this.held = new Map();
40
+ this.dir = dir;
41
+ // Several refreshes, so a slow owner is not mistaken for a dead one.
42
+ this.staleMs = (_a = options.ttlMs) !== null && _a !== void 0 ? _a : 30000;
43
+ }
44
+ path(sessionId) {
45
+ return join(this.dir, `${safeKey(sessionId)}.lease`);
46
+ }
47
+ /**
48
+ * Undefined when another process holds this session and is still refreshing.
49
+ *
50
+ * `onCompromised` fires when the lock is lost mid-turn — the owner stalled
51
+ * past the stale window and a successor took over. No lease scheme can stop
52
+ * that; the callback is how the displaced turn learns to stand down instead
53
+ * of answering alongside its successor.
54
+ */
55
+ acquire(sessionId, onCompromised) {
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ const existing = this.held.get(sessionId);
58
+ if (existing !== undefined) {
59
+ existing.refs += 1;
60
+ return this.handle(sessionId);
61
+ }
62
+ yield mkdir(this.dir, { recursive: true });
63
+ let release;
64
+ try {
65
+ release = yield lockfile.lock(this.path(sessionId), {
66
+ realpath: false,
67
+ retries: 0,
68
+ stale: this.staleMs,
69
+ // How often the library refreshes the lock's mtime while we hold it.
70
+ update: 5000,
71
+ onCompromised: () => {
72
+ this.held.delete(sessionId);
73
+ onCompromised === null || onCompromised === void 0 ? void 0 : onCompromised();
74
+ },
75
+ });
76
+ }
77
+ catch (_a) {
78
+ // Held elsewhere, or the store is unusable. Either way this process must
79
+ // not run the turn: coalescing costs latency, two servers on one session
80
+ // costs the conversation.
81
+ return undefined;
82
+ }
83
+ this.held.set(sessionId, { release, refs: 1 });
84
+ return this.handle(sessionId);
85
+ });
86
+ }
87
+ handle(sessionId) {
88
+ let released = false;
89
+ return {
90
+ release: () => __awaiter(this, void 0, void 0, function* () {
91
+ if (released) {
92
+ return;
93
+ }
94
+ released = true;
95
+ const lock = this.held.get(sessionId);
96
+ if (lock === undefined) {
97
+ return;
98
+ }
99
+ lock.refs -= 1;
100
+ if (lock.refs > 0) {
101
+ return;
102
+ }
103
+ this.held.delete(sessionId);
104
+ // Throws if the lock was already compromised, which is not our problem
105
+ // to solve here: the successor owns it.
106
+ yield lock.release().catch(() => { });
107
+ }),
108
+ };
109
+ }
110
+ /** Graceful shutdown: drop every claim so a successor need not wait it out. */
111
+ releaseAll() {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ for (const [sessionId, lock] of [...this.held]) {
114
+ this.held.delete(sessionId);
115
+ yield lock.release().catch(() => { });
116
+ }
117
+ });
118
+ }
119
+ /**
120
+ * The session is running in another server process. Mirrors the engine's
121
+ * in-memory `isTurnRunning`, which only ever sees this process.
122
+ */
123
+ runningElsewhere(sessionId) {
124
+ return __awaiter(this, void 0, void 0, function* () {
125
+ if (this.held.has(sessionId)) {
126
+ return false;
127
+ }
128
+ try {
129
+ return yield lockfile.check(this.path(sessionId), {
130
+ realpath: false,
131
+ stale: this.staleMs,
132
+ });
133
+ }
134
+ catch (_a) {
135
+ return false;
136
+ }
137
+ });
138
+ }
139
+ }
@@ -99,6 +99,20 @@ export declare function buildAgentsMdContent(agent: ResolvedAgent, options: {
99
99
  * are skipped by nested rule discovery.
100
100
  */
101
101
  export declare function isNestedInGitRepo(dir: string): Promise<boolean>;
102
+ /** Default harness parent for a nested-git agent project. */
103
+ export declare function defaultLocalHarnessCwd(dirName: string): string;
104
+ /**
105
+ * Give a session workspace its own git root so the harness roots *there*
106
+ * rather than at the enclosing repo (see {@link isNestedInGitRepo}). Without
107
+ * it the harness reads the outer repo's `.cursor/hooks.json`, rules, skills
108
+ * and `mcp.json`, and never sees the ones written into this workspace —
109
+ * instructions have an inline fallback, hooks have none.
110
+ *
111
+ * Best effort: a workspace that already has `.git` (a borrowed checkout or
112
+ * worktree) is left alone, and a failed `git init` leaves the harness where
113
+ * it already was.
114
+ */
115
+ export declare function ensureOwnGitRoot(dir: string): Promise<boolean>;
102
116
  export declare function materializeWorkspace(options: MaterializeWorkspaceOptions): Promise<void>;
103
117
  /**
104
118
  * Generate the SKILL.md the harness reads: `name` + `description`
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/internal/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgBH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACd,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,mBAAmB,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,GAAG,SAAS,CAapB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,GAAE;IAAE,cAAc,EAAE,OAAO,CAAA;CAA8B,GAC/D,MAAM,CA8CR;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GACjC,MAAM,CA6BR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,MAAM,CAeR;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAcrE;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAkCf;AAqGD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAO3D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CACX,MAAM,EACN,MAAM,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CACjE,GACA,OAAO,CAAC,IAAI,CAAC,CAcf"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/internal/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAmBH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACd,MAAM,aAAa,CAAC;AAMrB,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;;;;;;OAOG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,mBAAmB,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,GAAG,SAAS,CAapB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,GAAE;IAAE,cAAc,EAAE,OAAO,CAAA;CAA8B,GAC/D,MAAM,CA8CR;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GACjC,MAAM,CA6BR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,MAAM,CAeR;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAcrE;AAED,6DAA6D;AAC7D,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUpE;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAkCf;AAqGD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAO3D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CACX,MAAM,EACN,MAAM,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CACjE,GACA,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -15,12 +15,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
15
15
  step((generator = generator.apply(thisArg, _arguments || [])).next());
16
16
  });
17
17
  };
18
+ import { execFile } from "node:child_process";
18
19
  import { chmod, copyFile, lstat, mkdir, readlink, rm, stat, symlink, writeFile, } from "node:fs/promises";
20
+ import { homedir } from "node:os";
19
21
  import { dirname, join, parse, relative, resolve, sep } from "node:path";
22
+ import { promisify } from "node:util";
20
23
  import { agentStoreKeys, DEPLOYMENT_STORE_MOUNT_PATH } from "../files.js";
21
24
  import { MEMORY_DIR_NAME } from "../memory.js";
22
25
  import { parseFrontmatter, serializeFrontmatter } from "./frontmatter.js";
23
26
  import { buildIdentitySection } from "./prompt-context.js";
27
+ const execFileAsync = promisify(execFile);
24
28
  /**
25
29
  * First-turn preamble section for cloud-runtime sessions on hosted
26
30
  * deployments: cloud VMs read the memory journal from the store mount.
@@ -219,6 +223,35 @@ export function isNestedInGitRepo(dir) {
219
223
  return false;
220
224
  });
221
225
  }
226
+ /** Default harness parent for a nested-git agent project. */
227
+ export function defaultLocalHarnessCwd(dirName) {
228
+ return join(homedir(), ".cache", "agent-serve", dirName);
229
+ }
230
+ /**
231
+ * Give a session workspace its own git root so the harness roots *there*
232
+ * rather than at the enclosing repo (see {@link isNestedInGitRepo}). Without
233
+ * it the harness reads the outer repo's `.cursor/hooks.json`, rules, skills
234
+ * and `mcp.json`, and never sees the ones written into this workspace —
235
+ * instructions have an inline fallback, hooks have none.
236
+ *
237
+ * Best effort: a workspace that already has `.git` (a borrowed checkout or
238
+ * worktree) is left alone, and a failed `git init` leaves the harness where
239
+ * it already was.
240
+ */
241
+ export function ensureOwnGitRoot(dir) {
242
+ return __awaiter(this, void 0, void 0, function* () {
243
+ if (!(yield isNestedInGitRepo(dir))) {
244
+ return false;
245
+ }
246
+ try {
247
+ yield execFileAsync("git", ["init", "--quiet"], { cwd: dir });
248
+ return true;
249
+ }
250
+ catch (_a) {
251
+ return false;
252
+ }
253
+ });
254
+ }
222
255
  export function materializeWorkspace(options) {
223
256
  return __awaiter(this, void 0, void 0, function* () {
224
257
  const { agent, workspaceDir, seed, stateRoot } = options;