@rivet-dev/agentos-core 0.0.0-integrate-dylib-into-main.815fcda → 0.0.0-main.29b0797

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 (125) hide show
  1. package/README.md +43 -43
  2. package/dist/agent-os.d.ts +313 -226
  3. package/dist/agent-os.js +1418 -1545
  4. package/dist/agentos-package.d.ts +31 -0
  5. package/dist/agentos-package.js +91 -0
  6. package/dist/base-filesystem.d.ts +2 -15
  7. package/dist/base-filesystem.js +23 -171
  8. package/dist/{host-tools-zod.d.ts → bindings-zod.d.ts} +1 -1
  9. package/dist/{host-tools-zod.js → bindings-zod.js} +52 -25
  10. package/dist/bindings.d.ts +43 -0
  11. package/dist/bindings.js +34 -0
  12. package/dist/cron/cron-manager.js +43 -10
  13. package/dist/cron/index.d.ts +1 -1
  14. package/dist/cron/types.d.ts +26 -10
  15. package/dist/default-software.d.ts +8 -0
  16. package/dist/default-software.js +10 -0
  17. package/dist/filesystem-snapshot.d.ts +1 -2
  18. package/dist/filesystem-snapshot.js +0 -43
  19. package/dist/generated/AcpLimitsConfig.d.ts +20 -0
  20. package/dist/generated/AcpLimitsConfig.js +2 -0
  21. package/dist/generated/BindingLimitsConfig.d.ts +10 -0
  22. package/dist/generated/BindingLimitsConfig.js +2 -0
  23. package/dist/generated/CreateVmConfig.d.ts +28 -0
  24. package/dist/generated/FsPermissionRule.d.ts +6 -0
  25. package/dist/generated/FsPermissionRule.js +1 -0
  26. package/dist/generated/FsPermissionRuleSet.d.ts +6 -0
  27. package/dist/generated/FsPermissionRuleSet.js +1 -0
  28. package/dist/generated/FsPermissionScope.d.ts +3 -0
  29. package/dist/generated/FsPermissionScope.js +1 -0
  30. package/dist/generated/HttpLimitsConfig.d.ts +3 -0
  31. package/dist/generated/HttpLimitsConfig.js +2 -0
  32. package/dist/generated/JsModuleResolution.d.ts +1 -0
  33. package/dist/generated/JsModuleResolution.js +2 -0
  34. package/dist/generated/JsRuntimeConfig.d.ts +31 -0
  35. package/dist/generated/JsRuntimeConfig.js +1 -0
  36. package/dist/generated/JsRuntimeLimitsConfig.d.ts +11 -0
  37. package/dist/generated/JsRuntimeLimitsConfig.js +2 -0
  38. package/dist/generated/JsRuntimePlatform.d.ts +1 -0
  39. package/dist/generated/JsRuntimePlatform.js +2 -0
  40. package/dist/generated/MountPluginDescriptor.d.ts +4 -0
  41. package/dist/generated/MountPluginDescriptor.js +2 -0
  42. package/dist/generated/NativeRootFilesystemConfig.d.ts +5 -0
  43. package/dist/generated/NativeRootFilesystemConfig.js +1 -0
  44. package/dist/generated/PatternPermissionRule.d.ts +6 -0
  45. package/dist/generated/PatternPermissionRule.js +1 -0
  46. package/dist/generated/PatternPermissionRuleSet.d.ts +6 -0
  47. package/dist/generated/PatternPermissionRuleSet.js +1 -0
  48. package/dist/generated/PatternPermissionScope.d.ts +3 -0
  49. package/dist/generated/PatternPermissionScope.js +1 -0
  50. package/dist/generated/PermissionMode.d.ts +1 -0
  51. package/dist/generated/PermissionMode.js +2 -0
  52. package/dist/generated/PermissionsPolicy.d.ts +10 -0
  53. package/dist/generated/PermissionsPolicy.js +1 -0
  54. package/dist/generated/PluginLimitsConfig.d.ts +4 -0
  55. package/dist/generated/PluginLimitsConfig.js +2 -0
  56. package/dist/generated/ProcessLimitsConfig.d.ts +7 -0
  57. package/dist/generated/ProcessLimitsConfig.js +2 -0
  58. package/dist/generated/PythonLimitsConfig.d.ts +6 -0
  59. package/dist/generated/PythonLimitsConfig.js +2 -0
  60. package/dist/generated/ResourceLimitsConfig.d.ts +24 -0
  61. package/dist/generated/ResourceLimitsConfig.js +2 -0
  62. package/dist/generated/RootFilesystemConfig.d.ts +9 -0
  63. package/dist/generated/RootFilesystemConfig.js +1 -0
  64. package/dist/generated/RootFilesystemEntry.d.ts +13 -0
  65. package/dist/generated/RootFilesystemEntry.js +1 -0
  66. package/dist/generated/RootFilesystemEntryEncoding.d.ts +1 -0
  67. package/dist/generated/RootFilesystemEntryEncoding.js +2 -0
  68. package/dist/generated/RootFilesystemEntryKind.d.ts +1 -0
  69. package/dist/generated/RootFilesystemEntryKind.js +2 -0
  70. package/dist/generated/RootFilesystemLowerDescriptor.d.ts +7 -0
  71. package/dist/generated/RootFilesystemLowerDescriptor.js +1 -0
  72. package/dist/generated/RootFilesystemMode.d.ts +1 -0
  73. package/dist/generated/RootFilesystemMode.js +2 -0
  74. package/dist/generated/VmDnsConfig.d.ts +6 -0
  75. package/dist/generated/VmDnsConfig.js +2 -0
  76. package/dist/generated/VmGroupConfig.d.ts +5 -0
  77. package/dist/generated/VmGroupConfig.js +2 -0
  78. package/dist/generated/VmLimitsConfig.d.ts +20 -0
  79. package/dist/generated/VmLimitsConfig.js +1 -0
  80. package/dist/generated/VmListenPolicyConfig.d.ts +5 -0
  81. package/dist/generated/VmListenPolicyConfig.js +2 -0
  82. package/dist/generated/VmUserAccountConfig.d.ts +9 -0
  83. package/dist/generated/VmUserAccountConfig.js +2 -0
  84. package/dist/generated/VmUserConfig.d.ts +19 -0
  85. package/dist/generated/VmUserConfig.js +1 -0
  86. package/dist/generated/WasmLimitsConfig.d.ts +8 -0
  87. package/dist/generated/WasmLimitsConfig.js +2 -0
  88. package/dist/host-dir-mount.d.ts +1 -1
  89. package/dist/index.d.ts +6 -5
  90. package/dist/index.js +5 -5
  91. package/dist/layers.d.ts +7 -4
  92. package/dist/layers.js +0 -176
  93. package/dist/options-schema.d.ts +556 -0
  94. package/dist/options-schema.js +386 -0
  95. package/dist/packages.d.ts +17 -116
  96. package/dist/packages.js +35 -322
  97. package/dist/runtime-compat.d.ts +33 -46
  98. package/dist/runtime-compat.js +197 -511
  99. package/dist/runtime.d.ts +42 -8
  100. package/dist/sandbox.d.ts +112 -0
  101. package/dist/sandbox.js +264 -0
  102. package/dist/session-api.d.ts +180 -0
  103. package/dist/session-api.js +1 -0
  104. package/dist/sidecar/agentos-protocol.d.ts +509 -20
  105. package/dist/sidecar/agentos-protocol.js +808 -81
  106. package/dist/sidecar/native-process-client.d.ts +6 -2
  107. package/dist/sidecar/native-process-client.js +8 -1
  108. package/dist/sidecar/permissions.d.ts +1 -1
  109. package/dist/sidecar/permissions.js +4 -4
  110. package/dist/sidecar/rpc-client.d.ts +100 -9
  111. package/dist/sidecar/rpc-client.js +445 -110
  112. package/dist/test/runtime.d.ts +2 -1
  113. package/dist/test/runtime.js +2 -1
  114. package/dist/test/terminal-harness.js +0 -3
  115. package/dist/types.d.ts +13 -7
  116. package/package.json +46 -35
  117. package/dist/agent-session-types.d.ts +0 -67
  118. package/dist/agents.d.ts +0 -63
  119. package/dist/agents.js +0 -42
  120. package/dist/host-tools.d.ts +0 -45
  121. package/dist/host-tools.js +0 -26
  122. package/dist/overlay-filesystem.d.ts +0 -19
  123. package/dist/overlay-filesystem.js +0 -645
  124. package/fixtures/AGENTOS_SYSTEM_PROMPT.md +0 -21
  125. /package/dist/{agent-session-types.js → generated/CreateVmConfig.js} +0 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * agentOS package model (Linux-exact, Homebrew-modeled) — client-facing surface.
