@k2b/cloud 0.40.0 → 0.42.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 (279) hide show
  1. package/package.json +9 -5
  2. package/src/_internal/bounded-json.ts +14 -2
  3. package/src/_internal/capabilities.ts +87 -8
  4. package/src/_internal/capability-reviews.ts +6 -0
  5. package/src/_internal/capability-sentences.ts +2 -1
  6. package/src/_internal/capability-timeout.ts +71 -0
  7. package/src/_internal/define-app.ts +158 -92
  8. package/src/_internal/heartbeat.ts +203 -14
  9. package/src/_internal/http-drain.ts +56 -0
  10. package/src/_internal/registry-validation.ts +3 -0
  11. package/src/_internal/registry.ts +28 -1
  12. package/src/_internal/runtime-context.ts +1 -0
  13. package/src/_internal/setup-lock.ts +103 -0
  14. package/src/_internal/status-preserving-ssr.ts +2 -0
  15. package/src/access/PermissionEditor.tsx +16 -17
  16. package/src/access/PrincipalPicker.tsx +45 -10
  17. package/src/access/messages.ts +8 -0
  18. package/src/access/principal-label.ts +18 -0
  19. package/src/access/ui.ts +1 -0
  20. package/src/account/EntitySearch.tsx +5 -4
  21. package/src/ai/action-review.ts +2 -1
  22. package/src/ai/app-skill-store.ts +1 -1
  23. package/src/ai/capabilities.ts +21 -3
  24. package/src/ai/capability-execution.ts +14 -12
  25. package/src/ai/chat/action-card.ts +76 -4
  26. package/src/ai/chat/action-messages.ts +14 -0
  27. package/src/ai/chat/action-question.browser-harness.tsx +12 -0
  28. package/src/ai/chat/action-question.tsx +214 -23
  29. package/src/ai/chat/action-text.ts +288 -0
  30. package/src/ai/chat/tool-action-words.ts +31 -0
  31. package/src/ai/chat/tool-action.tsx +1 -26
  32. package/src/ai/chat-tasks.ts +2 -1
  33. package/src/ai/client/controller.ts +150 -32
  34. package/src/ai/client/transport.ts +14 -2
  35. package/src/ai/code-capability-routes.ts +27 -23
  36. package/src/ai/code-runtime-tools.ts +14 -16
  37. package/src/ai/code-source-tools.ts +16 -18
  38. package/src/ai/executor.ts +64 -21
  39. package/src/ai/fetch-file-tool.ts +67 -76
  40. package/src/ai/firecrawl-tools.ts +15 -2
  41. package/src/ai/http.ts +1 -0
  42. package/src/ai/index.ts +1 -0
  43. package/src/ai/migrate.ts +28 -0
  44. package/src/ai/open-questions.ts +168 -0
  45. package/src/ai/projects.ts +1 -2
  46. package/src/ai/protocol.ts +2 -2
  47. package/src/ai/question-text.ts +8 -0
  48. package/src/ai/recent-resources.ts +12 -5
  49. package/src/ai/review-content.ts +77 -0
  50. package/src/ai/routes.ts +119 -35
  51. package/src/ai/runtime.ts +1 -0
  52. package/src/ai/skill-tool.ts +17 -6
  53. package/src/ai/skills-routes.ts +72 -27
  54. package/src/ai/skills.ts +139 -60
  55. package/src/ai/store.ts +184 -31
  56. package/src/ai/testing.ts +36 -0
  57. package/src/ai/tool-sentences.ts +152 -34
  58. package/src/ai/tool-wording.ts +12 -6
  59. package/src/ai/tools.ts +8 -3
  60. package/src/ai/types.ts +25 -4
  61. package/src/ai/usage.ts +2 -2
  62. package/src/api/admin-core-settings.ts +15 -2
  63. package/src/api/admin-geo.ts +54 -0
  64. package/src/api/admin-linux-identities.ts +6 -3
  65. package/src/api/admin-outgoing-mail.ts +29 -15
  66. package/src/api/app-approval-actions.ts +31 -7
  67. package/src/api/approvals-loader.ts +3 -3
  68. package/src/api/approvals.ts +51 -0
  69. package/src/api/apps.ts +4 -2
  70. package/src/api/auth/schemas.ts +3 -0
  71. package/src/api/auth.ts +54 -18
  72. package/src/api/capabilities.ts +258 -181
  73. package/src/api/capability-streams.ts +21 -13
  74. package/src/api/cli-plugins.ts +4 -1
  75. package/src/api/geo-glyphs.ts +11 -0
  76. package/src/api/geo.ts +128 -0
  77. package/src/api/help.ts +12 -4
  78. package/src/api/index.ts +5 -0
  79. package/src/api/mcp.ts +73 -41
  80. package/src/api/me-panel-consent.ts +8 -5
  81. package/src/api/me.ts +79 -3
  82. package/src/api/search.ts +21 -14
  83. package/src/api/sync-ops.ts +19 -13
  84. package/src/api/widgets.ts +42 -18
  85. package/src/approvals/Approvals.tsx +30 -66
  86. package/src/approvals/approval-card.ts +68 -0
  87. package/src/browser/CloudResourceSearch.browser-harness.tsx +53 -1
  88. package/src/browser/CloudResourceSearch.tsx +3 -13
  89. package/src/browser/PanelLeaveNotice.tsx +18 -0
  90. package/src/browser/navigation-search.ts +78 -25
  91. package/src/browser/panel-leave.ts +69 -0
  92. package/src/browser/panel-messages.ts +12 -0
  93. package/src/browser/panel-slot.ts +173 -24
  94. package/src/browser/panel.ts +3 -0
  95. package/src/browser/resource-search-messages.ts +2 -0
  96. package/src/capabilities/client.ts +28 -1
  97. package/src/capabilities/executions.ts +22 -3
  98. package/src/capabilities/geo-client.ts +57 -0
  99. package/src/capabilities/response.ts +2 -1
  100. package/src/capabilities/review-storage.ts +24 -0
  101. package/src/capabilities/reviews.ts +17 -3
  102. package/src/capabilities/server.ts +36 -16
  103. package/src/cli/access.ts +15 -23
  104. package/src/cli/admin/linux.ts +13 -2
  105. package/src/cli/admin/outgoing-mail.ts +26 -4
  106. package/src/cli/capabilities.ts +19 -0
  107. package/src/config/env.ts +0 -6
  108. package/src/contracts/app-access.ts +48 -0
  109. package/src/contracts/app-approval.ts +3 -3
  110. package/src/contracts/app.ts +4 -1
  111. package/src/contracts/approvals.ts +2 -2
  112. package/src/contracts/avatar.ts +186 -0
  113. package/src/contracts/capabilities.ts +149 -55
  114. package/src/contracts/geo-admin.ts +127 -0
  115. package/src/contracts/geo-map.ts +19 -0
  116. package/src/contracts/geo-route.ts +168 -0
  117. package/src/contracts/geo.ts +248 -0
  118. package/src/contracts/index.ts +4 -0
  119. package/src/contracts/outgoing-mail.ts +17 -4
  120. package/src/contracts/registry.ts +2 -0
  121. package/src/contracts/shared.ts +3 -0
  122. package/src/events/app-access.ts +68 -0
  123. package/src/events/live-delivery.ts +128 -0
  124. package/src/events/live.ts +14 -130
  125. package/src/geo/CloudMap.tsx +95 -0
  126. package/src/geo/map-messages.ts +17 -0
  127. package/src/geo/ui.ts +1 -0
  128. package/src/index.ts +2 -0
  129. package/src/server/client-ip.ts +36 -0
  130. package/src/server/index.ts +3 -4
  131. package/src/server/middleware/app-access.ts +312 -0
  132. package/src/server/middleware/auth.ts +5 -3
  133. package/src/server/middleware/invocation.ts +11 -0
  134. package/src/server/middleware/rate-limit.ts +4 -4
  135. package/src/server/services/access.ts +13 -9
  136. package/src/server/services/index.ts +0 -2
  137. package/src/server/services/services.ts +0 -2
  138. package/src/services/accounts/app.ts +23 -3
  139. package/src/services/accounts/posix.ts +21 -7
  140. package/src/services/accounts/users.ts +12 -1
  141. package/src/services/allowed-network-fetch.ts +16 -10
  142. package/src/services/app-access-metrics.ts +24 -0
  143. package/src/services/app-access.ts +123 -0
  144. package/src/services/app-discovery.ts +27 -0
  145. package/src/services/approvals/content.ts +40 -0
  146. package/src/services/approvals/device.ts +49 -33
  147. package/src/services/approvals/index.ts +15 -6
  148. package/src/services/approvals/list.ts +6 -11
  149. package/src/services/approvals/question.ts +72 -0
  150. package/src/services/audit/index.ts +1 -0
  151. package/src/services/auth-flows/ipa.ts +39 -2
  152. package/src/services/auth-flows/password-reset.ts +32 -6
  153. package/src/services/downstream-budget.ts +87 -0
  154. package/src/services/geo/admin.ts +262 -0
  155. package/src/services/geo/bucket.ts +67 -0
  156. package/src/services/geo/cache.ts +57 -0
  157. package/src/services/geo/costs.ts +5 -0
  158. package/src/services/geo/errors.ts +41 -0
  159. package/src/services/geo/fixtures/README.md +17 -0
  160. package/src/services/geo/fixtures/along.json +355 -0
  161. package/src/services/geo/fixtures/autocomplete.json +218 -0
  162. package/src/services/geo/fixtures/geocode.json +129 -0
  163. package/src/services/geo/fixtures/places.json +355 -0
  164. package/src/services/geo/fixtures/reverse.json +61 -0
  165. package/src/services/geo/fixtures/routing.json +57 -0
  166. package/src/services/geo/geoapify-route.ts +93 -0
  167. package/src/services/geo/geoapify.ts +281 -0
  168. package/src/services/geo/ledger.ts +122 -0
  169. package/src/services/geo/map.ts +160 -0
  170. package/src/services/geo/migrate.ts +25 -0
  171. package/src/services/geo/polyline.ts +184 -0
  172. package/src/services/geo/route-chain.ts +145 -0
  173. package/src/services/geo/route-costs.ts +9 -0
  174. package/src/services/geo/route-geometry.ts +39 -0
  175. package/src/services/geo/route-plan.ts +172 -0
  176. package/src/services/geo/route-service.ts +433 -0
  177. package/src/services/geo/service.ts +300 -0
  178. package/src/services/geo/settings.ts +49 -0
  179. package/src/services/help/index.ts +16 -7
  180. package/src/services/help/types.ts +6 -1
  181. package/src/services/identity/invocation-actor.ts +20 -2
  182. package/src/services/identity/issue-invocation.ts +67 -0
  183. package/src/services/identity/key-ring.ts +5 -3
  184. package/src/services/identity/runtime-config.ts +23 -0
  185. package/src/services/index.ts +11 -0
  186. package/src/services/mandates/index.ts +40 -3
  187. package/src/services/network-security.ts +6 -3
  188. package/src/services/network-transport.ts +99 -0
  189. package/src/services/notifications/catalog.ts +3 -2
  190. package/src/services/notifications/runtime.ts +1 -0
  191. package/src/services/notifications/web-push-transport.ts +45 -38
  192. package/src/services/outgoing-mail/dispatcher.ts +6 -1
  193. package/src/services/outgoing-mail/index.ts +55 -1
  194. package/src/services/outgoing-mail/messages.ts +82 -3
  195. package/src/services/outgoing-mail/resolve-host.ts +2 -2
  196. package/src/services/outgoing-mail/retention.ts +13 -1
  197. package/src/services/outgoing-mail/store.ts +36 -6
  198. package/src/services/outgoing-mail/test-send.ts +34 -4
  199. package/src/services/outgoing-mail/transport.ts +1 -1
  200. package/src/services/pdf/gotenberg.ts +11 -38
  201. package/src/services/pdf/markdown.ts +160 -2
  202. package/src/services/pdf/template-preview.ts +1 -1
  203. package/src/services/public-http.ts +28 -40
  204. package/src/services/session/index.ts +203 -29
  205. package/src/services/settings/app.ts +4 -1
  206. package/src/services/settings/core-settings.ts +88 -0
  207. package/src/services/settings/defaults.ts +8 -2
  208. package/src/services/settings/errors.ts +11 -0
  209. package/src/services/settings/geo-budget.ts +40 -0
  210. package/src/services/settings/index.ts +4 -3
  211. package/src/services/settings/store.ts +25 -17
  212. package/src/services/weather/geo.ts +29 -111
  213. package/src/services/weather/index.ts +4 -3
  214. package/src/services/weather/locations.ts +8 -5
  215. package/src/services/weather/migrate.ts +1 -0
  216. package/src/services/weather/settings.ts +0 -16
  217. package/src/shared/__snapshots__/avatar-art.test.ts.snap +5 -0
  218. package/src/shared/avatar-art.ts +400 -0
  219. package/src/shared/index.ts +2 -0
  220. package/src/shared/network-address.ts +22 -3
  221. package/src/shared/template-rendering.ts +36 -4
  222. package/src/shared-text/documents.ts +1 -1
  223. package/src/shared-text/index.ts +2 -0
  224. package/src/shared-text/log.ts +51 -3
  225. package/src/shared-text/snapshots.ts +340 -0
  226. package/src/ssr/AdminLayout.tsx +4 -2
  227. package/src/ssr/CloudShell.island.tsx +6 -0
  228. package/src/ssr/HelpPanelArticle.island.tsx +308 -0
  229. package/src/ssr/HelpPanelBack.island.tsx +32 -0
  230. package/src/ssr/HelpPanelMenu.island.tsx +133 -0
  231. package/src/ssr/HelpPanelSearch.island.tsx +123 -0
  232. package/src/ssr/HelpPanelShortcuts.island.tsx +22 -0
  233. package/src/ssr/HelpPanelView.island.tsx +27 -0
  234. package/src/ssr/Layout.tsx +65 -15
  235. package/src/ssr/LayoutHelp.browser-harness.tsx +1 -1
  236. package/src/ssr/LayoutHelp.tsx +185 -542
  237. package/src/ssr/LayoutHelpPanel.browser-harness.tsx +6 -7
  238. package/src/ssr/LayoutHelpPanel.server.browser-harness.tsx +131 -0
  239. package/src/ssr/LayoutHelpPanel.server.tsx +115 -0
  240. package/src/ssr/PanelRuntime.island.tsx +11 -7
  241. package/src/ssr/PwaLayout.tsx +2 -2
  242. package/src/ssr/RailApps.tsx +6 -0
  243. package/src/ssr/ShellRuntime.island.tsx +23 -7
  244. package/src/ssr/__snapshots__/Layout.unchanged.render.test.tsx.snap +151 -0
  245. package/src/ssr/__snapshots__/LayoutHelp.ssr.render.test.tsx.snap +29 -0
  246. package/src/ssr/admin-navigation.ts +1 -0
  247. package/src/ssr/app-badges.ts +6 -1
  248. package/src/ssr/compact-shell.browser-harness.ts +44 -5
  249. package/src/ssr/help.ts +7 -5
  250. package/src/ssr/index.ts +2 -1
  251. package/src/ssr/islands/index.ts +3 -4
  252. package/src/ssr/layout-context.ts +2 -0
  253. package/src/ssr/layout-help-panel-controls.tsx +43 -0
  254. package/src/ssr/layout-help-panel-document.ts +67 -0
  255. package/src/ssr/layout-help-panel-lifecycle.ts +32 -0
  256. package/src/ssr/layout-help-panel-menu.tsx +113 -0
  257. package/src/ssr/layout-help-panel-modules.ts +7 -0
  258. package/src/ssr/layout-help-panel-reader.tsx +159 -0
  259. package/src/ssr/layout-help-panel-search.tsx +69 -0
  260. package/src/ssr/layout-help-panel-shortcuts.ts +7 -0
  261. package/src/ssr/layout-help-panel-state.ts +141 -0
  262. package/src/ssr/layout-help-panel-types.ts +19 -0
  263. package/src/ssr/layout-help-views.tsx +484 -0
  264. package/src/ssr/mobile-menu-history.ts +4 -0
  265. package/src/ssr/page-swap-fixture/Column.island.tsx +15 -0
  266. package/src/ssr/page-swap-fixture/ProviderProbe.island.tsx +31 -0
  267. package/src/ssr/page-swap.browser-harness.tsx +177 -0
  268. package/src/ssr/page-swap.ts +28 -0
  269. package/src/ssr/page-trail-runtime.ts +32 -13
  270. package/src/ssr/panel-consent.ts +2 -2
  271. package/src/ssr/panel-idle.ts +9 -0
  272. package/src/ssr/panel-slot.browser-harness.tsx +3 -0
  273. package/src/ssr/platform-messages.ts +8 -0
  274. package/src/ssr/runtime.ts +17 -0
  275. package/src/ssr/shell-data.tsx +10 -2
  276. package/src/styles/approvals.css +6 -0
  277. package/src/styles/effects.css +15 -0
  278. package/src/styles/global.css +70 -6
  279. package/src/server/services/geo.ts +0 -215
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import type { AccessSubject } from "../server";
3
+ import type { RequestAuthority } from "../server/middleware/auth";
3
4
  import { AI_SKILL_FILE_MOUNT } from "./file-mount";
