@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.
- package/package.json +9 -5
- package/src/_internal/bounded-json.ts +14 -2
- package/src/_internal/capabilities.ts +87 -8
- package/src/_internal/capability-reviews.ts +6 -0
- package/src/_internal/capability-sentences.ts +2 -1
- package/src/_internal/capability-timeout.ts +71 -0
- package/src/_internal/define-app.ts +158 -92
- package/src/_internal/heartbeat.ts +203 -14
- package/src/_internal/http-drain.ts +56 -0
- package/src/_internal/registry-validation.ts +3 -0
- package/src/_internal/registry.ts +28 -1
- package/src/_internal/runtime-context.ts +1 -0
- package/src/_internal/setup-lock.ts +103 -0
- package/src/_internal/status-preserving-ssr.ts +2 -0
- package/src/access/PermissionEditor.tsx +16 -17
- package/src/access/PrincipalPicker.tsx +45 -10
- package/src/access/messages.ts +8 -0
- package/src/access/principal-label.ts +18 -0
- package/src/access/ui.ts +1 -0
- package/src/account/EntitySearch.tsx +5 -4
- package/src/ai/action-review.ts +2 -1
- package/src/ai/app-skill-store.ts +1 -1
- package/src/ai/capabilities.ts +21 -3
- package/src/ai/capability-execution.ts +14 -12
- package/src/ai/chat/action-card.ts +76 -4
- package/src/ai/chat/action-messages.ts +14 -0
- package/src/ai/chat/action-question.browser-harness.tsx +12 -0
- package/src/ai/chat/action-question.tsx +214 -23
- package/src/ai/chat/action-text.ts +288 -0
- package/src/ai/chat/tool-action-words.ts +31 -0
- package/src/ai/chat/tool-action.tsx +1 -26
- package/src/ai/chat-tasks.ts +2 -1
- package/src/ai/client/controller.ts +150 -32
- package/src/ai/client/transport.ts +14 -2
- package/src/ai/code-capability-routes.ts +27 -23
- package/src/ai/code-runtime-tools.ts +14 -16
- package/src/ai/code-source-tools.ts +16 -18
- package/src/ai/executor.ts +64 -21
- package/src/ai/fetch-file-tool.ts +67 -76
- package/src/ai/firecrawl-tools.ts +15 -2
- package/src/ai/http.ts +1 -0
- package/src/ai/index.ts +1 -0
- package/src/ai/migrate.ts +28 -0
- package/src/ai/open-questions.ts +168 -0
- package/src/ai/projects.ts +1 -2
- package/src/ai/protocol.ts +2 -2
- package/src/ai/question-text.ts +8 -0
- package/src/ai/recent-resources.ts +12 -5
- package/src/ai/review-content.ts +77 -0
- package/src/ai/routes.ts +119 -35
- package/src/ai/runtime.ts +1 -0
- package/src/ai/skill-tool.ts +17 -6
- package/src/ai/skills-routes.ts +72 -27
- package/src/ai/skills.ts +139 -60
- package/src/ai/store.ts +184 -31
- package/src/ai/testing.ts +36 -0
- package/src/ai/tool-sentences.ts +152 -34
- package/src/ai/tool-wording.ts +12 -6
- package/src/ai/tools.ts +8 -3
- package/src/ai/types.ts +25 -4
- package/src/ai/usage.ts +2 -2
- package/src/api/admin-core-settings.ts +15 -2
- package/src/api/admin-geo.ts +54 -0
- package/src/api/admin-linux-identities.ts +6 -3
- package/src/api/admin-outgoing-mail.ts +29 -15
- package/src/api/app-approval-actions.ts +31 -7
- package/src/api/approvals-loader.ts +3 -3
- package/src/api/approvals.ts +51 -0
- package/src/api/apps.ts +4 -2
- package/src/api/auth/schemas.ts +3 -0
- package/src/api/auth.ts +54 -18
- package/src/api/capabilities.ts +258 -181
- package/src/api/capability-streams.ts +21 -13
- package/src/api/cli-plugins.ts +4 -1
- package/src/api/geo-glyphs.ts +11 -0
- package/src/api/geo.ts +128 -0
- package/src/api/help.ts +12 -4
- package/src/api/index.ts +5 -0
- package/src/api/mcp.ts +73 -41
- package/src/api/me-panel-consent.ts +8 -5
- package/src/api/me.ts +79 -3
- package/src/api/search.ts +21 -14
- package/src/api/sync-ops.ts +19 -13
- package/src/api/widgets.ts +42 -18
- package/src/approvals/Approvals.tsx +30 -66
- package/src/approvals/approval-card.ts +68 -0
- package/src/browser/CloudResourceSearch.browser-harness.tsx +53 -1
- package/src/browser/CloudResourceSearch.tsx +3 -13
- package/src/browser/PanelLeaveNotice.tsx +18 -0
- package/src/browser/navigation-search.ts +78 -25
- package/src/browser/panel-leave.ts +69 -0
- package/src/browser/panel-messages.ts +12 -0
- package/src/browser/panel-slot.ts +173 -24
- package/src/browser/panel.ts +3 -0
- package/src/browser/resource-search-messages.ts +2 -0
- package/src/capabilities/client.ts +28 -1
- package/src/capabilities/executions.ts +22 -3
- package/src/capabilities/geo-client.ts +57 -0
- package/src/capabilities/response.ts +2 -1
- package/src/capabilities/review-storage.ts +24 -0
- package/src/capabilities/reviews.ts +17 -3
- package/src/capabilities/server.ts +36 -16
- package/src/cli/access.ts +15 -23
- package/src/cli/admin/linux.ts +13 -2
- package/src/cli/admin/outgoing-mail.ts +26 -4
- package/src/cli/capabilities.ts +19 -0
- package/src/config/env.ts +0 -6
- package/src/contracts/app-access.ts +48 -0
- package/src/contracts/app-approval.ts +3 -3
- package/src/contracts/app.ts +4 -1
- package/src/contracts/approvals.ts +2 -2
- package/src/contracts/avatar.ts +186 -0
- package/src/contracts/capabilities.ts +149 -55
- package/src/contracts/geo-admin.ts +127 -0
- package/src/contracts/geo-map.ts +19 -0
- package/src/contracts/geo-route.ts +168 -0
- package/src/contracts/geo.ts +248 -0
- package/src/contracts/index.ts +4 -0
- package/src/contracts/outgoing-mail.ts +17 -4
- package/src/contracts/registry.ts +2 -0
- package/src/contracts/shared.ts +3 -0
- package/src/events/app-access.ts +68 -0
- package/src/events/live-delivery.ts +128 -0
- package/src/events/live.ts +14 -130
- package/src/geo/CloudMap.tsx +95 -0
- package/src/geo/map-messages.ts +17 -0
- package/src/geo/ui.ts +1 -0
- package/src/index.ts +2 -0
- package/src/server/client-ip.ts +36 -0
- package/src/server/index.ts +3 -4
- package/src/server/middleware/app-access.ts +312 -0
- package/src/server/middleware/auth.ts +5 -3
- package/src/server/middleware/invocation.ts +11 -0
- package/src/server/middleware/rate-limit.ts +4 -4
- package/src/server/services/access.ts +13 -9
- package/src/server/services/index.ts +0 -2
- package/src/server/services/services.ts +0 -2
- package/src/services/accounts/app.ts +23 -3
- package/src/services/accounts/posix.ts +21 -7
- package/src/services/accounts/users.ts +12 -1
- package/src/services/allowed-network-fetch.ts +16 -10
- package/src/services/app-access-metrics.ts +24 -0
- package/src/services/app-access.ts +123 -0
- package/src/services/app-discovery.ts +27 -0
- package/src/services/approvals/content.ts +40 -0
- package/src/services/approvals/device.ts +49 -33
- package/src/services/approvals/index.ts +15 -6
- package/src/services/approvals/list.ts +6 -11
- package/src/services/approvals/question.ts +72 -0
- package/src/services/audit/index.ts +1 -0
- package/src/services/auth-flows/ipa.ts +39 -2
- package/src/services/auth-flows/password-reset.ts +32 -6
- package/src/services/downstream-budget.ts +87 -0
- package/src/services/geo/admin.ts +262 -0
- package/src/services/geo/bucket.ts +67 -0
- package/src/services/geo/cache.ts +57 -0
- package/src/services/geo/costs.ts +5 -0
- package/src/services/geo/errors.ts +41 -0
- package/src/services/geo/fixtures/README.md +17 -0
- package/src/services/geo/fixtures/along.json +355 -0
- package/src/services/geo/fixtures/autocomplete.json +218 -0
- package/src/services/geo/fixtures/geocode.json +129 -0
- package/src/services/geo/fixtures/places.json +355 -0
- package/src/services/geo/fixtures/reverse.json +61 -0
- package/src/services/geo/fixtures/routing.json +57 -0
- package/src/services/geo/geoapify-route.ts +93 -0
- package/src/services/geo/geoapify.ts +281 -0
- package/src/services/geo/ledger.ts +122 -0
- package/src/services/geo/map.ts +160 -0
- package/src/services/geo/migrate.ts +25 -0
- package/src/services/geo/polyline.ts +184 -0
- package/src/services/geo/route-chain.ts +145 -0
- package/src/services/geo/route-costs.ts +9 -0
- package/src/services/geo/route-geometry.ts +39 -0
- package/src/services/geo/route-plan.ts +172 -0
- package/src/services/geo/route-service.ts +433 -0
- package/src/services/geo/service.ts +300 -0
- package/src/services/geo/settings.ts +49 -0
- package/src/services/help/index.ts +16 -7
- package/src/services/help/types.ts +6 -1
- package/src/services/identity/invocation-actor.ts +20 -2
- package/src/services/identity/issue-invocation.ts +67 -0
- package/src/services/identity/key-ring.ts +5 -3
- package/src/services/identity/runtime-config.ts +23 -0
- package/src/services/index.ts +11 -0
- package/src/services/mandates/index.ts +40 -3
- package/src/services/network-security.ts +6 -3
- package/src/services/network-transport.ts +99 -0
- package/src/services/notifications/catalog.ts +3 -2
- package/src/services/notifications/runtime.ts +1 -0
- package/src/services/notifications/web-push-transport.ts +45 -38
- package/src/services/outgoing-mail/dispatcher.ts +6 -1
- package/src/services/outgoing-mail/index.ts +55 -1
- package/src/services/outgoing-mail/messages.ts +82 -3
- package/src/services/outgoing-mail/resolve-host.ts +2 -2
- package/src/services/outgoing-mail/retention.ts +13 -1
- package/src/services/outgoing-mail/store.ts +36 -6
- package/src/services/outgoing-mail/test-send.ts +34 -4
- package/src/services/outgoing-mail/transport.ts +1 -1
- package/src/services/pdf/gotenberg.ts +11 -38
- package/src/services/pdf/markdown.ts +160 -2
- package/src/services/pdf/template-preview.ts +1 -1
- package/src/services/public-http.ts +28 -40
- package/src/services/session/index.ts +203 -29
- package/src/services/settings/app.ts +4 -1
- package/src/services/settings/core-settings.ts +88 -0
- package/src/services/settings/defaults.ts +8 -2
- package/src/services/settings/errors.ts +11 -0
- package/src/services/settings/geo-budget.ts +40 -0
- package/src/services/settings/index.ts +4 -3
- package/src/services/settings/store.ts +25 -17
- package/src/services/weather/geo.ts +29 -111
- package/src/services/weather/index.ts +4 -3
- package/src/services/weather/locations.ts +8 -5
- package/src/services/weather/migrate.ts +1 -0
- package/src/services/weather/settings.ts +0 -16
- package/src/shared/__snapshots__/avatar-art.test.ts.snap +5 -0
- package/src/shared/avatar-art.ts +400 -0
- package/src/shared/index.ts +2 -0
- package/src/shared/network-address.ts +22 -3
- package/src/shared/template-rendering.ts +36 -4
- package/src/shared-text/documents.ts +1 -1
- package/src/shared-text/index.ts +2 -0
- package/src/shared-text/log.ts +51 -3
- package/src/shared-text/snapshots.ts +340 -0
- package/src/ssr/AdminLayout.tsx +4 -2
- package/src/ssr/CloudShell.island.tsx +6 -0
- package/src/ssr/HelpPanelArticle.island.tsx +308 -0
- package/src/ssr/HelpPanelBack.island.tsx +32 -0
- package/src/ssr/HelpPanelMenu.island.tsx +133 -0
- package/src/ssr/HelpPanelSearch.island.tsx +123 -0
- package/src/ssr/HelpPanelShortcuts.island.tsx +22 -0
- package/src/ssr/HelpPanelView.island.tsx +27 -0
- package/src/ssr/Layout.tsx +65 -15
- package/src/ssr/LayoutHelp.browser-harness.tsx +1 -1
- package/src/ssr/LayoutHelp.tsx +185 -542
- package/src/ssr/LayoutHelpPanel.browser-harness.tsx +6 -7
- package/src/ssr/LayoutHelpPanel.server.browser-harness.tsx +131 -0
- package/src/ssr/LayoutHelpPanel.server.tsx +115 -0
- package/src/ssr/PanelRuntime.island.tsx +11 -7
- package/src/ssr/PwaLayout.tsx +2 -2
- package/src/ssr/RailApps.tsx +6 -0
- package/src/ssr/ShellRuntime.island.tsx +23 -7
- package/src/ssr/__snapshots__/Layout.unchanged.render.test.tsx.snap +151 -0
- package/src/ssr/__snapshots__/LayoutHelp.ssr.render.test.tsx.snap +29 -0
- package/src/ssr/admin-navigation.ts +1 -0
- package/src/ssr/app-badges.ts +6 -1
- package/src/ssr/compact-shell.browser-harness.ts +44 -5
- package/src/ssr/help.ts +7 -5
- package/src/ssr/index.ts +2 -1
- package/src/ssr/islands/index.ts +3 -4
- package/src/ssr/layout-context.ts +2 -0
- package/src/ssr/layout-help-panel-controls.tsx +43 -0
- package/src/ssr/layout-help-panel-document.ts +67 -0
- package/src/ssr/layout-help-panel-lifecycle.ts +32 -0
- package/src/ssr/layout-help-panel-menu.tsx +113 -0
- package/src/ssr/layout-help-panel-modules.ts +7 -0
- package/src/ssr/layout-help-panel-reader.tsx +159 -0
- package/src/ssr/layout-help-panel-search.tsx +69 -0
- package/src/ssr/layout-help-panel-shortcuts.ts +7 -0
- package/src/ssr/layout-help-panel-state.ts +141 -0
- package/src/ssr/layout-help-panel-types.ts +19 -0
- package/src/ssr/layout-help-views.tsx +484 -0
- package/src/ssr/mobile-menu-history.ts +4 -0
- package/src/ssr/page-swap-fixture/Column.island.tsx +15 -0
- package/src/ssr/page-swap-fixture/ProviderProbe.island.tsx +31 -0
- package/src/ssr/page-swap.browser-harness.tsx +177 -0
- package/src/ssr/page-swap.ts +28 -0
- package/src/ssr/page-trail-runtime.ts +32 -13
- package/src/ssr/panel-consent.ts +2 -2
- package/src/ssr/panel-idle.ts +9 -0
- package/src/ssr/panel-slot.browser-harness.tsx +3 -0
- package/src/ssr/platform-messages.ts +8 -0
- package/src/ssr/runtime.ts +17 -0
- package/src/ssr/shell-data.tsx +10 -2
- package/src/styles/approvals.css +6 -0
- package/src/styles/effects.css +15 -0
- package/src/styles/global.css +70 -6
- package/src/server/services/geo.ts +0 -215
package/src/ai/skill-tool.ts
CHANGED
|
@@ -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(
|
|
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 = (
|
|
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 };
|
package/src/ai/skills-routes.ts
CHANGED
|
@@ -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, {
|
|
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(
|
|
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
|
|
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(
|
|
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 &&
|
|
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) {
|