@evoke-build/evoke 0.6.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/dist/core.js ADDED
@@ -0,0 +1,102 @@
1
+ // The loader: core.wasm instantiated once, on first use, and one function over its three exports — the op and
2
+ // the input written as UTF-8 into buffers the module allocates, the call, the reply read back, every buffer freed.
3
+ // Synchronous: a rule costs microseconds and nothing here waits on the world. Nothing else in the SDK touches the
4
+ // module. In: an op name and one JSON argument object. Out: the raw reply, or the value with its error thrown.
5
+ import { readFileSync } from "node:fs";
6
+ import { DiagnosticError, FaultError } from "./errors.js";
7
+ const encoder = new TextEncoder();
8
+ const decoder = new TextDecoder();
9
+ let loaded;
10
+ /** The module, instantiated once; after a trap it is instantiated again, since a trap leaves its memory as it was. */
11
+ function core() {
12
+ if (loaded === undefined) {
13
+ const module = new WebAssembly.Module(readFileSync(new URL("../core.wasm", import.meta.url)));
14
+ loaded = new WebAssembly.Instance(module, {}).exports;
15
+ }
16
+ return loaded;
17
+ }
18
+ /** One op on one input: the raw reply. A trap in the core is a bug in evoke, thrown as one. A lone surrogate in
19
+ * any string — `JSON.stringify` writes it as an escape, and no Rust string can hold it — crosses as U+FFFD. */
20
+ export function reply(op, input) {
21
+ const wasm = core();
22
+ const opBytes = encoder.encode(op);
23
+ const inputBytes = encoder.encode(JSON.stringify(input).replace(/\\u(d[89a-f][0-9a-f]{2})/gi, "\\ufffd"));
24
+ try {
25
+ const opPtr = wasm.alloc(opBytes.length);
26
+ const inputPtr = wasm.alloc(inputBytes.length);
27
+ // Both views are made after both allocations: growing the memory detaches an earlier view.
28
+ new Uint8Array(wasm.memory.buffer, opPtr, opBytes.length).set(opBytes);
29
+ new Uint8Array(wasm.memory.buffer, inputPtr, inputBytes.length).set(inputBytes);
30
+ const packed = wasm.call(opPtr, opBytes.length, inputPtr, inputBytes.length);
31
+ const ptr = Number(packed >> 32n);
32
+ const len = Number(packed & 0xffffffffn);
33
+ const text = decoder.decode(new Uint8Array(wasm.memory.buffer, ptr, len));
34
+ wasm.free(ptr, len);
35
+ wasm.free(opPtr, opBytes.length);
36
+ wasm.free(inputPtr, inputBytes.length);
37
+ return JSON.parse(text);
38
+ }
39
+ catch (error) {
40
+ if (error instanceof WebAssembly.RuntimeError) {
41
+ loaded = undefined;
42
+ throw new Error(`evoke's core hit a bug in ${op}: ${error.message}`, { cause: error });
43
+ }
44
+ throw error;
45
+ }
46
+ }
47
+ /**
48
+ * One op, typed: the value, or the op's own error thrown as the CLI would print it — a `DiagnosticError` for
49
+ * diagnostics, a `FaultError` for a fault. `invoked` names the SDK call for a fix that says to try again.
50
+ */
51
+ export function call(op, input, invoked = "") {
52
+ const answer = reply(op, input);
53
+ if ("ok" in answer)
54
+ return answer.ok;
55
+ if ("bug" in answer)
56
+ throw bug(answer.bug);
57
+ throw raised(answer.err, invoked);
58
+ }
59
+ /** The command that fixes a problem, rendered by the core. */
60
+ export function command(fix, invoked = "") {
61
+ return call("fix", { fix, invoked });
62
+ }
63
+ /** A diagnostic with its command rendered. */
64
+ export function problem(diagnostic, invoked = "") {
65
+ return { ...diagnostic, command: command(diagnostic.fix, invoked) };
66
+ }
67
+ /** Diagnostics over something given in code — a manifest, words, a gate — where the core's `evoke check`, meant
68
+ * for a file, cannot apply: the fix is the call itself. */
69
+ export function fromCode(diagnostics, invoked) {
70
+ return new DiagnosticError(diagnostics.map(diagnostic => ({ ...diagnostic, command: diagnostic.fix.type === "check" ? invoked : command(diagnostic.fix, invoked) })));
71
+ }
72
+ /** A fault as the error it is, its words and command rendered by the core. */
73
+ export function faulted(fault, invoked = "") {
74
+ const { message, command } = call("fault", { fault, invoked });
75
+ return new FaultError(fault, message, command);
76
+ }
77
+ /** Why a text is no local or vocabulary name by the core's grammar, or nothing when it is one. */
78
+ export function misnamed(text, kind) {
79
+ const answer = reply("name", { text, kind });
80
+ if ("ok" in answer)
81
+ return undefined;
82
+ if ("bug" in answer)
83
+ throw bug(answer.bug);
84
+ return String(answer.err);
85
+ }
86
+ /** A bug in evoke — never a user error. */
87
+ export function bug(message) {
88
+ return new Error(`evoke's core hit a bug: ${message}`);
89
+ }
90
+ /** An op's `err` as the error it is: one diagnostic or several, or a fault; anything else is a bug in the SDK. */
91
+ function raised(err, invoked) {
92
+ if (Array.isArray(err)) {
93
+ return new DiagnosticError(err.map(diagnostic => problem(diagnostic, invoked)));
94
+ }
95
+ if (err !== null && typeof err === "object") {
96
+ if ("fix" in err)
97
+ return new DiagnosticError([problem(err, invoked)]);
98
+ if ("type" in err)
99
+ return faulted(err, invoked);
100
+ }
101
+ return bug(`an error of an unknown shape: ${JSON.stringify(err)}`);
102
+ }
@@ -0,0 +1,109 @@
1
+ import type { Trace } from "./adapter.ts";
2
+ import type { Result } from "./runtime.ts";
3
+ import type * as W from "./types.ts";
4
+ /** The four shapes evoke.d.ts declares, so a generated Reflexes and an inline one are one kind of thing. */
5
+ export type Option<K extends string = string> = {
6
+ type: "option";
7
+ key: K;
8
+ };
9
+ export type Word = {
10
+ type: "word";
11
+ word: string;
12
+ value?: string;
13
+ };
14
+ export type Pick<T extends W.Recognizer = W.Recognizer, V = number | string> = {
15
+ type: "pick";
16
+ span: W.Span;
17
+ value: {
18
+ type: T;
19
+ value: V;
20
+ };
21
+ };
22
+ export type Flag = {
23
+ type: "flag";
24
+ };
25
+ /** An argument's value as the wire carries it. */
26
+ export type Value = W.Value;
27
+ /** What a decision's args carry per reflex when nothing narrows it: any reflex, any arguments. */
28
+ export type AnyReflexes = Record<string, Record<string, Value>>;
29
+ /** A value as a body receives it: the key, the word's value else the word, the number or text, `true`. */
30
+ export type Plain<V> = V extends Option<infer K> ? K : V extends Word ? string : V extends Pick<W.Recognizer, infer X> ? X : V extends Flag ? true : never;
31
+ /** Plain values per argument; an optional argument stays optional. */
32
+ export type Values<A> = {
33
+ [N in keyof A]: Plain<NonNullable<A[N]>>;
34
+ };
35
+ /** What every decision carries beside the core's fields. */
36
+ export interface Line {
37
+ /** The input as decided. */
38
+ input: string;
39
+ /** The digest of the plan it was decided under: `fill` and `run` refuse another. */
40
+ plan: string;
41
+ /** One entry per adapter call. */
42
+ trace: Trace[];
43
+ }
44
+ /** A complete call: the typed args as read, the plain values a body receives, the one call grammar, the effect. */
45
+ export type Chosen<R, K extends keyof R & string> = Line & W.Judged & {
46
+ reflex: K;
47
+ args: R[K];
48
+ values: Values<R[K]>;
49
+ /** `lights room="den" state="off"` */
50
+ call: string;
51
+ effect: W.Effect;
52
+ };
53
+ /** A complete call over the floor: run it. */
54
+ export type Run<R = AnyReflexes> = {
55
+ [K in keyof R & string]: {
56
+ outcome: "run";
57
+ } & Chosen<R, K>;
58
+ }[keyof R & string];
59
+ /** A complete call that needs a yes: the prompt, and every reason in a fixed order. */
60
+ export type Confirm<R = AnyReflexes> = {
61
+ [K in keyof R & string]: {
62
+ outcome: "confirm";
63
+ prompt: W.Prompt;
64
+ because: W.NonEmpty<W.Cap>;
65
+ } & Chosen<R, K>;
66
+ }[keyof R & string];
67
+ /** A winner with required arguments missing: what was read so far, and what to ask. */
68
+ export type Ask<R = AnyReflexes> = {
69
+ [K in keyof R & string]: Line & W.Judged & {
70
+ outcome: "ask";
71
+ reflex: K;
72
+ args: Partial<R[K]>;
73
+ values: Partial<Values<R[K]>>;
74
+ unconsumed: W.Span[];
75
+ missing: W.NonEmpty<W.Missing>;
76
+ };
77
+ }[keyof R & string];
78
+ /** `none` won or the route is under its floor: the ranking, and every judgment. */
79
+ export type Abstain = Line & {
80
+ outcome: "abstain";
81
+ contenders: W.Contender[];
82
+ judgments: W.Judgment[];
83
+ };
84
+ /** One input decided. */
85
+ export type Decision<R = AnyReflexes> = Abstain | Run<R> | Confirm<R> | Ask<R>;
86
+ /** What an ask takes back for one value: an option's key, else the text a person typed. A flag is never asked. */
87
+ type Answer<P> = P extends true ? never : P extends string ? P : string;
88
+ /** What an ask is answered with, by argument name. */
89
+ export type Given<D> = D extends {
90
+ values: Partial<infer V>;
91
+ } ? {
92
+ [N in keyof V as NonNullable<V[N]> extends true ? never : N]?: Answer<NonNullable<V[N]>> | undefined;
93
+ } : never;
94
+ /** What `handle` returns; a failure of any kind throws. */
95
+ export type Handled<R = AnyReflexes> = {
96
+ outcome: "ran";
97
+ decision: Run<R> | Confirm<R>;
98
+ result: Result;
99
+ } | {
100
+ outcome: "abstained";
101
+ decision: Abstain;
102
+ } | {
103
+ outcome: "declined";
104
+ decision: Confirm<R> | Ask<R>;
105
+ } | {
106
+ outcome: "unanswered";
107
+ decision: Confirm<R> | Ask<R>;
108
+ };
109
+ export {};
@@ -0,0 +1,5 @@
1
+ // The decision as an app reads it: the CLI's --json line — the wire decision tagged by outcome — plus what the SDK
2
+ // knows around it: the input as decided, the plan it was decided under, one trace entry per adapter call, and the
3
+ // plain values a body receives beside the typed args. A union narrowed by `outcome`, then by `reflex`. R is what
4
+ // each reflex's arguments carry — `Reflexes` from evoke.d.ts, or inferred from reflexes handed as code.
5
+ export {};
@@ -0,0 +1,32 @@
1
+ import type { Diagnostic, Fault, Fix } from "./types.ts";
2
+ /** Every error evoke raises: its kind, and the command or line that fixes it. */
3
+ export declare abstract class EvokeError extends Error {
4
+ abstract readonly kind: "diagnostic" | "fault" | "failure";
5
+ /** The literal command or line that fixes it; empty when nothing but trying again applies. */
6
+ readonly command: string;
7
+ protected constructor(message: string, command: string, options?: ErrorOptions);
8
+ }
9
+ /** A diagnostic with its command rendered. */
10
+ export type Problem = Diagnostic & {
11
+ command: string;
12
+ };
13
+ /** Something a person fixes in the files or the environment: every problem the core found, each with its fix. */
14
+ export declare class DiagnosticError extends EvokeError {
15
+ readonly kind = "diagnostic";
16
+ readonly problems: readonly Problem[];
17
+ constructor(problems: readonly Problem[]);
18
+ }
19
+ /** The adapter failed, or its answers did not validate. */
20
+ export declare class FaultError extends EvokeError {
21
+ readonly kind = "fault";
22
+ readonly fault: Fault;
23
+ constructor(fault: Fault, message: string, command: string);
24
+ }
25
+ /** A host or a body failed: what was attempted, why, and what to do; a body's own error is the `cause`. */
26
+ export declare class FailureError extends EvokeError {
27
+ readonly kind = "failure";
28
+ readonly what: string;
29
+ readonly why: string | undefined;
30
+ readonly fix: Fix;
31
+ constructor(what: string, why: string | undefined, fix: Fix, command: string, options?: ErrorOptions);
32
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,50 @@
1
+ // The three errors, as the CLI's exits 3, 4 and 1: what went wrong as data, and the line that fixes it, rendered
2
+ // by the core. In: the core's diagnostics or fault, or a host's failure, each with its fixing command already
3
+ // rendered. Out: an Error whose message is the CLI's own line — `<reflex>: <what> → <fix>`, one per problem.
4
+ // `fix` is always the structured value, `command` always the rendered line.
5
+ /** Every error evoke raises: its kind, and the command or line that fixes it. */
6
+ export class EvokeError extends Error {
7
+ /** The literal command or line that fixes it; empty when nothing but trying again applies. */
8
+ command;
9
+ constructor(message, command, options) {
10
+ super(message, options);
11
+ this.name = new.target.name;
12
+ this.command = command;
13
+ }
14
+ }
15
+ /** Something a person fixes in the files or the environment: every problem the core found, each with its fix. */
16
+ export class DiagnosticError extends EvokeError {
17
+ kind = "diagnostic";
18
+ problems;
19
+ constructor(problems) {
20
+ super(problems.map(line).join("\n"), problems[0]?.command ?? "");
21
+ this.problems = problems;
22
+ }
23
+ }
24
+ /** The adapter failed, or its answers did not validate. */
25
+ export class FaultError extends EvokeError {
26
+ kind = "fault";
27
+ fault;
28
+ constructor(fault, message, command) {
29
+ super(command === "" ? message : `${message} → ${command}`, command);
30
+ this.fault = fault;
31
+ }
32
+ }
33
+ /** A host or a body failed: what was attempted, why, and what to do; a body's own error is the `cause`. */
34
+ export class FailureError extends EvokeError {
35
+ kind = "failure";
36
+ what;
37
+ why;
38
+ fix;
39
+ constructor(what, why, fix, command, options) {
40
+ super(`${what}${why === undefined ? "" : `: ${why}`} → ${command}`, command, options);
41
+ this.what = what;
42
+ this.why = why;
43
+ this.fix = fix;
44
+ }
45
+ }
46
+ /** The CLI's line for one problem. */
47
+ function line(problem) {
48
+ const where = problem.reflex === undefined ? "" : `${problem.reflex}: `;
49
+ return `${where}${problem.message} → ${problem.command}`;
50
+ }
@@ -0,0 +1,13 @@
1
+ /** The owned texts as found: absent when the file is. */
2
+ export interface Snapshot {
3
+ project?: string;
4
+ lock?: string;
5
+ overlays: Record<string, string>;
6
+ vocab: Record<string, string>;
7
+ }
8
+ /** The owned files under the root. */
9
+ export declare function snapshot(root: string): Snapshot;
10
+ /** A file's text, or nothing when there is no such file; one that will not read is a failure naming it. */
11
+ export declare function text(path: string): string | undefined;
12
+ /** A store entry's directory when every file under it still hashes to the digest; else nothing — `evoke sync`. */
13
+ export declare function entry(h1: string): string | undefined;
package/dist/files.js ADDED
@@ -0,0 +1,100 @@
1
+ // The project as files: the owned texts under a root — evoke.toml, evoke.lock, every overlay and vocabulary — a
2
+ // local reflex's directory with its manifest, and a remote reflex's store entry, every file re-hashed and the
3
+ // digest composed by the core so it runs only while it still hashes to the lock. Read whole, once; nothing here
4
+ // is written. In: a root, a path, a digest. Out: texts and directories, or their absence.
5
+ import { createHash } from "node:crypto";
6
+ import { readFileSync, readdirSync, statSync } from "node:fs";
7
+ import { homedir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { call, misnamed } from "./core.js";
10
+ import { FailureError } from "./errors.js";
11
+ /** The owned files under the root. */
12
+ export function snapshot(root) {
13
+ const project = text(join(root, "evoke.toml"));
14
+ const lock = text(join(root, "evoke.lock"));
15
+ return {
16
+ ...(project === undefined ? {} : { project }),
17
+ ...(lock === undefined ? {} : { lock }),
18
+ overlays: named(join(root, "overlays"), "local"),
19
+ vocab: named(join(root, "vocab"), "vocab"),
20
+ };
21
+ }
22
+ /** A file's text, or nothing when there is no such file; one that will not read is a failure naming it. */
23
+ export function text(path) {
24
+ try {
25
+ return readFileSync(path, "utf8");
26
+ }
27
+ catch (error) {
28
+ if (error.code === "ENOENT")
29
+ return undefined;
30
+ throw unreadable(path, error);
31
+ }
32
+ }
33
+ /** Every `<name>.toml` in a directory by name, in name order; none when there is no directory. A file whose stem
34
+ * is no name is not an owned file and is left alone, as the CLI leaves it. */
35
+ function named(dir, kind) {
36
+ const files = {};
37
+ let entries;
38
+ try {
39
+ entries = readdirSync(dir);
40
+ }
41
+ catch (error) {
42
+ if (error.code === "ENOENT")
43
+ return files;
44
+ throw unreadable(dir, error);
45
+ }
46
+ for (const entry of entries.sort()) {
47
+ if (!entry.endsWith(".toml"))
48
+ continue;
49
+ const stem = entry.slice(0, -5);
50
+ if (misnamed(stem, kind) !== undefined)
51
+ continue;
52
+ const path = join(dir, entry);
53
+ try {
54
+ files[stem] = readFileSync(path, "utf8");
55
+ }
56
+ catch (error) {
57
+ throw unreadable(path, error);
58
+ }
59
+ }
60
+ return files;
61
+ }
62
+ /** A path that exists and will not read — a directory where a file should be, a permission missing. */
63
+ function unreadable(path, error) {
64
+ const why = error instanceof Error ? error.message : String(error);
65
+ return new FailureError(`reading ${path}`, why, { type: "rerun" }, "load()");
66
+ }
67
+ /** The store: fetched trees under `$XDG_CACHE_HOME/evoke/store/<hex>/`. */
68
+ function store() {
69
+ const base = process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache");
70
+ return join(base, "evoke", "store");
71
+ }
72
+ /** A store entry's directory when every file under it still hashes to the digest; else nothing — `evoke sync`. */
73
+ export function entry(h1) {
74
+ const dir = join(store(), h1.replace(/^h1:/, ""));
75
+ try {
76
+ if (!statSync(dir).isDirectory())
77
+ return undefined;
78
+ }
79
+ catch {
80
+ return undefined;
81
+ }
82
+ const hashed = [];
83
+ const walk = (at, prefix) => {
84
+ for (const name of readdirSync(at).sort()) {
85
+ const path = join(at, name);
86
+ const relative = prefix === "" ? name : `${prefix}/${name}`;
87
+ if (statSync(path).isDirectory())
88
+ walk(path, relative);
89
+ else
90
+ hashed.push([relative, `h1:${createHash("sha256").update(readFileSync(path)).digest("hex")}`]);
91
+ }
92
+ };
93
+ try {
94
+ walk(dir, "");
95
+ }
96
+ catch (error) {
97
+ throw unreadable(dir, error);
98
+ }
99
+ return call("digest", { hashed }) === h1 ? dir : undefined;
100
+ }
@@ -0,0 +1,20 @@
1
+ import type { Agent } from "node:https";
2
+ /** What the server answered; with a 429, the pause it asked for before the next attempt, in milliseconds. */
3
+ export interface Response {
4
+ status: number;
5
+ body: string;
6
+ retryAfter?: number | undefined;
7
+ }
8
+ /** The pause a 429 asks for: `Retry-After` in seconds, at least one, so a service that says "now" is still paced;
9
+ * an HTTP date, which no engine sends, names no pause. */
10
+ export declare function pause(header: string | string[] | undefined): number | undefined;
11
+ /** Why nothing was answered, and whether a connection was made first. */
12
+ export declare class Unanswered extends Error {
13
+ readonly connected: boolean;
14
+ constructor(message: string, connected: boolean);
15
+ }
16
+ /** `POST url` with a bearer token and a JSON body; `via` is the proxy's host when one carries the connection. */
17
+ export declare function post(url: string, bearer: string, body: string, agent: Agent, signal: AbortSignal, timeout: number, via?: string): Promise<Response>;
18
+ /** What went wrong, in plain words: the host named, or the proxy when one carries the connection; the system's
19
+ * own cause, no code and no number. */
20
+ export declare function describe(error: NodeJS.ErrnoException, host: string, connected: boolean, via?: string): string;
package/dist/https.js ADDED
@@ -0,0 +1,109 @@
1
+ // One HTTPS POST, one attempt, over a kept-alive agent: the signal bounds the whole attempt, the timeout each
2
+ // step after connect; never retries. In: the url, a bearer, a JSON body, an agent, a signal, the step timeout.
3
+ // Out: the status and body, or a Unanswered saying in plain words what went wrong and whether a connection had
4
+ // been made — an attempt that never connected, or a pooled socket the server had already closed, is safe to
5
+ // repeat.
6
+ import { request } from "node:https";
7
+ import { getSystemErrorMessage } from "node:util";
8
+ /** The most a response may carry: a decision's answers are kilobytes, so anything beyond is not the classifier. */
9
+ const LIMIT = 10 * 1024 * 1024;
10
+ /** The pause a 429 asks for: `Retry-After` in seconds, at least one, so a service that says "now" is still paced;
11
+ * an HTTP date, which no engine sends, names no pause. */
12
+ export function pause(header) {
13
+ const text = Array.isArray(header) ? header[0] : header;
14
+ if (text === undefined || !/^\s*\d+\s*$/.test(text))
15
+ return undefined;
16
+ return Math.max(1, Number.parseInt(text, 10)) * 1000;
17
+ }
18
+ /** Why nothing was answered, and whether a connection was made first. */
19
+ export class Unanswered extends Error {
20
+ connected;
21
+ constructor(message, connected) {
22
+ super(message);
23
+ this.name = "Unanswered";
24
+ this.connected = connected;
25
+ }
26
+ }
27
+ /** `POST url` with a bearer token and a JSON body; `via` is the proxy's host when one carries the connection. */
28
+ export function post(url, bearer, body, agent, signal, timeout, via) {
29
+ const host = new URL(url).host;
30
+ return new Promise((resolve, reject) => {
31
+ let connected = false;
32
+ const sent = request(url, {
33
+ method: "POST",
34
+ agent,
35
+ signal,
36
+ headers: {
37
+ authorization: `Bearer ${bearer}`,
38
+ "content-type": "application/json",
39
+ "content-length": Buffer.byteLength(body),
40
+ },
41
+ }, response => {
42
+ connected = true;
43
+ let text = "";
44
+ let received = 0;
45
+ response.setEncoding("utf8");
46
+ response.on("data", (chunk) => {
47
+ received += Buffer.byteLength(chunk);
48
+ if (received > LIMIT)
49
+ response.destroy(new Error(`more than ${LIMIT} bytes`));
50
+ else
51
+ text += chunk;
52
+ });
53
+ response.on("end", () => {
54
+ const status = response.statusCode ?? 0;
55
+ const retryAfter = status === 429 ? pause(response.headers["retry-after"]) : undefined;
56
+ resolve({ status, body: text, ...(retryAfter === undefined ? {} : { retryAfter }) });
57
+ });
58
+ response.on("error", error => reject(new Unanswered(`reading the response from ${host}: ${reason(error)}`, true)));
59
+ });
60
+ // The step timeout is armed once the socket is connected; Node removes it when the socket returns to the pool.
61
+ sent.setTimeout(timeout, () => sent.destroy(new Error(`no answer within ${timeout / 1000} s`)));
62
+ sent.on("socket", socket => {
63
+ if (socket.connecting)
64
+ socket.once("connect", () => (connected = true));
65
+ else
66
+ connected = true;
67
+ });
68
+ sent.on("error", (error) => {
69
+ // A pooled socket the server closed while idle: nothing was received, so the attempt is safe to repeat.
70
+ const stale = sent.reusedSocket && error.code === "ECONNRESET";
71
+ const made = connected && !stale;
72
+ reject(new Unanswered(describe(error, host, made, via), made));
73
+ });
74
+ sent.end(body);
75
+ });
76
+ }
77
+ /** What went wrong, in plain words: the host named, or the proxy when one carries the connection; the system's
78
+ * own cause, no code and no number. */
79
+ export function describe(error, host, connected, via) {
80
+ if (error.code === "ERR_PROXY_TUNNEL") {
81
+ const status = "statusCode" in error && typeof error.statusCode === "number" ? `: ${error.statusCode}` : "";
82
+ return `the proxy ${via ?? "the environment names"} refused the connection${status}`;
83
+ }
84
+ if (error.syscall === "getaddrinfo") {
85
+ const named = "hostname" in error && typeof error.hostname === "string" ? error.hostname : (via ?? host);
86
+ return `could not resolve ${named}`;
87
+ }
88
+ const cause = reason(error);
89
+ if (connected)
90
+ return `${host}: ${cause}`;
91
+ return via === undefined ? `could not connect to ${host}: ${cause}` : `could not connect to the proxy ${via}: ${cause}`;
92
+ }
93
+ /** The system's words for the error's number, the first of an aggregate's; a reset by its name; else the message,
94
+ * else the code. */
95
+ function reason(error) {
96
+ const first = error instanceof AggregateError ? error.errors[0] : undefined;
97
+ const errno = error.errno ?? first?.errno;
98
+ if (typeof errno === "number") {
99
+ try {
100
+ return getSystemErrorMessage(errno);
101
+ }
102
+ catch {
103
+ // Not a number the system names: the words below say it.
104
+ }
105
+ }
106
+ if ((error.code ?? first?.code) === "ECONNRESET")
107
+ return "connection reset";
108
+ return error.message || first?.message || error.code || first?.code || "no reason given";
109
+ }
@@ -0,0 +1,10 @@
1
+ export { load } from "./project.ts";
2
+ export type { DecideOptions, Handlers, LoadOptions, Project, ReflexStatus, RunOptions, Turn, Vocab, WeaveOptions, Woven, WovenRound, WovenStep } from "./project.ts";
3
+ export { reflex } from "./reflex.ts";
4
+ export type { Args, Carried, Inline, InlineArg, InlineManifest, InlineRecords, ReflexesOf } from "./reflex.ts";
5
+ export type { Abstain, Ask, Confirm, Decision, Flag, Given, Handled, Option, Pick, Plain, AnyReflexes, Run, Value, Values, Word } from "./decision.ts";
6
+ export type { Context, Reflex, Result } from "./runtime.ts";
7
+ export type { Adapter, Trace } from "./adapter.ts";
8
+ export { DiagnosticError, EvokeError, FailureError, FaultError } from "./errors.ts";
9
+ export type { Problem } from "./errors.ts";
10
+ export type { Because, Binding, Bound, Cap, Choices, Contained, Contender, Diagnostic, Effect, Fault, Fix, Gate, Judgment, Limits, Missing, Needs, Prompt, Question, NonEmpty, Raw, Recognizer, Span, State, Status, Step, Text, Verdict, Weave, WeaveWhy, Why, Yield, } from "./types.ts";
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // @evoke-build/evoke: load a project, decide, run. Six things to learn, in order: reflex() · load() · handle() ·
2
+ // a Decision · run() · replay() — the last under ./testing, and the two doors to Jev under ./jev and ./openjev, so
3
+ // this entry imports no engine.
4
+ export { load } from "./project.js";
5
+ export { reflex } from "./reflex.js";
6
+ export { DiagnosticError, EvokeError, FailureError, FaultError } from "./errors.js";
package/dist/jev.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { Adapter } from "./adapter.ts";
2
+ import { type DoorOptions } from "./systemone.ts";
3
+ export type JevOptions = DoorOptions;
4
+ /** Jev, ready to answer; throws at once when no key is set, an override is not a probability, or the proxy named
5
+ * in the environment is no proxy address. */
6
+ export declare function jev(options?: JevOptions): Adapter;
package/dist/jev.js ADDED
@@ -0,0 +1,8 @@
1
+ // @evoke-build/evoke/jev: the first adapter, Jev at TypeSafe AI's own address, under TYPESAFE_API_KEY. The wire
2
+ // and the transport are ./systemone's; this entry names the door. In: options. Out: an Adapter.
3
+ import { through } from "./systemone.js";
4
+ /** Jev, ready to answer; throws at once when no key is set, an override is not a probability, or the proxy named
5
+ * in the environment is no proxy address. */
6
+ export function jev(options = {}) {
7
+ return through("jev", options);
8
+ }
@@ -0,0 +1,6 @@
1
+ import type { Adapter } from "./adapter.ts";
2
+ import { type DoorOptions } from "./systemone.ts";
3
+ export type OpenJevOptions = DoorOptions;
4
+ /** Jev through OpenJEV, ready to answer; throws at once when no key is set, an override is not a probability, or
5
+ * the proxy named in the environment is no proxy address. */
6
+ export declare function openjev(options?: OpenJevOptions): Adapter;
@@ -0,0 +1,9 @@
1
+ // @evoke-build/evoke/openjev: the same model through OpenJEV, an independent service that forwards requests to
2
+ // Jev, under OPENJEV_API_KEY. The wire and the transport are ./systemone's; this entry names the door. In:
3
+ // options. Out: an Adapter.
4
+ import { through } from "./systemone.js";
5
+ /** Jev through OpenJEV, ready to answer; throws at once when no key is set, an override is not a probability, or
6
+ * the proxy named in the environment is no proxy address. */
7
+ export function openjev(options = {}) {
8
+ return through("openjev", options);
9
+ }