@agent-native/core 0.7.22 → 0.7.24

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 (140) hide show
  1. package/README.md +2 -2
  2. package/dist/a2a/client.d.ts +10 -4
  3. package/dist/a2a/client.d.ts.map +1 -1
  4. package/dist/a2a/client.js +16 -1
  5. package/dist/a2a/client.js.map +1 -1
  6. package/dist/a2a/handlers.d.ts.map +1 -1
  7. package/dist/a2a/handlers.js +20 -17
  8. package/dist/a2a/handlers.js.map +1 -1
  9. package/dist/cli/create.d.ts +3 -1
  10. package/dist/cli/create.d.ts.map +1 -1
  11. package/dist/cli/create.js +33 -32
  12. package/dist/cli/create.js.map +1 -1
  13. package/dist/cli/index.js +23 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/workspace-dev.d.ts +3 -0
  16. package/dist/cli/workspace-dev.d.ts.map +1 -0
  17. package/dist/cli/workspace-dev.js +323 -0
  18. package/dist/cli/workspace-dev.js.map +1 -0
  19. package/dist/cli/workspacify.d.ts +3 -3
  20. package/dist/cli/workspacify.js +4 -4
  21. package/dist/cli/workspacify.js.map +1 -1
  22. package/dist/client/AgentPanel.d.ts.map +1 -1
  23. package/dist/client/AgentPanel.js +10 -9
  24. package/dist/client/AgentPanel.js.map +1 -1
  25. package/dist/client/AssistantChat.d.ts.map +1 -1
  26. package/dist/client/AssistantChat.js +2 -1
  27. package/dist/client/AssistantChat.js.map +1 -1
  28. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  29. package/dist/client/MultiTabAssistantChat.js +2 -1
  30. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  31. package/dist/client/components/ui/tooltip.d.ts +8 -0
  32. package/dist/client/components/ui/tooltip.d.ts.map +1 -0
  33. package/dist/client/components/ui/tooltip.js +11 -0
  34. package/dist/client/components/ui/tooltip.js.map +1 -0
  35. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  36. package/dist/client/resources/ResourceTree.js +21 -17
  37. package/dist/client/resources/ResourceTree.js.map +1 -1
  38. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  39. package/dist/client/resources/ResourcesPanel.js +13 -11
  40. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  41. package/dist/deploy/workspace-core.d.ts +1 -1
  42. package/dist/deploy/workspace-core.d.ts.map +1 -1
  43. package/dist/deploy/workspace-core.js +14 -11
  44. package/dist/deploy/workspace-core.js.map +1 -1
  45. package/dist/integrations/a2a-continuation-processor.d.ts +10 -0
  46. package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -0
  47. package/dist/integrations/a2a-continuation-processor.js +150 -0
  48. package/dist/integrations/a2a-continuation-processor.js.map +1 -0
  49. package/dist/integrations/a2a-continuations-store.d.ts +41 -0
  50. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -0
  51. package/dist/integrations/a2a-continuations-store.js +214 -0
  52. package/dist/integrations/a2a-continuations-store.js.map +1 -0
  53. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  54. package/dist/integrations/adapters/slack.js +4 -1
  55. package/dist/integrations/adapters/slack.js.map +1 -1
  56. package/dist/integrations/plugin.d.ts.map +1 -1
  57. package/dist/integrations/plugin.js +52 -0
  58. package/dist/integrations/plugin.js.map +1 -1
  59. package/dist/integrations/types.d.ts +5 -0
  60. package/dist/integrations/types.d.ts.map +1 -1
  61. package/dist/integrations/types.js.map +1 -1
  62. package/dist/integrations/webhook-handler.d.ts +6 -0
  63. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  64. package/dist/integrations/webhook-handler.js +69 -15
  65. package/dist/integrations/webhook-handler.js.map +1 -1
  66. package/dist/org/handlers.d.ts.map +1 -1
  67. package/dist/org/handlers.js +22 -16
  68. package/dist/org/handlers.js.map +1 -1
  69. package/dist/scripts/call-agent.d.ts.map +1 -1
  70. package/dist/scripts/call-agent.js +91 -30
  71. package/dist/scripts/call-agent.js.map +1 -1
  72. package/dist/server/agent-discovery.d.ts.map +1 -1
  73. package/dist/server/agent-discovery.js +17 -105
  74. package/dist/server/agent-discovery.js.map +1 -1
  75. package/dist/server/agents-bundle.js +1 -1
  76. package/dist/server/agents-bundle.js.map +1 -1
  77. package/dist/server/auth.d.ts.map +1 -1
  78. package/dist/server/auth.js +29 -120
  79. package/dist/server/auth.js.map +1 -1
  80. package/dist/server/better-auth-instance.d.ts +1 -0
  81. package/dist/server/better-auth-instance.d.ts.map +1 -1
  82. package/dist/server/better-auth-instance.js.map +1 -1
  83. package/dist/server/builder-browser.d.ts.map +1 -1
  84. package/dist/server/builder-browser.js +7 -5
  85. package/dist/server/builder-browser.js.map +1 -1
  86. package/dist/server/framework-request-handler.js +1 -1
  87. package/dist/server/framework-request-handler.js.map +1 -1
  88. package/dist/server/onboarding-html.d.ts +1 -8
  89. package/dist/server/onboarding-html.d.ts.map +1 -1
  90. package/dist/server/onboarding-html.js +321 -152
  91. package/dist/server/onboarding-html.js.map +1 -1
  92. package/dist/server/request-context.d.ts +14 -3
  93. package/dist/server/request-context.d.ts.map +1 -1
  94. package/dist/server/request-context.js +3 -0
  95. package/dist/server/request-context.js.map +1 -1
  96. package/dist/templates/default/_gitignore +2 -0
  97. package/dist/templates/workspace-core/AGENTS.md +18 -71
  98. package/dist/templates/workspace-core/package.json +2 -20
  99. package/dist/templates/workspace-core/src/client/index.ts +2 -26
  100. package/dist/templates/workspace-core/src/index.ts +1 -21
  101. package/dist/templates/workspace-core/src/server/index.ts +3 -22
  102. package/dist/templates/workspace-root/.prettierignore +19 -0
  103. package/dist/templates/workspace-root/README.md +17 -20
  104. package/dist/templates/workspace-root/_gitignore +8 -0
  105. package/dist/templates/workspace-root/package.json +8 -4
  106. package/dist/templates/workspace-root/pnpm-workspace.yaml +5 -2
  107. package/dist/vite/agents-bundle-plugin.js +2 -2
  108. package/dist/vite/agents-bundle-plugin.js.map +1 -1
  109. package/docs/content/authentication.md +3 -5
  110. package/docs/content/multi-app-workspace.md +38 -50
  111. package/package.json +1 -1
  112. package/src/templates/default/_gitignore +2 -0
  113. package/src/templates/workspace-core/AGENTS.md +18 -71
  114. package/src/templates/workspace-core/package.json +2 -20
  115. package/src/templates/workspace-core/src/client/index.ts +2 -26
  116. package/src/templates/workspace-core/src/index.ts +1 -21
  117. package/src/templates/workspace-core/src/server/index.ts +3 -22
  118. package/src/templates/workspace-root/.prettierignore +19 -0
  119. package/src/templates/workspace-root/README.md +17 -20
  120. package/src/templates/workspace-root/_gitignore +8 -0
  121. package/src/templates/workspace-root/package.json +8 -4
  122. package/src/templates/workspace-root/pnpm-workspace.yaml +5 -2
  123. package/dist/templates/default/.claude/settings.json +0 -100
  124. package/dist/templates/workspace-core/.agents/skills/company-policies/SKILL.md +0 -42
  125. package/dist/templates/workspace-core/actions/company-directory.ts +0 -38
  126. package/dist/templates/workspace-core/src/client/AuthenticatedLayout.tsx +0 -37
  127. package/dist/templates/workspace-core/src/credentials.ts +0 -67
  128. package/dist/templates/workspace-core/src/server/agent-chat-plugin.ts +0 -30
  129. package/dist/templates/workspace-core/src/server/auth-plugin.ts +0 -35
  130. package/dist/templates/workspace-core/styles/tokens.css +0 -22
  131. package/dist/templates/workspace-root/scripts/workspace-dev.ts +0 -377
  132. package/src/templates/default/.claude/settings.json +0 -100
  133. package/src/templates/workspace-core/.agents/skills/company-policies/SKILL.md +0 -42
  134. package/src/templates/workspace-core/actions/company-directory.ts +0 -38
  135. package/src/templates/workspace-core/src/client/AuthenticatedLayout.tsx +0 -37
  136. package/src/templates/workspace-core/src/credentials.ts +0 -67
  137. package/src/templates/workspace-core/src/server/agent-chat-plugin.ts +0 -30
  138. package/src/templates/workspace-core/src/server/auth-plugin.ts +0 -35
  139. package/src/templates/workspace-core/styles/tokens.css +0 -22
  140. package/src/templates/workspace-root/scripts/workspace-dev.ts +0 -377
@@ -1,113 +1,25 @@
1
+ import { visibleTemplates } from "../cli/templates-meta.js";
1
2
  /**
2
- * Built-in agent registry. Mirrors DEFAULT_APPS from @agent-native/shared-app-config
3
- * but inlined here to avoid a cross-package dependency that breaks tsc.
3
+ * Built-in agent registry. Derive this from the published CLI metadata so
4
+ * connected-agent discovery stays aligned with the public template allow-list
5
+ * without depending on @agent-native/shared-app-config at runtime.
4
6
  */
