@cursor/bdk 0.2.26 → 0.2.27

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 (149) hide show
  1. package/dist/docs/404.html +2 -2
  2. package/dist/docs/assets/{app.BITbgXMP.js → app.wA5xBBcd.js} +4 -4
  3. package/dist/docs/assets/changelog.md.BvHRIiMH.js +1 -0
  4. package/dist/docs/assets/{changelog.md.sdD6ctqK.lean.js → changelog.md.BvHRIiMH.lean.js} +1 -1
  5. package/dist/docs/assets/chunks/@localSearchIndexroot.BoDEJQWv.js +1 -0
  6. package/dist/docs/assets/chunks/{VPLocalSearchBox.3qo4-bX9.js → VPLocalSearchBox.C29HLCVL.js} +1 -1
  7. package/dist/docs/assets/chunks/{arc.CTrZocKU.js → arc.BOaoYWmh.js} +1 -1
  8. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.BkgIqxrv.js → architectureDiagram-Q4EWVU46.MfG0itQh.js} +1 -1
  9. package/dist/docs/assets/chunks/{baseUniq.5w0JfVgo.js → baseUniq.CUeJciCF.js} +1 -1
  10. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.BVLtPjQc.js → blockDiagram-DXYQGD6D.BrXMZRtK.js} +1 -1
  11. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.CQ7neZTW.js → c4Diagram-AHTNJAMY.DfkDHeB9.js} +1 -1
  12. package/dist/docs/assets/chunks/channel.D2BTz0L-.js +1 -0
  13. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.D-hJ7uKM.js → chunk-4BX2VUAB.xKz8CiXK.js} +1 -1
  14. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.RBYX5ywX.js → chunk-4TB4RGXK.kkfBh4zk.js} +1 -1
  15. package/dist/docs/assets/chunks/{chunk-55IACEB6.Br05HoEb.js → chunk-55IACEB6.BClJGb94.js} +1 -1
  16. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.BD_7QS60.js → chunk-EDXVE4YY.P9BpQ9L3.js} +1 -1
  17. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.BOPnMabX.js → chunk-FMBD7UC4.R4iYi58S.js} +1 -1
  18. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.DmGIdP8i.js → chunk-OYMX7WX6.Cpn8L1dw.js} +1 -1
  19. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.CGHmolCB.js → chunk-QZHKN3VN.BLftECqU.js} +1 -1
  20. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.C_Uhs25v.js → chunk-YZCP3GAM.BWDV1AYt.js} +1 -1
  21. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.DqByliAC.js +1 -0
  22. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.DqByliAC.js +1 -0
  23. package/dist/docs/assets/chunks/clone.CldT1lbQ.js +1 -0
  24. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.DsU6xpcZ.js → cose-bilkent-S5V4N54A.DGpAcJ55.js} +1 -1
  25. package/dist/docs/assets/chunks/{dagre-KV5264BT.BqQLDcoU.js → dagre-KV5264BT.BBXxGEaD.js} +1 -1
  26. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.Cgv8uUNF.js → diagram-5BDNPKRD.EKqOwmK2.js} +1 -1
  27. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.BXHPSXh_.js → diagram-G4DWMVQ6.CB8pdkoZ.js} +1 -1
  28. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.CgJzo8f_.js → diagram-MMDJMWI5.aHh4WGg9.js} +1 -1
  29. package/dist/docs/assets/chunks/{diagram-TYMM5635.CfiN6lgT.js → diagram-TYMM5635.YIsbRH20.js} +1 -1
  30. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.8n_hHzAd.js → erDiagram-SMLLAGMA.B3bTCW_e.js} +1 -1
  31. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.B2pb1Dv_.js → flowDiagram-DWJPFMVM.M81hXIXZ.js} +1 -1
  32. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.BFih4ucI.js → ganttDiagram-T4ZO3ILL.BKg7WY--.js} +1 -1
  33. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.CqZ8PTl8.js → gitGraphDiagram-UUTBAWPF.CLEMZgO3.js} +1 -1
  34. package/dist/docs/assets/chunks/{graph.0ufsI9gu.js → graph.DS38W_Q-.js} +1 -1
  35. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.BkPRFww4.js → infoDiagram-42DDH7IO.BTiWTi82.js} +1 -1
  36. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DCRK-cVX.js → ishikawaDiagram-UXIWVN3A.DcqY_KQL.js} +1 -1
  37. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.BFyAJo33.js → journeyDiagram-VCZTEJTY.0lQNZ40U.js} +1 -1
  38. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.CmA2SoGc.js → kanban-definition-6JOO6SKY.L5sKlf7X.js} +1 -1
  39. package/dist/docs/assets/chunks/{layout.CYY-CbMr.js → layout.7u4gFhQa.js} +1 -1
  40. package/dist/docs/assets/chunks/{linear.DeeDV4Oq.js → linear.D5v33SOb.js} +1 -1
  41. package/dist/docs/assets/chunks/{min.BL3XTBN2.js → min.Dc9uCxf9.js} +1 -1
  42. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.BcbY-G6H.js → mindmap-definition-QFDTVHPH.B56nGoB_.js} +1 -1
  43. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.dzDcQnPE.js → pieDiagram-DEJITSTG.Cba8e8lS.js} +1 -1
  44. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.RxR0m5iK.js → quadrantDiagram-34T5L4WZ.2YjBycHF.js} +1 -1
  45. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.DflaXb6Q.js → requirementDiagram-MS252O5E.D4P5RqVI.js} +1 -1
  46. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.BteLKQAe.js → sankeyDiagram-XADWPNL6.C0Hn8NUm.js} +1 -1
  47. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.BD8jM8oz.js → sequenceDiagram-FGHM5R23.BZm7EaoT.js} +1 -1
  48. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.C8SBkbPH.js → stateDiagram-FHFEXIEX.DcR4f3X2.js} +1 -1
  49. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.Bb4oMe0P.js +1 -0
  50. package/dist/docs/assets/chunks/{theme.DiViIOLe.js → theme.DvfKzyXq.js} +2 -2
  51. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.D64XF5dV.js → timeline-definition-GMOUNBTQ.CgDh96vg.js} +1 -1
  52. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.CwmeYan-.js → vennDiagram-DHZGUBPP.B4fagbC8.js} +1 -1
  53. package/dist/docs/assets/chunks/{wardley-RL74JXVD.DmAlXlpu.js → wardley-RL74JXVD.Ck68omim.js} +1 -1
  54. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.5VJ2-5K0.js → wardleyDiagram-NUSXRM2D.DBUg0bvz.js} +1 -1
  55. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.Cl6_fZVC.js → xychartDiagram-5P7HB3ND.DnKSGQE1.js} +1 -1
  56. package/dist/docs/assets/{reference_agent-config.md.CGSx8COP.js → reference_agent-config.md.CZrbHOfT.js} +4 -4
  57. package/dist/docs/assets/{reference_agent-config.md.CGSx8COP.lean.js → reference_agent-config.md.CZrbHOfT.lean.js} +1 -1
  58. package/dist/docs/building-with-agents.html +35 -35
  59. package/dist/docs/changelog.html +36 -36
  60. package/dist/docs/changelog.md +28 -0
  61. package/dist/docs/deployment.html +35 -35
  62. package/dist/docs/evals.html +35 -35
  63. package/dist/docs/guides/agent-to-agent.html +35 -35
  64. package/dist/docs/guides/bitbucket.html +35 -35
  65. package/dist/docs/guides/cloud-agents.html +35 -35
  66. package/dist/docs/guides/convert-automation.html +35 -35
  67. package/dist/docs/guides/export-grokbot.html +35 -35
  68. package/dist/docs/guides/github.html +35 -35
  69. package/dist/docs/guides/gitlab.html +35 -35
  70. package/dist/docs/guides/grokbot-agents.html +35 -35
  71. package/dist/docs/guides/hooks.html +35 -35
  72. package/dist/docs/guides/improve.html +35 -35
  73. package/dist/docs/guides/jev.html +35 -35
  74. package/dist/docs/guides/mcp-oauth.html +35 -35
  75. package/dist/docs/guides/migrate.html +35 -35
  76. package/dist/docs/guides/opentelemetry.html +35 -35
  77. package/dist/docs/guides/pagerduty.html +35 -35
  78. package/dist/docs/guides/slack.html +35 -35
  79. package/dist/docs/guides/webhooks.html +35 -35
  80. package/dist/docs/hashmap.json +1 -1
  81. package/dist/docs/hillclimbing.html +35 -35
  82. package/dist/docs/index.html +35 -35
  83. package/dist/docs/llms-full.txt +37 -0
  84. package/dist/docs/quickstart.html +35 -35
  85. package/dist/docs/reference/agent-config.html +38 -38
  86. package/dist/docs/reference/agent-config.md +9 -0
  87. package/dist/docs/reference/artifacts.html +35 -35
  88. package/dist/docs/reference/channels.html +35 -35
  89. package/dist/docs/reference/cli.html +35 -35
  90. package/dist/docs/reference/connections.html +35 -35
  91. package/dist/docs/reference/evals.html +35 -35
  92. package/dist/docs/reference/extensions.html +35 -35
  93. package/dist/docs/reference/hooks.html +35 -35
  94. package/dist/docs/reference/http-api.html +35 -35
  95. package/dist/docs/reference/instructions.html +35 -35
  96. package/dist/docs/reference/memory.html +35 -35
  97. package/dist/docs/reference/playground.html +35 -35
  98. package/dist/docs/reference/project-layout.html +35 -35
  99. package/dist/docs/reference/prompt.html +35 -35
  100. package/dist/docs/reference/schedules.html +35 -35
  101. package/dist/docs/reference/sessions.html +35 -35
  102. package/dist/docs/reference/skills.html +35 -35
  103. package/dist/docs/reference/subagents.html +35 -35
  104. package/dist/docs/reference/tools.html +35 -35
  105. package/dist/docs/templates/agentic-owners.html +35 -35
  106. package/dist/docs/templates/grokbot-agents.html +35 -35
  107. package/dist/docs/templates/security-reviewer.html +35 -35
  108. package/dist/docs/templates/thermo-quality-review.html +35 -35
  109. package/dist/docs/templates/thermo-review.html +35 -35
  110. package/dist/docs/templates/triage.html +35 -35
  111. package/dist/docs/troubleshooting.html +35 -35
  112. package/dist/extensions/cursor-cloud-agents/lib/backend.d.ts +4 -1
  113. package/dist/extensions/cursor-cloud-agents/lib/backend.d.ts.map +1 -1
  114. package/dist/extensions/cursor-cloud-agents/lib/backend.js +1 -5
  115. package/dist/filesystem.d.ts +26 -5
  116. package/dist/filesystem.d.ts.map +1 -1
  117. package/dist/filesystem.js +91 -18
  118. package/dist/internal/discovery/agent.d.ts.map +1 -1
  119. package/dist/internal/discovery/agent.js +29 -9
  120. package/dist/internal/docs-site.d.ts +2 -5
  121. package/dist/internal/docs-site.d.ts.map +1 -1
  122. package/dist/internal/docs-site.js +2 -5
  123. package/dist/internal/sdk-runner.d.ts +6 -0
  124. package/dist/internal/sdk-runner.d.ts.map +1 -1
  125. package/dist/internal/sdk-runner.js +41 -1
  126. package/dist/internal/session-engine.d.ts +8 -3
  127. package/dist/internal/session-engine.d.ts.map +1 -1
  128. package/dist/internal/session-engine.js +64 -20
  129. package/dist/internal/workspace.d.ts +10 -0
  130. package/dist/internal/workspace.d.ts.map +1 -1
  131. package/dist/internal/workspace.js +47 -1
  132. package/dist/playground/assets/cursor-icons-16-DfKNljMZ.woff2 +0 -0
  133. package/dist/playground/assets/{index-DpbzbqFY.js → index-B3_YohwW.js} +38 -38
  134. package/dist/playground/assets/index-Cn3-adsJ.css +1 -0
  135. package/dist/playground/index.html +2 -2
  136. package/dist/types.d.ts +41 -7
  137. package/dist/types.d.ts.map +1 -1
  138. package/docs/changelog.md +28 -0
  139. package/docs/reference/agent-config.md +9 -0
  140. package/package.json +5 -2
  141. package/dist/docs/assets/changelog.md.sdD6ctqK.js +0 -1
  142. package/dist/docs/assets/chunks/@localSearchIndexroot.B45uCZp9.js +0 -1
  143. package/dist/docs/assets/chunks/channel.Cv2w64wj.js +0 -1
  144. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CtO2atCr.js +0 -1
  145. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CtO2atCr.js +0 -1
  146. package/dist/docs/assets/chunks/clone.hfsCtgP4.js +0 -1
  147. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.BLz7Qyo3.js +0 -1
  148. package/dist/playground/assets/cursor-icons-16-DmHBTm1-.woff2 +0 -0
  149. package/dist/playground/assets/index-CyPkf2y7.css +0 -1
