apps 1.0.0-beta.0 → 1.0.0-beta.2

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 CHANGED
@@ -49,5 +49,6 @@ export default defineTool({
49
49
 
50
50
  The root export is pure and synchronous — no effect dependency, no node
51
51
  builtins — so authored files run unmodified anywhere, including sandboxed
52
- workers. Host machinery lives behind subpaths (`apps/manifest`,
53
- `apps/runner`) and requires `effect`.
52
+ workers. `apps/runtime` is the single execution core every environment
53
+ shares; host machinery lives behind `apps/manifest` and `apps/runner` and
54
+ requires `effect`.
@@ -10,17 +10,17 @@ import {
10
10
  service,
11
11
  setActiveRegistry,
12
12
  toolSpecOf
13
- } from "../index-8wmxmfhc.js";
13
+ } from "../chunk-LWKQDDLZ.js";
14
14
  export {
15
- toolSpecOf,
16
- setActiveRegistry,
17
- service,
18
- secrets,
19
- requirementSpecOf,
20
- oauth,
21
- newRegistry,
22
- defineTool,
23
- defineApp,
15
+ __enterFile,
24
16
  __leaveFile,
25
- __enterFile
17
+ defineApp,
18
+ defineTool,
19
+ newRegistry,
20
+ oauth,
21
+ requirementSpecOf,
22
+ secrets,
23
+ service,
24
+ setActiveRegistry,
25
+ toolSpecOf
26
26
  };
@@ -0,0 +1,99 @@
1
+ import {
2
+ __enterFile,
3
+ __leaveFile,
4
+ newRegistry,
5
+ setActiveRegistry
6
+ } from "./chunk-LWKQDDLZ.js";
7
+ import {
8
+ PublishError
9
+ } from "./chunk-B7NEUIJL.js";
10
+ import {
11
+ manifestOf
12
+ } from "./chunk-OGCPVWAZ.js";
13
+
14
+ // src/manifest/index.ts
15
+ import { fileURLToPath, pathToFileURL } from "node:url";
16
+ import { Effect, FileSystem, MutableRef, Semaphore } from "effect";
17
+ var moduleProblem = (where, error) => `${where}: failed to execute (${error instanceof Error ? error.message : String(error)})`;
18
+ var loadPermit = Semaphore.makeUnsafe(1);
19
+ var runNonce = MutableRef.make(0);
20
+ var importedAppUrls = MutableRef.make(/* @__PURE__ */ new Set());
21
+ var canonicalModuleUrl = (path, where) => FileSystem.FileSystem.pipe(
22
+ Effect.flatMap((fs) => fs.realPath(path)),
23
+ Effect.map(pathToFileURL),
24
+ Effect.mapError((error) => new PublishError({ problems: [moduleProblem(where, error)] }))
25
+ );
26
+ var importModule = (specifier, where) => Effect.tryPromise({
27
+ try: () => import(specifier),
28
+ catch: (error) => new PublishError({ problems: [moduleProblem(where, error)] })
29
+ }).pipe(Effect.asVoid);
30
+ var executeModule = (registry, where, load) => Effect.suspend(() => {
31
+ __enterFile(where);
32
+ return load;
33
+ }).pipe(
34
+ Effect.catchTag(
35
+ "PublishError",
36
+ (error) => Effect.sync(() => {
37
+ registry.problems.push(...error.problems.map((message) => ({ message })));
38
+ })
39
+ )
40
+ );
41
+ var appEntrySpecifier = (appUrl, nonce) => {
42
+ const seen = MutableRef.get(importedAppUrls);
43
+ if (!seen.has(appUrl.href)) {
44
+ MutableRef.set(importedAppUrls, /* @__PURE__ */ new Set([...seen, appUrl.href]));
45
+ return appUrl.href;
46
+ }
47
+ return `${fileURLToPath(appUrl)}?m=${nonce}`;
48
+ };
49
+ var executeModules = (appDir, files) => loadPermit.withPermit(
50
+ Effect.acquireUseRelease(
51
+ Effect.sync(() => {
52
+ const registry = newRegistry();
53
+ return { registry, previous: setActiveRegistry(registry) };
54
+ }),
55
+ ({ registry }) => Effect.gen(function* () {
56
+ const nonce = MutableRef.incrementAndGet(runNonce);
57
+ yield* executeModule(
58
+ registry,
59
+ "app.ts",
60
+ canonicalModuleUrl(`${appDir}/app.ts`, "app.ts").pipe(
61
+ Effect.flatMap((appUrl) => importModule(appEntrySpecifier(appUrl, nonce), "app.ts"))
62
+ )
63
+ );
64
+ for (const file of files) {
65
+ const where = `tools/${file}`;
66
+ yield* executeModule(
67
+ registry,
68
+ where,
69
+ canonicalModuleUrl(`${appDir}/tools/${file}`, where).pipe(
70
+ Effect.flatMap((url) => importModule(`${fileURLToPath(url)}?m=${nonce}`, where))
71
+ )
72
+ );
73
+ }
74
+ return registry;
75
+ }),
76
+ ({ previous }) => Effect.sync(() => {
77
+ __leaveFile();
78
+ setActiveRegistry(previous);
79
+ })
80
+ )
81
+ );
82
+ var toolFiles = (appDir) => FileSystem.FileSystem.pipe(
83
+ Effect.flatMap((fs) => fs.readDirectory(`${appDir}/tools`)),
84
+ Effect.mapError((error) => new PublishError({ problems: [`tools/: ${error.message}`] })),
85
+ Effect.map((entries) => entries.filter((file) => file.endsWith(".ts")).sort())
86
+ );
87
+ var loadApp = (appDir) => Effect.gen(function* () {
88
+ const files = yield* toolFiles(appDir);
89
+ const registry = yield* executeModules(appDir, files);
90
+ const outcome = yield* Effect.promise(() => manifestOf(registry));
91
+ if (!outcome.ok) return yield* new PublishError({ problems: outcome.problems });
92
+ return { registry, result: outcome.result };
93
+ });
94
+ var manifest = (appDir) => Effect.map(loadApp(appDir), ({ result }) => result);
95
+
96
+ export {
97
+ loadApp,
98
+ manifest
99
+ };
@@ -1,13 +1,14 @@
1
1
  // src/manifest/contract.ts
2
2
  import { Data, Schema } from "effect";
3
3
  var JsonSchemaObject = Schema.Record(Schema.String, Schema.Json);
4
-
5
- class PublishError extends Data.TaggedError("PublishError") {
4
+ var PublishError = class extends Data.TaggedError("PublishError") {
6
5
  get message() {
7
6
  return `publish failed:
8
- ${this.problems.map((problem) => ` - ${problem}`).join(`
9
- `)}`;
7
+ ${this.problems.map((problem) => ` - ${problem}`).join("\n")}`;
10
8
  }
11
- }
9
+ };
12
10
 
13
- export { JsonSchemaObject, PublishError };
11
+ export {
12
+ JsonSchemaObject,
13
+ PublishError
14
+ };
@@ -4,12 +4,12 @@ var oauth = (opts) => ({ kind: "oauth", ...opts });
4
4
  var RequirementKey = Symbol.for("executor/apps/requirement");
5
5
  var DynamicKey = Symbol.for("executor/apps/dynamic");
6
6
  var newRegistry = () => ({
7
- app: undefined,
8
- services: new Map,
9
- tools: new Map,
10
- dynamic: new Map,
7
+ app: void 0,
8
+ services: /* @__PURE__ */ new Map(),
9
+ tools: /* @__PURE__ */ new Map(),
10
+ dynamic: /* @__PURE__ */ new Map(),
11
11
  problems: [],
12
- toolFiles: new Map
12
+ toolFiles: /* @__PURE__ */ new Map()
13
13
  });
14
14
  var activeRegistry = newRegistry();
15
15
  var currentFile;
@@ -22,11 +22,10 @@ var __enterFile = (path) => {
22
22
  currentFile = path;
23
23
  };
24
24
  var __leaveFile = () => {
25
- currentFile = undefined;
25
+ currentFile = void 0;
26
26
  };
27
27
  var sourceFileFor = (claim) => {
28
- if (currentFile !== undefined)
29
- return currentFile;
28
+ if (currentFile !== void 0) return currentFile;
30
29
  activeRegistry.problems.push({
31
30
  message: `${claim} called outside an authored module import`
32
31
  });
@@ -51,16 +50,14 @@ var service = (decl) => {
51
50
  activeRegistry.services.set(decl.origin, { decl, file });
52
51
  return value;
53
52
  };
54
- var isRequirement = (value) => typeof value === "object" && value !== null && (RequirementKey in value);
55
- var isService = (value) => isRequirement(value) && ("decl" in value) && ("optional" in value) && ("array" in value) && ("grant" in value);
56
- var requirementSpecOf = (value) => isService(value) || isRequirement(value) ? value[RequirementKey] : undefined;
53
+ var isRequirement = (value) => typeof value === "object" && value !== null && RequirementKey in value;
54
+ var isService = (value) => isRequirement(value) && "decl" in value && "optional" in value && "array" in value && "grant" in value;
55
+ var requirementSpecOf = (value) => isService(value) || isRequirement(value) ? value[RequirementKey] : void 0;
57
56
  var defineApp = (manifest) => {
58
57
  const file = sourceFileFor("defineApp(...)");
59
58
  const value = { kind: "executor-app", ...manifest };
60
- if (activeRegistry.app === undefined)
61
- activeRegistry.app = value;
62
- else
63
- activeRegistry.problems.push({ message: `${file}: duplicate defineApp(...)` });
59
+ if (activeRegistry.app === void 0) activeRegistry.app = value;
60
+ else activeRegistry.problems.push({ message: `${file}: duplicate defineApp(...)` });
64
61
  return value;
65
62
  };
66
63
  var ToolKey = Symbol.for("executor/apps/tool");
@@ -73,18 +70,29 @@ var defineTool = (spec) => {
73
70
  const fileSummary = activeRegistry.toolFiles.get(file);
74
71
  activeRegistry.toolFiles.set(file, {
75
72
  definitions: (fileSummary?.definitions ?? 0) + 1,
76
- hasUnnamedTool: fileSummary?.hasUnnamedTool === true || spec.name === undefined
73
+ hasUnnamedTool: fileSummary?.hasUnnamedTool === true || spec.name === void 0
77
74
  });
78
75
  const existing = activeRegistry.tools.get(name);
79
- if (existing !== undefined) {
76
+ if (existing !== void 0) {
80
77
  activeRegistry.problems.push({
81
78
  message: `${file}: tool name '${name}' is already defined in ${existing.file}`
82
79
  });
83
- } else
84
- activeRegistry.tools.set(name, { spec, file });
80
+ } else activeRegistry.tools.set(name, { spec, file });
85
81
  return value;
86
82
  };
87
- var isTool = (value) => typeof value === "object" && value !== null && (ToolKey in value);
88
- var toolSpecOf = (value) => isTool(value) ? value[ToolKey] : undefined;
83
+ var isTool = (value) => typeof value === "object" && value !== null && ToolKey in value;
84
+ var toolSpecOf = (value) => isTool(value) ? value[ToolKey] : void 0;
89
85
 
90
- export { secrets, oauth, newRegistry, setActiveRegistry, __enterFile, __leaveFile, service, requirementSpecOf, defineApp, defineTool, toolSpecOf };
86
+ export {
87
+ secrets,
88
+ oauth,
89
+ newRegistry,
90
+ setActiveRegistry,
91
+ __enterFile,
92
+ __leaveFile,
93
+ service,
94
+ requirementSpecOf,
95
+ defineApp,
96
+ defineTool,
97
+ toolSpecOf
98
+ };
@@ -1,10 +1,11 @@
1
1
  // src/runner/protocol.ts
2
2
  import { Data } from "effect";
3
-
4
- class CallError extends Data.TaggedError("CallError") {
3
+ var CallError = class extends Data.TaggedError("CallError") {
5
4
  get message() {
6
5
  return `${this.target}: ${this.reason}`;
7
6
  }
8
- }
7
+ };
9
8
 
10
- export { CallError };
9
+ export {
10
+ CallError
11
+ };
@@ -0,0 +1,191 @@
1
+ // src/runtime/index.ts
2
+ var failure = (reason) => ({ ok: false, reason });
3
+ var errorMessage = (error) => error instanceof Error ? error.message : String(error);
4
+ var isJsonValue = (value) => {
5
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
6
+ if (typeof value === "number") return Number.isFinite(value);
7
+ if (Array.isArray(value)) return value.every(isJsonValue);
8
+ if (typeof value !== "object") return false;
9
+ return Object.values(value).every(isJsonValue);
10
+ };
11
+ var standardJsonSchemaOf = (input) => "~standard" in input ? input["~standard"].jsonSchema : void 0;
12
+ var strictify = (node) => {
13
+ if (typeof node !== "object" || node === null) return node;
14
+ if (Array.isArray(node)) return node.map(strictify);
15
+ const object = { ...node };
16
+ if (object.type === "object" && object.additionalProperties === void 0)
17
+ object.additionalProperties = false;
18
+ for (const key of ["items", "anyOf", "oneOf", "allOf"])
19
+ if (key in object) object[key] = strictify(object[key]);
20
+ for (const key of ["properties", "$defs"])
21
+ if (object[key] !== void 0 && typeof object[key] === "object" && object[key] !== null)
22
+ object[key] = Object.fromEntries(
23
+ Object.entries(object[key]).map(([name, value]) => [
24
+ name,
25
+ strictify(value)
26
+ ])
27
+ );
28
+ return object;
29
+ };
30
+ var compileInputSchema = (input, where) => {
31
+ const standard = standardJsonSchemaOf(input);
32
+ if ("~standard" in input && typeof standard?.input !== "function")
33
+ return {
34
+ problem: `${where}: input is a Standard Schema without the jsonSchema extension \u2014 use a library that implements it (zod 4+, effect Schema) or pass raw JSON schema`
35
+ };
36
+ try {
37
+ const compiled = strictify(
38
+ typeof standard?.input === "function" ? standard.input({ target: "draft-2020-12" }) : structuredClone(input)
39
+ );
40
+ if (typeof compiled !== "object" || compiled === null || Array.isArray(compiled) || !isJsonValue(compiled))
41
+ throw new Error("expected a JSON object");
42
+ return { value: compiled };
43
+ } catch (error) {
44
+ return {
45
+ problem: `${where}: input schema could not compile to JSON schema (${errorMessage(error)})`
46
+ };
47
+ }
48
+ };
49
+ var requirementKey = Symbol.for("executor/apps/requirement");
50
+ var requirementSpecOf = (value) => typeof value === "object" && value !== null && requirementKey in value ? value[requirementKey] : void 0;
51
+ var canonicalJson = (value) => {
52
+ const sortKeys = (node) => {
53
+ if (Array.isArray(node)) return node.map(sortKeys);
54
+ if (typeof node === "object" && node !== null)
55
+ return Object.fromEntries(
56
+ Object.entries(node).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, sortKeys(child)])
57
+ );
58
+ return node;
59
+ };
60
+ return JSON.stringify(sortKeys(value));
61
+ };
62
+ var collectRegistry = (registry) => {
63
+ const problems = registry.problems.map((problem) => problem.message);
64
+ const app = registry.app;
65
+ const claims = /* @__PURE__ */ new Map();
66
+ for (const [origin, registered] of registry.services) {
67
+ if (registered.file !== "app.ts") continue;
68
+ const { decl } = registered;
69
+ claims.set(origin, {
70
+ origin,
71
+ reach: decl.reach ?? [],
72
+ params: decl.params ?? {},
73
+ auth: decl.auth ?? {}
74
+ });
75
+ }
76
+ const collectRequirement = (role, requirement, where) => {
77
+ const spec = requirementSpecOf(requirement);
78
+ if (spec === void 0) {
79
+ problems.push(`${where}: requirement '${role}' is not a service/requirement value`);
80
+ return void 0;
81
+ }
82
+ const origin = spec.service.origin;
83
+ if (!claims.has(origin))
84
+ problems.push(`${where}: requirement '${role}' names ${origin}, which app.ts does not declare`);
85
+ if (spec.grant !== void 0 && !(spec.grant in (spec.service.auth ?? {})))
86
+ problems.push(
87
+ `${where}: requirement '${role}' pins grant '${spec.grant}', not a auth method on ${origin}`
88
+ );
89
+ return {
90
+ role,
91
+ service: origin,
92
+ arity: spec.arity,
93
+ ...spec.grant === void 0 ? {} : { grant: spec.grant },
94
+ ...spec.description === void 0 ? {} : { description: spec.description }
95
+ };
96
+ };
97
+ if (app === void 0) problems.push("app.ts must call defineApp({...})");
98
+ else if (typeof app.description !== "string" || app.description.trim().length === 0)
99
+ problems.push("app.ts: app description must not be empty");
100
+ for (const [file, summary] of registry.toolFiles) {
101
+ if (summary.definitions > 1 && summary.hasUnnamedTool)
102
+ problems.push(`${file}: multi-tool files must name every tool`);
103
+ }
104
+ const tools = [];
105
+ if (app !== void 0) {
106
+ for (const [name, registered] of registry.tools) {
107
+ const { spec, file } = registered;
108
+ const address = `${app.key}/${name}`;
109
+ if (typeof spec.description !== "string" || spec.description.trim().length === 0)
110
+ problems.push(`${file}: tool '${name}' description must not be empty`);
111
+ const requires = Object.entries(spec.requirements ?? {}).flatMap(([role, requirement]) => {
112
+ const collected = collectRequirement(role, requirement, address);
113
+ return collected === void 0 ? [] : [collected];
114
+ }).sort((left, right) => left.role.localeCompare(right.role));
115
+ const compiled = compileInputSchema(spec.input, address);
116
+ if ("problem" in compiled) {
117
+ problems.push(compiled.problem);
118
+ continue;
119
+ }
120
+ tools.push({
121
+ address,
122
+ name,
123
+ description: spec.description,
124
+ inputSchema: compiled.value,
125
+ annotations: spec.annotations ?? {},
126
+ requires,
127
+ file
128
+ });
129
+ }
130
+ }
131
+ if (problems.length > 0 || app === void 0) return { problems };
132
+ const services = [...claims.values()].sort(
133
+ (left, right) => left.origin.localeCompare(right.origin)
134
+ );
135
+ const sortedTools = [...tools].sort((left, right) => left.address.localeCompare(right.address));
136
+ const appResult = { key: app.key, label: app.label, description: app.description };
137
+ const manifest = { app: appResult, services, tools: sortedTools };
138
+ return { problems: [], manifest, canonical: canonicalJson(manifest) };
139
+ };
140
+ var digestOf = async (canonical) => {
141
+ const bytes = new Uint8Array(
142
+ await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonical))
143
+ );
144
+ return Array.from(bytes.slice(0, 8), (byte) => byte.toString(16).padStart(2, "0")).join("");
145
+ };
146
+ var manifestOf = async (registry) => {
147
+ const collected = collectRegistry(registry);
148
+ if (collected.problems.length > 0) return { ok: false, problems: collected.problems };
149
+ if (!("manifest" in collected))
150
+ return { ok: false, problems: ["validated registry projection unexpectedly missing"] };
151
+ return {
152
+ ok: true,
153
+ result: { digest: `snap:${await digestOf(collected.canonical)}`, ...collected.manifest }
154
+ };
155
+ };
156
+ var standardValidateOf = (input) => "~standard" in input && typeof input["~standard"].validate === "function" ? input["~standard"].validate : void 0;
157
+ var parseInput = async (spec, input) => {
158
+ const validate = standardValidateOf(spec.input);
159
+ if (validate === void 0)
160
+ return { ok: false, reason: "input schema does not implement Standard Schema validate" };
161
+ try {
162
+ const result = await validate(input);
163
+ if (result.issues !== void 0)
164
+ return {
165
+ ok: false,
166
+ reason: `invalid input (${result.issues.map((issue) => issue.message).join("; ")})`
167
+ };
168
+ return { ok: true, value: result.value };
169
+ } catch (error) {
170
+ return { ok: false, reason: `input validation threw (${errorMessage(error)})` };
171
+ }
172
+ };
173
+ var callTool = async (registry, name, input, ctx) => {
174
+ const registered = registry.tools.get(name);
175
+ if (registered === void 0) return failure("unknown tool");
176
+ const parsed = await parseInput(registered.spec, input);
177
+ if (!parsed.ok) return parsed;
178
+ try {
179
+ const handler = registered.spec.handler;
180
+ return { ok: true, value: await handler(parsed.value, ctx) };
181
+ } catch (error) {
182
+ return failure(`handler failed (${errorMessage(error)})`);
183
+ }
184
+ };
185
+ var discoverTool = async (_registry, _name, _binding) => failure("no dynamic tools yet");
186
+
187
+ export {
188
+ manifestOf,
189
+ callTool,
190
+ discoverTool
191
+ };
package/dist/index.d.ts CHANGED
@@ -1,9 +1 @@
1
- /**
2
- * The authoring surface: what app code imports. Pure and synchronous —
3
- * no effect dependency, no node builtins — so authored files run
4
- * unmodified in any execution environment, including sandboxed workers.
5
- *
6
- * Host-side machinery lives behind subpaths: "apps/manifest" loads and
7
- * validates authored sources, "apps/runner" executes them.
8
- */
9
1
  export * from "./authoring/index";
package/dist/index.js CHANGED
@@ -10,17 +10,17 @@ import {
10
10
  service,
11
11
  setActiveRegistry,
12
12
  toolSpecOf
13
- } from "./index-8wmxmfhc.js";
13
+ } from "./chunk-LWKQDDLZ.js";
14
14
  export {
15
- toolSpecOf,
16
- setActiveRegistry,
17
- service,
18
- secrets,
19
- requirementSpecOf,
20
- oauth,
21
- newRegistry,
22
- defineTool,
23
- defineApp,
15
+ __enterFile,
24
16
  __leaveFile,
25
- __enterFile
17
+ defineApp,
18
+ defineTool,
19
+ newRegistry,
20
+ oauth,
21
+ requirementSpecOf,
22
+ secrets,
23
+ service,
24
+ setActiveRegistry,
25
+ toolSpecOf
26
26
  };
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  JsonSchemaObject,
3
3
  PublishError
4
- } from "../index-mcjwntr2.js";
4
+ } from "../chunk-B7NEUIJL.js";
5
5
  export {
6
- PublishError,
7
- JsonSchemaObject
6
+ JsonSchemaObject,
7
+ PublishError
8
8
  };
@@ -1,9 +1,11 @@
1
1
  /**
2
- * Manifest: execute an authored app folder, read its registry, validate
3
- * every claim, and emit the deterministic publish manifest. Defines run
4
- * without user context; platform services begin at this boundary.
2
+ * Manifest: execute an authored app folder and project its registry.
3
+ * This module owns exactly what differs on a host with a filesystem —
4
+ * finding and importing authored modules. Everything after the modules
5
+ * load (validation, canonicalization, digesting) is the shared
6
+ * execution core in ../runtime; sandboxed guests run that same core.
5
7
  */
6
- import { Crypto, Effect, FileSystem } from "effect";
8
+ import { Effect, FileSystem } from "effect";
7
9
  import { type Registry } from "../authoring/index";
8
10
  import { PublishError, type AppManifestResult } from "./contract";
9
11
  export * from "./contract";
@@ -13,6 +15,6 @@ export interface LoadedApp {
13
15
  readonly result: AppManifestResult;
14
16
  }
15
17
  /** Loads an app once and returns both its live registry and manifest. @internal */
16
- export declare const loadApp: (appDir: string) => Effect.Effect<LoadedApp, PublishError, Crypto.Crypto | FileSystem.FileSystem>;
18
+ export declare const loadApp: (appDir: string) => Effect.Effect<LoadedApp, PublishError, FileSystem.FileSystem>;
17
19
  /** Executes an app and returns its deterministic publish manifest. */
18
- export declare const manifest: (appDir: string) => Effect.Effect<AppManifestResult, PublishError, Crypto.Crypto | FileSystem.FileSystem>;
20
+ export declare const manifest: (appDir: string) => Effect.Effect<AppManifestResult, PublishError, FileSystem.FileSystem>;
@@ -1,15 +1,16 @@
1
1
  import {
2
2
  loadApp,
3
3
  manifest
4
- } from "../index-wfngzvv2.js";
5
- import"../index-8wmxmfhc.js";
4
+ } from "../chunk-646MS7DD.js";
5
+ import "../chunk-LWKQDDLZ.js";
6
6
  import {
7
7
  JsonSchemaObject,
8
8
  PublishError
9
- } from "../index-mcjwntr2.js";
9
+ } from "../chunk-B7NEUIJL.js";
10
+ import "../chunk-OGCPVWAZ.js";
10
11
  export {
11
- manifest,
12
- loadApp,
12
+ JsonSchemaObject,
13
13
  PublishError,
14
- JsonSchemaObject
14
+ loadApp,
15
+ manifest
15
16
  };
@@ -1,61 +1,52 @@
1
1
  import {
2
2
  loadApp
3
- } from "../index-wfngzvv2.js";
4
- import"../index-8wmxmfhc.js";
5
- import"../index-mcjwntr2.js";
3
+ } from "../chunk-646MS7DD.js";
4
+ import "../chunk-LWKQDDLZ.js";
5
+ import "../chunk-B7NEUIJL.js";
6
6
  import {
7
7
  CallError
8
- } from "../index-dh4z81es.js";
8
+ } from "../chunk-NFLNA2SC.js";
9
+ import {
10
+ callTool,
11
+ discoverTool
12
+ } from "../chunk-OGCPVWAZ.js";
9
13
 
10
14
  // src/runner/index.ts
11
15
  import { Effect } from "effect";
12
- var hasStandardValidate = (input) => ("~standard" in input) && typeof input["~standard"].validate === "function";
13
- var parseInput = (name, spec, input) => {
14
- if (!hasStandardValidate(spec.input))
15
- return Effect.fail(new CallError({ target: name, reason: "input schema does not implement Standard Schema validate" }));
16
- const standard = spec.input["~standard"];
17
- return Effect.tryPromise({
18
- try: () => Promise.resolve(standard.validate(input)),
19
- catch: (error) => new CallError({
20
- target: name,
21
- reason: `input validation threw (${error instanceof Error ? error.message : String(error)})`
22
- })
23
- }).pipe(Effect.flatMap((result) => result.issues === undefined ? Effect.succeed(result.value) : Effect.fail(new CallError({
24
- target: name,
25
- reason: `invalid input (${result.issues.map((issue) => issue.message).join("; ")})`
26
- }))));
27
- };
28
16
  var localRunner = (appDir) => {
29
17
  let cachedLoad;
30
18
  const loaded = () => Effect.suspend(() => {
31
- if (cachedLoad !== undefined)
32
- return cachedLoad;
33
- return Effect.flatMap(Effect.cached(loadApp(appDir)), (effect) => Effect.sync(() => {
34
- cachedLoad = effect;
35
- return effect;
36
- }).pipe(Effect.flatten));
19
+ if (cachedLoad !== void 0) return cachedLoad;
20
+ return Effect.flatMap(
21
+ Effect.cached(loadApp(appDir)),
22
+ (effect) => Effect.sync(() => {
23
+ cachedLoad = effect;
24
+ return effect;
25
+ }).pipe(Effect.flatten)
26
+ );
37
27
  });
38
- const loadedFor = (target) => loaded().pipe(Effect.mapError((error) => new CallError({ target, reason: `app failed to load (${error.message})` })));
28
+ const registryFor = (target) => loaded().pipe(
29
+ Effect.map(({ registry }) => registry),
30
+ Effect.mapError(
31
+ (error) => new CallError({ target, reason: `app failed to load (${error.message})` })
32
+ )
33
+ );
34
+ const settle = (target, outcome) => outcome.ok ? Effect.succeed(outcome.value) : Effect.fail(new CallError({ target, reason: outcome.reason }));
39
35
  return {
40
36
  manifest: () => Effect.map(loaded(), ({ result }) => result),
41
- call: (name, input, ctx) => Effect.gen(function* () {
42
- const { registry } = yield* loadedFor(name);
43
- const registered = registry.tools.get(name);
44
- if (registered === undefined)
45
- return yield* new CallError({ target: name, reason: "unknown tool" });
46
- const parsed = yield* parseInput(name, registered.spec, input);
47
- return yield* Effect.tryPromise({
48
- try: () => registered.spec.handler(parsed, ctx),
49
- catch: (error) => new CallError({
50
- target: name,
51
- reason: `handler failed (${error instanceof Error ? error.message : String(error)})`
52
- })
53
- });
54
- }),
55
- discover: (name, _binding) => Effect.fail(new CallError({ target: name, reason: "no dynamic tools yet" }))
37
+ call: (name, input, ctx) => registryFor(name).pipe(
38
+ Effect.flatMap((registry) => Effect.promise(() => callTool(registry, name, input, ctx))),
39
+ Effect.flatMap((outcome) => settle(name, outcome))
40
+ ),
41
+ discover: (name, binding) => registryFor(name).pipe(
42
+ Effect.flatMap(
43
+ (registry) => Effect.promise(() => discoverTool(registry, name, binding))
44
+ ),
45
+ Effect.flatMap((outcome) => settle(name, outcome))
46
+ )
56
47
  };
57
48
  };
58
49
  export {
59
- localRunner,
60
- CallError
50
+ CallError,
51
+ localRunner
61
52
  };