4
5
  import { AI_SHORT_ID_PATTERN } from "./short-id";
5
6
  import { type AiSkillCatalogEntry, mergeAiSkillCatalog, rankAiSkillCatalog, searchAiSkillCatalog } from "./skill-catalog";
@@ -8,11 +9,17 @@ import { aiSkills } from "./skills";
8
9
  import { defineAiTool } from "./tools";
9
10
 
10
11
  /** Explicit selections use the same permission check and turn snapshot as load_skill. */
11
- export async function loadSelectedAiSkills(ids: readonly string[], turnId: string, subject: AccessSubject | null, allowed: boolean) {
12
+ export async function loadSelectedAiSkills(
13
+ ids: readonly string[],
14
+ turnId: string,
15
+ subject: AccessSubject | null,
16
+ allowed: boolean,
17
+ authority: RequestAuthority | null = null,
18
+ ) {
12
19
  const loaded = [];
13
20
  for (const id of new Set(ids)) {
14
21
  if (!subject || !allowed) throw new Error("The selected Skill requires a model and tool scope that allow Skills.");
15
- const skill = await aiSkills.loadForTurn(turnId, { id }, subject);
22
+ const skill = await aiSkills.loadForTurn(turnId, { id }, subject, authority);
16
23
  if (!skill) throw new Error(`Selected Skill ${id} is unavailable or access was revoked.`);
17
24
  loaded.push({
18
25
  name: skill.name,
@@ -51,7 +58,7 @@ export const CloudAiLoadSkillOutputSchema = z.object({
51
58
  files: z.array(z.string()),
52
59
  });
53
60
 
54
- export const createCloudAiLoadSkillTool = (subject: AccessSubject) =>
61
+ export const createCloudAiLoadSkillTool = (subject: AccessSubject, authority: RequestAuthority | null = null) =>
55
62
  defineAiTool({
56
63
  name: "load_skill",
57
64
  description:
@@ -62,7 +69,7 @@ export const createCloudAiLoadSkillTool = (subject: AccessSubject) =>
62
69
  }).server(async (input, ctx) => {
63
70
  if (!ctx.turnId) throw new Error("load_skill requires a turn context.");
64
71
  const selector = input.id ? { id: input.id } : input.name;
65
- const snapshot = selector ? await aiSkills.loadForTurn(ctx.turnId, selector, subject) : null;
72
+ const snapshot = selector ? await aiSkills.loadForTurn(ctx.turnId, selector, subject, authority) : null;
66
73
  if (!snapshot) throw new Error(`Skill "${input.id ?? input.name}" is unavailable or access was revoked.`);
67
74
  return {
68
75
  name: snapshot.name,
@@ -84,7 +91,11 @@ export const CloudAiSearchSkillsOutputSchema = z.object({
84
91
  more: z.boolean(),
85
92
  });
86
93
 
87
- export const createCloudAiSearchSkillsTool = (subject: AccessSubject | null, localSkills: readonly AiSkillCatalogEntry[] = []) =>
94
+ export const createCloudAiSearchSkillsTool = (
95
+ subject: AccessSubject | null,
96
+ localSkills: readonly AiSkillCatalogEntry[] = [],
97
+ authority: RequestAuthority | null = null,
98
+ ) =>
88
99
  defineAiTool({
89
100
  name: "search_skills",
90
101
  description:
@@ -94,7 +105,7 @@ export const createCloudAiSearchSkillsTool = (subject: AccessSubject | null, loc
94
105
  approval: "never",
95
106
  }).server(async (input) => {
96
107
  const result = subject
97
- ? await aiSkills.search(subject, input.query, input.limit + localSkills.length, { modelInvocableOnly: true })
108
+ ? await aiSkills.search(subject, input.query, input.limit + localSkills.length, { modelInvocableOnly: true, authority })
98
109
  : { skills: [], more: false };
99
110
  const cloud = result.skills.map(({ name, description }) => ({ name, description }));
100
111
  if (!localSkills.length) return { skills: cloud, more: result.more };
@@ -1,9 +1,13 @@
1
1
  import { Hono, type MiddlewareHandler } from "hono";
2
2
  import { HTTPException } from "hono/http-exception";
3
3
  import { z } from "zod";
4
+ import { getApp } from "../_internal/registry";
4
5
  import { AuthenticatedPrincipalSchema } from "../contracts/shared";
5
6
  import { type AuthContext, auth, err, fail, ok, rateLimit, respond, v } from "../server";
7
+ import { appAccessDeniedBody } from "../server/middleware/app-access";
6
8
  import { noTransform } from "../server/middleware/no-transform";
9
+ import { appAccessAuthority, canUseApp } from "../services/app-access";
10
+ import { recordAppAccessDenied } from "../services/app-access-metrics";
7
11
  import { localizedAppName } from "../ssr/runtime";
8
12
  import { aiProjects } from "./projects";
9
13
  import {
@@ -62,6 +66,20 @@ type AiSkillsRouteDependencies = {
62
66
  authenticate?: MiddlewareHandler<AuthContext>;
63
67
  };
64
68
 
69
+ // Core exempts this mixed router from its method-independent public-path gate.
70
+ // Only list/get are brokers; management retains Core entry and its user-backed policy.
71
+ const requireCoreAccess: MiddlewareHandler<AuthContext> = async (c, next) => {
72
+ const core = await getApp("core").catch(() => null);
73
+ const allowed = core && (await canUseApp(appAccessAuthority(c), core).catch(() => false));
74
+ if (!allowed) {
75
+ if (core) recordAppAccessDenied(core.id);
76
+ c.header("Cache-Control", "private, no-store");
77
+ c.header("X-Cloud-App-Access-Denied", "core");
78
+ return c.json(appAccessDeniedBody(core ?? { id: "core", name: "Core" }), 403);
79
+ }
80
+ await next();
81
+ };
82
+
65
83
  const buildAiSkillsRoutes = (dependencies: AiSkillsRouteDependencies = {}) =>
66
84
  new Hono<AuthContext>()
67
85
  // The list combines skills from separate grants; the writer of one can rename it next to another skill's text.
@@ -86,13 +104,19 @@ const buildAiSkillsRoutes = (dependencies: AiSkillsRouteDependencies = {}) =>
86
104
  const { q, name } = c.req.valid("query");
87
105
  const skills =
88
106
  name !== undefined
89
- ? await aiSkills.list(subject, { name })
107
+ ? await aiSkills.list(subject, { name, authority: appAccessAuthority(c) })
90
108
  : q === undefined
91
- ? await aiSkills.list(subject)
92
- : (await aiSkills.search(subject, q)).skills;
109
+ ? await aiSkills.list(subject, { authority: appAccessAuthority(c) })
110
+ : (await aiSkills.search(subject, q, 30, { authority: appAccessAuthority(c) })).skills;
93
111
  return respond(c, ok({ skills: skills.map(publicSummary(c)) }));
94
112
  },
95
113
  )
114
+ .get("/:skillId", async (c) => {
115
+ const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "read", appAccessAuthority(c));
116
+ return skill ? respond(c, ok({ skill: publicSkill(c, skill) })) : respond(c, fail(err.notFound("Skill")));
117
+ })
118
+ .use("*", requireCoreAccess)
119
+ .use("*", auth.requireUser())
96
120
  .get(
97
121
  "/project-links/:projectId",
98
122
  v(
@@ -108,7 +132,12 @@ const buildAiSkillsRoutes = (dependencies: AiSkillsRouteDependencies = {}) =>
108
132
  query = c.req.valid("query");
109
133
  const project = await aiProjects.getByShortId(c.req.param("projectId")!, subject, query.available === "true" ? "admin" : "read");
110
134
  const result = project
111
- ? await aiSkills.projectSkills(project.id, subject, { query: query.q, page: query.page, available: query.available === "true" })
135
+ ? await aiSkills.projectSkills(project.id, subject, {
136
+ query: query.q,
137
+ page: query.page,
138
+ available: query.available === "true",
139
+ authority: appAccessAuthority(c),
140
+ })
112
141
  : null;
113
142
  return result
114
143
  ? respond(c, ok({ ...result, items: result.items.map(publicSummary(c)) }))
@@ -117,8 +146,8 @@ const buildAiSkillsRoutes = (dependencies: AiSkillsRouteDependencies = {}) =>
117
146
  )
118
147
  .get("/:skillId/projects", async (c) => {
119
148
  const subject = c.get("accessSubject") ?? null;
120
- const skill = await aiSkills.getByShortId(c.req.param("skillId")!, subject, "admin");
121
- const projects = skill ? await aiSkills.linkedProjects(skill.id, subject) : null;
149
+ const skill = await aiSkills.getByShortId(c.req.param("skillId")!, subject, "admin", appAccessAuthority(c));
150
+ const projects = skill ? await aiSkills.linkedProjects(skill.id, subject, appAccessAuthority(c)) : null;
122
151
  return projects
123
152
  ? respond(c, ok({ projects: projects.map((project) => ({ id: project.shortId, name: project.name })) }))
124
153
  : respond(c, fail(err.notFound("Skill")));
@@ -126,11 +155,11 @@ const buildAiSkillsRoutes = (dependencies: AiSkillsRouteDependencies = {}) =>
126
155
  .put("/:skillId/projects/:projectId", v("json", z.object({ linked: z.boolean() }).strict()), async (c) => {
127
156
  const subject = c.get("accessSubject") ?? null;
128
157
  const [skill, project] = await Promise.all([
129
- aiSkills.getByShortId(c.req.param("skillId")!, subject, "admin"),
158
+ aiSkills.getByShortId(c.req.param("skillId")!, subject, "admin", appAccessAuthority(c)),
130
159
  aiProjects.getByShortId(c.req.param("projectId")!, subject, "admin"),
131
160
  ]);
132
161
  const linked = c.req.valid("json").linked;
133
- return skill && project && (await aiSkills.linkProject(skill.id, project.id, linked, subject))
162
+ return skill && project && (await aiSkills.linkProject(skill.id, project.id, linked, subject, appAccessAuthority(c)))
134
163
  ? respond(c, ok({ linked }))
135
164
  : respond(c, fail(err.notFound("Skill or Project")));
136
165
  })
@@ -138,22 +167,22 @@ const buildAiSkillsRoutes = (dependencies: AiSkillsRouteDependencies = {}) =>
138
167
  const subject = c.get("accessSubject");
139
168
  if (!subject) return respond(c, fail(err.forbidden("Skills require an authenticated access subject.")));
140
169
  try {
141
- return respond(c, ok({ skill: publicSkill(c, await aiSkills.create({ subject, ...c.req.valid("json") })) }), 201);
170
+ return respond(
171
+ c,
172
+ ok({ skill: publicSkill(c, await aiSkills.create({ subject, ...c.req.valid("json") }, appAccessAuthority(c))) }),
173
+ 201,
174
+ );
142
175
  } catch (error) {
143
176
  if (isUniqueViolation(error)) return respond(c, fail(err.conflict("A skill with this name already exists.")));
144
177
  if (error instanceof AiSkillInputError) return respond(c, fail(err.badInput(error.message)));
145
178
  throw error;
146
179
  }
147
180
  })
148
- .get("/:skillId", async (c) => {
149
- const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null);
150
- return skill ? respond(c, ok({ skill: publicSkill(c, skill) })) : respond(c, fail(err.notFound("Skill")));
151
- })
152
181
  .put("/:skillId", v("json", UpdateSkillSchema), async (c) => {
153
- const existing = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "write");
182
+ const existing = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "write", appAccessAuthority(c));
154
183
  if (!existing) return respond(c, fail(err.notFound("Skill")));
155
184
  try {
156
- const skill = await aiSkills.update(existing.id, c.get("accessSubject") ?? null, c.req.valid("json"));
185
+ const skill = await aiSkills.update(existing.id, c.get("accessSubject") ?? null, c.req.valid("json"), appAccessAuthority(c));
157
186
  return skill ? respond(c, ok({ skill: publicSkill(c, skill) })) : respond(c, fail(err.notFound("Skill")));
158
187
  } catch (error) {
159
188
  if (isUniqueViolation(error)) return respond(c, fail(err.conflict("A skill with this name already exists.")));
@@ -163,32 +192,41 @@ const buildAiSkillsRoutes = (dependencies: AiSkillsRouteDependencies = {}) =>
163
192
  }
164
193
  })
165
194
  .delete("/:skillId", async (c) => {
166
- const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin");
167
- return skill && (await aiSkills.delete(skill.id, c.get("accessSubject") ?? null))
195
+ const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin", appAccessAuthority(c));
196
+ return skill && (await aiSkills.delete(skill.id, c.get("accessSubject") ?? null, appAccessAuthority(c)))
168
197
  ? respond(c, ok({ deleted: true }))
169
198
  : respond(c, fail(err.notFound("Skill")));
170
199
  })
171
200
  .put("/:skillId/enabled", dependencies.authenticate ?? auth.requireRole("authenticated"), v("json", SkillEnabledSchema), async (c) => {
172
201
  const subject = c.get("accessSubject") ?? null;
173
- const skill = await aiSkills.getByShortId(c.req.param("skillId")!, subject);
174
- const enabled = skill ? await aiSkills.setEnabled(skill.id, subject, c.req.valid("json").enabled) : null;
202
+ const skill = await aiSkills.getByShortId(c.req.param("skillId")!, subject, "read", appAccessAuthority(c));
203
+ const enabled = skill ? await aiSkills.setEnabled(skill.id, subject, c.req.valid("json").enabled, appAccessAuthority(c)) : null;
175
204
  return enabled === null ? respond(c, fail(err.notFound("Skill"))) : respond(c, ok({ enabled }));
176
205
  })
177
206
  .get("/:skillId/access", async (c) => {
178
- const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin");
179
- const access = skill ? await aiSkills.listAccess(skill.id, c.get("accessSubject") ?? null) : null;
207
+ const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin", appAccessAuthority(c));
208
+ const access = skill ? await aiSkills.listAccess(skill.id, c.get("accessSubject") ?? null, appAccessAuthority(c)) : null;
180
209
  return access ? respond(c, ok({ access })) : respond(c, fail(err.notFound("Skill")));
181
210
  })
182
211
  .post("/:skillId/access", v("json", SkillAccessSchema), async (c) => {
183
- const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin");
184
- const access = skill ? await aiSkills.grantAccess(skill.id, c.get("accessSubject") ?? null, c.req.valid("json")) : null;
212
+ const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin", appAccessAuthority(c));
213
+ const access = skill
214
+ ? await aiSkills.grantAccess(skill.id, c.get("accessSubject") ?? null, c.req.valid("json"), undefined, appAccessAuthority(c))
215
+ : null;
185
216
  return access ? respond(c, ok({ access }), 201) : respond(c, fail(err.notFound("Skill")));
186
217
  })
187
218
  .patch("/:skillId/access/:accessId", v("json", SkillAccessUpdateSchema), async (c) => {
188
- const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin");
219
+ const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin", appAccessAuthority(c));
189
220
  try {
190
221
  return skill &&
191
- (await aiSkills.updateAccess(skill.id, c.req.param("accessId")!, c.get("accessSubject") ?? null, c.req.valid("json").permission))
222
+ (await aiSkills.updateAccess(
223
+ skill.id,
224
+ c.req.param("accessId")!,
225
+ c.get("accessSubject") ?? null,
226
+ c.req.valid("json").permission,
227
+ undefined,
228
+ appAccessAuthority(c),
229
+ ))
192
230
  ? respond(c, ok({ updated: true }))
193
231
  : respond(c, fail(err.notFound("Access entry")));
194
232
  } catch (error) {
@@ -197,9 +235,16 @@ const buildAiSkillsRoutes = (dependencies: AiSkillsRouteDependencies = {}) =>
197
235
  }
198
236
  })
199
237
  .delete("/:skillId/access/:accessId", async (c) => {
200
- const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin");
238
+ const skill = await aiSkills.getByShortId(c.req.param("skillId")!, c.get("accessSubject") ?? null, "admin", appAccessAuthority(c));
201
239
  try {
202
- return skill && (await aiSkills.revokeAccess(skill.id, c.req.param("accessId")!, c.get("accessSubject") ?? null))
240
+ return skill &&
241
+ (await aiSkills.revokeAccess(
242
+ skill.id,
243
+ c.req.param("accessId")!,
244
+ c.get("accessSubject") ?? null,
245
+ undefined,
246
+ appAccessAuthority(c),
247
+ ))
203
248
  ? respond(c, ok({ deleted: true }))
204
249
  : respond(c, fail(err.notFound("Access entry")));
205
250
  } catch (error) {