3
+ *
4
+ * A package is a self-contained directory produced by `@rivet-dev/agentos-toolchain
5
+ * pack`. The HOST no longer projects it: the client forwards only the package
6
+ * directory over the wire and the secure-exec sidecar owns the `/opt/agentos`
7
+ * projection. Package metadata lives in `<dir>/agentos-package.json`.
8
+ *
9
+ * This module is therefore only the client-facing package-dir surface plus the
10
+ * `/opt/agentos` path constants used for agent-config wiring.
11
+ *
12
+ * See `website/src/content/docs/docs/architecture/packages-and-command-resolution.mdx`.
13
+ */
14
+ import type { AgentosPackageManifest, PackageAgentDescriptor, PackageRef as ManifestPackageRef } from "@agentos-software/manifest";
15
+ /** Root of the agentOS package tree inside the VM. */
16
+ export declare const OPT_AGENTOS_ROOT = "/opt/agentos";
17
+ /** The symlink farm on `$PATH` (commands link here). */
18
+ export declare const OPT_AGENTOS_BIN = "/opt/agentos/bin";
19
+ export type AgentBlock = PackageAgentDescriptor;
20
+ export type PackageRef = ManifestPackageRef;
21
+ export type SoftwarePackageRef = {
22
+ packagePath: string;
23
+ };
24
+ /** Portable descriptor used to link a package into a running VM. */
25
+ export interface PackageDescriptor {
26
+ path: string;
27
+ }
28
+ /** Discriminate the dir-only package reference. */
29
+ export declare function isPackageDescriptor(value: unknown): value is PackageDescriptor;
30
+ export declare function readAgentosPackageManifest(dir: string): AgentosPackageManifest;
31
+ export declare function tryReadAgentosPackageManifest(dir: string): AgentosPackageManifest | undefined;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * agentOS package model (Linux-exact, Homebrew-modeled) — client-facing surface.
3
+ *
4
+ * A package is a self-contained directory produced by `@rivet-dev/agentos-toolchain
5
+ * pack`. The HOST no longer projects it: the client forwards only the package
6
+ * directory over the wire and the secure-exec sidecar owns the `/opt/agentos`
7
+ * projection. Package metadata lives in `<dir>/agentos-package.json`.
8
+ *
9
+ * This module is therefore only the client-facing package-dir surface plus the
10
+ * `/opt/agentos` path constants used for agent-config wiring.
11
+ *
12
+ * See `website/src/content/docs/docs/architecture/packages-and-command-resolution.mdx`.
13
+ */
14
+ import { readFileSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ /** Root of the agentOS package tree inside the VM. */
17
+ export const OPT_AGENTOS_ROOT = "/opt/agentos";
18
+ /** The symlink farm on `$PATH` (commands link here). */
19
+ export const OPT_AGENTOS_BIN = "/opt/agentos/bin";
20
+ /** Discriminate the dir-only package reference. */
21
+ export function isPackageDescriptor(value) {
22
+ return (typeof value === "object" &&
23
+ value !== null &&
24
+ !Array.isArray(value) &&
25
+ typeof value.path === "string");
26
+ }
27
+ export function readAgentosPackageManifest(dir) {
28
+ const manifestPath = join(dir, "agentos-package.json");
29
+ let parsed;
30
+ try {
31
+ parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
32
+ }
33
+ catch (error) {
34
+ const wrapped = new Error(`Failed to read agentOS package manifest at ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`);
35
+ wrapped.code = error.code;
36
+ throw wrapped;
37
+ }
38
+ return validateAgentosPackageManifest(parsed, manifestPath);
39
+ }
40
+ export function tryReadAgentosPackageManifest(dir) {
41
+ try {
42
+ return readAgentosPackageManifest(dir);
43
+ }
44
+ catch (error) {
45
+ if (error instanceof Error &&
46
+ error.code === "ENOENT") {
47
+ return undefined;
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ function validateAgentosPackageManifest(value, source) {
53
+ if (!isPlainObject(value) || typeof value.name !== "string") {
54
+ throw new Error(`Invalid agentOS package manifest at ${source}: missing name`);
55
+ }
56
+ if (typeof value.version !== "string") {
57
+ throw new Error(`Invalid agentOS package manifest at ${source}: missing version`);
58
+ }
59
+ const manifest = {
60
+ name: value.name,
61
+ version: value.version,
62
+ };
63
+ if (value.agent !== undefined) {
64
+ if (!isPlainObject(value.agent) ||
65
+ typeof value.agent.acpEntrypoint !== "string") {
66
+ throw new Error(`Invalid agentOS package manifest at ${source}: invalid agent.acpEntrypoint`);
67
+ }
68
+ manifest.agent = {
69
+ acpEntrypoint: value.agent.acpEntrypoint,
70
+ ...(isStringRecord(value.agent.env) ? { env: value.agent.env } : {}),
71
+ ...(Array.isArray(value.agent.launchArgs) &&
72
+ value.agent.launchArgs.every((arg) => typeof arg === "string")
73
+ ? { launchArgs: value.agent.launchArgs }
74
+ : {}),
75
+ ...(typeof value.agent.snapshot === "boolean"
76
+ ? { snapshot: value.agent.snapshot }
77
+ : {}),
78
+ };
79
+ }
80
+ if (value.provides !== undefined) {
81
+ manifest.provides = value.provides;
82
+ }
83
+ return manifest;
84
+ }
85
+ function isPlainObject(value) {
86
+ return typeof value === "object" && value !== null && !Array.isArray(value);
87
+ }
88
+ function isStringRecord(value) {
89
+ return (isPlainObject(value) &&
90
+ Object.values(value).every((entry) => typeof entry === "string"));
91
+ }
@@ -1,5 +1,4 @@
1
- import { type FilesystemEntry } from "./filesystem-snapshot.js";
2
- import { type VirtualFileSystem } from "./runtime-compat.js";
1
+ import type { FilesystemEntry } from "./filesystem-snapshot.js";
3
2
  export interface BaseFilesystemEnvironment {
4
3
  env: Record<string, string>;
5
4
  prompt: string;
@@ -18,17 +17,5 @@ export interface BaseFilesystemSnapshot {
18
17
  entries: BaseFilesystemEntry[];
19
18
  };
20
19
  }
21
- export declare function createBaseLowerFilesystem(): Promise<VirtualFileSystem>;
22
- export declare function createBootstrapAwareFilesystem(filesystem: VirtualFileSystem, existingRoot: VirtualFileSystem, options?: {
23
- readOnlyAfterBootstrap?: boolean;
24
- }): {
25
- filesystem: VirtualFileSystem;
26
- finishKernelBootstrap: () => void;
27
- };
28
- export declare function getBaseFilesystemSnapshot(): BaseFilesystemSnapshot;
20
+ /** The default VM environment (a fresh, mutable copy per call). */
29
21
  export declare function getBaseEnvironment(): Record<string, string>;
30
- export declare function getBaseFilesystemEntries(): BaseFilesystemEntry[];
31
- export declare function createBaseRootFilesystem(): Promise<{
32
- filesystem: VirtualFileSystem;
33
- finishKernelBootstrap: () => void;
34
- }>;
@@ -1,173 +1,25 @@
1
- import { readFileSync } from "node:fs";
2
- import { createRequire } from "node:module";
3
- import * as posixPath from "node:path/posix";
4
- import { createFilesystemFromEntries, } from "./filesystem-snapshot.js";
5
- import { createOverlayBackend } from "./overlay-filesystem.js";
6
- import { KernelError } from "./runtime-compat.js";
7
- const require = createRequire(import.meta.url);
8
- const SNAPSHOT_PATH = require.resolve("@secure-exec/core/fixtures/base-filesystem.json");
9
- const SUPPRESSED_KERNEL_BOOTSTRAP_DIRS = new Set([
10
- "/boot",
11
- "/usr/games",
12
- "/usr/include",
13
- "/usr/libexec",
14
- "/usr/man",
15
- ]);
16
- const SUPPRESSED_KERNEL_BOOTSTRAP_FILES = new Set(["/usr/bin/env"]);
17
- let snapshotCache = null;
18
- function loadSnapshot() {
19
- if (snapshotCache) {
20
- return snapshotCache;
21
- }
22
- snapshotCache = JSON.parse(readFileSync(SNAPSHOT_PATH, "utf-8"));
23
- return snapshotCache;
24
- }
25
- function normalizePath(path) {
26
- const normalized = posixPath.normalize(path);
27
- return normalized === "." ? "/" : normalized;
28
- }
29
- export async function createBaseLowerFilesystem() {
30
- return createFilesystemFromEntries(getBaseFilesystemEntries());
31
- }
32
- export function createBootstrapAwareFilesystem(filesystem, existingRoot, options) {
33
- let bootstrapActive = true;
34
- let writesLocked = false;
35
- function throwReadOnly() {
36
- throw new KernelError("EROFS", "read-only file system");
37
- }
38
- async function rootHasPath(path) {
39
- try {
40
- return await existingRoot.exists(path);
41
- }
42
- catch {
43
- return false;
44
- }
45
- }
46
- const wrapped = {
47
- ...filesystem,
48
- async createDir(path) {
49
- if (writesLocked) {
50
- throwReadOnly();
51
- }
52
- const normalized = normalizePath(path);
53
- if (bootstrapActive &&
54
- SUPPRESSED_KERNEL_BOOTSTRAP_DIRS.has(normalized) &&
55
- !(await rootHasPath(normalized))) {
56
- return;
57
- }
58
- return filesystem.createDir(path);
59
- },
60
- async mkdir(path, options) {
61
- if (writesLocked) {
62
- if (options?.recursive && (await rootHasPath(path))) {
63
- return;
64
- }
65
- throwReadOnly();
66
- }
67
- const normalized = normalizePath(path);
68
- if (bootstrapActive &&
69
- options?.recursive &&
70
- SUPPRESSED_KERNEL_BOOTSTRAP_DIRS.has(normalized) &&
71
- !(await rootHasPath(normalized))) {
72
- return;
73
- }
74
- return filesystem.mkdir(path, options);
75
- },
76
- async writeFile(path, content) {
77
- if (writesLocked) {
78
- throwReadOnly();
79
- }
80
- const normalized = normalizePath(path);
81
- if (bootstrapActive &&
82
- SUPPRESSED_KERNEL_BOOTSTRAP_FILES.has(normalized)) {
83
- return;
84
- }
85
- return filesystem.writeFile(path, content);
86
- },
87
- async removeFile(path) {
88
- if (writesLocked) {
89
- throwReadOnly();
90
- }
91
- return filesystem.removeFile(path);
92
- },
93
- async removeDir(path) {
94
- if (writesLocked) {
95
- throwReadOnly();
96
- }
97
- return filesystem.removeDir(path);
98
- },
99
- async rename(oldPath, newPath) {
100
- if (writesLocked) {
101
- throwReadOnly();
102
- }
103
- return filesystem.rename(oldPath, newPath);
104
- },
105
- async symlink(target, linkPath) {
106
- if (writesLocked) {
107
- throwReadOnly();
108
- }
109
- return filesystem.symlink(target, linkPath);
110
- },
111
- async link(oldPath, newPath) {
112
- if (writesLocked) {
113
- throwReadOnly();
114
- }
115
- return filesystem.link(oldPath, newPath);
116
- },
117
- async chmod(path, mode) {
118
- if (writesLocked) {
119
- throwReadOnly();
120
- }
121
- return filesystem.chmod(path, mode);
122
- },
123
- async chown(path, uid, gid) {
124
- if (writesLocked) {
125
- throwReadOnly();
126
- }
127
- return filesystem.chown(path, uid, gid);
128
- },
129
- async utimes(path, atime, mtime) {
130
- if (writesLocked) {
131
- throwReadOnly();
132
- }
133
- return filesystem.utimes(path, atime, mtime);
134
- },
135
- async truncate(path, length) {
136
- if (writesLocked) {
137
- throwReadOnly();
138
- }
139
- return filesystem.truncate(path, length);
140
- },
141
- async pwrite(path, offset, data) {
142
- if (writesLocked) {
143
- throwReadOnly();
144
- }
145
- return filesystem.pwrite(path, offset, data);
146
- },
147
- };
148
- return {
149
- filesystem: wrapped,
150
- finishKernelBootstrap() {
151
- bootstrapActive = false;
152
- writesLocked = options?.readOnlyAfterBootstrap ?? false;
153
- },
154
- };
155
- }
156
- export function getBaseFilesystemSnapshot() {
157
- return loadSnapshot();
158
- }
1
+ /**
2
+ * The base VM environment, baked in as a constant (verbatim from the single
3
+ * `base-filesystem.json` the sidecar embeds). The host no longer reads that JSON
4
+ * — the sidecar owns the base filesystem, and there is exactly one committed copy
5
+ * of it (`secure-exec/crates/vfs/assets/base-filesystem.json`). Regenerate both
6
+ * this constant and that file together with the build-tools snapshot script.
7
+ */
8
+ const BASE_ENVIRONMENT = Object.freeze({
9
+ CHARSET: "UTF-8",
10
+ HOME: "/home/agentos",
11
+ HOSTNAME: "secure-exec",
12
+ LANG: "C.UTF-8",
13
+ LC_COLLATE: "C",
14
+ LOGNAME: "agentos",
15
+ PAGER: "less",
16
+ PATH: "/usr/local/sbin:/usr/local/bin:/opt/agentos/bin:/usr/sbin:/usr/bin:/sbin:/bin",
17
+ MANPATH: "/opt/agentos/share/man:/usr/local/share/man:/usr/share/man",
18
+ SHELL: "/bin/sh",
19
+ USER: "agentos",
20
+ PS1: "\\h:\\w\\$ ",
21
+ });
22
+ /** The default VM environment (a fresh, mutable copy per call). */
159
23
  export function getBaseEnvironment() {
160
- const snapshot = loadSnapshot();
161
- return {
162
- ...snapshot.environment.env,
163
- PS1: snapshot.environment.prompt,
164
- };
165
- }
166
- export function getBaseFilesystemEntries() {
167
- return loadSnapshot().filesystem.entries;
168
- }
169
- export async function createBaseRootFilesystem() {
170
- const lower = await createBaseLowerFilesystem();
171
- const overlay = createOverlayBackend({ lower });
172
- return createBootstrapAwareFilesystem(overlay, lower);
24
+ return { ...BASE_ENVIRONMENT };
173
25
  }
@@ -1,5 +1,5 @@
1
1
  import type { ZodType } from "zod";
2
- export declare class HostToolSchemaConversionError extends Error {
2
+ export declare class BindingSchemaConversionError extends Error {
3
3
  readonly path: string;
4
4
  readonly zodType: string;
5
5
  constructor(path: string, zodType: string, details?: string);
@@ -1,3 +1,4 @@
1
+ import { zodToJsonSchema as zodV3ToJsonSchema } from "zod-to-json-schema";
1
2
  const OPTIONAL_WRAPPER_TYPES = new Set(["default", "optional"]);
2
3
  const TRANSPARENT_WRAPPER_TYPES = new Set([
3
4
  ...OPTIONAL_WRAPPER_TYPES,
@@ -14,7 +15,7 @@ const UNSUPPORTED_TYPES = new Set([
14
15
  "pipe",
15
16
  "tuple",
16
17
  ]);
17
- export class HostToolSchemaConversionError extends Error {
18
+ export class BindingSchemaConversionError extends Error {
18
19
  path;
19
20
  zodType;
20
21
  constructor(path, zodType, details) {
@@ -24,12 +25,15 @@ export class HostToolSchemaConversionError extends Error {
24
25
  ]
25
26
  .filter(Boolean)
26
27
  .join(" "));
27
- this.name = "HostToolSchemaConversionError";
28
+ this.name = "BindingSchemaConversionError";
28
29
  this.path = path;
29
30
  this.zodType = zodType;
30
31
  }
31
32
  }
32
33
  function getSchemaDef(schema) {
34
+ if (!schema || typeof schema !== "object") {
35
+ return {};
36
+ }
33
37
  return (schema._def ??
34
38
  schema.def ??
35
39
  {});
@@ -46,7 +50,10 @@ function normalizeTypeName(schema) {
46
50
  if (constructorName === "discriminatedunion" || "discriminator" in def) {
47
51
  return "discriminatedunion";
48
52
  }
49
- const rawTypeName = String(def.typeName ?? def.type ?? schema.type ?? constructorName);
53
+ const rawTypeName = String(def.typeName ??
54
+ def.type ??
55
+ schema.type ??
56
+ constructorName);
50
57
  return rawTypeName.replace(/^Zod/, "").toLowerCase();
51
58
  }
52
59
  function displayTypeName(typeName) {
@@ -89,24 +96,24 @@ function isCustomRefinement(check) {
89
96
  }
90
97
  function validateChecks(schema, path, typeName) {
91
98
  if (getChecks(schema).some(isCustomRefinement)) {
92
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "custom refinements cannot be represented faithfully in JSON Schema");
99
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "custom refinements cannot be represented faithfully in JSON Schema");
93
100
  }
94
101
  }
95
102
  function validateSchema(schema, path) {
96
103
  const typeName = normalizeTypeName(schema);
97
104
  if (metadataProducesRefs(schema)) {
98
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "metadata that emits $ref/$defs is not supported");
105
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "metadata that emits $ref/$defs is not supported");
99
106
  }
100
107
  if (UNSUPPORTED_TYPES.has(typeName)) {
101
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName));
108
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName));
102
109
  }
103
110
  if (typeName === "discriminatedunion") {
104
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName));
111
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName));
105
112
  }
