@almadar/shell-runtime 0.0.0-stage → 1.0.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.
Files changed (127) hide show
  1. package/dist/chunk-4SEK5ER2.js +8 -0
  2. package/dist/chunk-57SBCUSM.js +62 -0
  3. package/dist/chunk-625EP7W2.js +108 -0
  4. package/dist/chunk-64IH2SMY.js +22 -0
  5. package/dist/chunk-7SDV3QWR.js +67 -0
  6. package/dist/chunk-7WB6VWRK.js +798 -0
  7. package/dist/chunk-A2JJT4GA.js +56 -0
  8. package/dist/chunk-BAS26HBN.js +10 -0
  9. package/dist/chunk-BOVU4TCQ.js +65 -0
  10. package/dist/chunk-BY5G4225.js +6 -0
  11. package/dist/chunk-DFDNHVDW.js +284 -0
  12. package/dist/chunk-ELBLT2HZ.js +1 -0
  13. package/dist/chunk-EZZYLTWY.js +1 -0
  14. package/dist/chunk-FWA5K7Q2.js +48 -0
  15. package/dist/chunk-HC6ERSAH.js +55 -0
  16. package/dist/chunk-HLOUDLPI.js +48 -0
  17. package/dist/chunk-I3TKINSO.js +398 -0
  18. package/dist/chunk-IOPUS6Q5.js +15 -0
  19. package/dist/chunk-LKWYCYX5.js +22 -0
  20. package/dist/chunk-LYFIQPXX.js +1 -0
  21. package/dist/chunk-LZIOTBFX.js +1 -0
  22. package/dist/chunk-MU335ZA4.js +63 -0
  23. package/dist/chunk-MZKIL5IN.js +74 -0
  24. package/dist/chunk-N7HYNKK6.js +83 -0
  25. package/dist/chunk-NTFQ36UN.js +52 -0
  26. package/dist/chunk-NU6LVKGS.js +15 -0
  27. package/dist/chunk-O57GKTYU.js +30 -0
  28. package/dist/chunk-P2N6K2IV.js +20 -0
  29. package/dist/chunk-P53CKOME.js +1 -0
  30. package/dist/chunk-QCJWPXLH.js +40 -0
  31. package/dist/chunk-SKLMWHQD.js +109 -0
  32. package/dist/chunk-SOQDEPME.js +131 -0
  33. package/dist/chunk-UBN5JJKZ.js +26 -0
  34. package/dist/chunk-UD2CXYSJ.js +244 -0
  35. package/dist/chunk-UP6GGGAN.js +34 -0
  36. package/dist/chunk-V4EMDPCO.js +33 -0
  37. package/dist/chunk-VNGXRYFF.js +9 -0
  38. package/dist/chunk-WGCWJOT2.js +21 -0
  39. package/dist/chunk-X6W44WHO.js +26 -0
  40. package/dist/chunk-XXWNMJI6.js +15 -0
  41. package/dist/chunk-ZUSM4VW4.js +197 -0
  42. package/dist/client/EventTransport.d.ts +147 -0
  43. package/dist/client/EventTransport.js +1 -0
  44. package/dist/client/awaiting.d.ts +28 -0
  45. package/dist/client/awaiting.js +1 -0
  46. package/dist/client/channel-transport.d.ts +69 -0
  47. package/dist/client/channel-transport.js +1 -0
  48. package/dist/client/circuit-store.d.ts +87 -0
  49. package/dist/client/circuit-store.js +3 -0
  50. package/dist/client/client-kernel.d.ts +134 -0
  51. package/dist/client/client-kernel.js +1 -0
  52. package/dist/client/declared-input-dispatch.d.ts +22 -0
  53. package/dist/client/declared-input-dispatch.js +1 -0
  54. package/dist/client/inbound-dispatch.d.ts +24 -0
  55. package/dist/client/inbound-dispatch.js +1 -0
  56. package/dist/client/local-fold.d.ts +33 -0
  57. package/dist/client/local-fold.js +1 -0
  58. package/dist/client/render-sigils.d.ts +24 -0
  59. package/dist/client/render-sigils.js +1 -0
  60. package/dist/client/state-book.d.ts +30 -0
  61. package/dist/client/state-book.js +1 -0
  62. package/dist/client/trait-mount-error.d.ts +9 -0
  63. package/dist/client/trait-mount-error.js +1 -0
  64. package/dist/client/trait-types.d.ts +67 -0
  65. package/dist/client/trait-types.js +1 -0
  66. package/dist/credentials/env-vars.d.ts +18 -0
  67. package/dist/credentials/env-vars.js +1 -0
  68. package/dist/credentials/scope.d.ts +51 -0
  69. package/dist/credentials/scope.js +1 -0
  70. package/dist/credentials/vault.d.ts +142 -0
  71. package/dist/credentials/vault.js +1 -0
  72. package/dist/effects/in-flight-calls.d.ts +36 -0
  73. package/dist/effects/in-flight-calls.js +1 -0
  74. package/dist/effects/on-device-model.d.ts +22 -0
  75. package/dist/effects/on-device-model.js +1 -0
  76. package/dist/events/EventBus.d.ts +87 -0
  77. package/dist/events/EventBus.js +1 -0
  78. package/dist/events/emit-stamp.d.ts +47 -0
  79. package/dist/events/emit-stamp.js +1 -0
  80. package/dist/index.d.ts +43 -0
  81. package/dist/index.js +41 -0
  82. package/dist/kernel/decode.d.ts +13 -0
  83. package/dist/kernel/decode.js +1 -0
  84. package/dist/kernel/engine.d.ts +195 -0
  85. package/dist/kernel/engine.js +9 -0
  86. package/dist/kernel/frame-applier.d.ts +44 -0
  87. package/dist/kernel/frame-applier.js +1 -0
  88. package/dist/kernel/host.d.ts +206 -0
  89. package/dist/kernel/host.js +6 -0
  90. package/dist/kernel/lane.d.ts +7 -0
  91. package/dist/kernel/lane.js +1 -0
  92. package/dist/kernel/os-fetch-port.d.ts +7 -0
  93. package/dist/kernel/os-fetch-port.js +3 -0
  94. package/dist/kernel/os-port.d.ts +155 -0
  95. package/dist/kernel/os-port.js +1 -0
  96. package/dist/kernel/program-effects.d.ts +48 -0
  97. package/dist/kernel/program-effects.js +1 -0
  98. package/dist/kernel/secret-ports.d.ts +139 -0
  99. package/dist/kernel/secret-ports.js +2 -0
  100. package/dist/kernel/wire.d.ts +104 -0
  101. package/dist/kernel/wire.js +1 -0
  102. package/dist/loader/fetch-loader.d.ts +26 -0
  103. package/dist/loader/fetch-loader.js +1 -0
  104. package/dist/loader/lazy-page.d.ts +12 -0
  105. package/dist/loader/lazy-page.js +1 -0
  106. package/dist/loader/schema-loader.d.ts +144 -0
  107. package/dist/loader/schema-loader.js +1 -0
  108. package/dist/persistence/native-memory.d.ts +28 -0
  109. package/dist/persistence/native-memory.js +1 -0
  110. package/dist/runtime/entities/declaredCollections.d.ts +6 -0
  111. package/dist/runtime/entities/declaredCollections.js +1 -0
  112. package/dist/runtime/evaluation/local-store-transport.d.ts +59 -0
  113. package/dist/runtime/evaluation/local-store-transport.js +14 -0
  114. package/dist/runtime/evaluation/residence-transport.d.ts +15 -0
  115. package/dist/runtime/evaluation/residence-transport.js +1 -0
  116. package/dist/runtime/evaluation/routed-persistence.d.ts +9 -0
  117. package/dist/runtime/evaluation/routed-persistence.js +1 -0
  118. package/dist/runtime/events/identity/routing.d.ts +33 -0
  119. package/dist/runtime/events/identity/routing.js +1 -0
  120. package/dist/runtime/types.d.ts +374 -0
  121. package/dist/runtime/types.js +1 -0
  122. package/dist/service/default-call-service.d.ts +23 -0
  123. package/dist/service/default-call-service.js +2 -0
  124. package/dist/service/service-provider.d.ts +37 -0
  125. package/dist/service/service-provider.js +1 -0
  126. package/package.json +49 -3
  127. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ export { routeByEntity } from '../../chunk-O57GKTYU.js';
