@lloyal-labs/rig 2.1.0 → 3.0.1

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 (100) hide show
  1. package/LICENSE +107 -0
  2. package/LICENSE-FAQ.md +256 -0
  3. package/README.md +93 -74
  4. package/dist/bundle.d.ts +211 -0
  5. package/dist/bundle.d.ts.map +1 -0
  6. package/dist/bundle.js +296 -0
  7. package/dist/bundle.js.map +1 -0
  8. package/dist/cancellable-fetch.d.ts +98 -0
  9. package/dist/cancellable-fetch.d.ts.map +1 -0
  10. package/dist/cancellable-fetch.js +133 -0
  11. package/dist/cancellable-fetch.js.map +1 -0
  12. package/dist/config-store.d.ts +30 -0
  13. package/dist/config-store.d.ts.map +1 -0
  14. package/dist/config-store.js +45 -0
  15. package/dist/config-store.js.map +1 -0
  16. package/dist/define-app.d.ts +98 -0
  17. package/dist/define-app.d.ts.map +1 -0
  18. package/dist/define-app.js +232 -0
  19. package/dist/define-app.js.map +1 -0
  20. package/dist/grant-store.d.ts +31 -0
  21. package/dist/grant-store.d.ts.map +1 -0
  22. package/dist/grant-store.js +49 -0
  23. package/dist/grant-store.js.map +1 -0
  24. package/dist/index.d.ts +13 -6
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +37 -11
  27. package/dist/index.js.map +1 -1
  28. package/dist/node.d.ts +3 -2
  29. package/dist/node.d.ts.map +1 -1
  30. package/dist/node.js +3 -2
  31. package/dist/node.js.map +1 -1
  32. package/dist/protocol.d.ts +155 -0
  33. package/dist/protocol.d.ts.map +1 -0
  34. package/dist/protocol.js +184 -0
  35. package/dist/protocol.js.map +1 -0
  36. package/dist/registry.d.ts +87 -0
  37. package/dist/registry.d.ts.map +1 -0
  38. package/dist/registry.js +245 -0
  39. package/dist/registry.js.map +1 -0
  40. package/dist/reranker.d.ts +25 -7
  41. package/dist/reranker.d.ts.map +1 -1
  42. package/dist/reranker.js +103 -63
  43. package/dist/reranker.js.map +1 -1
  44. package/dist/resources/types.d.ts +10 -37
  45. package/dist/resources/types.d.ts.map +1 -1
  46. package/dist/resources/types.js +12 -0
  47. package/dist/resources/types.js.map +1 -1
  48. package/dist/spine-render.d.ts +97 -0
  49. package/dist/spine-render.d.ts.map +1 -0
  50. package/dist/spine-render.js +121 -0
  51. package/dist/spine-render.js.map +1 -0
  52. package/dist/tools/index.d.ts +26 -22
  53. package/dist/tools/index.d.ts.map +1 -1
  54. package/dist/tools/index.js +24 -28
  55. package/dist/tools/index.js.map +1 -1
  56. package/dist/tools/keyless-search.d.ts +67 -0
  57. package/dist/tools/keyless-search.d.ts.map +1 -0
  58. package/dist/tools/keyless-search.js +401 -0
  59. package/dist/tools/keyless-search.js.map +1 -0
  60. package/dist/tools/plan.d.ts +31 -4
  61. package/dist/tools/plan.d.ts.map +1 -1
  62. package/dist/tools/plan.js +46 -11
  63. package/dist/tools/plan.js.map +1 -1
  64. package/dist/tools/types.d.ts +12 -56
  65. package/dist/tools/types.d.ts.map +1 -1
  66. package/dist/tools/types.js +17 -0
  67. package/dist/tools/types.js.map +1 -1
  68. package/dist/tools/web-search.d.ts +9 -25
  69. package/dist/tools/web-search.d.ts.map +1 -1
  70. package/dist/tools/web-search.js +11 -119
  71. package/dist/tools/web-search.js.map +1 -1
  72. package/package.json +10 -7
  73. package/dist/sources/corpus.d.ts +0 -80
  74. package/dist/sources/corpus.d.ts.map +0 -1
  75. package/dist/sources/corpus.js +0 -100
  76. package/dist/sources/corpus.js.map +0 -1
  77. package/dist/sources/index.d.ts +0 -12
  78. package/dist/sources/index.d.ts.map +0 -1
  79. package/dist/sources/index.js +0 -14
  80. package/dist/sources/index.js.map +0 -1
  81. package/dist/sources/web.d.ts +0 -67
  82. package/dist/sources/web.d.ts.map +0 -1
  83. package/dist/sources/web.js +0 -104
  84. package/dist/sources/web.js.map +0 -1
  85. package/dist/tools/fetch-page.d.ts +0 -48
  86. package/dist/tools/fetch-page.d.ts.map +0 -1
  87. package/dist/tools/fetch-page.js +0 -309
  88. package/dist/tools/fetch-page.js.map +0 -1
  89. package/dist/tools/grep.d.ts +0 -35
  90. package/dist/tools/grep.d.ts.map +0 -1
  91. package/dist/tools/grep.js +0 -84
  92. package/dist/tools/grep.js.map +0 -1
  93. package/dist/tools/read-file.d.ts +0 -74
  94. package/dist/tools/read-file.d.ts.map +0 -1
  95. package/dist/tools/read-file.js +0 -192
  96. package/dist/tools/read-file.js.map +0 -1
  97. package/dist/tools/search.d.ts +0 -34
  98. package/dist/tools/search.d.ts.map +0 -1
  99. package/dist/tools/search.js +0 -101
  100. package/dist/tools/search.js.map +0 -1
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ /**
3
+ * `cancellableFetch(url, init, opts)` — Effection-native HTTP with
4
+ * scope-linked cancellation and a deadline timeout.
5
+ *
6
+ * Wraps the global `fetch` so:
7
+ *
8
+ * 1. **Outer-scope halt aborts the in-flight request.** The Effection
9
+ * `useAbortSignal()` returns a signal linked to the current scope;
10
+ * when the scope halts (because a containing operation throws,
11
+ * `race` chose another leg, the harness is cancelled, etc.) the
12
+ * signal aborts and the underlying socket closes. The fetch is
13
+ * *genuinely* cancelled — not abandoned.
14
+ *
15
+ * 2. **Timeout aborts the in-flight request.** A second leg sleeps for
16
+ * `opts.timeoutMs` and throws on completion. `race` halts whichever
17
+ * leg loses, propagating the abort the same way an outer halt does.
18
+ *
19
+ * Three current/planned consumers route through this primitive:
20
+ *
21
+ * - `@lloyal-labs/web-app/src/tools/fetch-page.ts` (post-migration —
22
+ * replaces raw `AbortController` + `setTimeout`, closes the latent
23
+ * socket-leak bug where a halted pool kept fetch-page sockets open).
24
+ * - `@lloyal-labs/web-app/src/tools/keyless-search.ts` (post-migration
25
+ * — replaces the private `fetchWithTimeout` from which this primitive
26
+ * was lifted; zero behavior change, just consolidation).
27
+ * - `@lloyal-labs/rig/src/bundle.ts` (`resolveAppEntry`) — fetches the
28
+ * signed catalog via `cancellableFetch` so a halted scope during
29
+ * resolution tears down cleanly. Used by `harness.dev install` to
30
+ * resolve names against the canonical channel.
31
+ *
32
+ * Third-party apps SHOULD use `cancellableFetch` for any HTTP they do
33
+ * under structured concurrency, rather than reinventing the
34
+ * `race + useAbortSignal` pattern.
35
+ *
36
+ * @packageDocumentation
37
+ * @category Contract
38
+ */
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.FetchTimeoutError = void 0;
41
+ exports.cancellableFetch = cancellableFetch;
42
+ const effection_1 = require("effection");
43
+ /**
44
+ * Thrown when the timeout leg of `cancellableFetch` wins the race.
45
+ * Distinct from generic `Error` so consumers can catch only the
46
+ * timeout case (e.g., to retry with a longer timeout) without also
47
+ * catching network-layer errors thrown from the fetch leg.
48
+ */
49
+ class FetchTimeoutError extends Error {
50
+ constructor(url, timeoutMs) {
51
+ super(`Fetch timed out after ${timeoutMs}ms: ${url}`);
52
+ this.name = 'FetchTimeoutError';
53
+ }
54
+ }
55
+ exports.FetchTimeoutError = FetchTimeoutError;
56
+ /**
57
+ * Default request timeout. Chosen to be comfortably longer than typical
58
+ * web pages (95th percentile of `fetch-page.ts` traces resolves in under
59
+ * 10s) while still bounded enough to fail fast on dead URLs. Override
60
+ * via `opts.timeoutMs` for known-slow endpoints.
61
+ */
62
+ const DEFAULT_TIMEOUT_MS = 30_000;
63
+ /**
64
+ * Fetch a URL with Effection-scope-linked cancellation and a timeout.
65
+ *
66
+ * @param url - The URL to fetch.
67
+ * @param init - Standard `RequestInit` options. `init.signal` is *replaced*
68
+ * by the Effection-scope-linked signal; callers cannot pass their own
69
+ * AbortController. (If you want to compose with an external abort
70
+ * source, do it at the outer-scope level — halting the outer scope
71
+ * propagates here.)
72
+ * @param opts - Timeout + injection knobs.
73
+ * @returns The `Response` object — unread. Callers `yield* call(() => res.text())`
74
+ * etc. as appropriate to their use case.
75
+ *
76
+ * @throws {FetchTimeoutError} If the timeout leg wins.
77
+ * @throws Network-layer errors thrown by the underlying `fetch` (e.g., DNS
78
+ * resolution failure, TLS error, socket reset). When the abort signal
79
+ * fires, `fetch` throws a `DOMException` with `name === 'AbortError'` —
80
+ * distinguishable from real network errors by that name.
81
+ *
82
+ * **Body buffering.** The returned `Response`'s body is **fully buffered
83
+ * in memory** before the function returns; the caller may safely call
84
+ * `.text()` / `.json()` / `.arrayBuffer()` on it without further async
85
+ * coordination. This is load-bearing: the underlying `useAbortSignal()`
86
+ * aborts when the http leg's scope unwinds (after `race` resolves),
87
+ * which would otherwise cause the caller's body-read to throw
88
+ * `AbortError` mid-flight (the body is still bound to the request's
89
+ * signal in undici). Pre-consuming inside the http leg, before the
90
+ * signal aborts, sidesteps that interaction. Cost: streaming is not
91
+ * supported — all responses are fully resident before return. Acceptable
92
+ * for the consumers we have (catalog JSON, manifest JSON, signed
93
+ * bundles up to a few hundred KB).
94
+ */
95
+ function* cancellableFetch(url, init, opts) {
96
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
97
+ const fetchImpl = opts?.fetchImpl ?? fetch;
98
+ const httpLeg = function* () {
99
+ const signal = yield* (0, effection_1.useAbortSignal)();
100
+ // Strip caller's signal if any — the Effection scope owns abort.
101
+ // Keeping caller-supplied signal would mean two abort sources, which
102
+ // confuses the cancellation chain.
103
+ const { signal: _ignored, ...restInit } = init ?? {};
104
+ const res = yield* (0, effection_1.call)(() => fetchImpl(url, { ...restInit, signal }));
105
+ // Pre-consume the body while the signal is still live. After `race`
106
+ // returns, this http leg's scope unwinds and the signal aborts —
107
+ // reading the original Response's body at that point throws
108
+ // AbortError from undici's consumeBody. Wrapping the buffered bytes
109
+ // in a fresh Response (which has no associated signal) lets the
110
+ // caller read the body on their own schedule.
111
+ const bytes = yield* (0, effection_1.call)(() => res.arrayBuffer());
112
+ return new Response(bytes, {
113
+ status: res.status,
114
+ statusText: res.statusText,
115
+ headers: res.headers,
116
+ });
117
+ };
118
+ const timeoutLeg = function* () {
119
+ if (timeoutMs === Infinity) {
120
+ // Sleep forever — the http leg will win or the outer scope halts.
121
+ // Using a deliberately-never-resolving operation rather than
122
+ // sleeping for MAX_SAFE_INTEGER ms (which Node's timer subsystem
123
+ // doesn't handle gracefully).
124
+ yield* (0, effection_1.call)(() => new Promise(() => { }));
125
+ // Unreachable, but type-required.
126
+ throw new FetchTimeoutError(url, timeoutMs);
127
+ }
128
+ yield* (0, effection_1.sleep)(timeoutMs);
129
+ throw new FetchTimeoutError(url, timeoutMs);
130
+ };
131
+ return yield* (0, effection_1.race)([httpLeg(), timeoutLeg()]);
132
+ }
133
+ //# sourceMappingURL=cancellable-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancellable-fetch.js","sourceRoot":"","sources":["../src/cancellable-fetch.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;;;AA4EH,4CA4CC;AArHD,yCAA8D;AAoB9D;;;;;GAKG;AACH,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,GAAW,EAAE,SAAiB;QACxC,KAAK,CAAC,yBAAyB,SAAS,OAAO,GAAG,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AALD,8CAKC;AAED;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,QAAe,CAAC,CAAC,gBAAgB,CAC/B,GAAW,EACX,IAAkB,EAClB,IAA8B;IAE9B,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,kBAAkB,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,KAAK,CAAC;IAE3C,MAAM,OAAO,GAAG,QAAQ,CAAC;QACvB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,IAAA,0BAAc,GAAE,CAAC;QACvC,iEAAiE;QACjE,qEAAqE;QACrE,mCAAmC;QACnC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAA,gBAAI,EAAC,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QACvE,oEAAoE;QACpE,iEAAiE;QACjE,4DAA4D;QAC5D,oEAAoE;QACpE,gEAAgE;QAChE,8CAA8C;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,IAAA,gBAAI,EAAC,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QACnD,OAAO,IAAI,QAAQ,CAAC,KAAK,EAAE;YACzB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,QAAQ,CAAC;QAC1B,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC3B,kEAAkE;YAClE,6DAA6D;YAC7D,iEAAiE;YACjE,8BAA8B;YAC9B,KAAK,CAAC,CAAC,IAAA,gBAAI,EAAC,GAAG,EAAE,CAAC,IAAI,OAAO,CAAQ,GAAG,EAAE,GAAwB,CAAC,CAAC,CAAC,CAAC;YACtE,kCAAkC;YAClC,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK,CAAC,CAAC,IAAA,iBAAK,EAAC,SAAS,CAAC,CAAC;QACxB,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC,CAAC;IAEF,OAAO,KAAK,CAAC,CAAC,IAAA,gBAAI,EAAC,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * In-memory implementation of {@link AppConfigStore}.
3
+ *
4
+ * The `AppConfigStore` interface itself lives in
5
+ * `@lloyal-labs/lloyal-agents` (so the framework context
6
+ * `AppConfigStoreCtx` and app factories can share it without a
7
+ * dependency cycle). This module supplies the reference impl that dev
8
+ * harnesses, examples, and tests use; harnesses needing durable
9
+ * storage implement the interface themselves.
10
+ *
11
+ * @packageDocumentation
12
+ * @category Contract
13
+ */
14
+ import type { AppConfigStore } from '@lloyal-labs/lloyal-agents';
15
+ /**
16
+ * Create an in-memory `AppConfigStore` backed by a `Map`.
17
+ *
18
+ * Intended for development, tests, and single-process harnesses that
19
+ * don't need cross-restart persistence. Harnesses needing durable
20
+ * storage implement the interface themselves against their preferred
21
+ * backend (file system, encrypted secret store, remote KV, etc.).
22
+ *
23
+ * Configs are stored as-is (no deep clone on set/get). If the caller
24
+ * mutates a returned config object, those mutations are visible to
25
+ * subsequent reads — which would violate the whole-replace semantics.
26
+ * Callers should treat returned configs as immutable and re-`set` to
27
+ * update.
28
+ */
29
+ export declare function createInMemoryConfigStore(): AppConfigStore;
30
+ //# sourceMappingURL=config-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../src/config-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,IAAI,cAAc,CAa1D"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ /**
3
+ * In-memory implementation of {@link AppConfigStore}.
4
+ *
5
+ * The `AppConfigStore` interface itself lives in
6
+ * `@lloyal-labs/lloyal-agents` (so the framework context
7
+ * `AppConfigStoreCtx` and app factories can share it without a
8
+ * dependency cycle). This module supplies the reference impl that dev
9
+ * harnesses, examples, and tests use; harnesses needing durable
10
+ * storage implement the interface themselves.
11
+ *
12
+ * @packageDocumentation
13
+ * @category Contract
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.createInMemoryConfigStore = createInMemoryConfigStore;
17
+ /**
18
+ * Create an in-memory `AppConfigStore` backed by a `Map`.
19
+ *
20
+ * Intended for development, tests, and single-process harnesses that
21
+ * don't need cross-restart persistence. Harnesses needing durable
22
+ * storage implement the interface themselves against their preferred
23
+ * backend (file system, encrypted secret store, remote KV, etc.).
24
+ *
25
+ * Configs are stored as-is (no deep clone on set/get). If the caller
26
+ * mutates a returned config object, those mutations are visible to
27
+ * subsequent reads — which would violate the whole-replace semantics.
28
+ * Callers should treat returned configs as immutable and re-`set` to
29
+ * update.
30
+ */
31
+ function createInMemoryConfigStore() {
32
+ const store = new Map();
33
+ return {
34
+ *get(appName) {
35
+ return store.get(appName);
36
+ },
37
+ *set(appName, config) {
38
+ store.set(appName, config);
39
+ },
40
+ *clear(appName) {
41
+ store.delete(appName);
42
+ },
43
+ };
44
+ }
45
+ //# sourceMappingURL=config-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../src/config-store.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AAmBH,8DAaC;AA3BD;;;;;;;;;;;;;GAaG;AACH,SAAgB,yBAAyB;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAmC,CAAC;IACzD,OAAO;QACL,CAAC,GAAG,CAAC,OAAe;YAClB,OAAO,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;QACD,CAAC,GAAG,CAAC,OAAe,EAAE,MAA+B;YACnD,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC;QACD,CAAC,KAAK,CAAC,OAAe;YACpB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * `defineApp(spec): App` — sync wiring helper called inside every app's
3
+ * factory after constructing its `Source` and `Tool[]` instances.
4
+ *
5
+ * Performs all framework-side validations of the app's declared shape
6
+ * before the App enters the registry:
7
+ *
8
+ * - **Manifest schema.** `name` and `protocol.name` match
9
+ * `[a-z][a-z0-9_-]{1,63}`; `protocol.tools` is a non-empty unique array
10
+ * of names matching the same regex; `protocol.useWhen` is a single
11
+ * bounded sentence with no chat-role markers, code fences, or newlines
12
+ * (metadata sanitization).
13
+ * - **App protocol version.** `manifest.appProtocolVersion` is in
14
+ * `SUPPORTED_APP_PROTOCOL_VERSIONS`. Absence is permitted
15
+ * (treated as `"3.0"`).
16
+ * - **Tool map coverage.** The keys of the supplied `tools` object equal
17
+ * `manifest.protocol.tools[]` as a set — every declared tool has an
18
+ * implementation, no extras.
19
+ * - **Boundary-marker double-emission.** `skill` (when string-typed) MUST
20
+ * NOT contain the literal `Apply the **` substring — the framework
21
+ * prepends the marker via `BOUNDARY_MARKER`, so an `skill.eta` that
22
+ * includes the line would emit it twice.
23
+ *
24
+ * Validation errors throw synchronously with a clear message naming the
25
+ * failing field and the violated rule. App factories should call
26
+ * `defineApp` last (after `yield*`ing tool factories) so a malformed
27
+ * manifest fails at construction time, not later at registration.
28
+ *
29
+ * @packageDocumentation
30
+ * @category Protocol
31
+ */
32
+ import type { Tool, Source, App, AppManifest, SkillTemplateFn, ExamplesTemplateFn, ConfigFlow, AppHints } from '@lloyal-labs/lloyal-agents';
33
+ /**
34
+ * Argument to {@link defineApp}. The fields that survive into the
35
+ * returned {@link App} are surfaced here with the same names. There are
36
+ * no lifecycle hooks — setup is the factory body, teardown is `ensure(...)`.
37
+ */
38
+ export interface DefineAppSpec {
39
+ /** The declarative app manifest, imported from `app.json`. */
40
+ manifest: AppManifest;
41
+ /** The app's Source. */
42
+ source: Source;
43
+ /**
44
+ * Map of tool-name → Tool instance. Keys MUST equal
45
+ * `manifest.protocol.tools[]` as a set (exact membership match — no
46
+ * missing tools, no extras). Each value's `.name` property must match
47
+ * its key (otherwise the catalog's `Tools:` line and the agent's
48
+ * dispatched tool call would disagree).
49
+ */
50
+ tools: Readonly<Record<string, Tool>>;
51
+ /**
52
+ * The per-spawn template body. String → rendered via Eta with the
53
+ * `AgentRenderCtx` fields available as `it.*`. Function → invoked
54
+ * directly with the render context.
55
+ *
56
+ * MUST NOT contain the literal `Apply the **` substring when given as
57
+ * a string — the framework prepends the boundary marker.
58
+ */
59
+ skill: string | SkillTemplateFn;
60
+ /**
61
+ * Optional discipline content rendered into the per-spawn preamble of
62
+ * agents assigned to this app. Never enters the shared spine.
63
+ */
64
+ examples?: string | ExamplesTemplateFn;
65
+ /** Optional UX/marketplace hints (overrides `manifest.hints` if both present). */
66
+ hints?: AppHints;
67
+ /** Optional interactive config flow. */
68
+ configFlow?: ConfigFlow;
69
+ }
70
+ /**
71
+ * Validate an app's declared shape and return the runtime {@link App}
72
+ * object the framework will register and render against.
73
+ *
74
+ * Throws synchronously on the first validation failure with a message
75
+ * naming the failing field and the violated rule.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * export function* createJiraApp(): Operation<App> {
80
+ * const cfgStore = yield* AppConfigStoreCtx.expect();
81
+ * const cfg = yield* cfgStore.get(manifest.name);
82
+ * if (!cfg) throw new Error('jira app requires config');
83
+ *
84
+ * const source = new JiraSource(cfg);
85
+ * const searchTool = yield* createJiraSearchTool(cfg);
86
+ * const readTool = yield* createJiraReadTool(cfg);
87
+ *
88
+ * return defineApp({
89
+ * manifest,
90
+ * source,
91
+ * tools: { jira_search: searchTool, jira_read: readTool },
92
+ * skill: skillTemplate,
93
+ * });
94
+ * }
95
+ * ```
96
+ */
97
+ export declare function defineApp(spec: DefineAppSpec): App;
98
+ //# sourceMappingURL=define-app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-app.d.ts","sourceRoot":"","sources":["../src/define-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EACV,IAAI,EACJ,MAAM,EACN,GAAG,EACH,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACT,MAAM,4BAA4B,CAAC;AAGpC;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,QAAQ,EAAE,WAAW,CAAC;IACtB,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IACtC;;;;;;;OAOG;IACH,KAAK,EAAE,MAAM,GAAG,eAAe,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACvC,kFAAkF;IAClF,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,wCAAwC;IACxC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AA+KD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,GAAG,CAmClD"}
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ /**
3
+ * `defineApp(spec): App` — sync wiring helper called inside every app's
4
+ * factory after constructing its `Source` and `Tool[]` instances.
5
+ *
6
+ * Performs all framework-side validations of the app's declared shape
7
+ * before the App enters the registry:
8
+ *
9
+ * - **Manifest schema.** `name` and `protocol.name` match
10
+ * `[a-z][a-z0-9_-]{1,63}`; `protocol.tools` is a non-empty unique array
11
+ * of names matching the same regex; `protocol.useWhen` is a single
12
+ * bounded sentence with no chat-role markers, code fences, or newlines
13
+ * (metadata sanitization).
14
+ * - **App protocol version.** `manifest.appProtocolVersion` is in
15
+ * `SUPPORTED_APP_PROTOCOL_VERSIONS`. Absence is permitted
16
+ * (treated as `"3.0"`).
17
+ * - **Tool map coverage.** The keys of the supplied `tools` object equal
18
+ * `manifest.protocol.tools[]` as a set — every declared tool has an
19
+ * implementation, no extras.
20
+ * - **Boundary-marker double-emission.** `skill` (when string-typed) MUST
21
+ * NOT contain the literal `Apply the **` substring — the framework
22
+ * prepends the marker via `BOUNDARY_MARKER`, so an `skill.eta` that
23
+ * includes the line would emit it twice.
24
+ *
25
+ * Validation errors throw synchronously with a clear message naming the
26
+ * failing field and the violated rule. App factories should call
27
+ * `defineApp` last (after `yield*`ing tool factories) so a malformed
28
+ * manifest fails at construction time, not later at registration.
29
+ *
30
+ * @packageDocumentation
31
+ * @category Protocol
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.defineApp = defineApp;
35
+ const protocol_1 = require("./protocol");
36
+ // ── Validation regexes / constants ───────────────────────────────
37
+ /**
38
+ * Identifier shape for app names and protocol names. Lowercase ASCII
39
+ * start, lowercase alphanumeric / underscore / hyphen rest, length 2-64.
40
+ * This grammar is the M3 sanitization on shared-spine metadata — it
41
+ * ensures app-supplied strings can't break the markdown bold in the
42
+ * boundary marker (no `*`) and can't inject newlines, code fences, or
43
+ * chat-role markers.
44
+ */
45
+ const ID_RE = /^[a-z][a-z0-9_-]{1,63}$/;
46
+ /**
47
+ * Maximum length of `protocol.useWhen`. Bounded so the rendered catalog
48
+ * stays compact and to limit the residual semantic-injection surface
49
+ * available within the grammar's allowed character set.
50
+ */
51
+ const USE_WHEN_MAX_LEN = 280;
52
+ /**
53
+ * Patterns forbidden anywhere in `protocol.useWhen` — chat-role markers
54
+ * (would confuse the model into treating the catalog text as a fake
55
+ * conversation) and markdown code fences (would let an attacker break
56
+ * out of the catalog block into structured content).
57
+ */
58
+ const USE_WHEN_FORBIDDEN = [
59
+ /\bSYSTEM:/i,
60
+ /\bUSER:/i,
61
+ /\bASSISTANT\s+calls?:/i,
62
+ /\bASSISTANT:/i,
63
+ /```/,
64
+ /\r/,
65
+ /\n/,
66
+ ];
67
+ /** Substring whose presence in `skill` (string form) would cause double-emission. */
68
+ const BOUNDARY_MARKER_PREFIX = 'Apply the **';
69
+ // ── Validation helpers ───────────────────────────────────────────
70
+ function assertIdentifier(value, field) {
71
+ if (typeof value !== 'string') {
72
+ throw new Error(`defineApp: ${field} must be a string, got ${typeof value}`);
73
+ }
74
+ if (!ID_RE.test(value)) {
75
+ throw new Error(`defineApp: ${field} ${JSON.stringify(value)} does not match the required ` +
76
+ `identifier grammar ${ID_RE.toString()} (lowercase alphanumeric + _-, length 2-64). ` +
77
+ `This is an App protocol metadata invariant — names appear in the boundary ` +
78
+ `marker and shared spine catalog where injection-prone characters must be excluded.`);
79
+ }
80
+ }
81
+ function assertUseWhen(value) {
82
+ if (typeof value !== 'string') {
83
+ throw new Error(`defineApp: manifest.protocol.useWhen must be a string, got ${typeof value}`);
84
+ }
85
+ if (value.length === 0 || value.length > USE_WHEN_MAX_LEN) {
86
+ throw new Error(`defineApp: manifest.protocol.useWhen length ${value.length} out of bounds ` +
87
+ `[1, ${USE_WHEN_MAX_LEN}]. Keep it to a single short sentence.`);
88
+ }
89
+ for (const pattern of USE_WHEN_FORBIDDEN) {
90
+ if (pattern.test(value)) {
91
+ throw new Error(`defineApp: manifest.protocol.useWhen contains forbidden pattern ${pattern.toString()}. ` +
92
+ `useWhen renders into the shared spine catalog; chat-role markers, code fences, and ` +
93
+ `line breaks are excluded to prevent injection at the catalog-text layer.`);
94
+ }
95
+ }
96
+ }
97
+ function assertProtocolTools(tools) {
98
+ if (!Array.isArray(tools) || tools.length === 0) {
99
+ throw new Error(`defineApp: manifest.protocol.tools must be a non-empty array of tool-name strings`);
100
+ }
101
+ const seen = new Set();
102
+ for (const name of tools) {
103
+ assertIdentifier(name, `manifest.protocol.tools[*] (${JSON.stringify(name)})`);
104
+ if (seen.has(name)) {
105
+ throw new Error(`defineApp: manifest.protocol.tools contains duplicate ${JSON.stringify(name)}`);
106
+ }
107
+ seen.add(name);
108
+ }
109
+ }
110
+ function assertAppProtocolVersion(version) {
111
+ // Undefined is permitted — apps that don't declare a version are
112
+ // assumed to target the framework's default ("3.0"). The registry
113
+ // (enable-time) may tighten this if needed.
114
+ if (version === undefined)
115
+ return;
116
+ if (!protocol_1.SUPPORTED_APP_PROTOCOL_VERSIONS.includes(version)) {
117
+ throw new Error(`defineApp: manifest.appProtocolVersion ${JSON.stringify(version)} is not in the ` +
118
+ `supported set ${JSON.stringify(protocol_1.SUPPORTED_APP_PROTOCOL_VERSIONS)}. ` +
119
+ `This build of @lloyal-labs/rig only validates apps targeting one of those versions.`);
120
+ }
121
+ }
122
+ function assertToolMapCoverage(protocolTools, toolsMap) {
123
+ const declared = new Set(protocolTools);
124
+ const provided = new Set(Object.keys(toolsMap));
125
+ // Missing — tools declared in the protocol but not supplied as instances.
126
+ const missing = [];
127
+ for (const name of declared) {
128
+ if (!provided.has(name))
129
+ missing.push(name);
130
+ }
131
+ if (missing.length > 0) {
132
+ throw new Error(`defineApp: tools map is missing implementations for protocol.tools: ` +
133
+ `${JSON.stringify(missing)}. Every declared tool must have a corresponding ` +
134
+ `entry in the \`tools\` map passed to defineApp.`);
135
+ }
136
+ // Extras — tools supplied as instances but not declared in the protocol.
137
+ const extras = [];
138
+ for (const name of provided) {
139
+ if (!declared.has(name))
140
+ extras.push(name);
141
+ }
142
+ if (extras.length > 0) {
143
+ throw new Error(`defineApp: tools map contains entries not declared in manifest.protocol.tools: ` +
144
+ `${JSON.stringify(extras)}. Add them to protocol.tools or remove from the tools map ` +
145
+ `— the catalog Tools: line is rendered from protocol.tools and the auth-guard's ` +
146
+ `allowed-tools set is derived from the same array, so extras would never be callable.`);
147
+ }
148
+ // Name agreement — each Tool instance's .name must match its key.
149
+ for (const [key, tool] of Object.entries(toolsMap)) {
150
+ if (tool.name !== key) {
151
+ throw new Error(`defineApp: tools[${JSON.stringify(key)}].name = ${JSON.stringify(tool.name)} ` +
152
+ `does not match its map key. The map key is what the framework dispatches against; ` +
153
+ `the Tool's name is what the model sees in the schema. They must agree.`);
154
+ }
155
+ }
156
+ }
157
+ function assertSkillTemplate(skill) {
158
+ if (typeof skill === 'function') {
159
+ // Function-typed templates can't be statically validated here. The
160
+ // framework's first-render check catches double-emission
161
+ // at the first preamble render, not at defineApp time.
162
+ return;
163
+ }
164
+ if (typeof skill !== 'string') {
165
+ throw new Error(`defineApp: spec.skill must be a string or SkillTemplateFn, got ${typeof skill}`);
166
+ }
167
+ if (skill.includes(BOUNDARY_MARKER_PREFIX)) {
168
+ throw new Error(`defineApp: skill template contains the literal ${JSON.stringify(BOUNDARY_MARKER_PREFIX)} substring. ` +
169
+ `The framework prepends \`Apply the **<name>** protocol.\\n\\n\` via BOUNDARY_MARKER at ` +
170
+ `render time; including it in the template would emit it twice. Strip the ` +
171
+ `\`Apply the **...** protocol.\` line (and its trailing blank line) from skill.eta.`);
172
+ }
173
+ }
174
+ // ── defineApp ─────────────────────────────────────────────────────
175
+ /**
176
+ * Validate an app's declared shape and return the runtime {@link App}
177
+ * object the framework will register and render against.
178
+ *
179
+ * Throws synchronously on the first validation failure with a message
180
+ * naming the failing field and the violated rule.
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * export function* createJiraApp(): Operation<App> {
185
+ * const cfgStore = yield* AppConfigStoreCtx.expect();
186
+ * const cfg = yield* cfgStore.get(manifest.name);
187
+ * if (!cfg) throw new Error('jira app requires config');
188
+ *
189
+ * const source = new JiraSource(cfg);
190
+ * const searchTool = yield* createJiraSearchTool(cfg);
191
+ * const readTool = yield* createJiraReadTool(cfg);
192
+ *
193
+ * return defineApp({
194
+ * manifest,
195
+ * source,
196
+ * tools: { jira_search: searchTool, jira_read: readTool },
197
+ * skill: skillTemplate,
198
+ * });
199
+ * }
200
+ * ```
201
+ */
202
+ function defineApp(spec) {
203
+ // 1. Manifest top-level identifier.
204
+ assertIdentifier(spec.manifest.name, 'manifest.name');
205
+ // 2. App protocol version (if declared).
206
+ assertAppProtocolVersion(spec.manifest.appProtocolVersion);
207
+ // 3. Protocol substructure: name, useWhen, tools.
208
+ assertIdentifier(spec.manifest.protocol.name, 'manifest.protocol.name');
209
+ assertUseWhen(spec.manifest.protocol.useWhen);
210
+ assertProtocolTools(spec.manifest.protocol.tools);
211
+ // 4. Tools map coverage and name agreement.
212
+ assertToolMapCoverage(spec.manifest.protocol.tools, spec.tools);
213
+ // 5. Agent template double-emission guard.
214
+ assertSkillTemplate(spec.skill);
215
+ // Preserve `protocol.tools` insertion order in the runtime tools array
216
+ // — that's the order the catalog renders and the order the spine
217
+ // prefill receives schemas in. The framework relies on stable ordering
218
+ // for the §10.1 snapshot gate.
219
+ const tools = spec.manifest.protocol.tools.map((name) => spec.tools[name]);
220
+ return {
221
+ name: spec.manifest.name,
222
+ manifest: spec.manifest,
223
+ source: spec.source,
224
+ tools,
225
+ skill: spec.skill,
226
+ examples: spec.examples,
227
+ configSchema: spec.manifest.configSchema,
228
+ hints: spec.hints ?? spec.manifest.hints,
229
+ configFlow: spec.configFlow,
230
+ };
231
+ }
232
+ //# sourceMappingURL=define-app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-app.js","sourceRoot":"","sources":["../src/define-app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * In-memory implementation of {@link GrantStore}.
3
+ *
4
+ * The `GrantStore` interface itself lives in `@lloyal-labs/lloyal-agents`
5
+ * (so the framework context `GrantStoreCtx` and app/harness code share it
6
+ * without a dependency cycle). This module supplies the reference impl that
7
+ * dev harnesses, examples, and tests use; harnesses that back grants with
8
+ * a secrets manager or remote authorization service implement the
9
+ * interface themselves.
10
+ *
11
+ * A grant records that the session has obtained consent to invoke a
12
+ * `protected` tool (see {@link Tool.protected}). The **credential** behind
13
+ * that consent (an OAuth token, an API key) is the harness's concern and
14
+ * never enters the model's context — this store holds only the binary
15
+ * decision the authGuard reads.
16
+ *
17
+ * @packageDocumentation
18
+ * @category Contract
19
+ */
20
+ import type { GrantStore } from '@lloyal-labs/lloyal-agents';
21
+ /**
22
+ * Create an in-memory `GrantStore` backed by a `Set`.
23
+ *
24
+ * Intended for development, tests, and single-process harnesses. Pass
25
+ * `initial` to pre-grant a set of protected tools at construction (a
26
+ * harness that has already obtained consent, or a test fixture).
27
+ * Harnesses needing durable or audited grants implement the interface
28
+ * themselves against their preferred backend.
29
+ */
30
+ export declare function createGrantStore(initial?: Iterable<string>): GrantStore;
31
+ //# sourceMappingURL=grant-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grant-store.d.ts","sourceRoot":"","sources":["../src/grant-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE7D;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,UAAU,CAgBvE"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /**
3
+ * In-memory implementation of {@link GrantStore}.
4
+ *
5
+ * The `GrantStore` interface itself lives in `@lloyal-labs/lloyal-agents`
6
+ * (so the framework context `GrantStoreCtx` and app/harness code share it
7
+ * without a dependency cycle). This module supplies the reference impl that
8
+ * dev harnesses, examples, and tests use; harnesses that back grants with
9
+ * a secrets manager or remote authorization service implement the
10
+ * interface themselves.
11
+ *
12
+ * A grant records that the session has obtained consent to invoke a
13
+ * `protected` tool (see {@link Tool.protected}). The **credential** behind
14
+ * that consent (an OAuth token, an API key) is the harness's concern and
15
+ * never enters the model's context — this store holds only the binary
16
+ * decision the authGuard reads.
17
+ *
18
+ * @packageDocumentation
19
+ * @category Contract
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.createGrantStore = createGrantStore;
23
+ /**
24
+ * Create an in-memory `GrantStore` backed by a `Set`.
25
+ *
26
+ * Intended for development, tests, and single-process harnesses. Pass
27
+ * `initial` to pre-grant a set of protected tools at construction (a
28
+ * harness that has already obtained consent, or a test fixture).
29
+ * Harnesses needing durable or audited grants implement the interface
30
+ * themselves against their preferred backend.
31
+ */
32
+ function createGrantStore(initial) {
33
+ const grants = new Set(initial);
34
+ return {
35
+ *has(toolName) {
36
+ return grants.has(toolName);
37
+ },
38
+ *grant(toolName) {
39
+ grants.add(toolName);
40
+ },
41
+ *revoke(toolName) {
42
+ grants.delete(toolName);
43
+ },
44
+ *granted() {
45
+ return [...grants];
46
+ },
47
+ };
48
+ }
49
+ //# sourceMappingURL=grant-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grant-store.js","sourceRoot":"","sources":["../src/grant-store.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;AAcH,4CAgBC;AAzBD;;;;;;;;GAQG;AACH,SAAgB,gBAAgB,CAAC,OAA0B;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAS,OAAO,CAAC,CAAC;IACxC,OAAO;QACL,CAAC,GAAG,CAAC,QAAgB;YACnB,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QACD,CAAC,KAAK,CAAC,QAAgB;YACrB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;QACD,CAAC,MAAM,CAAC,QAAgB;YACtB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;QACD,CAAC,OAAO;YACN,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}