106
113
  if (TRANSPARENT_WRAPPER_TYPES.has(typeName)) {
107
114
  const inner = getInnerSchema(schema);
108
115
  if (!inner) {
109
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "wrapper schema is missing its inner schema");
116
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "wrapper schema is missing its inner schema");
110
117
  }
111
118
  validateSchema(inner, path);
112
119
  return;
@@ -114,7 +121,7 @@ function validateSchema(schema, path) {
114
121
  if (typeName === "nullable") {
115
122
  const inner = getInnerSchema(schema);
116
123
  if (!inner) {
117
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "nullable schema is missing its inner schema");
124
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "nullable schema is missing its inner schema");
118
125
  }
119
126
  validateSchema(inner, path);
120
127
  return;
@@ -131,9 +138,10 @@ function validateSchema(schema, path) {
131
138
  return;
132
139
  }
133
140
  if (typeName === "array") {
134
- const itemSchema = getSchemaDef(schema).element;
141
+ const def = getSchemaDef(schema);
142
+ const itemSchema = (def.element ?? def.type);
135
143
  if (!itemSchema) {
136
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "array schema is missing its item schema");
144
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "array schema is missing its item schema");
137
145
  }
138
146
  validateSchema(itemSchema, `${path}[]`);
139
147
  return;
@@ -143,11 +151,11 @@ function validateSchema(schema, path) {
143
151
  const keySchema = def.keyType;
144
152
  const valueSchema = def.valueType;
145
153
  if (!keySchema || !valueSchema) {
146
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "record schema is missing its key or value schema");
154
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "record schema is missing its key or value schema");
147
155
  }