@@ -15,7 +15,7 @@ import { SlackAskDedupeStore, SlackNudgeStore } from "../channels/slack/nudge-st
15
15
  import { resolveDedicatedSlackHostBinding } from "../channels/slack/slack-channel.js";
16
16
  import { AGENT_SERVE_USER_STORE_FILES_SOURCE_ID, agentStoreKeys, DEPLOYMENT_STORE_MOUNT_PATH, USER_STORE_MOUNT_PATH, } from "../files.js";
17
17
  import { cursorHostedFiles, isCursorHostedFilesAvailable, isCursorUserStoreFilesAvailable, } from "../files-backends/cursor-hosted.js";
18
- import { isFileSystemToolAlias, isMutatingFileSystemTool, localFileSystem, resolveFileSystemTools, resolveHostHarnessToolOptions, tempFs, unionFs, writeWorkspaceFilesToRoot, } from "../filesystem.js";
18
+ import { isFileNotFoundError, isFileSystemToolAlias, isMutatingFileSystemTool, localFileSystem, readOnlyFs, resolveFileSystemTools, resolveHostHarnessToolOptions, sessionFileSystem, writeWorkspaceFilesToRoot, } from "../filesystem.js";
19
19
  import { storageKeysForArchitecture } from "../storage.js";
20
20
  import { DEFAULT_MODEL, DIRECT_TOOL_CALL_CHANNEL_ID, isCursorAccountTransport, isHostOauthConnectionTransport, isSymbolicConnectionTransport, } from "../types.js";
