@agent-native/core 0.87.0 → 0.88.0

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 (120) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +6 -0
  3. package/corpus/core/docs/content/agent-native-toolkit.mdx +162 -0
  4. package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +73 -0
  5. package/corpus/core/docs/content/locales/ar-SA/sharing.mdx +15 -7
  6. package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +77 -0
  7. package/corpus/core/docs/content/locales/de-DE/sharing.mdx +15 -7
  8. package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +77 -0
  9. package/corpus/core/docs/content/locales/es-ES/sharing.mdx +15 -7
  10. package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +79 -0
  11. package/corpus/core/docs/content/locales/fr-FR/sharing.mdx +15 -7
  12. package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +74 -0
  13. package/corpus/core/docs/content/locales/hi-IN/sharing.mdx +15 -7
  14. package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +67 -0
  15. package/corpus/core/docs/content/locales/ja-JP/sharing.mdx +15 -7
  16. package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +63 -0
  17. package/corpus/core/docs/content/locales/ko-KR/sharing.mdx +15 -7
  18. package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +77 -0
  19. package/corpus/core/docs/content/locales/pt-BR/sharing.mdx +15 -7
  20. package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +61 -0
  21. package/corpus/core/docs/content/locales/zh-CN/sharing.mdx +15 -7
  22. package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +61 -0
  23. package/corpus/core/docs/content/locales/zh-TW/sharing.mdx +15 -7
  24. package/corpus/core/docs/content/sharing.mdx +39 -7
  25. package/corpus/core/package.json +2 -1
  26. package/corpus/core/src/server/action-discovery.ts +4 -0
  27. package/corpus/core/src/server/action-routes.ts +8 -1
  28. package/corpus/core/src/server/index.ts +9 -0
  29. package/corpus/core/src/shared/agent-readable-resource.ts +111 -0
  30. package/corpus/core/src/shared/index.ts +9 -0
  31. package/corpus/core/src/sharing/actions/create-agent-resource-link.ts +91 -0
  32. package/corpus/core/src/sharing/registry.ts +19 -0
  33. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +92 -0
  34. package/corpus/core/src/vite/client.ts +1 -0
  35. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +9 -113
  36. package/corpus/templates/analytics/server/db/index.ts +14 -0
  37. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +156 -0
  38. package/corpus/templates/analytics/server/routes/[...page].get.ts +92 -25
  39. package/corpus/templates/analytics/server/routes/api/analysis-agent-context.json.get.ts +94 -0
  40. package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +109 -0
  41. package/corpus/templates/analytics/shared/resource-agent-access.ts +6 -0
  42. package/corpus/templates/content/app/routes/p.$id.tsx +114 -9
  43. package/corpus/templates/content/server/db/index.ts +9 -0
  44. package/corpus/templates/content/server/routes/api/document-agent-context.json.get.ts +90 -0
  45. package/corpus/templates/content/shared/agent-readable.ts +56 -0
  46. package/corpus/templates/design/server/db/index.ts +8 -0
  47. package/corpus/templates/design/server/routes/[...page].get.ts +94 -1
  48. package/corpus/templates/design/server/routes/api/design-agent-context.json.get.ts +84 -0
  49. package/corpus/templates/design/shared/agent-readable.ts +2 -0
  50. package/corpus/templates/plan/server/db/index.ts +12 -0
  51. package/corpus/templates/plan/server/plans.ts +25 -1
  52. package/corpus/templates/plan/server/routes/[...page].get.ts +107 -1
  53. package/corpus/templates/plan/server/routes/api/plan-agent-context.json.get.ts +65 -0
  54. package/corpus/templates/plan/shared/agent-readable.ts +2 -0
  55. package/corpus/templates/slides/app/routes/p.$id.tsx +126 -12
  56. package/corpus/templates/slides/app/routes/share.$token.tsx +55 -8
  57. package/corpus/templates/slides/server/db/index.ts +9 -0
  58. package/corpus/templates/slides/server/routes/api/deck-agent-context.json.get.ts +97 -0
  59. package/corpus/templates/slides/shared/agent-readable.ts +2 -0
  60. package/dist/collab/routes.d.ts +1 -1
  61. package/dist/collab/struct-routes.d.ts +1 -1
  62. package/dist/notifications/routes.d.ts +1 -1
  63. package/dist/observability/routes.d.ts +5 -5
  64. package/dist/progress/routes.d.ts +1 -1
  65. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  66. package/dist/resources/handlers.d.ts +1 -1
  67. package/dist/secrets/routes.d.ts +9 -9
  68. package/dist/server/action-discovery.d.ts.map +1 -1
  69. package/dist/server/action-discovery.js +4 -0
  70. package/dist/server/action-discovery.js.map +1 -1
  71. package/dist/server/action-routes.d.ts.map +1 -1
  72. package/dist/server/action-routes.js +8 -2
  73. package/dist/server/action-routes.js.map +1 -1
  74. package/dist/server/index.d.ts +1 -0
  75. package/dist/server/index.d.ts.map +1 -1
  76. package/dist/server/index.js +1 -0
  77. package/dist/server/index.js.map +1 -1
  78. package/dist/shared/agent-readable-resource.d.ts +29 -0
  79. package/dist/shared/agent-readable-resource.d.ts.map +1 -0
  80. package/dist/shared/agent-readable-resource.js +60 -0
  81. package/dist/shared/agent-readable-resource.js.map +1 -0
  82. package/dist/shared/index.d.ts +1 -0
  83. package/dist/shared/index.d.ts.map +1 -1
  84. package/dist/shared/index.js +1 -0
  85. package/dist/shared/index.js.map +1 -1
  86. package/dist/sharing/actions/create-agent-resource-link.d.ts +13 -0
  87. package/dist/sharing/actions/create-agent-resource-link.d.ts.map +1 -0
  88. package/dist/sharing/actions/create-agent-resource-link.js +72 -0
  89. package/dist/sharing/actions/create-agent-resource-link.js.map +1 -0
  90. package/dist/sharing/registry.d.ts +17 -0
  91. package/dist/sharing/registry.d.ts.map +1 -1
  92. package/dist/sharing/registry.js.map +1 -1
  93. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +92 -0
  94. package/dist/vite/client.d.ts.map +1 -1
  95. package/dist/vite/client.js +1 -0
  96. package/dist/vite/client.js.map +1 -1
  97. package/docs/content/agent-native-toolkit.mdx +162 -0
  98. package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +73 -0
  99. package/docs/content/locales/ar-SA/sharing.mdx +15 -7
  100. package/docs/content/locales/de-DE/agent-native-toolkit.mdx +77 -0
  101. package/docs/content/locales/de-DE/sharing.mdx +15 -7
  102. package/docs/content/locales/es-ES/agent-native-toolkit.mdx +77 -0
  103. package/docs/content/locales/es-ES/sharing.mdx +15 -7
  104. package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +79 -0
  105. package/docs/content/locales/fr-FR/sharing.mdx +15 -7
  106. package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +74 -0
  107. package/docs/content/locales/hi-IN/sharing.mdx +15 -7
  108. package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +67 -0
  109. package/docs/content/locales/ja-JP/sharing.mdx +15 -7
  110. package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +63 -0
  111. package/docs/content/locales/ko-KR/sharing.mdx +15 -7
  112. package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +77 -0
  113. package/docs/content/locales/pt-BR/sharing.mdx +15 -7
  114. package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +61 -0
  115. package/docs/content/locales/zh-CN/sharing.mdx +15 -7
  116. package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +61 -0
  117. package/docs/content/locales/zh-TW/sharing.mdx +15 -7
  118. package/docs/content/sharing.mdx +39 -7
  119. package/package.json +2 -1
  120. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +92 -0
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: "Agent-Native 工具包"
3
+ description: "用於協作、設定、分享、導覽、線上狀態、歷史、配置和 Agent UX 的可重用套件。"
4
+ ---
5
+
6
+ # Agent-Native 工具包
7
+
8
+ Agent-Native 應用程式不應重複建置 workspace 的通用能力。應用程式負責自己的領域模型、
9
+ 領域 actions 和產品視圖。Framework 與 `@agent-native/toolkit` 負責每個應用程式都應繼承的
10
+ 可重用產品表面:協作、分享、設定、導覽、組織、配置、Agent UX、歷史和營運可見性。
11
+
12
+ 使用者應該只學會一種分享方式、一種連接金鑰的方式、一種看到 Agent 一起編輯的方式、一個設定入口,
13
+ 以及一種理解變更的方式。
14
+
15
+ ## 工具包契約 {#toolkit-contract}
16
+
17
+ 當行為符合以下條件時,應移到 toolkit:
18
+
19
+ - **Workspace 層級** - 使用者期待所有應用程式都一致。
20
+ - **Agent 可見** - Agent 需要透過 actions、instructions 或 application state 使用同一能力。
21
+ - **受治理** - 權限、audit、secrets、組織政策、billing 或分享規則會參與。
22
+ - **重複出現** - 兩個應用程式已經建了相似 UI 或邏輯。
23
+ - **非領域專屬** - 應用程式提供 resource 名稱與 actions,但互動模式是通用的。
24
+
25
+ 如果行為綁定領域模型、專屬 workflow 或應用程式自己的心智模型,就保持 app-local。
26
+
27
+ ## 可重用套件 {#reusable-kits}
28
+
29
+ - **Settings kit** - account、workspace、AI models、LLM keys、connections、secrets、
30
+ usage、notifications、changelog 和 app preferences 的標準 tabs。持久設定放在 Settings;
31
+ Agent sidebar 只保留情境 quick controls 與 deep links。
32
+ - **Collaboration kit** - real-time editing、Yjs docs、presence、agent presence、live
33
+ cursors、remote selections、recent edit highlights 和 shared undo/redo。請參閱
34
+ [Real-Time Collaboration](/docs/real-time-collaboration)。
35
+ - **Sharing kit** - 用一個隱私與權限模型處理 private、workspace、org、public link、invites、
36
+ roles、expirations 和 agent-readable access。請參閱 [Sharing & Privacy](/docs/sharing)。
37
+ - **Navigation and command kit** - app shell、nav、breadcrumbs、app switcher、command
38
+ palette、recents、pinned resources 和 search。
39
+ - **Organization kit** - folders、tags、favorites、archive、trash、ownership、membership
40
+ 和 common metadata。
41
+ - **Setup and connections kit** - API keys、OAuth、connections、model readiness、
42
+ missing secrets 和 declarative onboarding。請參閱
43
+ [Workspace Connections](/docs/workspace-connections)。
44
+ - **Agent UX kit** - sidebar、composer、staged context、mentions、voice、human approval、
45
+ generative UI、progress 和 Agent-visible state。
46
+ - **History and recovery kit** - audit log、activity feed、version history、checkpoints、
47
+ undo、redo、restore 和 proof-of-done。請參閱 [Audit Log](/docs/audit-log)。
48
+ - **Comments and review kit** - anchored comments、pins、mentions、review requests、
49
+ resolved threads 和 Agent follow-up tasks。
50
+ - **Workflow and observability kit** - notifications、approvals、background runs、
51
+ recurring jobs、traces、evals、feedback 和 run timelines。請參閱
52
+ [Observability](/docs/observability)。
53
+
54
+ ## 實作順序 {#implementation-order}
55
+
56
+ 1. 將持久設定合併到標準 Settings tabs。
57
+ 2. 用共享 adapters 統一 collaboration、presence、agent presence、undo/redo 和 real-time editing。
58
+ 3. 將 navigation、commands、recents、favorites、folders、tags、archive 和 trash 移入共享 primitives。
59
+ 4. 讓所有可分享 resource 註冊到同一 permissions 和 agent-readable access 模型。
60
+ 5. 為每個 collaborative resource 提供一致的 activity、comments、review、restore 和 audit 體驗。
61
+ 6. 統一 notifications、approvals、run status、traces、evals 和 feedback。
@@ -93,9 +93,10 @@ description: "Google Docs 風格的共用,內建於框架中。每個使用者
93
93
  - **幻燈片** — 幻燈片