148
156
  const keyTypeName = normalizeTypeName(keySchema);
149
157
  if (keyTypeName !== "string" || getChecks(keySchema).length > 0) {
150
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "record keys must be unconstrained strings");
158
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "record keys must be unconstrained strings");
151
159
  }
152
160
  validateSchema(valueSchema, `${path}<record-value>`);
153
161
  return;
@@ -155,7 +163,7 @@ function validateSchema(schema, path) {
155
163
  if (typeName === "union") {
156
164
  const options = getSchemaDef(schema).options;
157
165
  if (!Array.isArray(options) || options.length === 0) {
158
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "union schema is missing its options");
166
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "union schema is missing its options");
159
167
  }
160
168
  for (let index = 0; index < options.length; index += 1) {
161
169
  validateSchema(options[index], `${path}<union:${index}>`);
@@ -163,12 +171,17 @@ function validateSchema(schema, path) {
163
171
  return;
164
172
  }
165
173
  if (typeName === "literal") {
166
- const values = getSchemaDef(schema).values;
167
- const literalValues = Array.isArray(values) ? values : [];
174
+ const def = getSchemaDef(schema);
175
+ const literalValues = Array.isArray(def.values)
176
+ ? def.values
177
+ : "value" in def
178
+ ? [def.value]
179
+ : [];
168
180
  const [literalValue] = literalValues;
169
181
  if (literalValues.length !== 1 ||
170
- !("string number boolean".split(" ").includes(typeof literalValue) || literalValue === null)) {
171
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "literal values must be JSON primitives");
182
+ !("string number boolean".split(" ").includes(typeof literalValue) ||
183
+ literalValue === null)) {
184
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName), "literal values must be JSON primitives");
172
185
  }