21
21
  import { resolveAdvertisedTools } from "./advertise-tools.js";
@@ -67,7 +67,7 @@ import { TurnGovernor } from "./turn-governor.js";
67
67
  import { TurnLeaseStore } from "./turn-lease-store.js";
68
68
  import { TurnOutbox } from "./turn-outbox.js";
69
69
  import { isCursorManagedV2Hosting, resolveAgentV2Hosting } from "./v2-hosting.js";
70
- import { buildAgentsMdContent, buildCloudMemorySection, buildCloudSessionWorkspaceSection, buildCloudWorkspaceSection, ensureOwnGitRoot, isNestedInGitRepo, materializeWorkspace, SERVER_TOOLS_MCP_SERVER_NAME, withIdentityPreamble, } from "./workspace.js";
70
+ import { buildAgentsMdContent, buildCloudMemorySection, buildCloudSessionWorkspaceSection, buildCloudWorkspaceSection, ensureOwnGitRoot, isNestedInGitRepo, materializeWorkspace, SERVER_TOOLS_MCP_SERVER_NAME, SKILLS_MOUNT_PATH, skillsFileSystem, withIdentityPreamble, } from "./workspace.js";
71
71
  import { syncSessionWorkspaceFiles, syncWorkspaceToStore, WorkspaceFileRefusal, wipeSessionWorkspace, } from "./workspace-sync.js";
