@evoke-build/evoke 0.8.0 → 0.9.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/core.wasm +0 -0
- package/dist/ops.d.ts +2 -1
- package/dist/project.js +50 -26
- package/dist/reflex.d.ts +25 -8
- package/dist/types.d.ts +71 -11
- package/package.json +1 -1
package/core.wasm
CHANGED
|
Binary file
|
package/dist/ops.d.ts
CHANGED
|
@@ -183,11 +183,12 @@ export interface Ops {
|
|
|
183
183
|
input: {
|
|
184
184
|
chosen: T.Chosen;
|
|
185
185
|
active: T.Active;
|
|
186
|
+
taken?: Record<T.ArgName, T.Json>;
|
|
186
187
|
input: T.Input;
|
|
187
188
|
deadline: T.Millis;
|
|
188
189
|
home: string;
|
|
189
190
|
};
|
|
190
|
-
output: T.Envelope
|
|
191
|
+
output: T.Result<T.Envelope, T.Diagnostic>;
|
|
191
192
|
};
|
|
192
193
|
argv: {
|
|
193
194
|
input: {
|
package/dist/project.js
CHANGED
|
@@ -248,27 +248,18 @@ function make(ground, invoked) {
|
|
|
248
248
|
}
|
|
249
249
|
if (outcome !== "run" && outcome !== "confirm")
|
|
250
250
|
throw new TypeError(`a ${outcome} decision cannot run`);
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const spent = chosen.trace.reduce((sum, entry) => sum + entry.ms, 0);
|
|
255
|
-
// The whole decision crosses: the core reads the fields of a Chosen and ignores the SDK's own.
|
|
256
|
-
const wire = chosen;
|
|
257
|
-
const envelope = call("envelope", { chosen: wire, active, input: chosen.input, deadline: Math.max(plan.deadline - spent, 0), home: homedir() });
|
|
258
|
-
const what = `running ${chosen.reflex}`;
|
|
259
|
-
const body = bodies[chosen.reflex];
|
|
260
|
-
if (body !== undefined)
|
|
261
|
-
return inline(what, body, envelope, options.signal);
|
|
262
|
-
const dir = dirs[chosen.reflex];
|
|
263
|
-
if (dir === undefined)
|
|
264
|
-
throw refused(chosen.reflex, `${chosen.reflex} has no body to run`, { type: "sync" }, "run(d)");
|
|
265
|
-
return contained(what, chosen, active, dir, envelope, options.signal);
|
|
251
|
+
// A whole result is handed by the plan alone: a call that takes one runs only as a step of a weave.
|
|
252
|
+
taker(chosen);
|
|
253
|
+
return running(chosen, {}, options);
|
|
266
254
|
},
|
|
267
255
|
async handle(input, options = {}) {
|
|
268
256
|
nonEmpty(input, "handle");
|
|
269
|
-
const
|
|
257
|
+
const decision = await project.decide(input, options);
|
|
258
|
+
if (decision.outcome !== "abstain")
|
|
259
|
+
taker(decision);
|
|
260
|
+
const readied = await ready(decision, options);
|
|
270
261
|
if (readied.ready)
|
|
271
|
-
return { outcome: "ran", decision: readied.decision, result: await
|
|
262
|
+
return { outcome: "ran", decision: readied.decision, result: await running(readied.decision, {}, signalled(options.signal)) };
|
|
272
263
|
if (readied.status === "refused")
|
|
273
264
|
return { outcome: "abstained", decision: readied.decision };
|
|
274
265
|
return { outcome: readied.status, decision: readied.decision };
|
|
@@ -446,7 +437,7 @@ function make(ground, invoked) {
|
|
|
446
437
|
record(handling, readied.decision, { status: readied.status, why: readied.why });
|
|
447
438
|
continue;
|
|
448
439
|
}
|
|
449
|
-
bodies.push(ran(readied.decision, signal).then(became => record(handling, readied.decision, became)));
|
|
440
|
+
bodies.push(ran(readied.decision, handling.taken ?? {}, signal).then(became => record(handling, readied.decision, became)));
|
|
450
441
|
}
|
|
451
442
|
await Promise.all(bodies);
|
|
452
443
|
}
|
|
@@ -506,16 +497,40 @@ function make(ground, invoked) {
|
|
|
506
497
|
...(ask === undefined ? {} : { ask: (decision) => ask(decision, turn) }),
|
|
507
498
|
};
|
|
508
499
|
}
|
|
509
|
-
/** A
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
500
|
+
/** A reflex that takes a whole result, met outside a weave: refused before any confirm, since only a request of
|
|
501
|
+
* several steps hands one. */
|
|
502
|
+
function taker(decision) {
|
|
503
|
+
const takes = Object.values(plan.active[decision.reflex]?.takes ?? {});
|
|
504
|
+
if (takes.length === 0)
|
|
505
|
+
return;
|
|
506
|
+
throw refused(decision.reflex, `${decision.reflex} takes ${words(takes)}, which a step before it in the same request returns`, { type: "rerun" }, 'weave("<input>")');
|
|
513
507
|
}
|
|
514
|
-
/**
|
|
515
|
-
*
|
|
516
|
-
|
|
508
|
+
/** The chosen call's body — in-process, in a child through the loader, or as an argv — with the whole results it
|
|
509
|
+
* takes beside its values, which only the weave hands; one the plan did not hand is refused by the envelope, the
|
|
510
|
+
* last guard. What `run` does for a call that takes none, and every step of a weave for its round. */
|
|
511
|
+
async function running(decision, taken, options) {
|
|
512
|
+
const chosen = own(decision, "run");
|
|
513
|
+
const active = plan.active[chosen.reflex];
|
|
514
|
+
if (active === undefined)
|
|
515
|
+
throw refused(chosen.reflex, `${chosen.reflex} is not active`, { type: "rerun" }, "run(d)");
|
|
516
|
+
const spent = chosen.trace.reduce((sum, entry) => sum + entry.ms, 0);
|
|
517
|
+
// The whole decision crosses: the core reads the fields of a Chosen and ignores the SDK's own.
|
|
518
|
+
const wire = chosen;
|
|
519
|
+
const envelope = call("envelope", { chosen: wire, active, taken, input: chosen.input, deadline: Math.max(plan.deadline - spent, 0), home: homedir() }, "run(d)");
|
|
520
|
+
const what = `running ${chosen.reflex}`;
|
|
521
|
+
const body = bodies[chosen.reflex];
|
|
522
|
+
if (body !== undefined)
|
|
523
|
+
return inline(what, body, envelope, options.signal);
|
|
524
|
+
const dir = dirs[chosen.reflex];
|
|
525
|
+
if (dir === undefined)
|
|
526
|
+
throw refused(chosen.reflex, `${chosen.reflex} has no body to run`, { type: "sync" }, "run(d)");
|
|
527
|
+
return contained(what, chosen, active, dir, envelope, options.signal);
|
|
528
|
+
}
|
|
529
|
+
/** One body run for a weave, the whole results its step takes beside it: what it returned, or its failure as the
|
|
530
|
+
* step's own outcome, never the weave's; a body the signal ended is the round cancelled. */
|
|
531
|
+
async function ran(decision, taken, signal) {
|
|
517
532
|
try {
|
|
518
|
-
return { status: "ran", result: await
|
|
533
|
+
return { status: "ran", result: await running(decision, taken, signalled(signal)) };
|
|
519
534
|
}
|
|
520
535
|
catch (error) {
|
|
521
536
|
if (signal?.aborted && error === signal.reason)
|
|
@@ -604,6 +619,15 @@ function carrying(reason, woven) {
|
|
|
604
619
|
}
|
|
605
620
|
return reason;
|
|
606
621
|
}
|
|
622
|
+
/** A signal as run options: none when there is none. */
|
|
623
|
+
function signalled(signal) {
|
|
624
|
+
return signal === undefined ? {} : { signal };
|
|
625
|
+
}
|
|
626
|
+
/** `a`, `a and b`, `a, b and c`. */
|
|
627
|
+
function words(names) {
|
|
628
|
+
const last = names.at(-1) ?? "";
|
|
629
|
+
return names.length < 2 ? last : `${names.slice(0, -1).join(", ")} and ${last}`;
|
|
630
|
+
}
|
|
607
631
|
/** Whether two asks want the same things for the same reasons. */
|
|
608
632
|
function same(after, before) {
|
|
609
633
|
return JSON.stringify(after) === JSON.stringify(before);
|
package/dist/reflex.d.ts
CHANGED
|
@@ -10,17 +10,21 @@ export interface InlineManifest {
|
|
|
10
10
|
effect?: Effect;
|
|
11
11
|
/** The one-line template a person confirms, naming required arguments only. */
|
|
12
12
|
confirm: string;
|
|
13
|
+
/** The arguments: a question and one source each, or a whole result an earlier step returns, taken by its name. */
|
|
13
14
|
args?: Record<string, InlineArg>;
|
|
14
15
|
/** What the body's `data` yields for a later step to take: per field, the recognizer that reads it, or a list of
|
|
15
16
|
* records with such fields. */
|
|
16
17
|
yields?: Record<string, Recognizer | {
|
|
17
18
|
each: Record<string, Recognizer>;
|
|
18
19
|
}>;
|
|
20
|
+
/** The name the body's whole `data` goes by, for a later step to take. */
|
|
21
|
+
returns?: string;
|
|
19
22
|
examples?: InlineRecords;
|
|
20
23
|
tests?: InlineRecords;
|
|
21
24
|
}
|
|
22
|
-
/** An argument: its question and exactly one source
|
|
23
|
-
|
|
25
|
+
/** An argument: its question and exactly one source, a flag optional by nature; or `takes` alone, a whole result
|
|
26
|
+
* an earlier step returns, by the name that result goes by — filled by the plan, never asked. */
|
|
27
|
+
export type InlineArg = ({
|
|
24
28
|
ask: string;
|
|
25
29
|
} & ({
|
|
26
30
|
options: Record<string, string>;
|
|
@@ -37,7 +41,9 @@ export type InlineArg = {
|
|
|
37
41
|
optional?: boolean;
|
|
38
42
|
} | {
|
|
39
43
|
flag: true;
|
|
40
|
-
})
|
|
44
|
+
})) | {
|
|
45
|
+
takes: string;
|
|
46
|
+
};
|
|
41
47
|
/** Utterances with what they assert: a record per argument — the text, or `false` for unstated, `true` for a flag —
|
|
42
48
|
* or `false` for never this reflex. */
|
|
43
49
|
export type InlineRecords = Record<string, Record<string, string | boolean> | false>;
|
|
@@ -57,23 +63,34 @@ type Absent<A> = A extends {
|
|
|
57
63
|
} | {
|
|
58
64
|
flag: true;
|
|
59
65
|
} ? true : false;
|
|
66
|
+
type Taken<A> = A extends {
|
|
67
|
+
takes: string;
|
|
68
|
+
} ? true : false;
|
|
60
69
|
type Flat<T> = {
|
|
61
70
|
[K in keyof T]: T[K];
|
|
62
71
|
} & {};
|
|
63
72
|
type ArgsOf<M extends InlineManifest> = NonNullable<M["args"]> extends Record<string, InlineArg> ? NonNullable<M["args"]> : Record<never, InlineArg>;
|
|
64
|
-
/**
|
|
73
|
+
/** The asked arguments alone: a taken one never travels in a decision. */
|
|
74
|
+
type AskedOf<M extends InlineManifest> = {
|
|
75
|
+
[N in keyof ArgsOf<M> as Taken<ArgsOf<M>[N]> extends true ? never : N]: ArgsOf<M>[N];
|
|
76
|
+
};
|
|
77
|
+
/** What a decision carries for a reflex handed as code: its asked arguments as the wire types them, optional ones
|
|
78
|
+
* optional. */
|
|
65
79
|
export type Carried<M extends InlineManifest> = Flat<{
|
|
66
|
-
[N in keyof
|
|
80
|
+
[N in keyof AskedOf<M> as Absent<AskedOf<M>[N]> extends true ? never : N]: Typed<AskedOf<M>[N]>;
|
|
67
81
|
} & {
|
|
68
|
-
[N in keyof
|
|
82
|
+
[N in keyof AskedOf<M> as Absent<AskedOf<M>[N]> extends true ? N : never]?: Typed<AskedOf<M>[N]>;
|
|
69
83
|
}>;
|
|
70
84
|
/** What decisions carry for a map of reflexes handed as code: `load<Reflexes & ReflexesOf<typeof own>>` when a
|
|
71
85
|
* project has installed reflexes beside them. */
|
|
72
86
|
export type ReflexesOf<I> = {
|
|
73
87
|
[K in keyof I]: I[K] extends Inline<infer S> ? S : never;
|
|
74
88
|
};
|
|
75
|
-
/** The body's arguments, plain: what `reflex`'s body receives
|
|
76
|
-
|
|
89
|
+
/** The body's arguments, plain: what `reflex`'s body receives — the asked arguments' values, and each whole result
|
|
90
|
+
* it takes as `unknown`, since evoke checks no shape. */
|
|
91
|
+
export type Args<M extends InlineManifest> = Flat<Values<Carried<M>> & {
|
|
92
|
+
[N in keyof ArgsOf<M> as Taken<ArgsOf<M>[N]> extends true ? N : never]: unknown;
|
|
93
|
+
}>;
|
|
77
94
|
/** What `reflex` returns and `load` takes; `shape` never holds a value — it is what a decision carries, for inference. */
|
|
78
95
|
export interface Inline<S = Record<string, Value>> {
|
|
79
96
|
readonly manifest: InlineManifest;
|
package/dist/types.d.ts
CHANGED
|
@@ -175,9 +175,14 @@ export interface Manifest {
|
|
|
175
175
|
/** What the body may touch; absent, the tightest declaration. Contract, like `run`. */
|
|
176
176
|
needs?: Needs;
|
|
177
177
|
config: Record<ConfigKey, ConfigSpec>;
|
|
178
|
+
/** The arguments the classifier is asked about: `ask` and one source each. */
|
|
178
179
|
args: Record<ArgName, Argument>;
|
|
180
|
+
/** The arguments an earlier step's whole result fills, by the name that result goes by; absent when none. Contract. */
|
|
181
|
+
takes?: Record<ArgName, FieldName>;
|
|
179
182
|
/** What the body's `data` yields for a later step to take, per field. */
|
|
180
183
|
yields: Record<FieldName, Yield>;
|
|
184
|
+
/** The name the body's whole `data` goes by, for a later step to take; absent when none. Contract. */
|
|
185
|
+
returns?: FieldName;
|
|
181
186
|
examples: Records;
|
|
182
187
|
tests: Records;
|
|
183
188
|
/** Keys the format does not know: reported, never fatal. */
|
|
@@ -604,9 +609,14 @@ export interface Active {
|
|
|
604
609
|
/** Absent: the tightest declaration. */
|
|
605
610
|
needs?: Needs;
|
|
606
611
|
confirm: Template;
|
|
612
|
+
/** The arguments the classifier is asked about. */
|
|
607
613
|
args: Record<ArgName, Argument>;
|
|
614
|
+
/** The arguments an earlier step's whole result fills, by the name that result goes by; absent when none. */
|
|
615
|
+
takes?: Record<ArgName, FieldName>;
|
|
608
616
|
/** What the body's `data` yields for a later step to take, per field. */
|
|
609
617
|
yields: Record<FieldName, Yield>;
|
|
618
|
+
/** The name the body's whole `data` goes by, for a later step to take; absent when none. */
|
|
619
|
+
returns?: FieldName;
|
|
610
620
|
config: Record<ConfigKey, Setting>;
|
|
611
621
|
tags: Tag[];
|
|
612
622
|
}
|
|
@@ -799,8 +809,9 @@ export interface Envelope {
|
|
|
799
809
|
reflex: LocalName;
|
|
800
810
|
/** Absent for an inline body. */
|
|
801
811
|
run?: Run;
|
|
802
|
-
/** An option key, a word's `value` if set else the word, a pick's value, `true` for a flag
|
|
803
|
-
|
|
812
|
+
/** An option key, a word's `value` if set else the word, a pick's value, `true` for a flag, and a whole result as
|
|
813
|
+
* its source returned it. */
|
|
814
|
+
args: Record<ArgName, Json>;
|
|
804
815
|
input: Input;
|
|
805
816
|
/** An `env` setting stays a reference; the host resolves it. */
|
|
806
817
|
config: Record<ConfigKey, Setting>;
|
|
@@ -883,15 +894,19 @@ export interface Step {
|
|
|
883
894
|
/** The steps this one must follow: an explicit `then`, or a binding. */
|
|
884
895
|
after?: number[];
|
|
885
896
|
}
|
|
886
|
-
/** How a bound value reaches its step: answering its own ask
|
|
887
|
-
|
|
888
|
-
|
|
897
|
+
/** How a bound value reaches its step: answering its own ask; the step decided again with the value in its words; or a
|
|
898
|
+
* whole result handed beside the decision, never through its words. */
|
|
899
|
+
export type Via = "fill" | "rewrite" | "takes";
|
|
900
|
+
/** A value of one step's result taken by a later step: which field, into which argument, how; or the whole result, by
|
|
901
|
+
* the name it goes by. */
|
|
889
902
|
export interface Binding {
|
|
890
903
|
from: number;
|
|
891
904
|
to: number;
|
|
892
905
|
arg: ArgName;
|
|
906
|
+
/** The field taken; for `takes`, the name the whole result goes by. */
|
|
893
907
|
field: FieldName;
|
|
894
|
-
|
|
908
|
+
/** The recognizer the field is read with; absent for a whole result. */
|
|
909
|
+
kind?: Recognizer;
|
|
895
910
|
via: Via;
|
|
896
911
|
/** The list field of the source's result whose records carry `field`: the step runs once per record. */
|
|
897
912
|
each?: FieldName;
|
|
@@ -920,6 +935,19 @@ export type Because = {
|
|
|
920
935
|
type: "takes_nothing";
|
|
921
936
|
step: number;
|
|
922
937
|
sources: number[];
|
|
938
|
+
}
|
|
939
|
+
/** A whole result the step takes by name that no step before it returns: refused, nothing answers it. */
|
|
940
|
+
| {
|
|
941
|
+
type: "no_source";
|
|
942
|
+
step: number;
|
|
943
|
+
name: FieldName;
|
|
944
|
+
}
|
|
945
|
+
/** What the step takes one of that several steps return, or one step once per record: refused. */
|
|
946
|
+
| {
|
|
947
|
+
type: "several_sources";
|
|
948
|
+
step: number;
|
|
949
|
+
name: FieldName;
|
|
950
|
+
sources: number[];
|
|
923
951
|
};
|
|
924
952
|
/** The verdict before anything runs, with every reason. */
|
|
925
953
|
export interface Verdict {
|
|
@@ -940,19 +968,20 @@ export interface Weave {
|
|
|
940
968
|
stages: number[][];
|
|
941
969
|
verdict: Verdict;
|
|
942
970
|
}
|
|
943
|
-
/** A value bound into a step at its turn. */
|
|
971
|
+
/** A value bound into a step at its turn; a whole result carries no value here, it stays on its source's line. */
|
|
944
972
|
export interface Bound {
|
|
945
973
|
arg: ArgName;
|
|
946
974
|
from: number;
|
|
947
975
|
field: FieldName;
|
|
948
|
-
value
|
|
976
|
+
value?: string;
|
|
949
977
|
}
|
|
950
978
|
/** What a body returned: its text, and data when it gave some. */
|
|
951
979
|
export interface Returned {
|
|
952
980
|
text: string;
|
|
953
981
|
data?: Json;
|
|
954
982
|
}
|
|
955
|
-
/** One round of a step for a host to take through the foundation's loop, the bound values in place
|
|
983
|
+
/** One round of a step for a host to take through the foundation's loop, the bound values in place and the whole
|
|
984
|
+
* results the body receives beside them. */
|
|
956
985
|
export interface Handling {
|
|
957
986
|
step: number;
|
|
958
987
|
/** From 0; a step bound to a list runs one round per record. */
|
|
@@ -960,14 +989,24 @@ export interface Handling {
|
|
|
960
989
|
decision: Decision;
|
|
961
990
|
input: string;
|
|
962
991
|
bound?: Bound[];
|
|
992
|
+
/** Per taken argument, its source's whole `data`: the same for every round of the step. */
|
|
993
|
+
taken?: Record<ArgName, Json>;
|
|
963
994
|
}
|
|
964
995
|
/** What became of a step, or of one of its rounds. */
|
|
965
996
|
export type Status = "ran" | "failed" | "declined" | "refused" | "skipped" | "unanswered";
|
|
966
997
|
/** Why a step did not run, or did not finish. */
|
|
967
998
|
export type WeaveWhy = {
|
|
968
999
|
type: "earlier_step";
|
|
969
|
-
}
|
|
1000
|
+
}
|
|
1001
|
+
/** The step it names yielded nothing it can take: no such field, no data, or null. */
|
|
1002
|
+
| {
|
|
970
1003
|
type: "nothing_to_take";
|
|
1004
|
+
from: number;
|
|
1005
|
+
}
|
|
1006
|
+
/** The step it names returned a whole result over the cap, a mebibyte of JSON. */
|
|
1007
|
+
| {
|
|
1008
|
+
type: "too_large";
|
|
1009
|
+
from: number;
|
|
971
1010
|
} | {
|
|
972
1011
|
type: "found_nothing";
|
|
973
1012
|
} | {
|
|
@@ -1035,7 +1074,7 @@ export interface ContractDiff {
|
|
|
1035
1074
|
}
|
|
1036
1075
|
/** `same`: nothing but wording, or a declaration narrowed. `minor`: additions, a declaration widened, and a config key gone. `major`: something a person's files or calls may not survive. */
|
|
1037
1076
|
export type Level = "same" | "minor" | "major";
|
|
1038
|
-
/** One change to the contract, in the order the diff walks: the previous arguments, the added ones, the body, what it may touch, config,
|
|
1077
|
+
/** One change to the contract, in the order the diff walks: the previous arguments, the added ones, the body, what it may touch, config, what the result yields, what the reflex takes, then what it returns. */
|
|
1039
1078
|
export type Change = {
|
|
1040
1079
|
type: "arg_removed";
|
|
1041
1080
|
arg: ArgName;
|
|
@@ -1093,6 +1132,27 @@ export type Change = {
|
|
|
1093
1132
|
} | {
|
|
1094
1133
|
type: "yield_changed";
|
|
1095
1134
|
field: FieldName;
|
|
1135
|
+
} | {
|
|
1136
|
+
type: "takes_added";
|
|
1137
|
+
arg: ArgName;
|
|
1138
|
+
name: FieldName;
|
|
1139
|
+
} | {
|
|
1140
|
+
type: "takes_removed";
|
|
1141
|
+
arg: ArgName;
|
|
1142
|
+
name: FieldName;
|
|
1143
|
+
} | {
|
|
1144
|
+
type: "takes_changed";
|
|
1145
|
+
arg: ArgName;
|
|
1146
|
+
name: FieldName;
|
|
1147
|
+
} | {
|
|
1148
|
+
type: "returns_added";
|
|
1149
|
+
name: FieldName;
|
|
1150
|
+
} | {
|
|
1151
|
+
type: "returns_removed";
|
|
1152
|
+
name: FieldName;
|
|
1153
|
+
} | {
|
|
1154
|
+
type: "returns_changed";
|
|
1155
|
+
name: FieldName;
|
|
1096
1156
|
};
|
|
1097
1157
|
/** `was` is flat and cumulative: a retired name never returns as a live argument, and never leaves the lists. */
|
|
1098
1158
|
export type WasViolation = {
|