173
186
  return;
174
187
  }
@@ -179,7 +192,7 @@ function validateSchema(schema, path) {
179
192
  typeName === "nativeenum") {
180
193
  return;
181
194
  }
182
- throw new HostToolSchemaConversionError(path, displayTypeName(typeName));
195
+ throw new BindingSchemaConversionError(path, displayTypeName(typeName));
183
196
  }
184
197
  function sanitizeJsonSchema(value) {
185
198
  if (Array.isArray(value)) {
@@ -194,7 +207,9 @@ function sanitizeJsonSchema(value) {
194
207
  if (key === "$schema") {
195
208
  continue;
196
209
  }
197
- if (key === "additionalProperties" && entry === false && record.type === "object") {
210
+ if (key === "additionalProperties" &&
211
+ entry === false &&
212
+ record.type === "object") {
198
213
  continue;
199
214
  }
200
215
  sanitized[key] = sanitizeJsonSchema(entry);
@@ -225,15 +240,27 @@ function findUnsupportedGeneratedKeyword(value, path) {
225
240
  }
226
241
  return null;
227
242
  }
243
+ function generateJsonSchema(schema) {
244
+ const nativeJsonSchema = schema.toJSONSchema?.();
245
+ if (nativeJsonSchema) {
246
+ return nativeJsonSchema;
247
+ }
248
+ const generated = zodV3ToJsonSchema(schema, {
249
+ $refStrategy: "none",
250
+ target: "jsonSchema7",
251
+ });
252
+ if (!generated ||
253
+ (typeof generated === "object" && Object.keys(generated).length === 0)) {
254
+ throw new BindingSchemaConversionError("$", displayTypeName(normalizeTypeName(schema)), "schema cannot be converted to JSON Schema");
255
+ }
256
+ return generated;
257
+ }
228
258
  export function zodToJsonSchema(schema) {
229
259
  validateSchema(schema, "$");
230
- const jsonSchema = schema.toJSONSchema?.();
231
- if (!jsonSchema) {
232
- throw new HostToolSchemaConversionError("$", displayTypeName(normalizeTypeName(schema)), "schema does not expose toJSONSchema()");
233
- }
260
+ const jsonSchema = generateJsonSchema(schema);
234
261
  const unsupportedKeyword = findUnsupportedGeneratedKeyword(jsonSchema, "$");
235
262
  if (unsupportedKeyword) {
236
- throw new HostToolSchemaConversionError("$", displayTypeName(normalizeTypeName(schema)), `${unsupportedKeyword.keyword} emitted at ${unsupportedKeyword.path} is not supported`);
263
+ throw new BindingSchemaConversionError("$", displayTypeName(normalizeTypeName(schema)), `${unsupportedKeyword.keyword} emitted at ${unsupportedKeyword.path} is not supported`);
237
264
  }
238
265
  const sanitized = sanitizeJsonSchema(jsonSchema);
239
266
  const description = getDescription(schema);
@@ -0,0 +1,43 @@
1
+ import type { ZodType } from "zod";
2
+ /** Maximum length for binding descriptions (characters). */
3
+ export declare const MAX_BINDING_DESCRIPTION_LENGTH = 200;
4
+ /**
5
+ * A single binding that executes on the host.
6
+ */
7
+ export interface Binding<INPUT = any, OUTPUT = any> {
8
+ /** Description shown to the agent in --help and prompt docs. Max 200 characters. */
9
+ description: string;
10
+ /** Zod schema for the input. Drives CLI flag generation and validation. */
11
+ inputSchema: ZodType<INPUT>;
12
+ /** Runs on the host when the agent invokes the binding. */
13
+ execute: (input: INPUT) => Promise<OUTPUT> | OUTPUT;
14
+ /** Examples included in auto-generated prompt docs. */
15
+ examples?: BindingExample<INPUT>[];
16
+ /** Timeout in ms. Default: 30000. */
17
+ timeout?: number;
18
+ }
19
+ export interface BindingExample<INPUT = any> {
20
+ /** Human description of what this example does. */
21
+ description: string;
22
+ /** The input args for the example. */
23
+ input: INPUT;
24
+ }
25
+ /**
26
+ * A named collection of bindings. Becomes a CLI binary: agentos-{name}.
27
+ */
28
+ export interface Bindings {
29
+ /** Collection name. Must be lowercase alphanumeric + hyphens. Becomes the CLI suffix: agentos-{name}. */
30
+ name: string;
31
+ /** Description shown in `agentos list-bindings` and prompt docs. */
32
+ description: string;
33
+ /** The bindings in this collection. Keys become subcommands. */
34
+ bindings: Record<string, Binding>;
35
+ }
36
+ /** Helper to create a binding with type inference. */
37
+ export declare function binding<INPUT, OUTPUT>(def: Binding<INPUT, OUTPUT>): Binding<INPUT, OUTPUT>;
38
+ /** Helper to create a named binding collection. */
39
+ export declare function bindings(def: Bindings): Bindings;
40
+ /**
41
+ * Validate every binding collection and binding.
42
+ */
43
+ export declare function validateBindings(collections: Bindings[]): void;
@@ -0,0 +1,34 @@
1
+ /** Maximum length for binding descriptions (characters). */
2
+ export const MAX_BINDING_DESCRIPTION_LENGTH = 200;
3
+ /** Helper to create a binding with type inference. */
4
+ export function binding(def) {
5
+ return def;
6
+ }
7
+ /** Helper to create a named binding collection. */
8
+ export function bindings(def) {
9
+ return def;
10
+ }
11
+ const BINDING_COMMAND_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
12
+ function validateBindingCommandName(kind, name) {
13
+ if (BINDING_COMMAND_NAME_RE.test(name)) {
14
+ return;
15
+ }
16
+ throw new Error(`${kind} name "${name}" must be lowercase alphanumeric with optional single hyphen separators`);
17
+ }
18
+ /**
19
+ * Validate every binding collection and binding.
20
+ */
21
+ export function validateBindings(collections) {
22
+ for (const collection of collections) {
23
+ validateBindingCommandName("Binding collection", collection.name);
24
+ if (collection.description.length > MAX_BINDING_DESCRIPTION_LENGTH) {
25
+ throw new Error(`Binding collection "${collection.name}" description is ${collection.description.length} characters, max is ${MAX_BINDING_DESCRIPTION_LENGTH}`);
26
+ }
27
+ for (const [bindingName, definition] of Object.entries(collection.bindings)) {
28
+ validateBindingCommandName("Binding", bindingName);
29
+ if (definition.description.length > MAX_BINDING_DESCRIPTION_LENGTH) {
30
+ throw new Error(`Binding "${collection.name}/${bindingName}" description is ${definition.description.length} characters, max is ${MAX_BINDING_DESCRIPTION_LENGTH}`);
31
+ }
32
+ }
33
+ }
34
+ }