5
- const BUILTIN_AGENTS = [
6
- {
7
- id: "mail",
8
- name: "Mail",
9
- description: "Email client",
10
- url: "https://mail.agent-native.com",
11
- devUrl: "http://localhost:8085",
12
- devPort: 8085,
13
- color: "#3B82F6",
14
- enabled: true,
15
- mode: "prod",
16
- },
17
- {
18
- id: "calendar",
19
- name: "Calendar",
20
- description: "Google Calendar integration",
21
- url: "https://calendar.agent-native.com",
22
- devUrl: "http://localhost:8082",
23
- devPort: 8082,
24
- color: "#8B5CF6",
25
- enabled: true,
26
- mode: "prod",
27
- },
28
- {
29
- id: "content",
30
- name: "Content",
31
- description: "Notion-like content workspace",
32
- url: "https://content.agent-native.com",
33
- devUrl: "http://localhost:8083",
34
- devPort: 8083,
35
- color: "#10B981",
36
- enabled: true,
37
- mode: "prod",
38
- },
39
- {
40
- id: "analytics",
41
- name: "Analytics",
42
- description: "Analytics dashboard",
43
- url: "https://analytics.agent-native.com",
44
- devUrl: "http://localhost:8088",
45
- devPort: 8088,
46
- color: "#F59E0B",
47
- enabled: true,
48
- mode: "prod",
49
- },
50
- {
51
- id: "slides",
52
- name: "Slides",
53
- description: "AI slide deck creator",
54
- url: "https://slides.agent-native.com",
55
- devUrl: "http://localhost:8086",
56
- devPort: 8086,
57
- color: "#EC4899",
58
- enabled: true,
59
- mode: "prod",
60
- },
61
- {
62
- id: "videos",
63
- name: "Videos",
64
- description: "AI video creator",
65
- url: "https://videos.agent-native.com",
66
- devUrl: "http://localhost:8087",
67
- devPort: 8087,
68
- color: "#EF4444",
69
- enabled: true,
70
- mode: "prod",
71
- },
72
- {
73
- id: "issues",
74
- name: "Issues",
75
- description: "Jira project tracker",
76
- url: "https://issues.agent-native.com",
77
- devUrl: "http://localhost:8091",
78
- devPort: 8091,
79
- color: "#6366F1",
80
- enabled: true,
81
- mode: "dev",
82
- },
83
- {
84
- id: "forms",
85
- name: "Forms",
86
- description: "Form builder",
87
- url: "https://forms.agent-native.com",
88
- devUrl: "http://localhost:8084",
89
- devPort: 8084,
90
- color: "#06B6D4",
91
- enabled: true,
92
- mode: "prod",
93
- },
94
- {
95
- id: "recruiting",
96
- name: "Recruiting",
97
- description: "AI-powered recruiting",
98
- url: "https://recruiting.agent-native.com",
99
- devUrl: "http://localhost:8090",
100
- devPort: 8090,
101
- color: "#16A34A",
102
- enabled: true,
103
- mode: "dev",
104
- },
105
- ];
7
+ const BUILTIN_AGENTS = visibleTemplates()
8
+ .filter((template) => !!template.prodUrl)
9
+ .map((template) => ({
10
+ id: template.name,
11
+ name: template.label,
12
+ description: template.description ?? template.hint,
13
+ url: template.prodUrl,
14
+ devUrl: `http://localhost:${template.devPort}`,
15
+ devPort: template.devPort,
16
+ color: template.color,
17
+ }));
106
18
  /**
107
19
  * Get built-in agents (static, no DB). Used as fallback and for seeding.
108
20
  */