@@ -0,0 +1,33 @@
1
+ import { EventId } from '@almadar/core';
2
+
3
+ /**
4
+ * Identity-keyed routing (Almadar Rabit V4, Phase 4 — interpreter path).
5
+ *
6
+ * The runtime routes cross-trait events by NAME today: the bus key is the
7
+ * event name and source filtering compares orbital/trait name strings. A
8
+ * mid-session rename (a ledger `curName` edit that updates a node's own
9
+ * display name but deliberately does NOT rewrite the name strings held by
10
+ * every reference) therefore breaks name routing — the emitter now stamps
11
+ * the new name while the listener still holds the old one.
12
+ *
13
+ * These helpers make routing resolve by ID when the schema carries ids
14
+ * (ledger-backed, V4), and fall back to name while dual-carry. Ids are the
15
+ * stable edge keys: a rename never touches a node's id or any `*Id`
16
+ * reference, so id-routed bindings survive it. Legacy id-free schemas take
17
+ * the name path unchanged — byte-for-byte the previous behavior.
18
+ *
19
+ * @packageDocumentation
20
+ */
21
+
22
+ /**
23
+ * The bus subscription/delivery key for an event. When an `eventId` is
24
+ * present the key is the id (namespaced so it can never collide with a
25
+ * bare event name); otherwise it is the event name (legacy path).
26
+ *
27
+ * The event ENVELOPE keeps the human name as its `type` — only the routing
28
+ * key changes — so observability, the client re-broadcast wire shape, and
29
+ * wildcard listeners are untouched.
30
+ */
31
+ declare function eventRouteKey(eventName: string, eventId?: EventId | string): string;
32
+
33
+ export { eventRouteKey };
@@ -0,0 +1 @@
1
+ export { eventRouteKey } from '../../../chunk-BY5G4225.js';
@@ -0,0 +1,374 @@
1
+ import { CallServiceHandler } from '../service/default-call-service.js';
2
+ import { ServiceCallContext } from '../service/service-provider.js';
3
+ import { EventPayload, BusEventSource, BusEventListener, Unsubscribe as Unsubscribe$1, BusEvent, EntityRow, TraitConfig, UserContext, NavItem, RuntimeValue, FieldValue, SExpr, FetchResult, RowSetRef, PatternConfig, PageFactField, BrowserPageFacts, JsonValue, ServiceHostPorts, AgentContext, LlmContext, WorkspaceContext, SessionContext, MemoryContext, TraceContext, ResolvedPatternProps } from '@almadar/core';
4
+ export { EntityRow, EventPayload, FetchResult, ServiceParams } from '@almadar/core';
5
+ import { ProgramEffectName, ProgramEffectOutcome } from '../kernel/program-effects.js';
6
+ import '@almadar/core/kernel-wire';
7
+
8
+ /**
9
+ * Unified Runtime Types
10
+ *
11
+ * Platform-agnostic interfaces for trait execution on client or server.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+
16
+ /** Alias for ResolvedPatternProps to avoid breaking internal consumers */
17
+ type PatternProps = ResolvedPatternProps;
18
+
19
+ type ConfigContext = TraitConfig;
20
+ /**
21
+ * Event structure for cross-trait communication.
22
+ * Re-export of `BusEvent` from `@almadar/core` so runtime + ui + codegen
23
+ * all agree on the bus envelope shape. `RuntimeEvent` is kept as a type
24
+ * alias for anyone importing by the old name.
25
+ */
26
+ type RuntimeEvent = BusEvent;
27
+ type EventListener = BusEventListener;
28
+ type Unsubscribe = Unsubscribe$1;
29
+ /**
30
+ * Event bus interface for pub/sub communication
31
+ */
32
+ interface IEventBus {
33
+ /** Emit an event. `routingKey` (V4) keys delivery by event-id when the
34
+ * schema carries ids; absent → keyed by `type` (name, legacy). */
35
+ emit(type: string, payload?: EventPayload, source?: BusEventSource, routingKey?: string): void;
36
+ /** Subscribe to an event */
37
+ on(type: string, listener: EventListener): Unsubscribe;
38
+ /** Subscribe to ALL events (wildcard listener) */
39
+ onAny(listener: EventListener): Unsubscribe;
40
+ /** Check if there are listeners for an event */
41
+ hasListeners(type: string): boolean;
42
+ /** Get all registered event types */
43
+ getRegisteredEvents(): string[];
44
+ /** Clear all listeners */
45
+ clear(): void;
46
+ }
47
+ /**
48
+ * Effect handlers interface - platform-specific implementations
49
+ *
50
+ * Client: React hooks, DOM, router
51
+ * Server: Express, database, integrators
52
+ */
53
+ interface EffectHandlers {
54
+ /**
55
+ * Emit an event to the event bus.
56
+ *
57
+ * `source` carries the emitter's identity (orbital + trait) so that
58
+ * source-scoped listeners (`TraitName EVENT -> TRIGGER` and
59
+ * `Orbital.TraitName EVENT -> TRIGGER` in .lolo) can filter incoming
60
+ * events by their originating trait. Omitted when the emit is
61
+ * synthesized by a non-trait context (e.g. test harness).
62
+ *
63
+ * `fromPersistSuccess` is set only by `EffectExecutor`'s `persist` case
64
+ * (batch and single-op), never inferred from the event name — the
65
+ * positional signal a server-side implementation uses to also fan this
66
+ * emit out to other connected clients (live-broadcast). Absent/false
67
+ * for every other emit source (plain `emit` effect, `set`/`call-service`/
68
+ * `fetch` success envelopes, cascade re-emits).
69
+ */
70
+ emit: (event: string, payload?: EventPayload, source?: RuntimeEvent['source'], fromPersistSuccess?: boolean) => void;
71
+ /**
72
+ * Persist data (create/update/delete/batch).
73
+ *
74
+ * Returns the persisted ROW — for a create that is the submitted data
75
+ * plus the store-minted `id`, which the caller's `emit:{success}`
76
+ * envelope carries. Without it a `*_CREATED` listener sees no id (the
77
+ * compiled path emits the created row), so anything routing on the new
78
+ * row's identity — navigating to the page just created — worked in one
79
+ * execution path only.
80
+ *
81
+ * `create`/`update`/`delete` (batch is separate — see `PersistBatchSummary`)
82
+ * return `undefined` ONLY to signal the write was DENIED or otherwise
83
+ * failed (a policy rejection, a missing row key, a no-op stub) — never
84
+ * a genuine success with nothing to report, since every real success
85
+ * branch sets a row. The caller (`EffectExecutor`'s `persist` case)
86
+ * treats `undefined` as a failure: it skips the declared `success`
87
+ * emit entirely rather than falling back to the submitted data, which
88
+ * previously made a denied delete indistinguishable from a completed
89
+ * one.
90
+ */
91
+ persist: (action: 'create' | 'upsert' | 'update' | 'delete' | 'batch', entityType: string, data?: EntityRow) => Promise<EntityRow | undefined>;
92
+ /**
93
+ * Runs a run of consecutive plain persists as stop-mode requests (one when nothing is refused) when the store declares it. Answers the
94
+ * per-op results in order (`undefined` = that persist failed, a handled outcome, and the ones after it still run).
95
+ * Answers `null` when the run cannot be pushed, and the executor then runs the effects one by one.
96
+ */
97
+ persistRun?: (ops: Array<{
98
+ action: 'create' | 'upsert' | 'update' | 'delete';
99
+ entityType: string;
100
+ data: EntityRow | string | undefined;
101
+ }>) => Promise<Array<EntityRow | undefined> | null>;
102
+ /**
103
+ * Bridge mode: the SERVER executes every persist of this dispatch and
104
+ * returns the real outcome in its response (`effectResults`), so the
105
+ * client's `persist` member is a placeholder that must never be read as
106
+ * a denial. When `true`, `EffectExecutor` skips the persist locally —
107
+ * no `persist:denied` error, no client-side `failure` emit (which fired
108
+ * the declared failure event in the browser while the server had
109
+ * succeeded), no `success` emit either (the server's cascade carries it).
110
+ * Set by `@almadar/ui`'s `createClientEffectHandlers` when no live
111
+ * client entity is supplied; absent everywhere a handler really writes.
112
+ */
113
+ persistDelegated?: true;
114
+ /**
115
+ * Bridge mode: the SERVER runs every `call-service` of this dispatch and
116
+ * its cascade carries the success/failure emits, so the client's mock
117
+ * `callService` must not also run one. Set by `@almadar/ui`'s
118
+ * `createClientEffectHandlers` when no consumer `callService` is wired.
119
+ */
120
+ callServiceDelegated?: true;
121
+ /**
122
+ * Set a field value on an entity. `void` for a client-side/in-memory
123
+ * handler (synchronous mutation); `Promise<void>` for a server-side
124
+ * handler backed by real persistence (e.g. `createServerEffectHandlers`,
125
+ * Firestore) — callers MUST `await` this, not just call it, or the
126
+ * write (and any telemetry it records) can still be in flight when the
127
+ * caller moves on. Verified 2026-09-15: `EffectExecutor.dispatch`'s
128
+ * 'set' case called this without `await`, invisible against every
129
+ * existing (synchronous, in-memory) test but a real dropped-write race
130
+ * the instant a real async persistence backend (Firestore) was wired in.
131
+ */
132
+ set: (entityId: string, field: string, value: FieldValue) => void | Promise<void>;
133
+ /** Call an external service. `context` carries the caller's identity
134
+ * (the same viewer entity ACL enforces against) so role-gated services
135
+ * can enforce server-side; hosts forward it to the integration factory. */
136
+ callService: CallServiceHandler;
137
+ /** Fetch entity data (server only) - returns data for client-side rendering.
138
+ *
139
+ * Always returns a `FetchResult` (`{rows, total}`) on success. `total`
140
+ * is the count of rows matching the `filter` BEFORE `offset`/`limit`
141
+ * are applied so a paginating caller can compute totalPages without
142
+ * a second round-trip. Single-id fetches return `total: 1`. `null`
143
+ * means "not found / failed".
144
+ */
145
+ fetch?: (entityType: string, options?: {
146
+ id?: string;
147
+ filter?: SExpr | Record<string, RuntimeValue>;
148
+ limit?: number;
149
+ offset?: number;
150
+ /** `"field"` or `"field:asc|desc"` — ordered before offset/limit */
151
+ orderBy?: string;
152
+ /** `none`: the store need not count every match; the success payload carries no `totalCount`. */
153
+ total?: 'exact' | 'none';
154
+ /** Relation fields to include (populate) in the response */
155
+ include?: string[];
156
+ }) => Promise<FetchResult | null>;
157
+ /** A collection fetch delivered by reference (`fetch … { deliver: ids }`, server only): the window's ids, the
158
+ * count of every match and the query that re-counts it at resolve time. Rejects when the fetch cannot be
159
+ * expressed as a row query, which the executor routes to `emit.failure`. */
160
+ fetchRowSet?: (entityType: string, options?: {
161
+ filter?: SExpr | Record<string, RuntimeValue>;
162
+ limit?: number;
163
+ offset?: number;
164
+ /** `"field"` or `"field:asc|desc"` — ordered before offset/limit */
165
+ orderBy?: string;
166
+ /** `none`: the store need not count every match; the success payload carries no `totalCount`. */
167
+ total?: 'exact' | 'none';
168
+ }) => Promise<RowSetRef>;
169
+ /** Stream an LLM or HTTP response (server only).
170
+ *
171
+ * Calls `onChunk` per incoming chunk; resolves with the final aggregated
172
+ * result on completion. The executor fires `emit.on_message` per chunk and
173
+ * `emit.success` on resolution. `null` means stream failed before any chunk.
174
+ */
175
+ fetchStream?: (entityType: string, options: {
176
+ id?: string;
177
+ filter?: SExpr | Record<string, RuntimeValue>;
178
+ } | undefined, onChunk: (chunk: RuntimeValue) => void) => Promise<RuntimeValue>;
179
+ /** Spawn a new entity instance */
180
+ spawn?: (entityType: string, props?: EntityRow) => void;
181
+ /** Despawn (delete) an entity instance */
182
+ despawn?: (entityId: string) => void;
183
+ /** Send an orbital event to the server over WebSocket (client-only).
184
+ *
185
+ * Produces the wire message `{ type: 'ORBITAL_EVENT', payload: { orbital, event, payload, entityId? } }`
186
+ * which `setupEventBroadcast` decodes → server bus → `processOrbitalEvent`.
187
+ */
188
+ sendServer?: (event: string, payload?: EventPayload) => void;
189
+ /** Render UI to a slot (client only). `pattern` is the post-interpolation
190
+ * `PatternConfig` from the trait's `(render-ui slot pattern)` SExpr, or
191
+ * `null` when the trait clears the slot (`render-ui slot null`).
192
+ * May be async: the server runtime injects relation option data
193
+ * (relationsData) read from the persistence adapter before pushing —
194
+ * the interpreter's mirror of codegen's build-time relationsData. */
195
+ renderUI?: (slot: string, pattern: PatternConfig | null) => void | Promise<void>;
196
+ /** Navigate to a route (client only). `crumb` labels the navigation-stack
197
+ * entry the client pushes for the target page (from the effect's
198
+ * `{ crumb: … }` options). */
199
+ navigate?: (path: string, params?: {
200
+ [key: string]: string;
201
+ }, crumb?: string) => void;
202
+ /** Pop the orbital-scoped navigation stack and return to the previous
203
+ * entry (client only). */
204
+ navigateBack?: () => void;
205
+ /** Log a message */
206
+ log?: (message: string, level?: 'log' | 'warn' | 'error', data?: RuntimeValue) => void;
207
+ /** browser/open-file-picker — resolves with `{ files }` inside `result` */
208
+ browserOpenFilePicker?: (options?: BrowserFilePickerOptions) => Promise<{
209
+ files: BrowserFileMeta[];
210
+ }>;
211
+ /** browser/clipboard-read — resolves with `{ text }` inside `result` */
212
+ browserClipboardRead?: () => Promise<{
213
+ text: string;
214
+ }>;
215
+ /** browser/clipboard-write — resolves with `{ text }` (echo) inside `result` */
216
+ browserClipboardWrite?: (text: string) => Promise<{
217
+ text: string;
218
+ }>;
219
+ /** browser/geolocation-current — resolves with the position inside `result` */
220
+ browserGeolocationCurrent?: (options?: BrowserGeolocationOptions) => Promise<BrowserGeolocationPosition>;
221
+ /**
222
+ * browser/page-facts — reads the requested facts in the order given and resolves with the flat facts
223
+ * (`PAGE_FACTS_SHAPE`). No page resolves `available: false`; a getter that throws rejects, which is not no-page.
224
+ */
225
+ browserPageFacts?: (fields: readonly PageFactField[]) => Promise<BrowserPageFacts>;
226
+ /**
227
+ * browser/prompt — the on-device model's raw reply text for `text` under the JSON Schema text; rejects with an
228
+ * `OnDeviceModelFailure` (`unconfigured`, `unavailable` or `failed`), and stops on an aborted `signal`.
229
+ */
230
+ browserPrompt?: (text: string, schemaText: string, key: string | null, signal?: AbortSignal) => Promise<string>;
231
+ /** browser/embed — one vector per text, in input order; rejects as `browserPrompt` does. */
232
+ browserEmbed?: (texts: readonly string[], key: string | null, signal?: AbortSignal) => Promise<number[][]>;
233
+ /** browser/push-subscribe — resolves with the flat Web Push subscription credentials inside `result` */
234
+ browserPushSubscribe?: () => Promise<{
235
+ endpoint: string;
236
+ p256dh: string;
237
+ auth: string;
238
+ }>;
239
+ programEffect?: (op: ProgramEffectName, args: readonly JsonValue[], context?: Pick<ServiceCallContext, 'principal' | 'role'>) => Promise<ProgramEffectOutcome>;
240
+ agentPorts?: () => ServiceHostPorts | undefined;
241
+ }
242
+ /** Options for `browser/open-file-picker`. */
243
+ interface BrowserFilePickerOptions {
244
+ /** Allow selecting multiple files. */
245
+ multiple?: boolean;
246
+ /** MIME type filter (e.g. "image/*"). Best-effort; host may ignore. */
247
+ accept?: string;
248
+ }
249
+ /** Metadata for a file chosen via `browser/open-file-picker`. */
250
+ interface BrowserFileMeta {
251
+ name: string;
252
+ size: number;
253
+ type: string;
254
+ lastModified: number;
255
+ }
256
+ /** Options for `browser/geolocation-current` (subset of PositionOptions). */
257
+ interface BrowserGeolocationOptions {
258
+ enableHighAccuracy?: boolean;
259
+ timeout?: number;
260
+ maximumAge?: number;
261
+ }
262
+ /** Position returned by `browser/geolocation-current`. */
263
+ interface BrowserGeolocationPosition {
264
+ latitude: number;
265
+ longitude: number;
266
+ accuracy: number;
267
+ }
268
+ /**
269
+ * Context for resolving bindings like @entity.field, @payload.value
270
+ */
271
+ interface BindingContext {
272
+ /** Current entity data */
273
+ entity?: EntityRow;
274
+ /** Event payload data */
275
+ payload?: EventPayload;
276
+ /** Current state name */
277
+ state?: string;
278
+ /** Trait-level state/config */
279
+ config?: ConfigContext;
280
+ /** Authenticated viewer behind `@user.x` — ownership (`@user.id`) and role gates. */
281
+ user?: UserContext;
282
+ /** The dispatch's one `now` stamp (ms epoch) — every guard, effect and time operator in it reads this. */
283
+ now?: number;
284
+ /** `@locale`: the viewer's locale (`EventRequest.locale`, else the program's first declared locale). */
285
+ locale?: string;
286
+ /** That locale's catalog — `i18n/t` reads it. */
287
+ messages?: Readonly<Record<string, string>>;
288
+ /** `@event`: the delivery being processed (Runtime Spec Clause 5.5). */
289
+ event?: EventPayload;
290
+ /** `@prevEvents`: deliveries this trait already received this dispatch. */
291
+ prevEvents?: EventPayload[];
292
+ /** `@prevStates`: states this trait left this dispatch. */
293
+ prevStates?: string[];
294
+ /** `@fromState` / `@toState`: the transition's ends. */
295
+ fromState?: string;
296
+ toState?: string;
297
+ /**
298
+ * The host orbital's pages for the `@pages` render sigil (`href`/`label`
299
+ * per inline page). Seeded onto the render binding context only — never
300
+ * present on a guard/tick context. Mirrors the compiler's
301
+ * `OirBindingRoot::Pages`.
302
+ */
303
+ pages?: NavItem[];
304
+ /**
305
+ * The `data-theme` key string for the `@currentTheme` render sigil,
306
+ * derived from the host orbital's `Orbital.theme`. Render-context only.
307
+ */
308
+ currentTheme?: string;
309
+ /**
310
+ * Local variables introduced by a `let` form, keyed by bare name and
311
+ * referenced via `@<name>` (the canonical evaluator convention — same as
312
+ * `createChildContext` in `@almadar/evaluator`). Carried on the context so
313
+ * a `let` body's effects resolve their value expressions against the
314
+ * `let`-bound locals.
315
+ */
316
+ locals?: Map<string, RuntimeValue>;
317
+ /**
318
+ * The composing effect's triggering payload, for a trait embedded via
319
+ * `@trait.X` inline into a parent's render-ui. Set when re-running an
320
+ * embedded child's lifecycle transition under its embedder's payload
321
+ * (see `OrbitalServerRuntime.executeEffects` / the client's
322
+ * `useTraitStateMachine`), so `@callsitePayload.<field>` resolves on the
323
+ * child's evaluation context — mirrors the compiled path's
324
+ * `CALLSITE_PAYLOAD_PREFIX` capture.
325
+ */
326
+ callsitePayload?: EventPayload;
327
+ /** Additional custom bindings */
328
+ [key: string]: RuntimeValue | undefined;
329
+ }
330
+ /**
331
+ * Executable effect tuple: operator name plus already-resolved arguments.
332
+ *
333
+ * Runtime-local on purpose — NOT `@almadar/core`'s `Effect` (`TypedEffect`),
334
+ * which is a CLOSED union of authoring-time tuples. The runtime's operator
335
+ * set is extensible (custom handlers, `os/*`, substrate ops), so the executor
336
+ * input is this open tuple. The wire-level type for effect lists stays
337
+ * `SExpr[]` (`TransitionResult.effects`, `TraitDefinition.transitions[].effects`);
338
+ * narrow it to `Effect[]` at the executor boundary with {@link isEffectTuple}.
339
+ */
340
+ type Effect = [string, ...RuntimeValue[]];
341
+ /**
342
+ * Result of executing a single effect, with status tracking.
343
+ */
344
+ interface EffectResult {
345
+ /** Effect operator (e.g., "persist", "render-ui") */
346
+ type: string;
347
+ /** Effect arguments */
348
+ args: RuntimeValue[];
349
+ /** Whether the effect executed successfully */
350
+ status: "executed" | "failed" | "skipped";
351
+ /** Error message if failed */
352
+ error?: string;
353
+ /** Execution duration in milliseconds */
354
+ durationMs?: number;
355
+ /** Refused before the effect's handler ran (e.g. a `persist create` missing a
356
+ * required field), so no handler recorded it — the host reports it. */
357
+ refusedBeforeHandler?: boolean;
358
+ }
359
+ /**
360
+ * Typed extensions that get spread onto every EvaluationContext.
361
+ * Each field here corresponds to an optional field on EvaluationContext.
362
+ */
363
+ interface EvaluationContextExtensions {
364
+ /** Agent context for agent/* operators (memory, LLM, tools, session) */
365
+ agent?: AgentContext;
366
+ /** Substrate contexts for the new operator namespaces */
367
+ llm?: LlmContext;
368
+ workspace?: WorkspaceContext;
369
+ session?: SessionContext;
370
+ memory?: MemoryContext;
371
+ trace?: TraceContext;
372
+ }
373
+
374
+ export type { BindingContext, Effect, EffectHandlers, EffectResult, EvaluationContextExtensions, EventListener, IEventBus, PatternProps, RuntimeEvent, Unsubscribe };
@@ -0,0 +1 @@
1
+ import '../chunk-LYFIQPXX.js';
@@ -0,0 +1,23 @@
1
+ import { ServiceParams, BusEventSource, EventPayload } from '@almadar/core';
2
+ import { ServiceCallContext } from './service-provider.js';
3
+
4
+ /**
5
+ * The runtime's own `call-service` answerer when the host injects none: the services a host plugged in with
6
+ * `registerServiceProvider`. A call to a service nobody plugged in fails by name, so the trait's declared failure event fires.
7
+ */
8
+
9
+ /**
10
+ * Where a running `call-service`'s live messages go: the call site's
11
+ * `emit.onMessage` event, stamped as the calling trait. Absent when the call
12
+ * site declares no `onMessage`.
13
+ */
14
+ interface ServiceMessageRoute {
15
+ event: string;
16
+ source?: BusEventSource;
17
+ }
18
+ /** Call an external service. `context` carries the caller's identity (the same viewer entity ACL enforces against) so role-gated services can enforce server-side; hosts forward it to the integration factory. */
19
+ type CallServiceHandler = (service: string, action: string, params?: ServiceParams, context?: ServiceCallContext, message?: ServiceMessageRoute) => Promise<EventPayload | null>;
20
+ declare function defaultCallService(service: string, action: string, params: ServiceParams | undefined, context?: ServiceCallContext): Promise<EventPayload | null>;
21
+
22
+ export { defaultCallService };
23
+ export type { CallServiceHandler, ServiceMessageRoute };
@@ -0,0 +1,2 @@
1
+ export { defaultCallService } from '../chunk-4SEK5ER2.js';
2
+ import '../chunk-UBN5JJKZ.js';
@@ -0,0 +1,37 @@
1
+ import { ServiceHostPorts, ServiceParams, EventPayload } from '@almadar/core';
2
+
3
+ /**
4
+ * Caller identity forwarded with a call-service dispatch (I-25) — the id and
5
+ * roster role of the SAME normalized viewer entity ACL enforces against.
6
+ * Absent when no viewer is bound (ticks, anonymous); role-gated services
7
+ * fail closed on absence.
8
+ */
9
+ interface ServiceCallContext {
10
+ principal?: string;
11
+ role?: string;
12
+ /** The running app, lent for this call as the caller (`page watch`). */
13
+ host?: ServiceHostPorts;
14
+ /** Aborted when `cancel-call` cancels this call; a provider stops its work on it. */
15
+ signal?: AbortSignal;
16
+ /** No request awaits this call (a follow-on step's call): the host holds no request's event queue around it. */
17
+ outsideRequest?: true;
18
+ }
19
+ /** Why a service call failed, for a provider to name: bad params, no host installed, no signed-in caller, an action it does not have. */
20
+ type ServiceCallErrorCode = 'VALIDATION_ERROR' | 'NOT_CONFIGURED' | 'AUTH_ERROR' | 'UNKNOWN_ACTION';
21
+ declare class ServiceCallError extends Error {
22
+ readonly code: ServiceCallErrorCode;
23
+ constructor(message: string, code: ServiceCallErrorCode);
24
+ }
25
+ /** A host's answerer for the `call-service` calls of one named service: resolves the payload, throws to fail the call. */
26
+ type ServiceProvider = (action: string, params: ServiceParams, context?: ServiceCallContext) => Promise<EventPayload | null>;
27
+ /** Plug a service's answerer into this process's `call-service`; a later registration of the same name replaces it. */
28
+ declare function registerServiceProvider(service: string, provider: ServiceProvider): void;
29
+ /** Testing/reset hook. */
30
+ declare function unregisterServiceProvider(service: string): void;
31
+ /** The names of the services a host has plugged in. */
32
+ declare function registeredServices(): string[];
33
+ /** Calls `service.action` through the registered provider; a service no host plugged in is a named failure. */
34
+ declare function callRegisteredService(service: string, action: string, params: ServiceParams | undefined, context?: ServiceCallContext): Promise<EventPayload | null>;
35
+
36
+ export { ServiceCallError, callRegisteredService, registerServiceProvider, registeredServices, unregisterServiceProvider };
37
+ export type { ServiceCallContext, ServiceCallErrorCode, ServiceProvider };
@@ -0,0 +1 @@
1
+ export { ServiceCallError, callRegisteredService, registerServiceProvider, registeredServices, unregisterServiceProvider } from '../chunk-UBN5JJKZ.js';
package/package.json CHANGED
@@ -1,6 +1,52 @@
1
1
  {
2
2
  "name": "@almadar/shell-runtime",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0",
4
+ "orbRelease": {
5
+ "severity": "normal"
6
+ },
7
+ "description": "Renderer-neutral kernel adapters and client orchestration for Almadar TypeScript hosts.",
8
+ "license": "BUSL-1.1",
9
+ "type": "module",
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./*": {
18
+ "types": "./dist/*.d.ts",
19
+ "import": "./dist/*.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "sideEffects": false,
26
+ "dependencies": {
27
+ "@almadar/core": "^11.1.0",
28
+ "@almadar/kernel": "^19.0.1",
29
+ "@almadar/logger": "^2.1.0",
30
+ "@almadar/std": "^17.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "tsup": "^9.0.0",
35
+ "typescript": "npm:@typescript/typescript6@^6.0.2",
36
+ "vitest": "^4.1.12"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/almadar-io/orbital-shell-typescript.git",
41
+ "directory": "runtime/kernel"
42
+ },
43
+ "publishConfig": {
44
+ "registry": "https://registry.npmjs.org",
45
+ "access": "public"
46
+ },
47
+ "scripts": {
48
+ "build": "NODE_OPTIONS=--max-old-space-size=8192 tsup",
49
+ "typecheck": "tsc --noEmit",
50
+ "test": "vitest --run"
51
+ }
6
52
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.