72
72
  export const HTTP_CHANNEL_ID = "http";
73
73
  export { mergeChannelStateSkipNull } from "./channel-state.js";
@@ -266,11 +266,11 @@ export class SessionEngine {
266
266
  this.cloudUsageBackfillDone = new Set();
267
267
  /** Deduped in-flight cloud usage backfills, keyed by session id. */
268
268
  this.cloudUsageBackfill = new Map();
269
- /** Per-session FileSystem handle cache (not a tree snapshot). */
269
+ /** Per-session authored `fs` and skills handles (not tree snapshots). */
270
270
  this.sessionRoots = new Map();
271
271
  /** In-flight factory resolves, so the first turn and a racing callTool share one handle. */
272
272
  this.sessionRootInflight = new Map();
273
- /** Per-turn `unionFs({ "/": authored, "/tmp": tempFs() })`. Dropped at end of turn. */
273
+ /** Per-turn union of the authored tree, `/agent/skills`, and `/tmp`. Dropped at end of turn. */
274
274
  this.turnRoots = new Map();
275
275
  this.project = options.project;
276
276
  applyAgentContinuationDefaults(this.project);
@@ -1388,10 +1388,14 @@ export class SessionEngine {
1388
1388
  return this.interrupt(existing.sessionId);
1389
1389
  }
1390
1390
  hasRootOverride() {
1391
- return this.project.agent.root !== undefined;
1391
+ return this.project.agent.fs !== undefined || this.project.agent.root !== undefined;
1392
+ }
1393
+ /** The field the author set, for messages. Discovery copies a lone `root` onto `fs`. */
1394
+ authoredFsField() {
1395
+ return this.project.agent.root === undefined ? "fs" : "root";
1392
1396
  }
1393
1397
  /**
1394
- * FileSystem for this turn or `callTool`. Authored `root` (static or
1398
+ * FileSystem for this turn or `callTool`. Authored `fs` (static or
1395
1399
  * factory) is cached per session when `cache` is set; unscoped
1396
1400
  * `callTool` passes the invocation id and does not cache, so factories
1397
1401
  * cannot share one tree across callers. A static handle is used as
@@ -1400,20 +1404,21 @@ export class SessionEngine {
1400
1404
  * the Cursor SDK natives, always through the synthesized tools.
1401
1405
  */
1402
1406
  async resolveFileSystem(options) {
1403
- const authored = this.project.agent.root;
1404
- if (authored === undefined) {
1407
+ if (!this.hasRootOverride()) {
1405
1408
  return localFileSystem({ cwd: options.cwd });
1406
1409
  }
1407
- const authoredRoot = await this.resolveAuthoredFileSystem(options);
1410
+ const authored = await this.resolveAuthoredFileSystem(options);
1408
1411
  if (options.cache) {
1409
1412
  const existing = this.turnRoots.get(options.sessionId);
1410
1413
  if (existing !== undefined) {
1411
1414
  return existing.root;
1412
1415
  }
1413
1416
  }
1414
- const root = unionFs({
1415
- "/": authoredRoot,
1416
- "/tmp": tempFs(),
1417
+ const root = sessionFileSystem({
1418
+ authored: authored.fs,
1419
+ skills: authored.skills === undefined
1420
+ ? undefined
1421
+ : { path: SKILLS_MOUNT_PATH, fs: authored.skills },
1417
1422
  });
1418
1423
  if (options.cache && this.isTurnRunning(options.sessionId)) {
1419
1424
  this.turnRoots.set(options.sessionId, { root, cwd: options.cwd });
@@ -1421,9 +1426,10 @@ export class SessionEngine {
1421
1426
  return root;
1422
1427
  }
1423
1428
  async resolveAuthoredFileSystem(options) {
1424
- const authored = this.project.agent.root;
1429
+ const agent = this.project.agent;
1430
+ const authored = agent.fs ?? agent.root;
1425
1431
  if (authored === undefined) {
1426
- throw new Error("resolveAuthoredFileSystem requires an authored root");
1432
+ throw new Error("resolveAuthoredFileSystem requires an authored fs");
1427
1433
  }
1428
1434
  if (options.cache) {
1429
1435
  const cached = this.sessionRoots.get(options.sessionId);
@@ -1435,14 +1441,14 @@ export class SessionEngine {
1435
1441
  return inflight;
1436
1442
  }
1437
1443
  }
1438
- const resolve = async () => {
1444
+ const resolveFs = async () => {
1439
1445
  if (typeof authored !== "function") {
1440
1446
  return authored;
1441
1447
  }
1442
1448
  const host = this.hostForSession(options.cache ? options.sessionId : undefined);
1443
1449
  const ctx = {
1444
1450
  sessionId: options.sessionId,
1445
- agentName: this.project.agent.name,
1451
+ agentName: agent.name,
1446
1452
  ...(options.continuationKey === undefined
1447
1453
  ? {}
1448
1454
  : { continuationKey: options.continuationKey }),
@@ -1450,6 +1456,37 @@ export class SessionEngine {
1450
1456
  };
1451
1457
  return await authored(ctx);
1452
1458
  };
1459
+ const resolve = async () => {
1460
+ const fs = await resolveFs();
1461
+ if (agent.skillsMount === false) {
1462
+ return { fs, skills: undefined };
1463
+ }
1464
+ let skillsOccupied = false;
1465
+ try {
1466
+ skillsOccupied = (await fs.stat(SKILLS_MOUNT_PATH)).kind !== "missing";
1467
+ }
1468
+ catch (error) {
1469
+ if (!isFileNotFoundError(error)) {
1470
+ throw error;
1471
+ }
1472
+ skillsOccupied = false;
1473
+ }
1474
+ if (skillsOccupied) {
1475
+ throw new Error(`Agent "${agent.name}" ${this.authoredFsField()} already has ${SKILLS_MOUNT_PATH}, where BDK mounts the agent's skills. Remove ${SKILLS_MOUNT_PATH} from ${this.authoredFsField()}, or set skills: false to keep yours.`);
1476
+ }
1477
+ const skills = await this.baseSkillsFileSystem();
1478
+ if (agent.skillsMount === undefined) {
1479
+ return { fs, skills };
1480
+ }
1481
+ return {
1482
+ fs,
1483
+ skills: readOnlyFs(await agent.skillsMount({
1484
+ skills,
1485
+ sessionId: options.sessionId,
1486
+ continuationKey: options.continuationKey,
1487
+ })),
1488
+ };
1489
+ };
1453
1490
  if (!options.cache) {
1454
1491
  return resolve();
1455
1492
  }
@@ -1464,6 +1501,13 @@ export class SessionEngine {
1464
1501
  this.sessionRootInflight.delete(options.sessionId);
1465
1502
  }
1466
1503
  }
1504
+ baseSkillsFileSystem() {
1505
+ this.baseSkills ??= skillsFileSystem(this.project.agent.skills).catch((error) => {
1506
+ this.baseSkills = undefined;
1507
+ throw error;
1508
+ });
1509
+ return this.baseSkills;
1510
+ }
1467
1511
  dropTurnFileSystem(sessionId) {
1468
1512
  this.turnRoots.delete(sessionId);
1469
1513
  }
@@ -2121,11 +2165,11 @@ export class SessionEngine {
2121
2165
  //
2122
2166
  // Factory roots omit `allowedTools` at discovery (the live handle is
2123
2167
  // resolved per session). The allowlist guard below therefore never
2124
- // fires for `defineAgent({ root: (ctx) => … })` with omitted `tools`,
2168
+ // fires for `defineAgent({ fs: (ctx) => … })` with omitted `tools`,
2125
2169
  // and a per-send `cloud` attach would skip the virtual-root allowlist
2126
- // and run unrestricted on a VM. Any authored root refuses non-local turns.
2170
+ // and run unrestricted on a VM. Any authored fs refuses non-local turns.
2127
2171
  if (runtime !== "local" && this.hasRootOverride()) {
2128
- throw new Error(`Agent "${agent.name}" declares root, which cannot be served on ${runtime} turns. Refusing the session rather than running it against the host VM.`);
2172
+ throw new Error(`Agent "${agent.name}" declares ${this.authoredFsField()}, which cannot be served on ${runtime} turns. Refusing the session rather than running it against the host VM.`);
2129
2173
  }
2130
2174
  if (runtime !== "local" && agent.allowedTools !== undefined) {
2131
2175
  throw new Error(`Agent "${agent.name}" declares a built-in tool allowlist (tools), which cannot be enforced on ${runtime} turns. Refusing the session rather than running it unrestricted.`);
@@ -2252,7 +2296,7 @@ export class SessionEngine {
2252
2296
  // synthesized file tools and embedded script bodies.
2253
2297
  const localInstructions = runtime === "local"
2254
2298
  ? authoredRoot
2255
- ? buildAgentsMdContent({ ...instructionsAgent, tools: [...instructionsAgent.tools, ...synthesized] }, { includeScripts: true })
2299
+ ? buildAgentsMdContent({ ...instructionsAgent, tools: [...instructionsAgent.tools, ...synthesized] }, { includeScripts: true, skillsIndex: agent.skillsMount !== false })
2256
2300
  : buildAgentsMdContent(instructionsAgent, {
2257
2301
  includeScripts: this.hasBorrowedWorkspace(record),
2258
2302
  })
@@ -8,6 +8,7 @@
8
8
  * deliver them as the harness system prompt ({@link buildAgentsMdContent}),
9
9
  * and cloud / grokbot harnesses never read the session workspace.
10
10
  */
11
+ import { type FileSystem } from "../filesystem.js";
11
12
  import type { DiscoveredSkill, DiscoveredTool, ResolvedAgent } from "../types.js";
12
13
  export interface MaterializeWorkspaceOptions {
13
14
  agent: ResolvedAgent;
@@ -102,7 +103,16 @@ export declare function buildServerToolsCatalog(tools: DiscoveredTool[], options
102
103
  export declare function buildAgentsMdContent(agent: ResolvedAgent, options: {
103
104
  includeScripts: boolean;
104
105
  serverToolsMcpName?: string;
106
+ skillsIndex?: boolean;
105
107
  }): string;
108
+ /** Where an authored `fs` sees {@link skillsFileSystem}. */
109
+ export declare const SKILLS_MOUNT_PATH = "/agent/skills";
110
+ export declare const FS_AND_ROOT_CONFLICT = "Set `fs` or `root`, not both; `root` is a deprecated alias of `fs`.";
111
+ /**
112
+ * The discovered skills as a read-only tree: `/<name>/SKILL.md`, the same
113
+ * bytes {@link materializeSkill} writes, plus each skill's sibling files.
114
+ */
115
+ export declare function skillsFileSystem(skills: readonly DiscoveredSkill[]): Promise<FileSystem>;
106
116
  /**
107
117
  * True when `dir` sits strictly inside a git repository (a `.git` exists in
108
118
  * an ancestor directory but not in `dir` itself). The Cursor harness resolves
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/internal/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmBH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMlF,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,MAAM,CAOR;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;;;;;;;;;;;;;;GAcG;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,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B9F;AAyFD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAO3D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACtF,OAAO,CAAC,IAAI,CAAC,CAYf"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/internal/workspace.ts"],"names":[],"mappings":"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"}
@@ -9,11 +9,12 @@
9
9
  * and cloud / grokbot harnesses never read the session workspace.
10
10
  */
11
11
  import { execFile } from "node:child_process";
12
- import { chmod, copyFile, lstat, mkdir, readlink, rm, stat, symlink, writeFile, } from "node:fs/promises";
12
+ import { chmod, copyFile, lstat, mkdir, readFile, readlink, rm, stat, symlink, writeFile, } from "node:fs/promises";
13
13
  import { homedir } from "node:os";
14
14
  import { dirname, join, parse, relative, resolve, sep } from "node:path";
15
15
  import { promisify } from "node:util";
16
16
  import { agentStoreKeys, DEPLOYMENT_STORE_MOUNT_PATH } from "../files.js";
17
+ import { readOnlyFs, tempFs } from "../filesystem.js";
17
18
  import { MEMORY_DIR_NAME } from "./memory-dir.js";
18
19
  import { parseFrontmatter, serializeFrontmatter } from "./frontmatter.js";
19
20
  import { buildIdentitySection } from "./prompt-context.js";
@@ -209,10 +210,55 @@ export function buildAgentsMdContent(agent, options) {
209
210
  buildAgentToolsCatalog(agent.tools, {
210
211
  includeScripts: options.includeScripts,
211
212
  }),
213
+ options.skillsIndex === true ? buildSkillsIndex(agent.skills) : "",
212
214
  ]
213
215
  .filter((part) => part !== "")
214
216
  .join("\n\n");
215
217
  }
218
+ /** Where an authored `fs` sees {@link skillsFileSystem}. */
219
+ export const SKILLS_MOUNT_PATH = "/agent/skills";
220
+ export const FS_AND_ROOT_CONFLICT = "Set `fs` or `root`, not both; `root` is a deprecated alias of `fs`.";
221
+ /**
222
+ * Index of the discovered skills under {@link SKILLS_MOUNT_PATH}. An `fs`
223
+ * agent has no `.cursor/skills/` for the harness to discover, so the
224
+ * instructions name each SKILL.md instead.
225
+ */
226
+ function buildSkillsIndex(skills) {
227
+ if (skills.length === 0) {
228
+ return "";
229
+ }
230
+ return [
231
+ "## Skills",
232
+ "",
233
+ `Skills are on-demand procedures under \`${SKILLS_MOUNT_PATH}\`. When a task matches a skill's description, read its \`SKILL.md\` before acting on that part of the task and follow it.`,
234
+ "",
235
+ ...skills.map((skill) => `- \`${skill.name}\` (\`${SKILLS_MOUNT_PATH}/${skill.name}/SKILL.md\`): ${skill.description.trim()}`),
236
+ ].join("\n");
237
+ }
238
+ function skillFilePath(skillName, relativePath) {
239
+ const parts = relativePath.split("/");
240
+ if (relativePath.includes("\0") ||
241
+ relativePath.startsWith("/") ||
242
+ parts.some((part) => part === "" || part === "..")) {
243
+ throw new Error(`Skill "${skillName}" file "${relativePath}" escapes its directory.`);
244
+ }
245
+ return `/${skillName}/${relativePath}`;
246
+ }
247
+ /**
248
+ * The discovered skills as a read-only tree: `/<name>/SKILL.md`, the same
249
+ * bytes {@link materializeSkill} writes, plus each skill's sibling files.
250
+ */
251
+ export async function skillsFileSystem(skills) {
252
+ const files = {};
253
+ for (const skill of skills) {
254
+ files[`/${skill.name}/SKILL.md`] = buildSkillMd(skill);
255
+ for (const [relativePath, source] of Object.entries(skill.files)) {
256
+ files[skillFilePath(skill.name, relativePath)] =
257
+ "contents" in source ? source.contents : await readFile(source.sourcePath);
258
+ }
259
+ }
260
+ return readOnlyFs(tempFs(files));
261
+ }
216
262
  /**
217
263
  * True when `dir` sits strictly inside a git repository (a `.git` exists in
218
264
  * an ancestor directory but not in `dir` itself). The Cursor harness resolves