@k2b/cloud 0.6.0 → 0.8.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/README.md +2 -2
- package/package.json +22 -11
- package/scripts/README.md +10 -0
- package/scripts/browser-performance.ts +14 -0
- package/scripts/build-pdf-renderer.ts +39 -0
- package/scripts/build.ts +20 -35
- package/scripts/preload.ts +16 -12
- package/scripts/sync-recovery-smoke.ts +22 -6
- package/src/_internal/app-presentation.ts +14 -2
- package/src/_internal/build-metadata.ts +8 -1
- package/src/_internal/capabilities.ts +131 -7
- package/src/_internal/capability-streams.ts +81 -0
- package/src/_internal/define-app.ts +80 -37
- package/src/_internal/heartbeat.ts +4 -0
- package/src/_internal/help-catalog.ts +27 -172
- package/src/_internal/help.ts +13 -76
- package/src/_internal/page-responses.ts +2 -0
- package/src/_internal/postgres-application-name.ts +30 -0
- package/src/_internal/process-identity.ts +15 -0
- package/src/_internal/process-sync.ts +1 -1
- package/src/_internal/readiness.ts +4 -1
- package/src/_internal/registry-validation.ts +29 -25
- package/src/_internal/registry.ts +2 -53
- package/src/_internal/runtime-context.ts +5 -16
- package/src/_internal/server-timing.ts +13 -0
- package/src/_internal/status-preserving-ssr.ts +18 -6
- package/src/_internal/web-vitals-asset.ts +10 -0
- package/src/access/PermissionEditor.tsx +18 -151
- package/src/access/PrincipalPicker.tsx +110 -0
- package/src/access/ResourceApiKeys.tsx +1 -1
- package/src/access/ui.ts +1 -0
- package/src/ai/admin.ts +14 -13
- package/src/ai/assistant-models.ts +12 -1
- package/src/ai/audio-format.ts +34 -0
- package/src/ai/audio-tool.ts +90 -0
- package/src/ai/browser-code-contracts.ts +201 -0
- package/src/ai/browser.ts +4 -0
- package/src/ai/capabilities.ts +55 -36
- package/src/ai/capability-execution.ts +47 -12
- package/src/ai/chat/blocks.tsx +229 -90
- package/src/ai/chat/builtin-tools.tsx +2 -4
- package/src/ai/chat/capability-result.ts +15 -0
- package/src/ai/chat/capability-table.tsx +2 -10
- package/src/ai/chat/composer-adapter.ts +83 -3
- package/src/ai/chat/message-actions.tsx +8 -7
- package/src/ai/chat/message-utils.ts +25 -1
- package/src/ai/chat/messages.ts +2 -0
- package/src/ai/chat/presentation.tsx +31 -47
- package/src/ai/chat/primitives.tsx +43 -1
- package/src/ai/chat/tool-disclosure.tsx +21 -2
- package/src/ai/chat/tool-groups.ts +58 -0
- package/src/ai/chat-quotas.ts +25 -0
- package/src/ai/chat-task-contracts.ts +14 -10
- package/src/ai/chat-tasks.ts +297 -43
- package/src/ai/client/controller.ts +165 -39
- package/src/ai/client/file-source.ts +12 -6
- package/src/ai/client/live-connection.ts +1 -0
- package/src/ai/client/projection.ts +29 -11
- package/src/ai/client/transport.ts +6 -0
- package/src/ai/code-capability-routes.ts +105 -0
- package/src/ai/code-capability-transport.ts +39 -0
- package/src/ai/code-execution.ts +53 -0
- package/src/ai/code-mode-skill.ts +118 -0
- package/src/ai/code-runtime-tools.ts +179 -0
- package/src/ai/code-source-contracts.ts +270 -0
- package/src/ai/code-source-tools.ts +188 -0
- package/src/ai/compaction.ts +27 -6
- package/src/ai/data-analysis-skill.ts +10 -0
- package/src/ai/default-tools.ts +99 -3
- package/src/ai/dictation-runtime.ts +171 -0
- package/src/ai/dictations.ts +188 -0
- package/src/ai/draft-content.ts +49 -0
- package/src/ai/enrich.ts +6 -0
- package/src/ai/executor.ts +189 -33
- package/src/ai/fetch-file-tool.ts +2 -2
- package/src/ai/file-content-version.ts +27 -0
- package/src/ai/file-context.ts +2 -1
- package/src/ai/file-media-type.ts +12 -0
- package/src/ai/file-reference-contracts.ts +15 -0
- package/src/ai/file-tools.ts +8 -1
- package/src/ai/files-store.ts +212 -71
- package/src/ai/fixtures/vision-encrypted.pdf +0 -0
- package/src/ai/grids-skill.ts +42 -10
- package/src/ai/http.ts +26 -8
- package/src/ai/index.ts +26 -3
- package/src/ai/inference-calls.ts +197 -0
- package/src/ai/live-events.ts +5 -1
- package/src/ai/live.ts +1 -1
- package/src/ai/markdown-pdf-tool.ts +2 -2
- package/src/ai/memories.ts +30 -27
- package/src/ai/memory-learning-runs.ts +1 -1
- package/src/ai/memory-learning.ts +64 -32
- package/src/ai/memory-tool.ts +1 -5
- package/src/ai/memory-workflow-evidence.ts +9 -4
- package/src/ai/message-queue.ts +178 -0
- package/src/ai/migrate.ts +189 -11
- package/src/ai/model-pricing.ts +43 -0
- package/src/ai/pdf-render-worker.ts +75 -0
- package/src/ai/pdf-render.fixture.ts +28 -0
- package/src/ai/pdf-render.ts +77 -0
- package/src/ai/projects-routes.ts +18 -43
- package/src/ai/projects.ts +33 -14
- package/src/ai/protocol.ts +3 -0
- package/src/ai/provider.ts +1 -8
- package/src/ai/quota-provider.ts +192 -0
- package/src/ai/quota-report.ts +152 -0
- package/src/ai/quotas-migrate.ts +45 -0
- package/src/ai/quotas.ts +168 -0
- package/src/ai/routes.ts +241 -11
- package/src/ai/run-timeout.ts +12 -0
- package/src/ai/runtime-tools.ts +7 -5
- package/src/ai/runtime.ts +74 -17
- package/src/ai/settings.ts +36 -8
- package/src/ai/short-id.ts +4 -5
- package/src/ai/skill-catalog.ts +0 -10
- package/src/ai/skill-search.ts +58 -0
- package/src/ai/skill-seeds.ts +114 -20
- package/src/ai/skill-tool.ts +21 -5
- package/src/ai/skills-routes.ts +49 -4
- package/src/ai/skills.ts +358 -163
- package/src/ai/store.ts +416 -201
- package/src/ai/stream.ts +5 -0
- package/src/ai/structured-runs.ts +4 -3
- package/src/ai/structured.ts +12 -1
- package/src/ai/system-prompt.ts +14 -2
- package/src/ai/task-contracts.ts +84 -0
- package/src/ai/task-execution.ts +92 -0
- package/src/ai/timeline.ts +2 -5
- package/src/ai/todo-contracts.ts +32 -0
- package/src/ai/todo-tool.ts +19 -0
- package/src/ai/tool-audit.ts +30 -40
- package/src/ai/tools.ts +6 -0
- package/src/ai/transcription.ts +202 -0
- package/src/ai/turn-timing.ts +114 -0
- package/src/ai/types.ts +58 -10
- package/src/ai/ui.tsx +3 -0
- package/src/ai/usage.ts +118 -118
- package/src/ai/vision-tool.ts +60 -10
- package/src/api/admin-ai-projects.ts +2 -2
- package/src/api/admin-ai-quotas.ts +80 -0
- package/src/api/admin-ai-skills.ts +48 -5
- package/src/api/admin-ai-usage.ts +2 -2
- package/src/api/admin-core-settings.ts +25 -0
- package/src/api/admin-identity.ts +91 -51
- package/src/api/admin-linux-identities.ts +10 -4
- package/src/api/admin-rail.ts +58 -0
- package/src/api/announcements.ts +14 -0
- package/src/api/app-approval.ts +2 -2
- package/src/api/auth.ts +1 -1
- package/src/api/capabilities.ts +324 -43
- package/src/api/capability-streams.ts +262 -0
- package/src/api/help.ts +8 -44
- package/src/api/index.ts +8 -2
- package/src/api/mcp.ts +45 -34
- package/src/api/me-web-vitals.ts +35 -0
- package/src/api/me.ts +2 -0
- package/src/api/search/schemas.ts +26 -15
- package/src/api/search.bench.ts +1 -1
- package/src/api/search.ts +54 -17
- package/src/browser/CloudResourceSearch.tsx +640 -702
- package/src/browser/app-approval-vault.ts +19 -7
- package/src/browser/command-bridge.ts +109 -0
- package/src/browser/command-shortcuts.ts +76 -0
- package/src/browser/commands.ts +67 -0
- package/src/browser/navigation-search.ts +48 -0
- package/src/browser/notifications.ts +1 -1
- package/src/browser/resource-picker.tsx +5 -18
- package/src/browser/resource-search-dialog.ts +9 -0
- package/src/browser/resource-search-input.ts +46 -0
- package/src/browser/resource-search-messages.ts +76 -40
- package/src/browser/resource-search.ts +7 -0
- package/src/browser/search-bridge.ts +102 -0
- package/src/browser/search-commands.ts +59 -0
- package/src/browser/search.ts +13 -0
- package/src/browser/spotlight-position.ts +208 -0
- package/src/browser/testing.ts +6 -0
- package/src/browser/web-vitals.ts +25 -0
- package/src/capabilities/claims.ts +179 -0
- package/src/capabilities/client.ts +34 -0
- package/src/capabilities/command-link.ts +16 -0
- package/src/capabilities/executions.ts +298 -0
- package/src/capabilities/migrate.ts +81 -0
- package/src/capabilities/server.ts +116 -35
- package/src/capabilities/stream-body.ts +16 -0
- package/src/capabilities/streams.ts +28 -0
- package/src/cli/admin/ai-quotas.ts +161 -0
- package/src/cli/admin/ai-skills.ts +64 -0
- package/src/cli/admin/ai-usage.ts +53 -30
- package/src/cli/admin/app-credentials.ts +77 -0
- package/src/cli/admin/data.ts +17 -0
- package/src/cli/admin/index.ts +10 -1
- package/src/cli/admin/instance.ts +2 -2
- package/src/cli/admin/linux.ts +4 -2
- package/src/cli/admin/sync.ts +1 -1
- package/src/cli/capabilities.ts +42 -0
- package/src/cli/capability-streams.ts +25 -0
- package/src/cli/index.ts +3 -2
- package/src/config/define-env.ts +97 -0
- package/src/config/env.ts +147 -51
- package/src/config/index.ts +3 -1
- package/src/contracts/app.ts +23 -3
- package/src/contracts/capabilities.ts +75 -5
- package/src/contracts/capability-streams.ts +46 -0
- package/src/contracts/commands.ts +49 -0
- package/src/contracts/index.ts +5 -2
- package/src/contracts/rail-admin.ts +38 -0
- package/src/contracts/rail-preferences.ts +16 -0
- package/src/contracts/registry.ts +5 -27
- package/src/contracts/settings-types.ts +1 -1
- package/src/contracts/shared.ts +18 -5
- package/src/contracts/web-vitals.ts +27 -0
- package/src/desktop/index.ts +1 -0
- package/src/desktop/solid.tsx +1 -1
- package/src/index.ts +8 -6
- package/src/server/index.ts +3 -0
- package/src/server/middleware/auth.ts +3 -2
- package/src/server/middleware/route-template.ts +9 -3
- package/src/server/middleware/runtime.ts +2 -1
- package/src/server/middleware/settings.ts +17 -11
- package/src/server/ratelimit.ts +1 -1
- package/src/server/services/access-revision.ts +10 -0
- package/src/server/services/access.ts +3 -1
- package/src/server/services/index.ts +1 -0
- package/src/services/account-category-policy.ts +9 -0
- package/src/services/account-lifecycle/audit.ts +1 -1
- package/src/services/accounts/app.ts +12 -2
- package/src/services/accounts/email-write.ts +23 -0
- package/src/services/accounts/groups.ts +15 -4
- package/src/services/accounts/identities.ts +249 -0
- package/src/services/accounts/identity-reconciliation.ts +87 -0
- package/src/services/accounts/ipa-data.ts +2 -2
- package/src/services/accounts/local-groups.ts +2 -2
- package/src/services/accounts/notification-sender.ts +12 -2
- package/src/services/accounts/posix.ts +45 -29
- package/src/services/accounts/users.ts +2 -2
- package/src/services/announcements/index.ts +69 -8
- package/src/services/app-approval.ts +11 -10
- package/src/services/audit/index.ts +1 -1
- package/src/services/cache-fill.ts +35 -0
- package/src/services/help/index.ts +109 -0
- package/src/services/help/maintenance.ts +25 -0
- package/src/services/help/store.ts +180 -0
- package/src/services/help/types.ts +46 -0
- package/src/services/identity/invocation-actor.ts +2 -2
- package/src/services/identity/key-config.ts +8 -5
- package/src/services/identity/key-ring.ts +1 -1
- package/src/services/identity/runtime-config.ts +6 -5
- package/src/services/index.ts +15 -0
- package/src/services/ipa/posix.ts +1 -1
- package/src/services/ipa/sync.ts +1 -1
- package/src/services/ipa/users.ts +268 -221
- package/src/services/legal-consent.ts +1 -1
- package/src/services/logging/index.ts +15 -13
- package/src/services/logging/trace.ts +2 -1
- package/src/services/logging/web-vitals.ts +81 -0
- package/src/services/mandates/index.ts +21 -4
- package/src/services/mandates/policy.ts +165 -2
- package/src/services/notifications/batches.ts +125 -57
- package/src/services/notifications/browser.ts +12 -0
- package/src/services/notifications/index.ts +0 -2
- package/src/services/notifications/platform.ts +0 -4
- package/src/services/oauth-tokens.ts +3 -3
- package/src/services/pdf/gotenberg.ts +131 -72
- package/src/services/pdf/index.ts +11 -8
- package/src/services/providers/local/users.ts +25 -16
- package/src/services/public-http.ts +101 -0
- package/src/services/rail-shortcuts.ts +95 -0
- package/src/services/rail-snapshot.ts +53 -0
- package/src/services/request-cache-redis.ts +29 -0
- package/src/services/session/index.ts +15 -2
- package/src/services/session/user.ts +62 -37
- package/src/services/settings/app.ts +5 -1
- package/src/services/settings/core-settings.ts +26 -35
- package/src/services/settings/defaults.ts +5 -0
- package/src/services/settings/index.ts +3 -3
- package/src/services/settings/store.ts +58 -84
- package/src/services/webauthn.ts +1 -1
- package/src/shared/ai-costs.ts +42 -0
- package/src/shared/ai-platform-prompt.ts +1 -1
- package/src/shared/ai-quotas.ts +136 -0
- package/src/shared/ai-usage.ts +6 -16
- package/src/shared/app-presentation.ts +21 -15
- package/src/shared/capability-messages.ts +14 -0
- package/src/shared/help.ts +6 -42
- package/src/shared/index.ts +3 -0
- package/src/shared/markdown/extensions/info-blocks.ts +1 -1
- package/src/ssr/AdminLayout.tsx +7 -5
- package/src/ssr/AdminSidebar.tsx +30 -16
- package/src/ssr/AppLaunchpad.island.tsx +33 -136
- package/src/ssr/AppLaunchpadPanel.tsx +181 -0
- package/src/ssr/BrowserPushRegistration.island.tsx +12 -0
- package/src/ssr/GlobalSearchDialog.tsx +167 -20
- package/src/ssr/GlobalSearchTrigger.island.tsx +33 -22
- package/src/ssr/Layout.tsx +17 -6
- package/src/ssr/LayoutBreadcrumbs.island.tsx +3 -5
- package/src/ssr/LayoutFooter.tsx +1 -1
- package/src/ssr/LayoutHeader.tsx +46 -14
- package/src/ssr/LayoutHelp.tsx +22 -23
- package/src/ssr/{HotkeysHelpRail.island.tsx → LayoutHelpTrigger.island.tsx} +18 -12
- package/src/ssr/LayoutRail.tsx +17 -9
- package/src/ssr/MinimalLayout.tsx +1 -1
- package/src/ssr/MobileNavigation.tsx +71 -0
- package/src/ssr/MobileProfileActions.tsx +49 -0
- package/src/ssr/ProfilePreferences.island.tsx +3 -36
- package/src/ssr/RailApps.island.tsx +2 -2
- package/src/ssr/RailEditor.tsx +17 -2
- package/src/ssr/WorkspaceNavigation.island.tsx +7 -0
- package/src/ssr/WorkspaceNavigationProvider.tsx +16 -0
- package/src/ssr/admin-navigation.ts +11 -1
- package/src/ssr/help.ts +29 -0
- package/src/ssr/islands/SearchBar.tsx +67 -0
- package/src/ssr/islands/index.ts +3 -1
- package/src/ssr/layout-context.ts +2 -2
- package/src/ssr/layout-help-search.ts +15 -0
- package/src/ssr/mobile-menu-history.ts +70 -0
- package/src/ssr/platform-messages.ts +16 -8
- package/src/ssr/profile-actions.ts +42 -0
- package/src/ssr/rail-context.ts +8 -4
- package/src/ssr/rail-messages.ts +2 -0
- package/src/ssr/rail-navigation.ts +3 -3
- package/src/ssr/workspace-navigation.ts +75 -0
- package/src/styles/effects.css +6 -6
- package/src/styles/global.css +54 -0
- package/src/styles/input.css +43 -41
- package/src/styles/resource-search.css +505 -0
- package/src/styles/utilities-feedback.css +13 -0
- package/src/styles/utilities-layout.css +1 -5
- package/src/styles/utilities-navigation.css +3 -39
- package/src/types/ambient.d.ts +5 -0
- package/src/workflows/ai/index.ts +2 -2
- package/src/workflows/ai/runtime.ts +19 -90
- package/src/workflows/ai/store.ts +2 -0
- package/src/workflows/ai/types.ts +6 -82
- package/src/workflows/ai-actions.ts +16 -13
- package/src/workflows/definition.ts +10 -5
- package/src/workflows/store/actions.ts +44 -20
- package/src/workflows/store/index.ts +4 -2
- package/src/workflows/store/runs.ts +36 -0
- package/src/workflows/store/worker-pool.ts +55 -0
- package/src/workflows/store/worker-runtime.ts +90 -0
- package/src/ai/kit-skill.ts +0 -22
- package/src/ai/usage-migrate.ts +0 -81
- package/src/browser/notification-target.ts +0 -27
- package/src/contracts/notification-live.ts +0 -66
- package/src/server/services/freeipa/test-certificates.ts +0 -44
- package/src/services/notifications/live.ts +0 -50
- package/src/services/session/test-fixture.ts +0 -18
- package/src/ssr/BrowserNotifications.island.tsx +0 -135
- package/src/ssr/islands/SearchBar.island.tsx +0 -80
package/src/cli/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ export type CloudCliContext = {
|
|
|
32
32
|
setDefault: (key: string, value: string | undefined) => Promise<void>;
|
|
33
33
|
createApiClient: <TApi extends Hono<any, any, any>>(basePath: string) => CloudApiClient<TApi>;
|
|
34
34
|
fetch: (path: string, init?: RequestInit) => Promise<Response>;
|
|
35
|
-
readJson: <T>(response: Response) => Promise<T>;
|
|
35
|
+
readJson: <T>(response: Pick<Response, "json" | "text" | "ok" | "status" | "statusText">) => Promise<T>;
|
|
36
36
|
print: (value?: string) => void;
|
|
37
37
|
/** Write a stdout chunk without adding a newline. */
|
|
38
38
|
/** Resolves once the value is flushed; await it when writing large output. */
|
|
@@ -51,7 +51,8 @@ export type CloudCliModule = {
|
|
|
51
51
|
booleanFlags?: readonly string[];
|
|
52
52
|
requiresCloud?: boolean;
|
|
53
53
|
requiresCloudFor?: (args: string[], flags: CloudCliFlags) => boolean;
|
|
54
|
-
help
|
|
54
|
+
/** Render module help in the request locale; command syntax stays unchanged. */
|
|
55
|
+
help?: (locale?: string) => string;
|
|
55
56
|
run: (context: CloudCliContext) => Promise<number | void> | number | void;
|
|
56
57
|
};
|
|
57
58
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment registry factory.
|
|
3
|
+
*
|
|
4
|
+
* Every runtime environment variable is declared once with a schema, a
|
|
5
|
+
* default, a scope and a one-sentence doc. Registries read `process.env`
|
|
6
|
+
* lazily: each key is parsed on access, so tests can change variables and
|
|
7
|
+
* consumers never depend on an import-time snapshot. `.env.example`,
|
|
8
|
+
* `.env.prod.example` and the configuration reference are generated from the
|
|
9
|
+
* `$specs` of every registry by `scripts/generate-config-docs.ts`.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `runtime` is read by deployed processes, `secret` is a runtime credential,
|
|
15
|
+
* `development` only matters for host-run development, builds or tooling.
|
|
16
|
+
*/
|
|
17
|
+
export type EnvScope = "runtime" | "secret" | "development";
|
|
18
|
+
|
|
19
|
+
export type EnvSpec<T> = {
|
|
20
|
+
/** Parses the trimmed raw value. Empty and unset values never reach the schema. */
|
|
21
|
+
schema: z.ZodType<T, unknown>;
|
|
22
|
+
/** Used when the variable is unset or empty; a function is evaluated on every access. */
|
|
23
|
+
default?: T | (() => T);
|
|
24
|
+
/** One sentence for operators; rendered into the generated files. */
|
|
25
|
+
doc: string;
|
|
26
|
+
/** Default `runtime`. */
|
|
27
|
+
scope?: EnvScope;
|
|
28
|
+
/** Host-run development value written to `.env.example`. */
|
|
29
|
+
example?: string;
|
|
30
|
+
/** Throw on access when unset and no default exists. */
|
|
31
|
+
required?: boolean;
|
|
32
|
+
/** Alternative variable names, consulted after the canonical key. */
|
|
33
|
+
aliases?: string[];
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type EnvSpecs = Record<string, EnvSpec<unknown>>;
|
|
37
|
+
|
|
38
|
+
type EnvValue<S extends EnvSpec<unknown>> = S extends { default: unknown } | { required: true }
|
|
39
|
+
? z.output<S["schema"]>
|
|
40
|
+
: z.output<S["schema"]> | undefined;
|
|
41
|
+
|
|
42
|
+
export type EnvRegistry<S extends EnvSpecs> = { readonly [K in keyof S]: EnvValue<S[K]> } & {
|
|
43
|
+
readonly $specs: S;
|
|
44
|
+
readonly $keys: readonly string[];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const rawValue = (key: string, aliases: string[] = []): string | undefined => {
|
|
48
|
+
for (const name of [key, ...aliases]) {
|
|
49
|
+
const value = process.env[name]?.trim();
|
|
50
|
+
if (value) return value;
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const isFactory = <T>(value: T | (() => T)): value is () => T => typeof value === "function";
|
|
56
|
+
|
|
57
|
+
export const readEnv = <T>(key: string, spec: EnvSpec<T>): T | undefined => {
|
|
58
|
+
const raw = rawValue(key, spec.aliases);
|
|
59
|
+
if (raw === undefined) {
|
|
60
|
+
if (spec.default !== undefined) return isFactory(spec.default) ? spec.default() : spec.default;
|
|
61
|
+
if (spec.required) throw new Error(`${key} is required`);
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const parsed = spec.schema.safeParse(raw);
|
|
65
|
+
if (!parsed.success) {
|
|
66
|
+
const reason = parsed.error.issues.map((issue) => issue.message).join("; ") || "is invalid";
|
|
67
|
+
throw new Error(`${key} ${reason}`);
|
|
68
|
+
}
|
|
69
|
+
return parsed.data;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const defineEnv = <S extends EnvSpecs>(specs: S): EnvRegistry<S> => {
|
|
73
|
+
const keys = Object.freeze(Object.keys(specs));
|
|
74
|
+
const registry: Record<string, unknown> = { $specs: specs, $keys: keys };
|
|
75
|
+
for (const key of keys) {
|
|
76
|
+
Object.defineProperty(registry, key, { enumerable: true, configurable: true, get: () => readEnv(key, specs[key]!) });
|
|
77
|
+
}
|
|
78
|
+
// The getters above are the only way to build a typed lazy object.
|
|
79
|
+
return registry as EnvRegistry<S>;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Any non-empty string; empty values are treated as unset before parsing. */
|
|
83
|
+
export const envString = z.string();
|
|
84
|
+
|
|
85
|
+
/** `true` or `1` (case-insensitive) is true; everything else is false. */
|
|
86
|
+
export const envBoolean = z.string().transform((value) => {
|
|
87
|
+
const normalized = value.toLowerCase();
|
|
88
|
+
return normalized === "true" || normalized === "1";
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
/** Comma-separated entries; whitespace and empty entries are dropped. */
|
|
92
|
+
export const envList = z.string().transform((value) =>
|
|
93
|
+
value
|
|
94
|
+
.split(",")
|
|
95
|
+
.map((entry) => entry.trim())
|
|
96
|
+
.filter(Boolean),
|
|
97
|
+
);
|
package/src/config/env.ts
CHANGED
|
@@ -1,54 +1,150 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Platform environment registry.
|
|
3
|
+
* Every variable a Cloud process reads is declared here or in an application's
|
|
4
|
+
* `src/env.ts`; values are parsed lazily on access (see `define-env.ts`).
|
|
4
5
|
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { defineEnv, envBoolean, envList } from "./define-env";
|
|
5
8
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
9
|
+
const syncReplicas = z
|
|
10
|
+
.enum(["1", "3", "5"], { error: "must be 1, 3, or 5" })
|
|
11
|
+
.transform((value): 1 | 3 | 5 => (value === "1" ? 1 : value === "3" ? 3 : 5));
|
|
12
|
+
|
|
13
|
+
const registry = defineEnv({
|
|
14
|
+
// Process
|
|
15
|
+
NODE_ENV: {
|
|
16
|
+
schema: z.string(),
|
|
17
|
+
doc: "Release images set `production`; `development` enables development-only behavior such as insecure cookies and HTTP issuers.",
|
|
18
|
+
},
|
|
19
|
+
HOSTNAME: {
|
|
20
|
+
schema: z.string(),
|
|
21
|
+
doc: "Container or host name; the default instance identity in worker leases and gateway registration.",
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Infrastructure
|
|
25
|
+
DATABASE_URL: {
|
|
26
|
+
schema: z.string(),
|
|
27
|
+
example: "postgresql://ipa:ipa@localhost:5432/ipa",
|
|
28
|
+
doc: "Postgres connection read by Bun SQL and by application-owned pools.",
|
|
29
|
+
},
|
|
30
|
+
REDIS_URL: {
|
|
31
|
+
schema: z.string(),
|
|
32
|
+
aliases: ["VALKEY_URL"],
|
|
33
|
+
example: "redis://localhost:6379",
|
|
34
|
+
doc: "Valkey connection used by Bun Redis for caches and rate limits.",
|
|
35
|
+
},
|
|
36
|
+
NATS_SERVERS: {
|
|
37
|
+
schema: envList,
|
|
38
|
+
default: [],
|
|
39
|
+
example: "nats://localhost:4222",
|
|
40
|
+
doc: "Comma-separated NATS JetStream bootstrap servers; the client dials all of them.",
|
|
41
|
+
},
|
|
42
|
+
SYNC_NAMESPACE: {
|
|
43
|
+
schema: z.string(),
|
|
44
|
+
default: "",
|
|
45
|
+
example: "dev",
|
|
46
|
+
doc: "Sync namespace shared by every app of one installation; isolates its NATS resources from other installations on the same cluster.",
|
|
47
|
+
},
|
|
48
|
+
SYNC_REPLICAS: {
|
|
49
|
+
schema: syncReplicas,
|
|
50
|
+
default: 3,
|
|
51
|
+
example: "1",
|
|
52
|
+
doc: "Persistent JetStream replica count (1, 3 or 5); keep it consistent across the installation and migrate existing resources before changing it.",
|
|
53
|
+
},
|
|
54
|
+
NATS_CREDS_FILE: {
|
|
55
|
+
schema: z.string(),
|
|
56
|
+
doc: "Path to a mounted NATS `.creds` file (JWT and NKey); unset means server-side no-auth.",
|
|
57
|
+
},
|
|
58
|
+
NATS_TLS_CA_FILE: {
|
|
59
|
+
schema: z.string(),
|
|
60
|
+
doc: "Path to a mounted CA certificate that enables TLS to NATS; unset means plain TCP.",
|
|
61
|
+
},
|
|
62
|
+
NATS_IGNORE_CLUSTER_UPDATES: {
|
|
63
|
+
schema: envBoolean,
|
|
64
|
+
default: true,
|
|
65
|
+
example: "true",
|
|
66
|
+
doc: "Only dial the listed servers and ignore cluster-advertised peer addresses; set to `false` when every advertised address is reachable.",
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// Installation
|
|
70
|
+
APP_URL: {
|
|
71
|
+
schema: z.string(),
|
|
72
|
+
example: "localhost:3000",
|
|
73
|
+
doc: "Public Cloud URL used to bootstrap the `app.url` setting; the stored setting wins once written.",
|
|
74
|
+
},
|
|
75
|
+
APP_SECRET: {
|
|
76
|
+
schema: z.string(),
|
|
77
|
+
default: "",
|
|
78
|
+
scope: "secret",
|
|
79
|
+
example: "change-me-generate-with-openssl-rand-hex-32",
|
|
80
|
+
doc: "Deployment-wide secret for at-rest settings encryption and signed cursors; generate once with `openssl rand -hex 32` and never change it after data has been written.",
|
|
81
|
+
},
|
|
82
|
+
ADMIN_LOGIN_TOKEN: {
|
|
83
|
+
schema: z.string(),
|
|
84
|
+
default: "",
|
|
85
|
+
scope: "secret",
|
|
86
|
+
doc: "Core only: temporary first-administrator or recovery login token; remove it after normal administrator sign-in works.",
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
// Identity and OAuth
|
|
90
|
+
CLOUD_IDENTITY_KEY_ENCRYPTION_KEY: {
|
|
91
|
+
schema: z.string(),
|
|
92
|
+
scope: "secret",
|
|
93
|
+
example: "change-me-generate-with-openssl-rand-hex-32",
|
|
94
|
+
doc: "Core only: 64-hex KEK for platform identity signing keys stored in Postgres; generate once with `openssl rand -hex 32` and never distribute it to other apps.",
|
|
95
|
+
},
|
|
96
|
+
CLOUD_IDENTITY_NEXT_KEY: {
|
|
97
|
+
schema: z.string(),
|
|
98
|
+
scope: "secret",
|
|
99
|
+
doc: "Core only: pre-distributed next KEK before promoting it to current; cannot be combined with `CLOUD_IDENTITY_PREVIOUS_KEY`.",
|
|
100
|
+
},
|
|
101
|
+
CLOUD_IDENTITY_PREVIOUS_KEY: {
|
|
102
|
+
schema: z.string(),
|
|
103
|
+
scope: "secret",
|
|
104
|
+
doc: "Core only: old KEK set during an explicit rolling rewrap of stored identity signing keys, then removed.",
|
|
105
|
+
},
|
|
106
|
+
CLOUD_OAUTH_BROKER_SECRET: {
|
|
107
|
+
schema: z.string(),
|
|
108
|
+
scope: "secret",
|
|
109
|
+
doc: "Core and OAuth only: 64-hex secret that lets the OAuth app request token signatures from Core; generate independently with `openssl rand -hex 32`.",
|
|
110
|
+
},
|
|
111
|
+
CLOUD_CORE_INTERNAL_ORIGIN: {
|
|
112
|
+
schema: z.string(),
|
|
113
|
+
doc: "Direct Core listener origin for OAuth issuance, mandate-backed background work and internal callbacks; host-run callers use the Core port, not the gateway.",
|
|
114
|
+
},
|
|
115
|
+
CLOUD_APP_CREDENTIAL: {
|
|
116
|
+
schema: z.string(),
|
|
117
|
+
scope: "secret",
|
|
118
|
+
doc: "App-bound workload credential provisioned through Core's admin workload API; background apps such as Mail need one with `identity:invoke`.",
|
|
119
|
+
},
|
|
120
|
+
CLOUD_IDENTITY_JWKS_ORIGIN: {
|
|
121
|
+
schema: z.string(),
|
|
122
|
+
doc: "Optional private origin of the Core listener for session and invocation JWKS; unset fetches keys from the public issuer origin.",
|
|
123
|
+
},
|
|
124
|
+
CLOUD_OAUTH_JWKS_ORIGIN: {
|
|
125
|
+
schema: z.string(),
|
|
126
|
+
doc: "Optional private origin of the OAuth listener for OAuth JWKS; unset fetches keys from the public issuer origin.",
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Build and standalone development
|
|
130
|
+
APP_DIR: {
|
|
131
|
+
schema: z.string(),
|
|
132
|
+
scope: "development",
|
|
133
|
+
doc: "Application directory for standalone consumers running `@k2b/cloud/scripts/build.ts` or the SSR dev server outside the monorepo; defaults to the package directory.",
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
// Desktop
|
|
137
|
+
CLOUD_DESKTOP_SQLITE_PATH: {
|
|
138
|
+
schema: z.string(),
|
|
139
|
+
scope: "development",
|
|
140
|
+
doc: "SQLite file used by `desktop.sql` in the Bun desktop process; defaults to `.local/desktop.sqlite` in the working directory.",
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
type PlatformEnv = typeof registry & { readonly IS_DEVELOPMENT: boolean };
|
|
145
|
+
|
|
146
|
+
/** Platform environment; `IS_DEVELOPMENT` derives from `NODE_ENV === "development"`. */
|
|
147
|
+
export const env: PlatformEnv = Object.defineProperty(registry as PlatformEnv, "IS_DEVELOPMENT", {
|
|
148
|
+
enumerable: true,
|
|
149
|
+
get: () => registry.NODE_ENV === "development",
|
|
150
|
+
});
|
package/src/config/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Main config export.
|
|
3
|
-
* Re-exports
|
|
3
|
+
* Re-exports the platform environment registry and the registry factory used
|
|
4
|
+
* by application `src/env.ts` files. SSR config is per-app via defineApp().
|
|
4
5
|
*/
|
|
5
6
|
|
|
7
|
+
export { defineEnv, type EnvRegistry, type EnvScope, type EnvSpec, type EnvSpecs, envBoolean, envList, envString } from "./define-env";
|
|
6
8
|
export { env } from "./env";
|
package/src/contracts/app.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Sync } from "@k2b/sync";
|
|
2
|
-
import type {
|
|
2
|
+
import type { AppRegistryHelpSummary } from "./registry";
|
|
3
3
|
import type { Role } from "./shared";
|
|
4
4
|
import type { DashboardWidgetPresentation } from "./widgets";
|
|
5
5
|
|
|
@@ -14,6 +14,18 @@ export type LegalLink = {
|
|
|
14
14
|
icon?: string;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
/** Static page links for the global search UI, ranked after resource results.
|
|
18
|
+
* These declare navigation only; they do not create capabilities or readers.
|
|
19
|
+
*/
|
|
20
|
+
export type AppSearchLink = {
|
|
21
|
+
label: string;
|
|
22
|
+
/** Optional plain-text context shown with the result and its preview. */
|
|
23
|
+
description?: string;
|
|
24
|
+
href: string;
|
|
25
|
+
icon?: string;
|
|
26
|
+
keywords?: readonly string[];
|
|
27
|
+
};
|
|
28
|
+
|
|
17
29
|
export type AppAppearanceColor = `#${string}`;
|
|
18
30
|
|
|
19
31
|
export type AppAppearance = {
|
|
@@ -35,6 +47,8 @@ export type AppAdminNavigationLink = {
|
|
|
35
47
|
};
|
|
36
48
|
|
|
37
49
|
export type AppAdminNavigationGroup = {
|
|
50
|
+
/** Contribute links to the platform AI section instead of a separate group. */
|
|
51
|
+
section?: "ai";
|
|
38
52
|
/** Stable key used only to localize this presentation group. */
|
|
39
53
|
id?: string;
|
|
40
54
|
label: string;
|
|
@@ -50,10 +64,14 @@ export type AppPresentationTranslation = {
|
|
|
50
64
|
adminLinks?: Readonly<Record<string, string>>;
|
|
51
65
|
/** Legal-link labels keyed by their stable same-origin href. */
|
|
52
66
|
legalLinks?: Readonly<Record<string, string>>;
|
|
67
|
+
/** Search-link labels keyed by their stable same-origin href. */
|
|
68
|
+
searchLinks?: Readonly<Record<string, string>>;
|
|
69
|
+
/** Search-link descriptions keyed by their stable same-origin href. */
|
|
70
|
+
searchLinkDescriptions?: Readonly<Record<string, string>>;
|
|
53
71
|
};
|
|
54
72
|
|
|
55
73
|
export type AppPresentationCatalog = {
|
|
56
|
-
/** Locale of the complete `name`, `description`, `adminNav`, and `
|
|
74
|
+
/** Locale of the complete `name`, `description`, `adminNav`, `legalLinks`, and `searchLinks` declaration. */
|
|
57
75
|
baseLocale: string;
|
|
58
76
|
/** Partial presentation overlays with exact -> ancestor -> base fallback. */
|
|
59
77
|
translations: Readonly<Record<string, AppPresentationTranslation>>;
|
|
@@ -87,6 +105,8 @@ export type AppMeta = {
|
|
|
87
105
|
* contributes its own (e.g. settings → terms/privacy/imprint, faq → FAQ).
|
|
88
106
|
*/
|
|
89
107
|
legalLinks?: LegalLink[];
|
|
108
|
+
/** Static search destinations, visible when the app is in the user's navigation catalog. */
|
|
109
|
+
searchLinks?: readonly AppSearchLink[];
|
|
90
110
|
/**
|
|
91
111
|
* Dashboard widget endpoints this app exposes. Each entry references an
|
|
92
112
|
* HTTP endpoint that returns a `WidgetResponse` (see `contracts/widgets.ts`).
|
|
@@ -111,7 +131,7 @@ export type WidgetEndpoint = {
|
|
|
111
131
|
};
|
|
112
132
|
|
|
113
133
|
export type RuntimeAppMeta = AppMeta & {
|
|
114
|
-
help?:
|
|
134
|
+
help?: AppRegistryHelpSummary;
|
|
115
135
|
searchTags?: string[];
|
|
116
136
|
searchHelp?: string;
|
|
117
137
|
searchTagHelp?: AppSearchTagHelpEntry[];
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CapabilityStream,
|
|
3
|
+
type CapabilityStreamDefinition,
|
|
4
|
+
CapabilityStreamPolicySchema,
|
|
5
|
+
CapabilityStreamSchema,
|
|
6
|
+
} from "./capability-streams";
|
|
7
|
+
|
|
8
|
+
export * from "./capability-streams";
|
|
9
|
+
|
|
1
10
|
import { z } from "zod";
|
|
11
|
+
import { CommandPathSchema } from "./commands";
|
|
2
12
|
import type { AccessSubject, RequestActor, User } from "./shared";
|
|
3
13
|
|
|
4
|
-
export const CAPABILITY_PROTOCOL_VERSION =
|
|
14
|
+
export const CAPABILITY_PROTOCOL_VERSION = 2 as const;
|
|
5
15
|
export const CAPABILITY_MAX_REQUEST_BYTES = 256 * 1024;
|
|
6
16
|
export const CAPABILITY_MAX_RESULT_BYTES = 256 * 1024;
|
|
7
17
|
export const CAPABILITY_MAX_CATALOG_BYTES = 2 * 1024 * 1024;
|
|
@@ -14,6 +24,8 @@ export const CAPABILITY_FRAMEWORK_ERROR_CODES = {
|
|
|
14
24
|
idempotencyKeyRequired: "IDEMPOTENCY_KEY_REQUIRED",
|
|
15
25
|
idempotencyKeyNotAllowed: "IDEMPOTENCY_KEY_NOT_ALLOWED",
|
|
16
26
|
idempotencyConflict: "IDEMPOTENCY_CONFLICT",
|
|
27
|
+
idempotencyInProgress: "IDEMPOTENCY_IN_PROGRESS",
|
|
28
|
+
idempotencyUncertain: "IDEMPOTENCY_UNCERTAIN",
|
|
17
29
|
deadlineExceeded: "DEADLINE_EXCEEDED",
|
|
18
30
|
actionOutcomeUnknown: "ACTION_OUTCOME_UNKNOWN",
|
|
19
31
|
requestCancelled: "REQUEST_CANCELLED",
|
|
@@ -32,6 +44,17 @@ export const capabilityIdempotencyConflict = (
|
|
|
32
44
|
...(details ? { details } : {}),
|
|
33
45
|
});
|
|
34
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Cloud surface a capability invocation came from. The dispatcher resolves it
|
|
49
|
+
* once, records it on the execution row, and forwards it to the owning app.
|
|
50
|
+
*/
|
|
51
|
+
export const CAPABILITY_ORIGINS = ["assistant", "mcp", "http", "app"] as const;
|
|
52
|
+
export type CapabilityOrigin = (typeof CAPABILITY_ORIGINS)[number];
|
|
53
|
+
export const CapabilityOriginSchema = z.enum(CAPABILITY_ORIGINS);
|
|
54
|
+
|
|
55
|
+
/** Transports the resolved origin from the Cloud dispatcher to the app endpoint. */
|
|
56
|
+
export const CAPABILITY_ORIGIN_HEADER = "x-cloud-capability-origin";
|
|
57
|
+
|
|
35
58
|
export const CapabilityIdempotencyKeySchema = z
|
|
36
59
|
.string()
|
|
37
60
|
.trim()
|
|
@@ -94,10 +117,13 @@ const CapabilityActionReviewDetailSchema = z
|
|
|
94
117
|
label: z.string().min(1).max(120),
|
|
95
118
|
value: z.string().max(10_000),
|
|
96
119
|
display: z.enum(["inline", "block"]).optional(),
|
|
97
|
-
format: z.enum(["date", "date-time"]).optional(),
|
|
120
|
+
format: z.enum(["date", "date-time", "markdown"]).optional(),
|
|
98
121
|
})
|
|
99
122
|
.strict()
|
|
100
123
|
.superRefine((detail, context) => {
|
|
124
|
+
if (detail.format === "markdown" && detail.display !== "block") {
|
|
125
|
+
context.addIssue({ code: "custom", path: ["display"], message: "Markdown review details require block display" });
|
|
126
|
+
}
|
|
101
127
|
const schema =
|
|
102
128
|
detail.format === "date" ? CapabilityReviewDateSchema : detail.format === "date-time" ? CapabilityReviewDateTimeSchema : null;
|
|
103
129
|
if (schema?.safeParse(detail.value).success === false) {
|
|
@@ -175,6 +201,7 @@ export const capabilityDataAtPath = (data: unknown, path: readonly string[]): un
|
|
|
175
201
|
|
|
176
202
|
export type CapabilityResult<T> = {
|
|
177
203
|
data: T;
|
|
204
|
+
stream?: CapabilityStream;
|
|
178
205
|
/** Provider-authored, user-facing summary of the successful result. Render as escaped plain text. */
|
|
179
206
|
summary?: string;
|
|
180
207
|
refs?: CloudResourceReference[];
|
|
@@ -190,6 +217,7 @@ export const capabilityResultSchema = <T extends z.ZodType>(
|
|
|
190
217
|
z
|
|
191
218
|
.object({
|
|
192
219
|
data,
|
|
220
|
+
stream: CapabilityStreamSchema.optional(),
|
|
193
221
|
summary: z.string().trim().min(1).max(500).optional(),
|
|
194
222
|
refs: z.array(CloudResourceReferenceSchema).max(100).optional(),
|
|
195
223
|
page: CapabilityPageSchema.optional(),
|
|
@@ -264,6 +292,9 @@ export const UniversalSearchInputSchema = z
|
|
|
264
292
|
.object({
|
|
265
293
|
query: z.string().max(500).describe("User-entered search text. Empty text is allowed when a facet narrows the query."),
|
|
266
294
|
tags: z.array(z.string().min(1).max(64)).max(20).describe("Canonical search facets supported by this query."),
|
|
295
|
+
scope: CloudResourceRefSchema.optional().describe(
|
|
296
|
+
"Optional resource containing the search results; must be an explicitly supported scope type.",
|
|
297
|
+
),
|
|
267
298
|
limit: z.number().int().min(1).max(100).describe("Maximum number of results to return."),
|
|
268
299
|
})
|
|
269
300
|
.strict();
|
|
@@ -285,6 +316,14 @@ export type CapabilityExecutionContext = {
|
|
|
285
316
|
* error codes and data must not depend on it.
|
|
286
317
|
*/
|
|
287
318
|
locale: string;
|
|
319
|
+
/**
|
|
320
|
+
* Correlation id of the originating Cloud request. Write it into the app's
|
|
321
|
+
* own audit rows so a capability execution record and the app's domain trail
|
|
322
|
+
* can be joined without sharing payloads.
|
|
323
|
+
*/
|
|
324
|
+
requestId: string;
|
|
325
|
+
/** Cloud surface that invoked this capability. */
|
|
326
|
+
origin: CapabilityOrigin;
|
|
288
327
|
signal: AbortSignal;
|
|
289
328
|
};
|
|
290
329
|
|
|
@@ -304,6 +343,8 @@ export type CapabilitySearchTagDefinition = {
|
|
|
304
343
|
|
|
305
344
|
export type CapabilityUniversalSearchDefinition = {
|
|
306
345
|
tags: readonly CapabilitySearchTagDefinition[];
|
|
346
|
+
/** Local resource types whose contents this Query can search. */
|
|
347
|
+
scopeTypes?: readonly string[];
|
|
307
348
|
};
|
|
308
349
|
|
|
309
350
|
export type CapabilitySchemaPresentation = Readonly<Record<string, string>>;
|
|
@@ -323,6 +364,7 @@ export type CapabilityPresentationTranslation = {
|
|
|
323
364
|
types?: Readonly<Record<string, { title?: string; description?: string }>>;
|
|
324
365
|
queries?: Readonly<Record<string, CapabilityOperationPresentationTranslation>>;
|
|
325
366
|
actions?: Readonly<Record<string, CapabilityOperationPresentationTranslation>>;
|
|
367
|
+
commands?: Readonly<Record<string, Pick<CapabilityOperationPresentationTranslation, "title" | "description" | "input">>>;
|
|
326
368
|
};
|
|
327
369
|
|
|
328
370
|
export type CapabilityPresentationCatalog = {
|
|
@@ -338,6 +380,7 @@ export type CapabilityQueryDefinition<Input extends z.ZodType = z.ZodType<any>,
|
|
|
338
380
|
input: Input;
|
|
339
381
|
data: Data;
|
|
340
382
|
openWorld: boolean;
|
|
383
|
+
stream?: CapabilityStreamDefinition;
|
|
341
384
|
universalSearch?: CapabilityUniversalSearchDefinition;
|
|
342
385
|
run: (
|
|
343
386
|
input: z.output<Input>,
|
|
@@ -346,7 +389,7 @@ export type CapabilityQueryDefinition<Input extends z.ZodType = z.ZodType<any>,
|
|
|
346
389
|
};
|
|
347
390
|
|
|
348
391
|
export type CapabilityIdempotencyPolicy = "none" | "required";
|
|
349
|
-
export type CapabilityActionApprovalPolicy = "rememberable";
|
|
392
|
+
export type CapabilityActionApprovalPolicy = "rememberable" | "none";
|
|
350
393
|
|
|
351
394
|
export type CapabilityActionDefinition<Input extends z.ZodType = z.ZodType<any>, Data extends z.ZodType = z.ZodType<any>> = {
|
|
352
395
|
title: string;
|
|
@@ -355,6 +398,7 @@ export type CapabilityActionDefinition<Input extends z.ZodType = z.ZodType<any>,
|
|
|
355
398
|
data: Data;
|
|
356
399
|
destructive: boolean;
|
|
357
400
|
openWorld: boolean;
|
|
401
|
+
stream?: CapabilityStreamDefinition;
|
|
358
402
|
idempotency: CapabilityIdempotencyPolicy;
|
|
359
403
|
approval?: CapabilityActionApprovalPolicy;
|
|
360
404
|
review?: (
|
|
@@ -367,6 +411,29 @@ export type CapabilityActionDefinition<Input extends z.ZodType = z.ZodType<any>,
|
|
|
367
411
|
) => CapabilityInvocationResult<z.output<Data>> | Promise<CapabilityInvocationResult<z.output<Data>>>;
|
|
368
412
|
};
|
|
369
413
|
|
|
414
|
+
/** A declarative UI entry. Resolution never executes application code or writes domain data. */
|
|
415
|
+
export type CapabilityCommandDefinition = {
|
|
416
|
+
title: string;
|
|
417
|
+
description: string;
|
|
418
|
+
icon?: string;
|
|
419
|
+
keywords?: readonly string[];
|
|
420
|
+
input: z.ZodType;
|
|
421
|
+
path: string;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
export const CapabilityCommandManifestSchema = z
|
|
425
|
+
.object({
|
|
426
|
+
localId: CapabilityLocalIdSchema,
|
|
427
|
+
title: z.string().min(1).max(120),
|
|
428
|
+
description: z.string().min(1).max(1000),
|
|
429
|
+
icon: z.string().min(1).max(120).optional(),
|
|
430
|
+
keywords: z.array(z.string().min(1).max(120)).max(30),
|
|
431
|
+
inputSchema: z.record(z.string(), z.unknown()),
|
|
432
|
+
path: CommandPathSchema,
|
|
433
|
+
})
|
|
434
|
+
.strict();
|
|
435
|
+
export type CapabilityCommandManifest = z.infer<typeof CapabilityCommandManifestSchema>;
|
|
436
|
+
|
|
370
437
|
type CapabilityDefinitionCatalog<T> = Readonly<Record<string, T>>;
|
|
371
438
|
|
|
372
439
|
export type CapabilityDefinitions = {
|
|
@@ -375,6 +442,7 @@ export type CapabilityDefinitions = {
|
|
|
375
442
|
types?: CapabilityDefinitionCatalog<CapabilityResourceTypeDefinition>;
|
|
376
443
|
queries?: CapabilityDefinitionCatalog<CapabilityQueryDefinition>;
|
|
377
444
|
actions?: CapabilityDefinitionCatalog<CapabilityActionDefinition>;
|
|
445
|
+
commands?: CapabilityDefinitionCatalog<CapabilityCommandDefinition>;
|
|
378
446
|
};
|
|
379
447
|
|
|
380
448
|
/**
|
|
@@ -409,6 +477,7 @@ const CapabilityOperationManifestBaseSchema = z
|
|
|
409
477
|
description: z.string().min(1).max(1000),
|
|
410
478
|
inputSchema: z.record(z.string(), z.unknown()),
|
|
411
479
|
dataSchema: z.record(z.string(), z.unknown()),
|
|
480
|
+
stream: CapabilityStreamPolicySchema.optional(),
|
|
412
481
|
schemaHash: z.string().regex(/^[a-f0-9]{64}$/),
|
|
413
482
|
})
|
|
414
483
|
.strict();
|
|
@@ -416,7 +485,7 @@ const CapabilityOperationManifestBaseSchema = z
|
|
|
416
485
|
export const CapabilityQueryManifestSchema = CapabilityOperationManifestBaseSchema.extend({
|
|
417
486
|
openWorld: z.boolean(),
|
|
418
487
|
universalSearch: z
|
|
419
|
-
.object({ tags: z.array(CapabilitySearchTagManifestSchema).max(100) })
|
|
488
|
+
.object({ tags: z.array(CapabilitySearchTagManifestSchema).max(100), scopeTypes: z.array(CapabilityLocalIdSchema).max(100).optional() })
|
|
420
489
|
.strict()
|
|
421
490
|
.optional(),
|
|
422
491
|
}).strict();
|
|
@@ -425,7 +494,7 @@ export const CapabilityActionManifestSchema = CapabilityOperationManifestBaseSch
|
|
|
425
494
|
destructive: z.boolean(),
|
|
426
495
|
openWorld: z.boolean(),
|
|
427
496
|
idempotency: z.enum(["none", "required"]),
|
|
428
|
-
approval: z.
|
|
497
|
+
approval: z.enum(["rememberable", "none"]).optional(),
|
|
429
498
|
review: z.literal(true).optional(),
|
|
430
499
|
}).strict();
|
|
431
500
|
|
|
@@ -443,6 +512,7 @@ export const CapabilityManifestSchema = z
|
|
|
443
512
|
types: z.array(CapabilityResourceTypeManifestSchema).max(200),
|
|
444
513
|
queries: z.array(CapabilityQueryManifestSchema).max(200),
|
|
445
514
|
actions: z.array(CapabilityActionManifestSchema).max(200),
|
|
515
|
+
commands: z.array(CapabilityCommandManifestSchema).max(200),
|
|
446
516
|
})
|
|
447
517
|
.strict();
|
|
448
518
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CapabilityExecutionContext, CapabilityResult } from "./capabilities";
|
|
3
|
+
|
|
4
|
+
/** One binary payload. Provider IDs are limited to 2 KiB UTF-8; Core seals them into opaque references, never URLs. */
|
|
5
|
+
export const CapabilityStreamSchema = z
|
|
6
|
+
.object({
|
|
7
|
+
id: z.string().min(1).max(8192),
|
|
8
|
+
direction: z.enum(["read", "write"]),
|
|
9
|
+
name: z.string().min(1).max(255).optional(),
|
|
10
|
+
mediaType: z
|
|
11
|
+
.string()
|
|
12
|
+
.min(1)
|
|
13
|
+
.max(255)
|
|
14
|
+
.regex(/^[\x20-\x7e]+$/),
|
|
15
|
+
size: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
16
|
+
expiresAt: z.iso.datetime(),
|
|
17
|
+
})
|
|
18
|
+
.strict();
|
|
19
|
+
export type CapabilityStream = z.infer<typeof CapabilityStreamSchema>;
|
|
20
|
+
export const CapabilityStreamPolicySchema = z
|
|
21
|
+
.object({
|
|
22
|
+
direction: z.enum(["read", "write"]),
|
|
23
|
+
maxBytes: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
24
|
+
})
|
|
25
|
+
.strict();
|
|
26
|
+
export const CapabilityStreamStatusSchema = z.discriminatedUnion("state", [
|
|
27
|
+
z.object({ state: z.literal("open") }).strict(),
|
|
28
|
+
z.object({ state: z.literal("aborted") }).strict(),
|
|
29
|
+
z.object({ state: z.literal("completed"), result: z.unknown() }).strict(),
|
|
30
|
+
]);
|
|
31
|
+
export type CapabilityStreamStatus = z.infer<typeof CapabilityStreamStatusSchema>;
|
|
32
|
+
export type CapabilityStreamDefinition = z.infer<typeof CapabilityStreamPolicySchema> &
|
|
33
|
+
(
|
|
34
|
+
| { direction: "read"; read: (stream: CapabilityStream, context: CapabilityExecutionContext) => Promise<Response> }
|
|
35
|
+
| {
|
|
36
|
+
direction: "write";
|
|
37
|
+
/** Consume completely, then publish. Must reconcile retries using stream.id. */
|
|
38
|
+
write: (
|
|
39
|
+
stream: CapabilityStream,
|
|
40
|
+
body: ReadableStream<Uint8Array>,
|
|
41
|
+
context: CapabilityExecutionContext,
|
|
42
|
+
) => Promise<CapabilityResult<unknown>>;
|
|
43
|
+
status: (stream: CapabilityStream, context: CapabilityExecutionContext) => Promise<CapabilityStreamStatus>;
|
|
44
|
+
abort: (stream: CapabilityStream, context: CapabilityExecutionContext) => Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
);
|