94
94
  - **設計** — 設計和資產
95
95
  - **剪輯** — 螢幕錄製(Loom 風格)
96
+ - **Plan** — visual plans and PR recaps
96
97
  - **表單** — 表單定義
97
98
  - **行事曆** — 活動和預訂連結
98
- - **分析** - 儀表板(推出 - 請參閱分析範本的 `AGENTS.md`)
99
+ - **分析** - dashboards, saved analyses, and tokenized session replays
99
100
  - **擴充功能** - 沙盒迷你應用程式(參見 [Extensions](/docs/extensions#sharing))
100
101
 
101
102
  其中每一個都使用相同的 `ownableColumns()` 模式助手、相同的 `share-resource` 操作和相同的 `<ShareButton>` UI。從一個範本行動到另一個範本,共用對話框看起來相同。
@@ -136,15 +137,22 @@ import { ShareButton } from "@agent-native/core/client";
136
137
 
137
138
  框架在每個範本中自動安裝這些 actions - 代理將它們稱為工具,UI 透過 `useActionQuery` / `useActionMutation` 呼叫它們:
138
139
 
139
- | 行動 | 它的作用 |
140
- | ------------------------- | ---------------------------------------------------------------------- |
141
- | `share-resource` | 授予使用者或組織特定角色的存取權限。可選的 `notify` 控制電子郵件通知。 |
142
- | `unshare-resource` | 撤銷使用者或組織的存取權限。 |
143
- | `list-resource-shares` | 顯示目前可見性以及所有顯式授權。 |
144
- | `set-resource-visibility` | 更改為 `private`、`org` 或 `public`。 |
140
+ | 行動 | 它的作用 |
141
+ | ---------------------------- | --------------------------------------------------------------------------------------- |
142
+ | `share-resource` | 授予使用者或組織特定角色的存取權限。可選的 `notify` 控制電子郵件通知。 |
143
+ | `unshare-resource` | 撤銷使用者或組織的存取權限。 |
144
+ | `list-resource-shares` | 顯示目前可見性以及所有顯式授權。 |
145
+ | `set-resource-visibility` | 更改為 `private`、`org` 或 `public`。 |
146
+ | `create-agent-resource-link` | Mint a temporary read-only `agent_access` URL for a registered agent-readable resource. |
145
147
 
146
148
  告訴代理“與作為編輯的行銷團隊共用此設計”,它會針對 UI 使用的同一端點呼叫 `share-resource`。結果將顯示在下一次渲染的共用對話框中。
147
149
 
150
+ ## Agent-readable share links {#agent-readable-links}
151
+
152
+ Human share links should also work for agents when the resource is a document-like artifact: plans, documents, decks, designs, analytics dashboards, saved analyses, clips, and similar "things you would send to a person." Public links expose a small SSR discovery script that points at structured JSON. Private resources use a short-lived `agent_access` token scoped to exactly one resource.
153
+
154
+ Register the resource with `agentReadable`, add a read-only JSON context endpoint, inject the SSR discovery script with `renderAgentReadableResourceDiscoveryScript()`, and let agents call `create-agent-resource-link` when they need a temporary private URL. The endpoint must return data only when the row is `public` or `verifyScopedAgentAccessToken()` accepts the token for that exact `resourceKind` and `resourceId`.
155
+
148
156
  ## 將其建置到新範本中 {#building}
149
157
 
150
158
  如果您正在建立範本(請參閱 [Creating Templates](/docs/creating-templates)),則共用接線會很短。您的架構中新增了兩項內容:
@@ -93,9 +93,10 @@ Every template that stores user-authored work uses this model. Concretely:
93
93
  - **Slides** — decks
94
94
  - **Design** — designs and assets
95
95
  - **Clips** — screen recordings (Loom-style)
96
+ - **Plan** — visual plans and PR recaps
96
97
  - **Forms** — form definitions
97
98
  - **Calendar** — events and booking links
98
- - **Analytics** — dashboards (rolling out see the analytics template's `AGENTS.md`)
99
+ - **Analytics** — dashboards, saved analyses, and tokenized session replays
99
100
  - **Extensions** — sandboxed mini-apps (see [Extensions](/docs/extensions#sharing))
100
101
 
101
102
  Every one of these uses the same `ownableColumns()` schema helper, the same `share-resource` action, and the same `<ShareButton>` UI. Move from one template to another and the share dialog looks identical.
@@ -136,15 +137,46 @@ For lists, drop a `<VisibilityBadge visibility={row.visibility} />` next to each
136
137
 
137
138
  The framework auto-mounts these actions in every template — the agent calls them as tools, and the UI calls them through `useActionQuery` / `useActionMutation`:
138
139
 
139
- | Action | What it does |
140
- | ------------------------- | ---------------------------------------------------------------------------------------------- |
141
- | `share-resource` | Grant a user or org access at a specific role. Optional `notify` controls email notifications. |
142
- | `unshare-resource` | Revoke access for a user or org. |
143
- | `list-resource-shares` | Show current visibility plus all explicit grants. |
144
- | `set-resource-visibility` | Change to `private`, `org`, or `public`. |
140
+ | Action | What it does |
141
+ | ---------------------------- | ---------------------------------------------------------------------------------------------- |
142
+ | `share-resource` | Grant a user or org access at a specific role. Optional `notify` controls email notifications. |
143
+ | `unshare-resource` | Revoke access for a user or org. |
144
+ | `list-resource-shares` | Show current visibility plus all explicit grants. |
145
+ | `set-resource-visibility` | Change to `private`, `org`, or `public`. |
146
+ | `create-agent-resource-link` | Mint a temporary read-only `agent_access` URL for a registered agent-readable resource. |
145
147
 
146
148
  Tell the agent "share this design with the marketing team as editors" and it calls `share-resource` against the same endpoint the UI uses. The result shows up in the share dialog the next render.
147
149
 
150
+ ## Agent-readable share links {#agent-readable-links}
151
+
152
+ Human share links should also work for agents when the resource is a document-like artifact: plans, documents, decks, designs, analytics dashboards, saved analyses, clips, and similar "things you would send to a person." Public links expose a small SSR discovery script that points at structured JSON. Private resources use a short-lived `agent_access` token scoped to exactly one resource.
153
+
154
+ The default flow is:
155
+
156
+ 1. Register the resource with `agentReadable`.
157
+ 2. Add a read-only JSON endpoint that returns the same content a viewer can see.
158
+ 3. Add an SSR discovery script on the human page with `renderAgentReadableResourceDiscoveryScript()`.
159
+ 4. Let agents call `create-agent-resource-link` when they need a temporary private URL.
160
+
161
+ ```ts
162
+ registerShareableResource({
163
+ type: "deck",
164
+ resourceTable: schema.decks,
165
+ sharesTable: schema.deckShares,
166
+ displayName: "Deck",
167
+ titleColumn: "title",
168
+ getResourcePath: (deck) => `/p/${deck.id}`,
169
+ agentReadable: {
170
+ resourceKind: "slides:deck",
171
+ getContextPath: () => "/api/deck-agent-context.json",
172
+ getPagePath: (deck) => `/p/${deck.id}`,
173
+ },
174
+ getDb,
175
+ });
176
+ ```
177
+
178
+ The context endpoint must be read-only. It should return data only when the row is `public` or `verifyScopedAgentAccessToken()` accepts the token for that exact `resourceKind` and `resourceId`. Set `Cache-Control: no-store`, `Referrer-Policy: no-referrer`, and avoid including write credentials, provider blob URLs, or secrets. Token links should not change the resource visibility.
179
+
148
180
  ## Building it into a new template {#building}
149
181
 
150
182
  If you're creating a template (see [Creating Templates](/docs/creating-templates)), wiring sharing in is short. Two additions to your schema:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.87.0",
3
+ "version": "0.88.0",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -132,6 +132,7 @@
132
132
  "./sharing/actions/unshare-resource": "./dist/sharing/actions/unshare-resource.js",
133
133
  "./sharing/actions/list-resource-shares": "./dist/sharing/actions/list-resource-shares.js",
134
134
  "./sharing/actions/set-resource-visibility": "./dist/sharing/actions/set-resource-visibility.js",
135
+ "./sharing/actions/create-agent-resource-link": "./dist/sharing/actions/create-agent-resource-link.js",
135
136
  "./client/sharing": "./dist/client/sharing/index.js",
136
137
  "./client/extensions": "./dist/client/extensions/index.js",
137
138
  "./client/tools": "./dist/client/extensions/index.js",
@@ -562,6 +562,10 @@ export async function mergeCoreSharingActions(
562
562
  "set-resource-visibility",
563
563
  () => import("../sharing/actions/set-resource-visibility.js"),
564
564
  ],
565
+ [
566
+ "create-agent-resource-link",
567
+ () => import("../sharing/actions/create-agent-resource-link.js"),
568
+ ],
565
569
  ["upload-image", () => import("../file-upload/actions/upload-image.js")],
566
570
  [
567
571
  "context-manifest-get",
@@ -5,6 +5,7 @@ import {
5
5
  getMethod,
6
6
  getQuery,
7
7
  getHeader,
8
+ getRequestURL,
8
9
  } from "h3";
9
10
 
10
11
  import { isAgentActionStopError } from "../action.js";
@@ -282,7 +283,13 @@ export function mountActionRoutes(
282
283
  const timezone = readTimezoneHeader(event);
283
284
 
284
285
  return runWithRequestContext(
285
- { userEmail, userName, orgId, timezone },
286
+ {
287
+ userEmail,
288
+ userName,
289
+ orgId,
290
+ timezone,
291
+ requestOrigin: getRequestURL(event).origin,
292
+ },
286
293
  async () => {
287
294
  // Reject oversize bodies from Content-Length before parsing, so a
288
295
  // public no-auth POST can't force parse work on a huge request.
@@ -478,6 +478,15 @@ export {
478
478
  type ScopedAgentAccessGrant,
479
479
  type ScopedAgentAccessTokenOptions,
480
480
  } from "./agent-access.js";
481
+ export {
482
+ AGENT_READABLE_RESOURCE_PAYLOAD_TYPE,
483
+ AGENT_READABLE_RESOURCE_SCRIPT_TYPE,
484
+ buildAgentReadableResourceDiscovery,
485
+ renderAgentReadableResourceDiscoveryScript,
486
+ safeJsonForHtml,
487
+ type AgentReadableResourceDiscovery,
488
+ type BuildAgentReadableResourceDiscoveryOptions,
489
+ } from "../shared/agent-readable-resource.js";
481
490
 
482
491
  // SSR handler is NOT re-exported here — it uses a virtual module
483
492
  // (virtual:react-router/server-build) that only exists at Vite dev/build time.
@@ -0,0 +1,111 @@
1
+ import {
2
+ AGENT_ACCESS_PARAM,
3
+ buildAgentAccessApiUrl,
4
+ buildAgentAccessUrl,
5
+ toAgentAccessUrl,
6
+ type AgentAccessUrlOptions,
7
+ } from "./agent-access.js";
8
+
9
+ export const AGENT_READABLE_RESOURCE_SCRIPT_TYPE =
10
+ "application/agent-native+json";
11
+ export const AGENT_READABLE_RESOURCE_PAYLOAD_TYPE =
12
+ "agent-native.resource.discovery";
13
+
14
+ export interface AgentReadableResourceDiscovery {
15
+ type: typeof AGENT_READABLE_RESOURCE_PAYLOAD_TYPE;
16
+ resourceType: string;
17
+ resourceId: string;
18
+ title?: string;
19
+ url?: string;
20
+ contextUrl: string;
21
+ expiresAt?: string;
22
+ instructions?: string;
23
+ }
24
+
25
+ export interface BuildAgentReadableResourceDiscoveryOptions extends AgentAccessUrlOptions {
26
+ resourceType: string;
27
+ resourceId: string;
28
+ title?: string | null;
29
+ path?: string | null;
30
+ contextEndpoint: string;
31
+ token?: string | null;
32
+ expiresAt?: string | null;
33
+ instructions?: string | null;
34
+ }
35
+
36
+ export function safeJsonForHtml(value: unknown): string {
37
+ return JSON.stringify(value).replace(/[<>&\u2028\u2029]/g, (char) => {
38
+ switch (char) {
39
+ case "<":
40
+ return "\\u003c";
41
+ case ">":
42
+ return "\\u003e";
43
+ case "&":
44
+ return "\\u0026";
45
+ case "\u2028":
46
+ return "\\u2028";
47
+ case "\u2029":
48
+ return "\\u2029";
49
+ default:
50
+ return char;
51
+ }
52
+ });
53
+ }
54
+
55
+ export function buildAgentReadableResourceDiscovery({
56
+ resourceType,
57
+ resourceId,
58
+ title,
59
+ path,
60
+ contextEndpoint,
61
+ token,
62
+ expiresAt,
63
+ instructions,
64
+ origin,
65
+ basePath,
66
+ tokenParam = AGENT_ACCESS_PARAM,
67
+ }: BuildAgentReadableResourceDiscoveryOptions): AgentReadableResourceDiscovery {
68
+ return {
69
+ type: AGENT_READABLE_RESOURCE_PAYLOAD_TYPE,
70
+ resourceType,
71
+ resourceId,
72
+ ...(title ? { title } : {}),
73
+ ...(path
74
+ ? {
75
+ url: token
76
+ ? buildAgentAccessUrl({
77
+ path,
78
+ token,
79
+ origin,
80
+ basePath,
81
+ tokenParam,
82
+ })
83
+ : toAgentAccessUrl(path, { origin, basePath }),
84
+ }
85
+ : {}),
86
+ contextUrl: buildAgentAccessApiUrl({
87
+ endpoint: contextEndpoint,
88
+ resourceId,
89
+ token,
90
+ origin,
91
+ basePath,
92
+ tokenParam,
93
+ }),
94
+ ...(expiresAt ? { expiresAt } : {}),
95
+ ...(instructions ? { instructions } : {}),
96
+ };
97
+ }
98
+
99
+ export function renderAgentReadableResourceDiscoveryScript(
100
+ discovery: AgentReadableResourceDiscovery,
101
+ options: { id?: string } = {},
102
+ ): string {
103
+ const id = options.id ? ` id="${escapeHtmlAttribute(options.id)}"` : "";
104
+ return `<script type="${AGENT_READABLE_RESOURCE_SCRIPT_TYPE}"${id}>${safeJsonForHtml(
105
+ discovery,
106
+ )}</script>`;
107
+ }
108
+
109
+ function escapeHtmlAttribute(value: string): string {
110
+ return value.replace(/[&"]/g, (char) => (char === "&" ? "&amp;" : "&quot;"));
111
+ }
@@ -72,3 +72,12 @@ export {
72
72
  type AgentAccessResourceScope,
73
73
  type AgentAccessUrlOptions,
74
74
  } from "./agent-access.js";
75
+ export {
76
+ AGENT_READABLE_RESOURCE_PAYLOAD_TYPE,
77
+ AGENT_READABLE_RESOURCE_SCRIPT_TYPE,
78
+ buildAgentReadableResourceDiscovery,
79
+ renderAgentReadableResourceDiscoveryScript,
80
+ safeJsonForHtml,
81
+ type AgentReadableResourceDiscovery,
82
+ type BuildAgentReadableResourceDiscoveryOptions,
83
+ } from "./agent-readable-resource.js";
@@ -0,0 +1,91 @@
1
+ import { z } from "zod";
2
+
3
+ import { defineAction } from "../../action.js";
4
+ import {
5
+ buildAgentAccessApiUrl,
6
+ buildAgentAccessUrl,
7
+ createScopedAgentAccessGrant,
8
+ } from "../../server/agent-access.js";
9
+ import { getConfiguredAppBasePath } from "../../server/app-base-path.js";
10
+ import {
11
+ getRequestContext,
12
+ getRequestUserEmail,
13
+ } from "../../server/request-context.js";
14
+ import { ForbiddenError, resolveAccess } from "../access.js";
15
+ import { requireShareableResource } from "../registry.js";
16
+
17
+ function appOrigin(): string {
18
+ const origin =
19
+ getRequestContext()?.requestOrigin ||
20
+ process.env.APP_URL ||
21
+ process.env.BETTER_AUTH_URL ||
22
+ "http://localhost:3000";
23
+ try {
24
+ return new URL(origin).origin;
25
+ } catch {
26
+ return "http://localhost:3000";
27
+ }
28
+ }
29
+
30
+ export default defineAction({
31
+ description:
32
+ "Create a temporary, read-only, agent-readable link for a registered shareable resource. The token is scoped to exactly one resource and does not change the resource visibility.",
33
+ schema: z.object({
34
+ resourceType: z.string().describe("Shareable resource type"),
35
+ resourceId: z.string().describe("Resource ID"),
36
+ }),
37
+ readOnly: true,
38
+ run: async (args) => {
39
+ const reg = requireShareableResource(args.resourceType);
40
+ const agentReadable = reg.agentReadable;
41
+ if (!agentReadable) {
42
+ throw new ForbiddenError(
43
+ `${reg.displayName} does not expose an agent-readable context endpoint.`,
44
+ );
45
+ }
46
+
47
+ const access = await resolveAccess(args.resourceType, args.resourceId);
48
+ if (!access) {
49
+ throw new ForbiddenError(
50
+ `No access to ${args.resourceType} ${args.resourceId}`,
51
+ );
52
+ }
53
+
54
+ const pagePath =
55
+ agentReadable.getPagePath?.(access.resource) ??
56
+ reg.getResourcePath?.(access.resource);
57
+ const contextPath = agentReadable.getContextPath(access.resource);
58
+ if (!pagePath || !contextPath) {
59
+ throw new ForbiddenError(`${reg.displayName} is not agent-readable yet.`);
60
+ }
61
+
62
+ const grant = createScopedAgentAccessGrant({
63
+ resourceKind: agentReadable.resourceKind,
64
+ resourceId: args.resourceId,
65
+ viewerEmail: getRequestUserEmail() || undefined,
66
+ ttlSeconds: agentReadable.ttlSeconds,
67
+ });
68
+ const origin = appOrigin();
69
+ const basePath = getConfiguredAppBasePath();
70
+
71
+ return {
72
+ resourceType: args.resourceType,
73
+ resourceId: args.resourceId,
74
+ url: buildAgentAccessUrl({
75
+ path: pagePath,
76
+ origin,
77
+ basePath,
78
+ token: grant.token,
79
+ }),
80
+ contextUrl: buildAgentAccessApiUrl({
81
+ endpoint: contextPath,
82
+ resourceId: args.resourceId,
83
+ origin,
84
+ basePath,
85
+ token: grant.token,
86
+ }),
87
+ expiresAt: grant.expiresAt,
88
+ ttlSeconds: grant.ttlSeconds,
89
+ };
90
+ },
91
+ });
@@ -105,6 +105,25 @@ export interface ShareableResourceRegistration {
105
105
  * Default: `false`.
106
106
  */
107
107
  ownerAccessIgnoresOrg?: boolean;
108
+ /**
109
+ * Optional external-agent read handoff. When set, the framework-level
110
+ * `create-agent-resource-link` action can mint a short-lived, read-only
111
+ * `agent_access` URL for this resource. The context endpoint is owned by the
112
+ * template so it can expose the same intentionally shareable shape as the
113
+ * public page, not a generic raw database row.
114
+ */
115
+ agentReadable?:
116
+ | false
117
+ | {
118
+ /** Token scope. Include the app name to avoid cross-app collisions. */
119
+ resourceKind: string;
120
+ /** App-relative JSON endpoint that accepts `id` + `agent_access`. */
121
+ getContextPath: (resource: any) => string | undefined;
122
+ /** Optional override for the page URL. Defaults to getResourcePath. */
123
+ getPagePath?: (resource: any) => string | undefined;
124
+ /** Optional override for the default two-hour token lifetime. */
125
+ ttlSeconds?: number;
126
+ };
108
127
  }
109
128
 
110
129
  // Stash the registry on globalThis so it survives SSR bundle duplication.
@@ -0,0 +1,92 @@
1
+ # Agent-Native Toolkit
2
+
3
+ Use this skill when deciding whether app chrome, settings, collaboration,
4
+ sharing, navigation, organization, setup, history, comments, or agent UX should
5
+ be built app-locally or moved into reusable framework/toolkit pieces.
6
+
7
+ ## Core Rule
8
+
9
+ Apps own domain models, domain actions, and product-specific workflows. The
10
+ framework and `@agent-native/toolkit` own repeated workspace behavior users
11
+ expect to work the same everywhere.
12
+
13
+ Move behavior into shared toolkit primitives when it is:
14
+
15
+ - workspace-wide, such as settings, nav, search, org membership, or setup
16
+ - agent-visible, such as context, actions, run progress, or proof-of-done
17
+ - governed, such as secrets, permissions, sharing, audit, or billing
18
+ - repeated by two or more apps
19
+ - not tied to one domain model
20
+
21
+ Keep behavior app-local when the abstraction would hide important domain
22
+ language or make a simple app-specific workflow harder to understand.
23
+
24
+ ## Settings Direction
25
+
26
+ Durable settings belong in the Settings app or a registered settings route. The
27
+ agent sidebar should not become a second settings app. It can show contextual
28
+ quick controls and deep links such as:
29
+
30
+ - `/settings/ai`
31
+ - `/settings/connections`
32
+ - `/settings/secrets`
33
+ - `/settings/usage`
34
+ - `/settings/apps/:appId`
35
+
36
+ When adding a new API key, OAuth grant, provider connection, model selector, app
37
+ preference, notification preference, or usage/billing surface, register it as a
38
+ settings tab or app settings panel first. Only add sidebar UI when it is needed
39
+ in the moment of agent use.
40
+
41
+ ## Reusable Kits
42
+
43
+ - **Settings kit**: account, workspace, AI models, LLM keys, connections,
44
+ secrets, usage, notifications, changelog, and app-specific panels.
45
+ - **Collaboration kit**: Yjs docs, presence, agent presence, live cursors,
46
+ remote selections, recent edit highlights, real-time sync indicators, and
47
+ undo/redo grouping.
48
+ - **Sharing kit**: private/workspace/org/public-link access, invites, roles,
49
+ expirations, agent-readable links, and resource registration.
50
+ - **Navigation and command kit**: app shell, side nav, breadcrumbs, app switcher,
51
+ command palette entries, recent resources, pinned resources, and global search.
52
+ - **Organization kit**: folders, tags, favorites, archive, trash, ownership,
53
+ membership, and common resource metadata.
54
+ - **Setup and connections kit**: declarative setup requirements, model readiness,
55
+ missing-secret states, OAuth grants, and provider connection health.
56
+ - **Agent UX kit**: sidebar, composer, staged context, mentions, voice, human
57
+ approval, generative UI, progress, and screen-state exposure.
58
+ - **History and recovery kit**: audit log, activity feed, version history,
59
+ checkpoints, undo, redo, restore, and proof-of-done.
60
+ - **Comments and review kit**: anchored comments, pins, mentions, review
61
+ requests, resolved threads, agent follow-up tasks, and notifications.
62
+ - **Workflow and observability kit**: notifications, approvals, scheduled work,
63
+ background runs, recurring jobs, traces, evals, feedback, and run timelines.
64
+
65
+ ## Implementation Checklist
66
+
67
+ When adding or refactoring one of these areas:
68
+
69
+ 1. Search existing framework and template code for duplicated UI or actions.
70
+ 2. Decide the shared contract: data shape, action API, React component/hook, and
71
+ app adapter points.
72
+ 3. Keep shared data provider-agnostic and scoped by auth/sharing rules.
73
+ 4. Expose the same capability to the UI and agent through actions or documented
74
+ client helpers.
75
+ 5. Register app-specific labels, routes, resource adapters, and settings panels
76
+ instead of hardcoding app names in core UI.
77
+ 6. Update docs and relevant skills so future apps discover the shared path.
78
+
79
+ ## Related Skills
80
+
81
+ Read these alongside this skill when the work touches the specific area:
82
+
83
+ - `sharing`
84
+ - `real-time-collab`
85
+ - `real-time-sync`
86
+ - `client-side-routing`
87
+ - `context-awareness`
88
+ - `onboarding`
89
+ - `secrets`
90
+ - `audit-log`
91
+ - `observability`
92
+ - `frontend-design`
@@ -1739,6 +1739,7 @@ function ssrStubPlugin(packages: string[]): Plugin | null {
1739
1739
  "captureException",
1740
1740
  "common",
1741
1741
  "createLowlight",
1742
+ "createNodeFromContent",
1742
1743
  "defaultUrlTransform",
1743
1744
  "extensions",
1744
1745
  "findTable",