109
21
  export function getBuiltinAgents(selfAppId) {
110
- return BUILTIN_AGENTS.filter((app) => app.id !== selfAppId && app.enabled && !app.placeholder && app.url).map((app) => ({
22
+ return BUILTIN_AGENTS.filter((app) => app.id !== selfAppId && app.url).map((app) => ({
111
23
  id: app.id,
112
24
  name: app.name,
113
25
  description: app.description,
@@ -202,7 +114,7 @@ function resolveAgentUrl(app) {
202
114
  * DB, which would override the built-in's prod URL for every later
203
115
  * production deploy.
204
116
  */
205
- export const BUILTIN_AGENTS_FOR_SEEDING = BUILTIN_AGENTS.filter((app) => app.enabled && !app.placeholder && app.url).map((app) => ({
117
+ export const BUILTIN_AGENTS_FOR_SEEDING = BUILTIN_AGENTS.filter((app) => app.url).map((app) => ({
206
118
  id: app.id,
207
119
  name: app.name,
208
120
  description: app.description,
@@ -1 +1 @@
1
- {"version":3,"file":"agent-discovery.js","sourceRoot":"","sources":["../../src/server/agent-discovery.ts"],"names":[],"mappings":"AAqBA;;;GAGG;AACH,MAAM,cAAc,GAAiB;IACnC;QACE,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,cAAc;QAC3B,GAAG,EAAE,+BAA+B;QACpC,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,MAAM;KACb;IACD;QACE,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,6BAA6B;QAC1C,GAAG,EAAE,mCAAmC;QACxC,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,MAAM;KACb;IACD;QACE,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,+BAA+B;QAC5C,GAAG,EAAE,kCAAkC;QACvC,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,MAAM;KACb;IACD;QACE,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,qBAAqB;QAClC,GAAG,EAAE,oCAAoC;QACzC,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,MAAM;KACb;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,uBAAuB;QACpC,GAAG,EAAE,iCAAiC;QACtC,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,MAAM;KACb;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,kBAAkB;QAC/B,GAAG,EAAE,iCAAiC;QACtC,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,MAAM;KACb;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,sBAAsB;QACnC,GAAG,EAAE,iCAAiC;QACtC,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,KAAK;KACZ;IACD;QACE,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,cAAc;QAC3B,GAAG,EAAE,gCAAgC;QACrC,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,MAAM;KACb;IACD;QACE,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,uBAAuB;QACpC,GAAG,EAAE,qCAAqC;QAC1C,MAAM,EAAE,uBAAuB;QAC/B,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,KAAK;KACZ;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAkB;IACjD,OAAO,cAAc,CAAC,MAAM,CAC1B,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,CAC5E,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACd,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC;QACzB,KAAK,EAAE,GAAG,CAAC,KAAK;KACjB,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAkB;IAElB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEtD,uBAAuB;IACvB,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,uCAAuC;IACvC,IAAI,CAAC;QACH,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,sBAAsB,EAAE,GACvE,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QACxC,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAE1D,MAAM,SAAS,GACb,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,QAAQ,KAAK,YAAY,CAAC;QAE3E,MAAM,SAAS,GAAG,SAAS;YACzB,CAAC,CAAC,MAAM,sBAAsB,CAAC,mBAAmB,EAAE,gBAAgB,CAAC;YACrE,CAAC,CAAC,MAAM,YAAY,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;QACvD,MAAM,EAAE,wBAAwB,EAAE,GAChC,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;QAE3C,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,SAAS;YACxC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACrC,IAAI,CAAC,IAAI;oBAAE,SAAS;gBACpB,MAAM,QAAQ,GAAG,wBAAwB,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;gBAChE,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS;oBAAE,SAAS;gBAErD,qEAAqE;gBACrE,qEAAqE;gBACrE,gEAAgE;gBAChE,qEAAqE;gBACrE,kEAAkE;gBAClE,sEAAsE;gBACtE,2DAA2D;gBAC3D,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC;gBACvB,IACE,CAAC,SAAS;oBACV,OAAO,GAAG,KAAK,QAAQ;oBACvB,yDAAyD,CAAC,IAAI,CAAC,GAAG,CAAC,EACnE,CAAC;oBACD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;oBAC5C,IAAI,OAAO,EAAE,GAAG;wBAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;gBACtC,CAAC;gBAED,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE;oBAC1B,EAAE,EAAE,QAAQ,CAAC,EAAE;oBACf,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE;oBACvC,GAAG;oBACH,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,SAAS;iBACnC,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,4BAA4B;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+CAA+C;IACjD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAgB,EAChB,SAAkB;IAElB,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,CACL,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,QAAQ,KAAK,YAAY,CACzE,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAAe;IACtC,IAAI,gBAAgB,EAAE,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,MAAM,IAAI,oBAAoB,GAAG,CAAC,OAAO,EAAE,CAAC;IACzD,CAAC;IACD,OAAO,GAAG,CAAC,GAAG,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,0BAA0B,GACrC,cAAc,CAAC,MAAM,CACnB,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,CACpD,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACd,EAAE,EAAE,GAAG,CAAC,EAAE;IACV,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,WAAW,EAAE,GAAG,CAAC,WAAW;IAC5B,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,cAAc;IAC5B,KAAK,EAAE,GAAG,CAAC,KAAK;CACjB,CAAC,CAAC,CAAC","sourcesContent":["export interface DiscoveredAgent {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n}\n\ninterface AgentEntry {\n id: string;\n name: string;\n description: string;\n url: string;\n devUrl?: string;\n devPort: number;\n color: string;\n enabled: boolean;\n placeholder?: boolean;\n mode?: \"dev\" | \"prod\";\n}\n\n/**\n * Built-in agent registry. Mirrors DEFAULT_APPS from @agent-native/shared-app-config\n * but inlined here to avoid a cross-package dependency that breaks tsc.\n */\nconst BUILTIN_AGENTS: AgentEntry[] = [\n {\n id: \"mail\",\n name: \"Mail\",\n description: \"Email client\",\n url: \"https://mail.agent-native.com\",\n devUrl: \"http://localhost:8085\",\n devPort: 8085,\n color: \"#3B82F6\",\n enabled: true,\n mode: \"prod\",\n },\n {\n id: \"calendar\",\n name: \"Calendar\",\n description: \"Google Calendar integration\",\n url: \"https://calendar.agent-native.com\",\n devUrl: \"http://localhost:8082\",\n devPort: 8082,\n color: \"#8B5CF6\",\n enabled: true,\n mode: \"prod\",\n },\n {\n id: \"content\",\n name: \"Content\",\n description: \"Notion-like content workspace\",\n url: \"https://content.agent-native.com\",\n devUrl: \"http://localhost:8083\",\n devPort: 8083,\n color: \"#10B981\",\n enabled: true,\n mode: \"prod\",\n },\n {\n id: \"analytics\",\n name: \"Analytics\",\n description: \"Analytics dashboard\",\n url: \"https://analytics.agent-native.com\",\n devUrl: \"http://localhost:8088\",\n devPort: 8088,\n color: \"#F59E0B\",\n enabled: true,\n mode: \"prod\",\n },\n {\n id: \"slides\",\n name: \"Slides\",\n description: \"AI slide deck creator\",\n url: \"https://slides.agent-native.com\",\n devUrl: \"http://localhost:8086\",\n devPort: 8086,\n color: \"#EC4899\",\n enabled: true,\n mode: \"prod\",\n },\n {\n id: \"videos\",\n name: \"Videos\",\n description: \"AI video creator\",\n url: \"https://videos.agent-native.com\",\n devUrl: \"http://localhost:8087\",\n devPort: 8087,\n color: \"#EF4444\",\n enabled: true,\n mode: \"prod\",\n },\n {\n id: \"issues\",\n name: \"Issues\",\n description: \"Jira project tracker\",\n url: \"https://issues.agent-native.com\",\n devUrl: \"http://localhost:8091\",\n devPort: 8091,\n color: \"#6366F1\",\n enabled: true,\n mode: \"dev\",\n },\n {\n id: \"forms\",\n name: \"Forms\",\n description: \"Form builder\",\n url: \"https://forms.agent-native.com\",\n devUrl: \"http://localhost:8084\",\n devPort: 8084,\n color: \"#06B6D4\",\n enabled: true,\n mode: \"prod\",\n },\n {\n id: \"recruiting\",\n name: \"Recruiting\",\n description: \"AI-powered recruiting\",\n url: \"https://recruiting.agent-native.com\",\n devUrl: \"http://localhost:8090\",\n devPort: 8090,\n color: \"#16A34A\",\n enabled: true,\n mode: \"dev\",\n },\n];\n\n/**\n * Get built-in agents (static, no DB). Used as fallback and for seeding.\n */\nexport function getBuiltinAgents(selfAppId?: string): DiscoveredAgent[] {\n return BUILTIN_AGENTS.filter(\n (app) => app.id !== selfAppId && app.enabled && !app.placeholder && app.url,\n ).map((app) => ({\n id: app.id,\n name: app.name,\n description: app.description,\n url: resolveAgentUrl(app),\n color: app.color,\n }));\n}\n\n/**\n * Discover all agents: built-in + custom agents stored as resources.\n * Custom agents override built-in agents with the same ID.\n */\nexport async function discoverAgents(\n selfAppId?: string,\n): Promise<DiscoveredAgent[]> {\n const builtins = getBuiltinAgents(selfAppId);\n const agentsById = new Map<string, DiscoveredAgent>();\n\n // Start with built-ins\n for (const agent of builtins) {\n agentsById.set(agent.id, agent);\n }\n\n // Overlay custom agents from resources\n try {\n const { resourceList, resourceGet, SHARED_OWNER, resourceListAccessible } =\n await import(\"../resources/store.js\");\n const { DEV_MODE_USER_EMAIL } = await import(\"./auth.js\");\n\n const isDevMode =\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\n const resources = isDevMode\n ? await resourceListAccessible(DEV_MODE_USER_EMAIL, \"remote-agents/\")\n : await resourceList(SHARED_OWNER, \"remote-agents/\");\n const { parseRemoteAgentManifest } =\n await import(\"../resources/metadata.js\");\n\n for (const r of resources) {\n if (!r.path.endsWith(\".json\")) continue;\n try {\n const full = await resourceGet(r.id);\n if (!full) continue;\n const manifest = parseRemoteAgentManifest(full.content, r.path);\n if (!manifest || manifest.id === selfAppId) continue;\n\n // If the resource override carries a localhost URL but we're running\n // in production (e.g. a stale dev-time seed got promoted to the prod\n // DB), fall back to the matching built-in's prod URL instead of\n // letting the override win — otherwise outbound `call-agent` fetches\n // from a serverless function would target localhost and fail with\n // \"fetch failed\" instantly. The override still wins for non-localhost\n // URLs (the supported case for self-hosted custom agents).\n let url = manifest.url;\n if (\n !isDevMode &&\n typeof url === \"string\" &&\n /^https?:\\/\\/(localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0)(:|\\/|$)/.test(url)\n ) {\n const builtin = agentsById.get(manifest.id);\n if (builtin?.url) url = builtin.url;\n }\n\n agentsById.set(manifest.id, {\n id: manifest.id,\n name: manifest.name,\n description: manifest.description || \"\",\n url,\n color: manifest.color || \"#6B7280\",\n });\n } catch {\n // Skip unreadable resources\n }\n }\n } catch {\n // Resources not available — use built-ins only\n }\n\n return Array.from(agentsById.values());\n}\n\n/**\n * Look up a single agent by ID or name (case-insensitive).\n */\nexport async function findAgent(\n idOrName: string,\n selfAppId?: string,\n): Promise<DiscoveredAgent | undefined> {\n const lower = idOrName.toLowerCase();\n const agents = await discoverAgents(selfAppId);\n return agents.find((a) => a.id === lower || a.name.toLowerCase() === lower);\n}\n\nfunction isDevEnvironment(): boolean {\n return (\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\"\n );\n}\n\nfunction resolveAgentUrl(app: AgentEntry): string {\n if (isDevEnvironment()) {\n return app.devUrl || `http://localhost:${app.devPort}`;\n }\n return app.url;\n}\n\n/**\n * Like `getBuiltinAgents`, but always returns the production URL — never the\n * env-resolved devUrl. Used by the resource seeder so that a one-time seed\n * (`ON CONFLICT DO NOTHING`) can't permanently bake a localhost URL into the\n * DB, which would override the built-in's prod URL for every later\n * production deploy.\n */\nexport const BUILTIN_AGENTS_FOR_SEEDING: DiscoveredAgent[] =\n BUILTIN_AGENTS.filter(\n (app) => app.enabled && !app.placeholder && app.url,\n ).map((app) => ({\n id: app.id,\n name: app.name,\n description: app.description,\n url: app.url, // ALWAYS prod\n color: app.color,\n }));\n"]}
1
+ {"version":3,"file":"agent-discovery.js","sourceRoot":"","sources":["../../src/server/agent-discovery.ts"],"names":[],"mappings":"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","sourcesContent":["import { visibleTemplates } from \"../cli/templates-meta.js\";\n\nexport interface DiscoveredAgent {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n}\n\ninterface AgentEntry {\n id: string;\n name: string;\n description: string;\n url: string;\n devUrl?: string;\n devPort: number;\n color: string;\n}\n\n/**\n * Built-in agent registry. Derive this from the published CLI metadata so\n * connected-agent discovery stays aligned with the public template allow-list\n * without depending on @agent-native/shared-app-config at runtime.\n */\nconst BUILTIN_AGENTS: AgentEntry[] = visibleTemplates()\n .filter((template) => !!template.prodUrl)\n .map((template) => ({\n id: template.name,\n name: template.label,\n description: template.description ?? template.hint,\n url: template.prodUrl!,\n devUrl: `http://localhost:${template.devPort}`,\n devPort: template.devPort,\n color: template.color,\n }));\n\n/**\n * Get built-in agents (static, no DB). Used as fallback and for seeding.\n */\nexport function getBuiltinAgents(selfAppId?: string): DiscoveredAgent[] {\n return BUILTIN_AGENTS.filter((app) => app.id !== selfAppId && app.url).map(\n (app) => ({\n id: app.id,\n name: app.name,\n description: app.description,\n url: resolveAgentUrl(app),\n color: app.color,\n }),\n );\n}\n\n/**\n * Discover all agents: built-in + custom agents stored as resources.\n * Custom agents override built-in agents with the same ID.\n */\nexport async function discoverAgents(\n selfAppId?: string,\n): Promise<DiscoveredAgent[]> {\n const builtins = getBuiltinAgents(selfAppId);\n const agentsById = new Map<string, DiscoveredAgent>();\n\n // Start with built-ins\n for (const agent of builtins) {\n agentsById.set(agent.id, agent);\n }\n\n // Overlay custom agents from resources\n try {\n const { resourceList, resourceGet, SHARED_OWNER, resourceListAccessible } =\n await import(\"../resources/store.js\");\n const { DEV_MODE_USER_EMAIL } = await import(\"./auth.js\");\n\n const isDevMode =\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\n const resources = isDevMode\n ? await resourceListAccessible(DEV_MODE_USER_EMAIL, \"remote-agents/\")\n : await resourceList(SHARED_OWNER, \"remote-agents/\");\n const { parseRemoteAgentManifest } =\n await import(\"../resources/metadata.js\");\n\n for (const r of resources) {\n if (!r.path.endsWith(\".json\")) continue;\n try {\n const full = await resourceGet(r.id);\n if (!full) continue;\n const manifest = parseRemoteAgentManifest(full.content, r.path);\n if (!manifest || manifest.id === selfAppId) continue;\n\n // If the resource override carries a localhost URL but we're running\n // in production (e.g. a stale dev-time seed got promoted to the prod\n // DB), fall back to the matching built-in's prod URL instead of\n // letting the override win — otherwise outbound `call-agent` fetches\n // from a serverless function would target localhost and fail with\n // \"fetch failed\" instantly. The override still wins for non-localhost\n // URLs (the supported case for self-hosted custom agents).\n let url = manifest.url;\n if (\n !isDevMode &&\n typeof url === \"string\" &&\n /^https?:\\/\\/(localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0)(:|\\/|$)/.test(url)\n ) {\n const builtin = agentsById.get(manifest.id);\n if (builtin?.url) url = builtin.url;\n }\n\n agentsById.set(manifest.id, {\n id: manifest.id,\n name: manifest.name,\n description: manifest.description || \"\",\n url,\n color: manifest.color || \"#6B7280\",\n });\n } catch {\n // Skip unreadable resources\n }\n }\n } catch {\n // Resources not available — use built-ins only\n }\n\n return Array.from(agentsById.values());\n}\n\n/**\n * Look up a single agent by ID or name (case-insensitive).\n */\nexport async function findAgent(\n idOrName: string,\n selfAppId?: string,\n): Promise<DiscoveredAgent | undefined> {\n const lower = idOrName.toLowerCase();\n const agents = await discoverAgents(selfAppId);\n return agents.find((a) => a.id === lower || a.name.toLowerCase() === lower);\n}\n\nfunction isDevEnvironment(): boolean {\n return (\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\"\n );\n}\n\nfunction resolveAgentUrl(app: AgentEntry): string {\n if (isDevEnvironment()) {\n return app.devUrl || `http://localhost:${app.devPort}`;\n }\n return app.url;\n}\n\n/**\n * Like `getBuiltinAgents`, but always returns the production URL — never the\n * env-resolved devUrl. Used by the resource seeder so that a one-time seed\n * (`ON CONFLICT DO NOTHING`) can't permanently bake a localhost URL into the\n * DB, which would override the built-in's prod URL for every later\n * production deploy.\n */\nexport const BUILTIN_AGENTS_FOR_SEEDING: DiscoveredAgent[] =\n BUILTIN_AGENTS.filter((app) => app.url).map((app) => ({\n id: app.id,\n name: app.name,\n description: app.description,\n url: app.url, // ALWAYS prod\n color: app.color,\n }));\n"]}
@@ -85,7 +85,7 @@ import path from "node:path";
85
85
  * both the template and workspace-core paths can reuse it. `dirPrefix` is
86
86
  * the display path that will be reported to the agent (e.g.
87
87
  * `.agents/skills/<name>` for templates, or
88
- * `<workspace-core-package>/skills/<name>` for the workspace core).
88
+ * `<workspace-shared-package>/.agents/skills/<name>` for the workspace layer).
89
89
  */
90
90
  function readSkillsDir(skillsDir, rootForRelative, out, skipExistingNames) {
91
91
  if (!fs.existsSync(skillsDir))
@@ -1 +1 @@
1
- {"version":3,"file":"agents-bundle.js","sourceRoot":"","sources":["../../src/server/agents-bundle.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Agents bundle — loads AGENTS.md and .agents/skills/ from the template.\n *\n * This is the single source of truth the framework's agent uses to mirror what\n * Claude Code / Codex / any other agent would see when running locally in the\n * repo. The filesystem is the canonical source; this module is just a loader\n * that works both in dev (direct fs read) and production (content bundled at\n * build time via the `virtual:agents-bundle` Vite plugin).\n *\n * Resolution order inside `loadAgentsBundle()`:\n * 1. Virtual module (`virtual:agents-bundle`) — inlined at build time by the\n * framework's Vite plugin. This is the ONLY path that works on edge\n * runtimes (Cloudflare Workers) where `readFileSync` doesn't exist.\n * 2. Filesystem fallback — `process.cwd()/AGENTS.md` +\n * `process.cwd()/.agents/skills/`. Only reliable in local dev and Node\n * production (`agent-native start`); not on Netlify/Vercel/CF at runtime.\n * 3. Empty bundle — everything silently returns empty strings.\n *\n * Result is cached in module scope so it's only computed once per cold start.\n */\n\nexport interface SkillMeta {\n name: string;\n description: string;\n}\n\nexport interface Skill {\n meta: SkillMeta;\n /** Contents of SKILL.md (the entry file of the skill). */\n content: string;\n /**\n * Filesystem path to the skill directory, relative to the template root\n * (e.g. `.agents/skills/create-deck`). The agent can read any file here via\n * shell in dev — skills are folders, not single files, and may contain\n * supporting assets, scripts, or additional markdown.\n */\n dir: string;\n /**\n * Files inside the skill directory (relative to the skill dir), excluding\n * `SKILL.md`. Lets the agent know what else is available without a separate\n * `ls` call. Empty array if the skill is single-file.\n */\n extraFiles: string[];\n}\n\nexport interface AgentsBundle {\n /** Contents of the template's AGENTS.md (empty string if missing). */\n agentsMd: string;\n /**\n * Contents of the workspace core's AGENTS.md, if the app is inside an\n * enterprise monorepo with a `workspaceCore` configured. Empty string\n * otherwise. Sits between the framework system prompt and the template's\n * AGENTS.md in the instruction stack.\n */\n workspaceAgentsMd?: string;\n /**\n * Map from skill name → skill content. Contains skills merged from the\n * workspace core layer (if present) and the template layer. On name\n * collision, the template's version wins so apps can override a shared\n * enterprise skill by dropping a same-named file under\n * `.agents/skills/<name>/`.\n */\n skills: Record<string, Skill>;\n}\n\nconst EMPTY: AgentsBundle = { agentsMd: \"\", workspaceAgentsMd: \"\", skills: {} };\n\nlet cached: AgentsBundle | null = null;\n\n/**\n * Parse the YAML frontmatter at the top of a skill file.\n * Only pulls out `name` and `description` — deliberately simple, no YAML lib.\n * Handles:\n * - Inline: `description: Some text`\n * - Folded scalar: `description: >-\\n multi\\n line` → \"multi line\"\n * - Literal scalar: `description: |\\n multi\\n line` → \"multi\\nline\"\n */\nexport function parseSkillFrontmatter(content: string): Partial<SkillMeta> {\n const match = content.match(/^---\\r?\\n([\\s\\S]+?)\\r?\\n---/);\n if (!match) return {};\n const lines = match[1].split(/\\r?\\n/);\n const result: Partial<SkillMeta> = {};\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const keyMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\\s*(.*)$/);\n if (!keyMatch) continue;\n const [, key, valueRaw] = keyMatch;\n const trimmed = valueRaw.trim();\n\n const isFolded = trimmed === \">\" || trimmed === \">-\";\n const isLiteral = trimmed === \"|\" || trimmed === \"|-\";\n\n let value: string;\n if (isFolded || isLiteral) {\n // Collect subsequent indented lines (at least one leading space).\n const block: string[] = [];\n let j = i + 1;\n while (j < lines.length) {\n const next = lines[j];\n if (next.length === 0) {\n block.push(\"\");\n j++;\n continue;\n }\n if (!/^\\s/.test(next)) break;\n block.push(next.replace(/^\\s+/, \"\"));\n j++;\n }\n // Trim trailing blank lines\n while (block.length > 0 && block[block.length - 1] === \"\") block.pop();\n value = isFolded\n ? block.filter((l) => l !== \"\").join(\" \")\n : block.join(\"\\n\");\n i = j - 1;\n } else {\n value = trimmed;\n }\n\n if (key === \"name\" && value) result.name = value;\n else if (key === \"description\" && value) result.description = value;\n }\n\n return result;\n}\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Paths to a workspace-core's agent resources, for merging into a template's\n * bundle. All fields optional — pass null for any missing piece.\n */\nexport interface WorkspaceAgentsSource {\n /** Absolute path to the workspace core's skills/ directory. */\n skillsDir: string | null;\n /** Absolute path to the workspace core's AGENTS.md. */\n agentsMdPath: string | null;\n /** Root dir (used to compute `dir` paths for workspace-core skills). */\n rootDir: string;\n}\n\n/**\n * Read one skills directory into a `Record<string, Skill>`. Extracted so\n * both the template and workspace-core paths can reuse it. `dirPrefix` is\n * the display path that will be reported to the agent (e.g.\n * `.agents/skills/<name>` for templates, or\n * `<workspace-core-package>/skills/<name>` for the workspace core).\n */\nfunction readSkillsDir(\n skillsDir: string,\n rootForRelative: string,\n out: Record<string, Skill>,\n skipExistingNames: boolean,\n): void {\n if (!fs.existsSync(skillsDir)) return;\n const entries = fs.readdirSync(skillsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n const skillDirAbs = path.join(skillsDir, entry.name);\n const skillFile = path.join(skillDirAbs, \"SKILL.md\");\n try {\n const realSkillFile = fs.realpathSync(skillFile);\n if (!fs.existsSync(realSkillFile)) continue;\n const content = fs.readFileSync(realSkillFile, \"utf-8\");\n const meta = parseSkillFrontmatter(content);\n const name = meta.name ?? entry.name;\n if (skipExistingNames && out[name]) continue; // Template wins\n\n const extraFiles: string[] = [];\n try {\n const walk = (subdir: string, prefix: string) => {\n for (const e of fs.readdirSync(subdir, { withFileTypes: true })) {\n const abs = path.join(subdir, e.name);\n const rel = prefix ? `${prefix}/${e.name}` : e.name;\n if (e.isDirectory() || e.isSymbolicLink()) {\n try {\n const stat = fs.statSync(abs);\n if (stat.isDirectory()) walk(abs, rel);\n } catch {}\n } else if (e.isFile() && e.name !== \"SKILL.md\") {\n extraFiles.push(rel);\n }\n }\n };\n walk(skillDirAbs, \"\");\n } catch {}\n extraFiles.sort();\n\n out[name] = {\n meta: { name, description: meta.description ?? \"\" },\n content,\n dir: path.relative(rootForRelative, skillDirAbs).replace(/\\\\/g, \"/\"),\n extraFiles,\n };\n } catch {\n // Skip unreadable skills\n }\n }\n}\n\n/**\n * Read AGENTS.md + all skills directly from the filesystem rooted at `cwd`.\n * Optionally also reads a workspace-core's AGENTS.md and skills directory\n * and merges them in (template wins on name collisions). Used by both the\n * Vite plugin (at build time) and the runtime fallback (in dev / Node prod).\n *\n * Synchronous — the Vite plugin's load hook calls it inline during the build.\n */\nexport function readAgentsBundleFromFs(\n cwd: string,\n workspaceSource: WorkspaceAgentsSource | null = null,\n): AgentsBundle {\n let agentsMd = \"\";\n try {\n const agentsMdPath = path.join(cwd, \"AGENTS.md\");\n if (fs.existsSync(agentsMdPath)) {\n agentsMd = fs.readFileSync(agentsMdPath, \"utf-8\");\n }\n } catch {}\n\n let workspaceAgentsMd = \"\";\n if (workspaceSource?.agentsMdPath) {\n try {\n if (fs.existsSync(workspaceSource.agentsMdPath)) {\n workspaceAgentsMd = fs.readFileSync(\n workspaceSource.agentsMdPath,\n \"utf-8\",\n );\n }\n } catch {}\n }\n\n // Merge skills: template first (so its entries are authoritative), then\n // workspace-core with skipExistingNames=true so same-named skills don't\n // overwrite the template's.\n const skills: Record<string, Skill> = {};\n try {\n const skillsDir = path.join(cwd, \".agents\", \"skills\");\n readSkillsDir(skillsDir, cwd, skills, false);\n } catch {}\n\n if (workspaceSource?.skillsDir) {\n try {\n readSkillsDir(\n workspaceSource.skillsDir,\n workspaceSource.rootDir,\n skills,\n true,\n );\n } catch {}\n }\n\n return { agentsMd, workspaceAgentsMd, skills };\n}\n\n/**\n * Load the agents bundle. Returns a cached result on subsequent calls.\n * Tries the virtual module first (works everywhere, including edge), then\n * falls back to filesystem reads from `process.cwd()` — which, when a\n * workspace core is present, also merges in the workspace core's skills\n * and AGENTS.md.\n */\nexport async function loadAgentsBundle(): Promise<AgentsBundle> {\n if (cached) return cached;\n\n // 1. Try the Vite-emitted virtual module. This is the path that works on\n // every deployment target because the content is inlined at build time.\n // The Vite plugin itself is responsible for merging workspace-core\n // content into the bundle it emits.\n try {\n // @ts-expect-error — virtual module is resolved at build time by our\n // Vite plugin; nothing exists at this path on disk.\n const mod = await import(\"virtual:agents-bundle\");\n if (mod && mod.default) {\n cached = mod.default as AgentsBundle;\n return cached;\n }\n } catch {\n // Virtual module not available — fall through to filesystem.\n }\n\n // 2. Filesystem fallback — works in dev / Node prod. If a workspace core\n // is present in the ancestor chain, merge its skills + AGENTS.md in.\n try {\n let workspaceSource: WorkspaceAgentsSource | null = null;\n try {\n const { getWorkspaceCoreExports } =\n await import(\"../deploy/workspace-core.js\");\n const ws = await getWorkspaceCoreExports(process.cwd());\n if (ws) {\n workspaceSource = {\n skillsDir: ws.skillsDir,\n agentsMdPath: ws.agentsMdPath,\n rootDir: ws.packageDir,\n };\n }\n } catch {\n // workspace-core discovery isn't available (e.g. edge runtime).\n }\n cached = readAgentsBundleFromFs(process.cwd(), workspaceSource);\n return cached;\n } catch {\n cached = EMPTY;\n return cached;\n }\n}\n\n/**\n * Generate the `<skills>` block to inject into the system prompt.\n *\n * Skills are folders at `.agents/skills/<name>/` containing a `SKILL.md` entry\n * file plus any number of supporting files (additional markdown, examples,\n * images, scripts). This block lists what's available and how to read them.\n *\n * In dev mode the agent has shell access and reads skills via `cat` — exactly\n * like running `claude` locally in the repo. In production mode the agent has\n * no shell; templates that need skill content at runtime should inline the\n * critical parts directly in `AGENTS.md`.\n */\nexport function generateSkillsPromptBlock(bundle: AgentsBundle): string {\n const entries = Object.values(bundle.skills);\n if (entries.length === 0) return \"\";\n\n const lines = entries.map((s) => {\n const extras =\n s.extraFiles.length > 0\n ? ` (also contains: ${s.extraFiles.join(\", \")})`\n : \"\";\n return `- \\`${s.meta.name}\\` at \\`${s.dir}/\\` — ${s.meta.description || \"(no description)\"}${extras}`;\n });\n\n return `<skills>\nThe following skills live in the repo at \\`.agents/skills/<name>/\\`. Each skill is a folder containing a \\`SKILL.md\\` entry file and sometimes supporting files. Read a skill BEFORE starting a task it applies to.\n\nTo read a skill in dev mode (when you have shell access):\n \\`shell(command=\"cat .agents/skills/<name>/SKILL.md\")\\`\n \\`shell(command=\"ls .agents/skills/<name>/\")\\` to see all files in the folder\n\nAvailable skills:\n${lines.join(\"\\n\")}\n</skills>`;\n}\n\n/** For tests — reset the module cache. */\nexport function __resetAgentsBundleCache(): void {\n cached = null;\n}\n"]}
1
+ {"version":3,"file":"agents-bundle.js","sourceRoot":"","sources":["../../src/server/agents-bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA8CH,MAAM,KAAK,GAAiB,EAAE,QAAQ,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAEhF,IAAI,MAAM,GAAwB,IAAI,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACnE,IAAI,CAAC,QAAQ;YAAE,SAAS;QACxB,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC;QACnC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEhC,MAAM,QAAQ,GAAG,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC;QACrD,MAAM,SAAS,GAAG,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC;QAEtD,IAAI,KAAa,CAAC;QAClB,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;YAC1B,kEAAkE;YAClE,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACtB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACf,CAAC,EAAE,CAAC;oBACJ,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,MAAM;gBAC7B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;gBACrC,CAAC,EAAE,CAAC;YACN,CAAC;YACD,4BAA4B;YAC5B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;gBAAE,KAAK,CAAC,GAAG,EAAE,CAAC;YACvE,KAAK,GAAG,QAAQ;gBACd,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBACzC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,OAAO,CAAC;QAClB,CAAC;QAED,IAAI,GAAG,KAAK,MAAM,IAAI,KAAK;YAAE,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC;aAC5C,IAAI,GAAG,KAAK,aAAa,IAAI,KAAK;YAAE,MAAM,CAAC,WAAW,GAAG,KAAK,CAAC;IACtE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAe7B;;;;;;GAMG;AACH,SAAS,aAAa,CACpB,SAAiB,EACjB,eAAuB,EACvB,GAA0B,EAC1B,iBAA0B;IAE1B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO;IACtC,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE;YAAE,SAAS;QAC9D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACrD,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YACjD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;gBAAE,SAAS;YAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;YACrC,IAAI,iBAAiB,IAAI,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS,CAAC,gBAAgB;YAE9D,MAAM,UAAU,GAAa,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,MAAc,EAAE,EAAE;oBAC9C,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;wBAChE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;wBACtC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpD,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;4BAC1C,IAAI,CAAC;gCACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gCAC9B,IAAI,IAAI,CAAC,WAAW,EAAE;oCAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;4BACzC,CAAC;4BAAC,MAAM,CAAC,CAAA,CAAC;wBACZ,CAAC;6BAAM,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;4BAC/C,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;wBACvB,CAAC;oBACH,CAAC;gBACH,CAAC,CAAC;gBACF,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YACV,UAAU,CAAC,IAAI,EAAE,CAAC;YAElB,GAAG,CAAC,IAAI,CAAC,GAAG;gBACV,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE,EAAE;gBACnD,OAAO;gBACP,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;gBACpE,UAAU;aACX,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAW,EACX,kBAAgD,IAAI;IAEpD,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACjD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAChC,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,IAAI,iBAAiB,GAAG,EAAE,CAAC;IAC3B,IAAI,eAAe,EAAE,YAAY,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;gBAChD,iBAAiB,GAAG,EAAE,CAAC,YAAY,CACjC,eAAe,CAAC,YAAY,EAC5B,OAAO,CACR,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,wEAAwE;IACxE,wEAAwE;IACxE,4BAA4B;IAC5B,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QACtD,aAAa,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,IAAI,eAAe,EAAE,SAAS,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,aAAa,CACX,eAAe,CAAC,SAAS,EACzB,eAAe,CAAC,OAAO,EACvB,MAAM,EACN,IAAI,CACL,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,yEAAyE;IACzE,2EAA2E;IAC3E,sEAAsE;IACtE,uCAAuC;IACvC,IAAI,CAAC;QACH,qEAAqE;QACrE,oDAAoD;QACpD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAClD,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,CAAC,OAAuB,CAAC;YACrC,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;IAC/D,CAAC;IAED,yEAAyE;IACzE,wEAAwE;IACxE,IAAI,CAAC;QACH,IAAI,eAAe,GAAiC,IAAI,CAAC;QACzD,IAAI,CAAC;YACH,MAAM,EAAE,uBAAuB,EAAE,GAC/B,MAAM,MAAM,CAAC,6BAA6B,CAAC,CAAC;YAC9C,MAAM,EAAE,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACxD,IAAI,EAAE,EAAE,CAAC;gBACP,eAAe,GAAG;oBAChB,SAAS,EAAE,EAAE,CAAC,SAAS;oBACvB,YAAY,EAAE,EAAE,CAAC,YAAY;oBAC7B,OAAO,EAAE,EAAE,CAAC,UAAU;iBACvB,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;QAClE,CAAC;QACD,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;QAChE,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,KAAK,CAAC;QACf,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAoB;IAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9B,MAAM,MAAM,GACV,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;YACrB,CAAC,CAAC,oBAAoB,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YAChD,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,kBAAkB,GAAG,MAAM,EAAE,CAAC;IACxG,CAAC,CAAC,CAAC;IAEH,OAAO;;;;;;;;EAQP,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;UACR,CAAC;AACX,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,wBAAwB;IACtC,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC","sourcesContent":["/**\n * Agents bundle — loads AGENTS.md and .agents/skills/ from the template.\n *\n * This is the single source of truth the framework's agent uses to mirror what\n * Claude Code / Codex / any other agent would see when running locally in the\n * repo. The filesystem is the canonical source; this module is just a loader\n * that works both in dev (direct fs read) and production (content bundled at\n * build time via the `virtual:agents-bundle` Vite plugin).\n *\n * Resolution order inside `loadAgentsBundle()`:\n * 1. Virtual module (`virtual:agents-bundle`) — inlined at build time by the\n * framework's Vite plugin. This is the ONLY path that works on edge\n * runtimes (Cloudflare Workers) where `readFileSync` doesn't exist.\n * 2. Filesystem fallback — `process.cwd()/AGENTS.md` +\n * `process.cwd()/.agents/skills/`. Only reliable in local dev and Node\n * production (`agent-native start`); not on Netlify/Vercel/CF at runtime.\n * 3. Empty bundle — everything silently returns empty strings.\n *\n * Result is cached in module scope so it's only computed once per cold start.\n */\n\nexport interface SkillMeta {\n name: string;\n description: string;\n}\n\nexport interface Skill {\n meta: SkillMeta;\n /** Contents of SKILL.md (the entry file of the skill). */\n content: string;\n /**\n * Filesystem path to the skill directory, relative to the template root\n * (e.g. `.agents/skills/create-deck`). The agent can read any file here via\n * shell in dev — skills are folders, not single files, and may contain\n * supporting assets, scripts, or additional markdown.\n */\n dir: string;\n /**\n * Files inside the skill directory (relative to the skill dir), excluding\n * `SKILL.md`. Lets the agent know what else is available without a separate\n * `ls` call. Empty array if the skill is single-file.\n */\n extraFiles: string[];\n}\n\nexport interface AgentsBundle {\n /** Contents of the template's AGENTS.md (empty string if missing). */\n agentsMd: string;\n /**\n * Contents of the workspace core's AGENTS.md, if the app is inside an\n * enterprise monorepo with a `workspaceCore` configured. Empty string\n * otherwise. Sits between the framework system prompt and the template's\n * AGENTS.md in the instruction stack.\n */\n workspaceAgentsMd?: string;\n /**\n * Map from skill name → skill content. Contains skills merged from the\n * workspace core layer (if present) and the template layer. On name\n * collision, the template's version wins so apps can override a shared\n * enterprise skill by dropping a same-named file under\n * `.agents/skills/<name>/`.\n */\n skills: Record<string, Skill>;\n}\n\nconst EMPTY: AgentsBundle = { agentsMd: \"\", workspaceAgentsMd: \"\", skills: {} };\n\nlet cached: AgentsBundle | null = null;\n\n/**\n * Parse the YAML frontmatter at the top of a skill file.\n * Only pulls out `name` and `description` — deliberately simple, no YAML lib.\n * Handles:\n * - Inline: `description: Some text`\n * - Folded scalar: `description: >-\\n multi\\n line` → \"multi line\"\n * - Literal scalar: `description: |\\n multi\\n line` → \"multi\\nline\"\n */\nexport function parseSkillFrontmatter(content: string): Partial<SkillMeta> {\n const match = content.match(/^---\\r?\\n([\\s\\S]+?)\\r?\\n---/);\n if (!match) return {};\n const lines = match[1].split(/\\r?\\n/);\n const result: Partial<SkillMeta> = {};\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const keyMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\\s*(.*)$/);\n if (!keyMatch) continue;\n const [, key, valueRaw] = keyMatch;\n const trimmed = valueRaw.trim();\n\n const isFolded = trimmed === \">\" || trimmed === \">-\";\n const isLiteral = trimmed === \"|\" || trimmed === \"|-\";\n\n let value: string;\n if (isFolded || isLiteral) {\n // Collect subsequent indented lines (at least one leading space).\n const block: string[] = [];\n let j = i + 1;\n while (j < lines.length) {\n const next = lines[j];\n if (next.length === 0) {\n block.push(\"\");\n j++;\n continue;\n }\n if (!/^\\s/.test(next)) break;\n block.push(next.replace(/^\\s+/, \"\"));\n j++;\n }\n // Trim trailing blank lines\n while (block.length > 0 && block[block.length - 1] === \"\") block.pop();\n value = isFolded\n ? block.filter((l) => l !== \"\").join(\" \")\n : block.join(\"\\n\");\n i = j - 1;\n } else {\n value = trimmed;\n }\n\n if (key === \"name\" && value) result.name = value;\n else if (key === \"description\" && value) result.description = value;\n }\n\n return result;\n}\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Paths to a workspace-core's agent resources, for merging into a template's\n * bundle. All fields optional — pass null for any missing piece.\n */\nexport interface WorkspaceAgentsSource {\n /** Absolute path to the workspace core's skills/ directory. */\n skillsDir: string | null;\n /** Absolute path to the workspace core's AGENTS.md. */\n agentsMdPath: string | null;\n /** Root dir (used to compute `dir` paths for workspace-core skills). */\n rootDir: string;\n}\n\n/**\n * Read one skills directory into a `Record<string, Skill>`. Extracted so\n * both the template and workspace-core paths can reuse it. `dirPrefix` is\n * the display path that will be reported to the agent (e.g.\n * `.agents/skills/<name>` for templates, or\n * `<workspace-shared-package>/.agents/skills/<name>` for the workspace layer).\n */\nfunction readSkillsDir(\n skillsDir: string,\n rootForRelative: string,\n out: Record<string, Skill>,\n skipExistingNames: boolean,\n): void {\n if (!fs.existsSync(skillsDir)) return;\n const entries = fs.readdirSync(skillsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n const skillDirAbs = path.join(skillsDir, entry.name);\n const skillFile = path.join(skillDirAbs, \"SKILL.md\");\n try {\n const realSkillFile = fs.realpathSync(skillFile);\n if (!fs.existsSync(realSkillFile)) continue;\n const content = fs.readFileSync(realSkillFile, \"utf-8\");\n const meta = parseSkillFrontmatter(content);\n const name = meta.name ?? entry.name;\n if (skipExistingNames && out[name]) continue; // Template wins\n\n const extraFiles: string[] = [];\n try {\n const walk = (subdir: string, prefix: string) => {\n for (const e of fs.readdirSync(subdir, { withFileTypes: true })) {\n const abs = path.join(subdir, e.name);\n const rel = prefix ? `${prefix}/${e.name}` : e.name;\n if (e.isDirectory() || e.isSymbolicLink()) {\n try {\n const stat = fs.statSync(abs);\n if (stat.isDirectory()) walk(abs, rel);\n } catch {}\n } else if (e.isFile() && e.name !== \"SKILL.md\") {\n extraFiles.push(rel);\n }\n }\n };\n walk(skillDirAbs, \"\");\n } catch {}\n extraFiles.sort();\n\n out[name] = {\n meta: { name, description: meta.description ?? \"\" },\n content,\n dir: path.relative(rootForRelative, skillDirAbs).replace(/\\\\/g, \"/\"),\n extraFiles,\n };\n } catch {\n // Skip unreadable skills\n }\n }\n}\n\n/**\n * Read AGENTS.md + all skills directly from the filesystem rooted at `cwd`.\n * Optionally also reads a workspace-core's AGENTS.md and skills directory\n * and merges them in (template wins on name collisions). Used by both the\n * Vite plugin (at build time) and the runtime fallback (in dev / Node prod).\n *\n * Synchronous — the Vite plugin's load hook calls it inline during the build.\n */\nexport function readAgentsBundleFromFs(\n cwd: string,\n workspaceSource: WorkspaceAgentsSource | null = null,\n): AgentsBundle {\n let agentsMd = \"\";\n try {\n const agentsMdPath = path.join(cwd, \"AGENTS.md\");\n if (fs.existsSync(agentsMdPath)) {\n agentsMd = fs.readFileSync(agentsMdPath, \"utf-8\");\n }\n } catch {}\n\n let workspaceAgentsMd = \"\";\n if (workspaceSource?.agentsMdPath) {\n try {\n if (fs.existsSync(workspaceSource.agentsMdPath)) {\n workspaceAgentsMd = fs.readFileSync(\n workspaceSource.agentsMdPath,\n \"utf-8\",\n );\n }\n } catch {}\n }\n\n // Merge skills: template first (so its entries are authoritative), then\n // workspace-core with skipExistingNames=true so same-named skills don't\n // overwrite the template's.\n const skills: Record<string, Skill> = {};\n try {\n const skillsDir = path.join(cwd, \".agents\", \"skills\");\n readSkillsDir(skillsDir, cwd, skills, false);\n } catch {}\n\n if (workspaceSource?.skillsDir) {\n try {\n readSkillsDir(\n workspaceSource.skillsDir,\n workspaceSource.rootDir,\n skills,\n true,\n );\n } catch {}\n }\n\n return { agentsMd, workspaceAgentsMd, skills };\n}\n\n/**\n * Load the agents bundle. Returns a cached result on subsequent calls.\n * Tries the virtual module first (works everywhere, including edge), then\n * falls back to filesystem reads from `process.cwd()` — which, when a\n * workspace core is present, also merges in the workspace core's skills\n * and AGENTS.md.\n */\nexport async function loadAgentsBundle(): Promise<AgentsBundle> {\n if (cached) return cached;\n\n // 1. Try the Vite-emitted virtual module. This is the path that works on\n // every deployment target because the content is inlined at build time.\n // The Vite plugin itself is responsible for merging workspace-core\n // content into the bundle it emits.\n try {\n // @ts-expect-error — virtual module is resolved at build time by our\n // Vite plugin; nothing exists at this path on disk.\n const mod = await import(\"virtual:agents-bundle\");\n if (mod && mod.default) {\n cached = mod.default as AgentsBundle;\n return cached;\n }\n } catch {\n // Virtual module not available — fall through to filesystem.\n }\n\n // 2. Filesystem fallback — works in dev / Node prod. If a workspace core\n // is present in the ancestor chain, merge its skills + AGENTS.md in.\n try {\n let workspaceSource: WorkspaceAgentsSource | null = null;\n try {\n const { getWorkspaceCoreExports } =\n await import(\"../deploy/workspace-core.js\");\n const ws = await getWorkspaceCoreExports(process.cwd());\n if (ws) {\n workspaceSource = {\n skillsDir: ws.skillsDir,\n agentsMdPath: ws.agentsMdPath,\n rootDir: ws.packageDir,\n };\n }\n } catch {\n // workspace-core discovery isn't available (e.g. edge runtime).\n }\n cached = readAgentsBundleFromFs(process.cwd(), workspaceSource);\n return cached;\n } catch {\n cached = EMPTY;\n return cached;\n }\n}\n\n/**\n * Generate the `<skills>` block to inject into the system prompt.\n *\n * Skills are folders at `.agents/skills/<name>/` containing a `SKILL.md` entry\n * file plus any number of supporting files (additional markdown, examples,\n * images, scripts). This block lists what's available and how to read them.\n *\n * In dev mode the agent has shell access and reads skills via `cat` — exactly\n * like running `claude` locally in the repo. In production mode the agent has\n * no shell; templates that need skill content at runtime should inline the\n * critical parts directly in `AGENTS.md`.\n */\nexport function generateSkillsPromptBlock(bundle: AgentsBundle): string {\n const entries = Object.values(bundle.skills);\n if (entries.length === 0) return \"\";\n\n const lines = entries.map((s) => {\n const extras =\n s.extraFiles.length > 0\n ? ` (also contains: ${s.extraFiles.join(\", \")})`\n : \"\";\n return `- \\`${s.meta.name}\\` at \\`${s.dir}/\\` — ${s.meta.description || \"(no description)\"}${extras}`;\n });\n\n return `<skills>\nThe following skills live in the repo at \\`.agents/skills/<name>/\\`. Each skill is a folder containing a \\`SKILL.md\\` entry file and sometimes supporting files. Read a skill BEFORE starting a task it applies to.\n\nTo read a skill in dev mode (when you have shell access):\n \\`shell(command=\"cat .agents/skills/<name>/SKILL.md\")\\`\n \\`shell(command=\"ls .agents/skills/<name>/\")\\` to see all files in the folder\n\nAvailable skills:\n${lines.join(\"\\n\")}\n</skills>`;\n}\n\n/** For tests — reset the module cache. */\nexport function __resetAgentsBundleCache(): void {\n cached = null;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAsChE,KAAK,KAAK,GAAG,SAAS,CAAC;AASvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAuBlE;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAMD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7D;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF;;OAEG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAqBD,eAAO,MAAM,WAAW,QAER,CAAC;AA8DjB;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAG1C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAUrE;AAoKD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7E;AAED,uDAAuD;AACvD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAShE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmB3E;AA8CD,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAeD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,QAWd;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,2BAA2B,QAOnC;AAmGD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAG5C;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AA+NrD;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAwI5E;AAqyCD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,KAAK,EACV,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,OAAO,CAAC,CA+KlB;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAEzE"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,4 @@
1
1
  import crypto from "node:crypto";
2
- import path from "node:path";
3
- // Lazy fs — loaded via dynamic import() on first use.
4
- // Avoids static require() which crashes on CF Workers.
5
- let _fs;
6
- async function getFs() {
7
- if (!_fs) {
8
- _fs = await import("node:fs");
9
- }
10
- return _fs;
11
- }
12
2
  import { defineEventHandler, getMethod, getQuery, getRequestIP, sendRedirect, setResponseHeader, setResponseStatus, getCookie, setCookie, deleteCookie, } from "h3";
13
3
  // In h3 v2, `event.req` IS the web Request — but in Nitro's dev server (srvx
14
4
  // runtime), event.url and event.req share the same underlying URL object.
@@ -90,7 +80,6 @@ function getOAuthStateAppId() {
90
80
  return slug || undefined;
91
81
  }
92
82
  const DEFAULT_MAX_AGE = 60 * 60 * 24 * 30; // 30 days
93
- const LOCAL_MODE_MARKER_PATH = path.resolve(process.cwd(), ".agent-native", "auth-mode");
94
83
  // ---------------------------------------------------------------------------
95
84
  // AUTH_MODE detection
96
85
  // ---------------------------------------------------------------------------
@@ -98,9 +87,7 @@ let _warnedRemoteLocalMode = false;
98
87
  /**
99
88
  * Check if the app is in local-only mode (no auth).
100
89
  *
101
- * Returns true when AUTH_MODE=local is explicitly set or when the dev
102
- * onboarding flow has enabled local mode for the current workspace via
103
- * a runtime marker file.
90
+ * Returns true when AUTH_MODE=local is explicitly set.
104
91
  *
105
92
  * Local mode is an explicit escape hatch for when you want to guarantee
106
93
  * no auth is used. In development, getSession() also falls back to
@@ -112,24 +99,17 @@ let _warnedRemoteLocalMode = false;
112
99
  * a shared DB every developer would land on the same account and collide.
113
100
  */
114
101
  async function isLocalModeEnabled() {
102
+ if (process.env.AUTH_MODE !== "local")
103
+ return false;
115
104
  if (!isLocalDatabase()) {
116
- if (process.env.AUTH_MODE === "local" && !_warnedRemoteLocalMode) {
105
+ if (!_warnedRemoteLocalMode) {
117
106
  _warnedRemoteLocalMode = true;
118
107
  console.warn("[agent-native] AUTH_MODE=local ignored: database is not local SQLite. " +
119
108
  "local@localhost has no per-user scoping and would collide across developers on a shared DB.");
120
109
  }
121
110
  return false;
122
111
  }
123
- if (process.env.AUTH_MODE === "local")
124
- return true;
125
- try {
126
- const fs = await getFs();
127
- const mode = fs.readFileSync(LOCAL_MODE_MARKER_PATH, "utf-8").trim();
128
- return mode === "local";
129
- }
130
- catch {
131
- return false;
132
- }
112
+ return true;
133
113
  }
134
114
  /**
135
115
  * Check if we're in a development/test environment.
@@ -808,8 +788,8 @@ export async function getSession(event) {
808
788
  return querySession;
809
789
  // 7. Dev-mode safety net — in development on a local SQLite database, fall
810
790
  // back to local@localhost so the app is usable without any auth configuration.
811
- // This prevents 401 errors when Better Auth isn't configured, the marker file
812
- // is missing, or the user simply wants to play around locally.
791
+ // This prevents 401 errors when Better Auth isn't configured or the user
792
+ // simply wants to play around locally.
813
793
  //
814
794
  // Gated on isLocalDatabase() because local@localhost has no per-user scoping:
815
795
  // on a shared DB (Postgres, Turso, D1) this fallback would land every
@@ -1056,35 +1036,19 @@ const TOKEN_LOGIN_HTML = `<!DOCTYPE html>
1056
1036
  </body>
1057
1037
  </html>`;
1058
1038
  // ---------------------------------------------------------------------------
1059
- // setAuthModeLocal write AUTH_MODE=local to .env for the escape hatch
1039
+ // Local mode route helpers
1060
1040
  // ---------------------------------------------------------------------------
1061
- async function setAuthModeLocal() {
1062
- try {
1063
- const fs = await getFs();
1064
- fs.mkdirSync(path.dirname(LOCAL_MODE_MARKER_PATH), { recursive: true });
1065
- fs.writeFileSync(LOCAL_MODE_MARKER_PATH, "local\n", "utf-8");
1066
- process.env.AUTH_MODE = "local"; // guard:allow-env-mutation — escape-hatch writes the local-mode marker file; mirrored into env so the in-flight process honors the change without restart
1067
- return true;
1068
- }
1069
- catch {
1070
- return false;
1071
- }
1041
+ function localModeMarkerDisabled(event) {
1042
+ setResponseStatus(event, 410);
1043
+ return {
1044
+ error: "The local-mode marker file has been removed. Set AUTH_MODE=local in your local shell or .env only for one-off local development.",
1045
+ };
1072
1046
  }
1073
- async function removeAuthModeLocal() {
1074
- try {
1075
- const fs = await getFs();
1076
- try {
1077
- fs.unlinkSync(LOCAL_MODE_MARKER_PATH);
1078
- }
1079
- catch {
1080
- // Marker already absent
1081
- }
1082
- delete process.env.AUTH_MODE; // guard:allow-env-mutation — escape-hatch removes the local-mode marker; mirrored into env so the in-flight process honors the change without restart
1083
- return true;
1084
- }
1085
- catch {
1086
- return false;
1087
- }
1047
+ function exitLocalMode(event) {
1048
+ // Mark the browser so getSession's dev-mode fallback won't silently
1049
+ // re-authenticate the user as local@localhost on the next request.
1050
+ setUpgradePendingCookie(event);
1051
+ return { ok: true };
1088
1052
  }
1089
1053
  /**
1090
1054
  * POST /_agent-native/auth/migrate-local-data handler. Exposed here (not
@@ -1489,31 +1453,14 @@ async function mountBetterAuthRoutes(app, options) {
1489
1453
  }
1490
1454
  return response;
1491
1455
  }));
1492
- // POST /_agent-native/auth/local-mode — switch to local mode (onboarding escape hatch)
1493
- // Only available in dev production requires real accounts for usage tracking.
1456
+ // POST /_agent-native/auth/local-mode — legacy endpoint kept so old clients
1457
+ // receive an explicit error instead of creating a persistent local marker.
1494
1458
  app.use("/_agent-native/auth/local-mode", defineEventHandler(async (event) => {
1495
1459
  if (getMethod(event) !== "POST") {
1496
1460
  setResponseStatus(event, 405);
1497
1461
  return { error: "Method not allowed" };
1498
1462
  }
1499
- if (!isDevEnvironment()) {
1500
- setResponseStatus(event, 403);
1501
- return {
1502
- error: "Local mode is not available in production. Create an account to continue.",
1503
- };
1504
- }
1505
- if (!isLocalDatabase()) {
1506
- setResponseStatus(event, 400);
1507
- return {
1508
- error: "Local mode is only available on a local SQLite database. Your DATABASE_URL points at a shared database — create an account instead.",
1509
- };
1510
- }
1511
- const ok = await setAuthModeLocal();
1512
- if (!ok) {
1513
- setResponseStatus(event, 500);
1514
- return { error: "Failed to enable local mode" };
1515
- }
1516
- return { ok: true };
1463
+ return localModeMarkerDisabled(event);
1517
1464
  }));
1518
1465
  // POST /_agent-native/auth/exit-local-mode — switch back to real auth
1519
1466
  app.use("/_agent-native/auth/exit-local-mode", defineEventHandler(async (event) => {
@@ -1521,15 +1468,7 @@ async function mountBetterAuthRoutes(app, options) {
1521
1468
  setResponseStatus(event, 405);
1522
1469
  return { error: "Method not allowed" };
1523
1470
  }
1524
- const ok = await removeAuthModeLocal();
1525
- if (!ok) {
1526
- setResponseStatus(event, 500);
1527
- return { error: "Failed to disable local mode" };
1528
- }
1529
- // Mark the browser so getSession's dev-mode fallback won't silently
1530
- // re-authenticate the user as local@localhost on the next request.
1531
- setUpgradePendingCookie(event);
1532
- return { ok: true };
1471
+ return exitLocalMode(event);
1533
1472
  }));
1534
1473
  // Backward-compat: POST /_agent-native/auth/login
1535
1474
  app.use("/_agent-native/auth/login", defineEventHandler(async (event) => {
@@ -1606,6 +1545,9 @@ async function mountBetterAuthRoutes(app, options) {
1606
1545
  const body = await readBody(event);
1607
1546
  const email = body?.email?.trim?.()?.toLowerCase?.();
1608
1547
  const password = body?.password;
1548
+ const callbackURL = typeof body?.callbackURL === "string"
1549
+ ? safeReturnPath(body.callbackURL)
1550
+ : "/";
1609
1551
  if (!email || typeof email !== "string" || !email.includes("@")) {
1610
1552
  setResponseStatus(event, 400);
1611
1553
  return { error: "Valid email is required" };
@@ -1616,7 +1558,7 @@ async function mountBetterAuthRoutes(app, options) {
1616
1558
  }
1617
1559
  try {
1618
1560
  await auth.api.signUpEmail({
1619
- body: { email, password, name: email.split("@")[0] },
1561
+ body: { email, password, name: email.split("@")[0], callbackURL },
1620
1562
  });
1621
1563
  return { ok: true };
1622
1564
  }
@@ -1814,15 +1756,7 @@ function mountLocalModeRoutes(app) {
1814
1756
  setResponseStatus(event, 405);
1815
1757
  return { error: "Method not allowed" };
1816
1758
  }
1817
- const ok = await removeAuthModeLocal();
1818
- if (!ok) {
1819
- setResponseStatus(event, 500);
1820
- return { error: "Failed to disable local mode" };
1821
- }
1822
- // Mark the browser so getSession's dev-mode fallback won't silently
1823
- // re-authenticate the user as local@localhost on the next request.
1824
- setUpgradePendingCookie(event);
1825
- return { ok: true };
1759
+ return exitLocalMode(event);
1826
1760
  }));
1827
1761
  // Upgrade path: migrate-local-data must be reachable from local mode
1828
1762
  // because the user is still in local mode when they trigger the upgrade.
@@ -1925,39 +1859,14 @@ function mountAuthFallbackRoutes(app) {
1925
1859
  setResponseStatus(event, 405);
1926
1860
  return { error: "Method not allowed" };
1927
1861
  }
1928
- if (!isDevEnvironment()) {
1929
- setResponseStatus(event, 403);
1930
- return {
1931
- error: "Local mode is not available in production. Create an account to continue.",
1932
- };
1933
- }
1934
- if (!isLocalDatabase()) {
1935
- setResponseStatus(event, 400);
1936
- return {
1937
- error: "Local mode is only available on a local SQLite database. Your DATABASE_URL points at a shared database — create an account instead.",
1938
- };
1939
- }
1940
- const ok = await setAuthModeLocal();
1941
- if (!ok) {
1942
- setResponseStatus(event, 500);
1943
- return { error: "Failed to enable local mode" };
1944
- }
1945
- return { ok: true };
1862
+ return localModeMarkerDisabled(event);
1946
1863
  }));
1947
1864
  app.use("/_agent-native/auth/exit-local-mode", defineEventHandler(async (event) => {
1948
1865
  if (getMethod(event) !== "POST") {
1949
1866
  setResponseStatus(event, 405);
1950
1867
  return { error: "Method not allowed" };
1951
1868
  }
1952
- const ok = await removeAuthModeLocal();
1953
- if (!ok) {
1954
- setResponseStatus(event, 500);
1955
- return { error: "Failed to disable local mode" };
1956
- }
1957
- // Mark the browser so getSession's dev-mode fallback won't silently
1958
- // re-authenticate the user as local@localhost on the next request.
1959
- setUpgradePendingCookie(event);
1960
- return { ok: true };
1869
+ return exitLocalMode(event);
1961
1870
  }));
1962
1871
  app.use("/_agent-native/auth/session", defineEventHandler(async (event) => {
1963
1872
  if (!isReadMethod(event)) {