@swirls/looms 0.2.0 → 0.4.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 (113) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/actor/host.js +4 -6
  3. package/dist/actor/index.d.ts +1 -1
  4. package/dist/actor/index.js +1 -1
  5. package/dist/actor/routing.d.ts +5 -0
  6. package/dist/actor/routing.js +14 -0
  7. package/dist/agent/agent-session.js +1 -0
  8. package/dist/agent/debugger/agent-chat.js +45 -38
  9. package/dist/agent/debugger/streaming-text.d.ts +6 -0
  10. package/dist/agent/debugger/streaming-text.js +33 -0
  11. package/dist/agent/debugger/summarize.js +2 -0
  12. package/dist/agent/effects.d.ts +30 -0
  13. package/dist/agent/events.d.ts +2 -0
  14. package/dist/agent/events.js +2 -0
  15. package/dist/agent/llm.js +1 -8
  16. package/dist/agent/module.d.ts +230 -160
  17. package/dist/agent/module.js +11 -7
  18. package/dist/agent/projections.d.ts +5 -0
  19. package/dist/agent/projections.js +43 -2
  20. package/dist/agent/scope.d.ts +2 -0
  21. package/dist/agent/signals.d.ts +5 -0
  22. package/dist/agent/signals.js +7 -0
  23. package/dist/agent/threads.js +35 -21
  24. package/dist/agent/transcript.d.ts +7 -0
  25. package/dist/agent/transcript.js +19 -0
  26. package/dist/agent/types.d.ts +10 -0
  27. package/dist/agent/types.js +4 -0
  28. package/dist/approval/debugger/approvals-view.js +5 -3
  29. package/dist/approval/effects.d.ts +12 -0
  30. package/dist/approval/module.d.ts +24 -0
  31. package/dist/client/client.d.ts +292 -0
  32. package/dist/client/client.js +17 -1
  33. package/dist/cloudflare/router.d.ts +1 -1
  34. package/dist/cloudflare/router.js +6 -8
  35. package/dist/core/attempts.d.ts +8 -0
  36. package/dist/core/attempts.js +27 -0
  37. package/dist/core/effects.d.ts +7 -0
  38. package/dist/core/effects.js +1 -0
  39. package/dist/core/fold.js +12 -6
  40. package/dist/core/fork.d.ts +35 -0
  41. package/dist/core/fork.js +129 -0
  42. package/dist/core/index.d.ts +3 -0
  43. package/dist/core/index.js +2 -0
  44. package/dist/core/module-scope.d.ts +1 -0
  45. package/dist/core/module.d.ts +2 -2
  46. package/dist/core/projection.d.ts +5 -4
  47. package/dist/core/projection.js +1 -0
  48. package/dist/core/protocol.d.ts +10 -1
  49. package/dist/core/protocol.js +11 -0
  50. package/dist/{react → core}/register.d.ts +9 -8
  51. package/dist/core/replay.d.ts +8 -0
  52. package/dist/core/snapshots.js +3 -17
  53. package/dist/core/state.d.ts +14 -0
  54. package/dist/core/state.js +25 -2
  55. package/dist/core/store.d.ts +1 -0
  56. package/dist/debugger/app/assets/index-CgDzWJg7.css +2 -0
  57. package/dist/debugger/app/assets/index-D--9esm9.js +22 -0
  58. package/dist/debugger/app/assets/routes-Dakrdusf.js +47 -0
  59. package/dist/debugger/app/index.html +2 -2
  60. package/dist/debugger/components/composer.d.ts +5 -2
  61. package/dist/debugger/components/composer.js +5 -4
  62. package/dist/debugger/components/run-tree.js +2 -5
  63. package/dist/debugger/events/catalog.js +1 -3
  64. package/dist/debugger/events/protocol-summarize.js +7 -0
  65. package/dist/debugger/lib/event-counts.d.ts +2 -2
  66. package/dist/debugger/lib/event-counts.js +5 -9
  67. package/dist/debugger/shell/debugger-shell.js +1 -1
  68. package/dist/debugger/shell/run-controls.d.ts +2 -1
  69. package/dist/debugger/shell/run-controls.js +40 -13
  70. package/dist/debugger/shell/run-search.js +1 -3
  71. package/dist/evaluator/effects.d.ts +45 -33
  72. package/dist/evaluator/module.d.ts +90 -66
  73. package/dist/projectors/index-model.d.ts +13 -7
  74. package/dist/projectors/index-model.js +21 -26
  75. package/dist/projectors/memory.js +19 -11
  76. package/dist/projectors/postgres.js +20 -19
  77. package/dist/projectors/schema.js +20 -18
  78. package/dist/projectors/sqlite.js +32 -27
  79. package/dist/react/derived.d.ts +26 -8
  80. package/dist/react/derived.js +23 -26
  81. package/dist/react/index.d.ts +3 -3
  82. package/dist/react/index.js +2 -2
  83. package/dist/react/materialize.js +16 -11
  84. package/dist/react/react.d.ts +12 -9
  85. package/dist/react/react.js +9 -6
  86. package/dist/react/store.d.ts +4 -5
  87. package/dist/react/tables.d.ts +3 -2
  88. package/dist/runtime/cancellation.js +14 -27
  89. package/dist/runtime/errors.d.ts +39 -0
  90. package/dist/runtime/errors.js +32 -0
  91. package/dist/runtime/helpers.d.ts +2 -0
  92. package/dist/runtime/helpers.js +23 -1
  93. package/dist/runtime/index.d.ts +1 -1
  94. package/dist/runtime/index.js +1 -1
  95. package/dist/runtime/looms.d.ts +4 -0
  96. package/dist/runtime/looms.js +1 -0
  97. package/dist/runtime/run-start.js +1 -3
  98. package/dist/runtime/runtime.d.ts +1 -1
  99. package/dist/runtime/runtime.js +45 -18
  100. package/dist/runtime/server/http.d.ts +2 -0
  101. package/dist/runtime/server/http.js +17 -2
  102. package/dist/runtime/server/routes/runs.js +35 -2
  103. package/dist/runtime/types.d.ts +8 -0
  104. package/dist/runtime/wake-engine.js +5 -2
  105. package/dist/s2/snapshot-store.js +2 -6
  106. package/dist/workflow/effects.d.ts +24 -0
  107. package/dist/workflow/effects.js +1 -0
  108. package/dist/workflow/module.d.ts +48 -0
  109. package/package.json +2 -2
  110. package/dist/debugger/app/assets/index-B3Ah8WAE.css +0 -2
  111. package/dist/debugger/app/assets/index-Qb371t_O.js +0 -22
  112. package/dist/debugger/app/assets/routes-CjtEHgPQ.js +0 -47
  113. /package/dist/{react → core}/register.js +0 -0
@@ -0,0 +1,129 @@
1
+ import { Data, Effect, Predicate } from 'effect';
2
+ import { isPrimitiveEffect, isWithdrawnError, } from './effects.js';
3
+ import { createEvent } from './envelope.js';
4
+ import { foldEvent, foldRun } from './fold.js';
5
+ import { emptyRunState, isRunTerminal } from './state.js';
6
+ import { isTerminalStatus } from './thread.js';
7
+ export class ForkSourceError extends Data.TaggedError('ForkSourceError') {
8
+ constructor(runId, message) {
9
+ super({ runId, message });
10
+ this.name = 'ForkSourceError';
11
+ }
12
+ }
13
+ function payloadThreadId(event) {
14
+ const threadId = Predicate.isObject(event.payload) ? event.payload.threadId : undefined;
15
+ return Predicate.isString(threadId) ? threadId : event.threadId;
16
+ }
17
+ function rootTerminal(state) {
18
+ const root = state.rootThreadId ? state.threads[state.rootThreadId] : undefined;
19
+ return isRunTerminal(state) || (root !== undefined && isTerminalStatus(root.status));
20
+ }
21
+ /** Where the cancellation that wrote `event` began, when it recorded that; a seq is an index + 1. */
22
+ function cancellationStart(event) {
23
+ const resumeSeq = event.type === 'runtime.thread.cancelled' && Predicate.isObject(event.payload)
24
+ ? event.payload.resumeSeq
25
+ : undefined;
26
+ return Predicate.isNumber(resumeSeq) ? resumeSeq : undefined;
27
+ }
28
+ /**
29
+ * Fold the source until its root thread ends. Everything from that event on is how the run
30
+ * finished, so the fork leaves it out; a cancellation that recorded where it began is left
31
+ * out from there.
32
+ */
33
+ function scanSource(events, registry) {
34
+ const effects = new Map();
35
+ const failedAt = new Map();
36
+ let state = emptyRunState(events[0]?.runId ?? '');
37
+ for (const [index, event] of events.entries()) {
38
+ state = foldEvent(state, event, registry);
39
+ for (const item of state.outstandingEffects) {
40
+ effects.set(item.effectId, item.effect);
41
+ }
42
+ for (const record of Object.values(state.threads)) {
43
+ if (record.status === 'failed' && !failedAt.has(record.threadId)) {
44
+ failedAt.set(record.threadId, index);
45
+ }
46
+ }
47
+ if (rootTerminal(state)) {
48
+ const root = state.rootThreadId ? state.threads[state.rootThreadId] : undefined;
49
+ const rootFailed = root?.status === 'failed' || state.status === 'failed';
50
+ return { cut: cancellationStart(event) ?? index, effects, failedAt, rootFailed };
51
+ }
52
+ }
53
+ return { cut: events.length, effects, failedAt, rootFailed: false };
54
+ }
55
+ /**
56
+ * Walk back from the root's failure to the effect outcome that started it, so the fork
57
+ * re-issues that effect instead of replaying a failure the modules already folded in.
58
+ */
59
+ function failureOrigin(events, scan, registry) {
60
+ const indexById = new Map(events.map((event, index) => [event.id, index]));
61
+ /** A failed thread leads back to where the fold failed it, anything else to its cause. */
62
+ const previous = (index) => {
63
+ const event = events[index];
64
+ const threadId = event.type === 'runtime.thread.failed' ? payloadThreadId(event) : null;
65
+ const failedAt = threadId ? scan.failedAt.get(threadId) : undefined;
66
+ const cause = event.causationId ? indexById.get(event.causationId) : undefined;
67
+ const next = failedAt !== undefined && failedAt < index ? failedAt : cause;
68
+ return next !== undefined && next < index ? next : undefined;
69
+ };
70
+ for (let index = scan.cut; index !== undefined; index = previous(index)) {
71
+ const event = events[index];
72
+ const effect = event.effectId ? scan.effects.get(event.effectId) : undefined;
73
+ const error = Predicate.isObject(event.payload) ? event.payload.error : undefined;
74
+ const withdrawn = Predicate.isString(error) && isWithdrawnError(error);
75
+ if (effect &&
76
+ !isPrimitiveEffect(effect) &&
77
+ !registry.effects.get(effect.type)?.deterministic &&
78
+ !withdrawn) {
79
+ return index;
80
+ }
81
+ }
82
+ return scan.cut;
83
+ }
84
+ function copyEvent(event, runId, reissued) {
85
+ if (event.ephemeral && event.effectId && reissued.has(event.effectId)) {
86
+ return { ...event, runId, type: 'runtime.fork.elided', payload: { type: event.type } };
87
+ }
88
+ if (event.type === 'runtime.snapshot.taken' && Predicate.isObject(event.payload)) {
89
+ const { state: _state, ...pointer } = event.payload;
90
+ return { ...event, runId, payload: pointer };
91
+ }
92
+ if (event.type === 'runtime.run.started') {
93
+ return { ...event, runId, idempotencyKey: null };
94
+ }
95
+ return { ...event, runId };
96
+ }
97
+ /**
98
+ * Plan a new run that continues where the source run ended. The fork copies the source's
99
+ * history up to the point the run finished, keeping sequence numbers so effect ids still
100
+ * line up, and its next wake re-issues whatever effects were outstanding there.
101
+ */
102
+ export function planFork(input) {
103
+ const { sourceRunId, runId, events, registry } = input;
104
+ if (events.length === 0) {
105
+ return Effect.fail(new ForkSourceError(sourceRunId, `Run "${sourceRunId}" has no events`));
106
+ }
107
+ if (events.some((event, index) => event.seq !== index + 1)) {
108
+ return Effect.fail(new ForkSourceError(sourceRunId, `Run "${sourceRunId}" does not have its full history from seq 1; it cannot be forked`));
109
+ }
110
+ const scan = scanSource(events, registry);
111
+ const cut = scan.rootFailed ? failureOrigin(events, scan, registry) : scan.cut;
112
+ const prefix = events.slice(0, cut);
113
+ const atCut = foldRun(prefix, registry, { runId });
114
+ if (!atCut.rootThreadId) {
115
+ return Effect.fail(new ForkSourceError(sourceRunId, `Run "${sourceRunId}" never started a root thread`));
116
+ }
117
+ const reissued = new Set(atCut.outstandingEffects.map((item) => item.effectId));
118
+ const marker = createEvent(runId, {
119
+ type: 'runtime.run.forked',
120
+ payload: { sourceRunId, sourceSeq: cut },
121
+ threadId: null,
122
+ origin: { type: 'system' },
123
+ }, { seq: cut + 1 });
124
+ return Effect.succeed({
125
+ events: [...prefix.map((event) => copyEvent(event, runId, reissued)), marker],
126
+ sourceSeq: cut,
127
+ rootThreadId: atCut.rootThreadId,
128
+ });
129
+ }
@@ -13,7 +13,10 @@ export * from './state';
13
13
  export * from './match';
14
14
  export * from './fold';
15
15
  export * from './replay';
16
+ export * from './fork';
16
17
  export * from './projection';
18
+ export * from './attempts';
19
+ export type * from './register';
17
20
  export * from './module';
18
21
  export * from './kind';
19
22
  export * from './module-scope';
@@ -12,7 +12,9 @@ export * from './state.js';
12
12
  export * from './match.js';
13
13
  export * from './fold.js';
14
14
  export * from './replay.js';
15
+ export * from './fork.js';
15
16
  export * from './projection.js';
17
+ export * from './attempts.js';
16
18
  export * from './module.js';
17
19
  export * from './kind.js';
18
20
  export * from './module-scope.js';
@@ -65,6 +65,7 @@ export interface ModuleScope<TNamespace extends string, U extends EventEnvelope<
65
65
  input?: TSchema;
66
66
  retry?: RetryPolicy;
67
67
  execution?: EffectExecution;
68
+ deterministic?: boolean;
68
69
  execute?: (input: TInput, ctx: ScopedEffectContext<EventInputOf<U>>) => EffectHandlerResult<R, EventInputOf<U>, HandlerError>;
69
70
  }): NoInfer<EffectDefinition<TInput, R, EventInputOf<U>>>;
70
71
  input<K extends keyof (TEvents extends EventCatalog<any, infer E> ? E : never) & string>(key: K, payload: InferPayload<(TEvents extends EventCatalog<any, infer E> ? E : never)[K]>, meta?: Omit<EventInput, 'type' | 'payload'>): Omit<EventInput, 'type' | 'payload'> & {
@@ -10,8 +10,8 @@ export type NextEffectHandler = (effect: RuntimeEffect, ctx: EffectContext) => E
10
10
  export type EffectMiddleware = (effect: RuntimeEffect, ctx: EffectContext, next: NextEffectHandler) => Effect.Effect<ReadonlyArray<EventInput>, Error>;
11
11
  /**
12
12
  * Names the threads whose in-process effects an admitted signal event interrupts, so a running
13
- * effect (such as a model call) can stop early. Return an empty array when the event interrupts
14
- * nothing.
13
+ * effect (such as a model call) can stop early. The runtime also interrupts each named thread's
14
+ * descendants. Return an empty array when the event interrupts nothing.
15
15
  */
16
16
  export type SignalInterruptRule = (event: EventInput) => readonly string[];
17
17
  export interface RuntimeModuleDependency {
@@ -1,5 +1,6 @@
1
1
  import { Schema, Stream, type Effect } from 'effect';
2
2
  import type { EventEnvelope } from './envelope';
3
+ import type { AnyEventEnvelope, RegisteredEvent } from './register';
3
4
  import type { InferSchemaOutput, SchemaInput } from './schema';
4
5
  import type { RunState, ThreadRecord } from './state';
5
6
  export interface ProjectionDefinition<S = unknown> {
@@ -8,17 +9,17 @@ export interface ProjectionDefinition<S = unknown> {
8
9
  initialState: S;
9
10
  reduce(state: S, event: EventEnvelope): S;
10
11
  }
11
- export declare function defineProjection<S = unknown>(def: {
12
+ export declare function defineProjection<S = unknown, TEvent extends AnyEventEnvelope = RegisteredEvent>(def: {
12
13
  readonly name: string;
13
14
  readonly shape?: undefined;
14
15
  readonly initialState: S;
15
- reduce(state: S, event: EventEnvelope): S;
16
+ reduce(state: S, event: TEvent): S;
16
17
  }): ProjectionDefinition<S>;
17
- export declare function defineProjection<TShape extends SchemaInput>(def: {
18
+ export declare function defineProjection<TShape extends SchemaInput, TEvent extends AnyEventEnvelope = RegisteredEvent>(def: {
18
19
  readonly name: string;
19
20
  readonly shape: TShape;
20
21
  readonly initialState: InferSchemaOutput<TShape>;
21
- reduce(state: NoInfer<InferSchemaOutput<TShape>>, event: EventEnvelope): InferSchemaOutput<TShape>;
22
+ reduce(state: NoInfer<InferSchemaOutput<TShape>>, event: TEvent): InferSchemaOutput<TShape>;
22
23
  }): ProjectionDefinition<InferSchemaOutput<TShape>>;
23
24
  export declare function foldProjection<S>(projection: ProjectionDefinition<S>, events: readonly EventEnvelope[], initial?: S): S;
24
25
  /** Fold a projection over events, skipping ephemeral ones. */
@@ -174,6 +174,7 @@ export function toThreadTree(state) {
174
174
  status: 'running',
175
175
  rootThreadId: state.rootThreadId,
176
176
  startIdentity: null,
177
+ forkedFrom: null,
177
178
  threads: state.records,
178
179
  waits: {},
179
180
  outstandingEffects: [],
@@ -17,6 +17,13 @@ export declare const protocolCatalog: import("./catalog").EventCatalog<"runtime"
17
17
  'run.cancelled': Schema.Struct<{
18
18
  readonly reason: Schema.optional<Schema.String>;
19
19
  }>;
20
+ 'run.forked': Schema.Struct<{
21
+ readonly sourceRunId: Schema.String;
22
+ readonly sourceSeq: Schema.Finite;
23
+ }>;
24
+ 'fork.elided': Schema.Struct<{
25
+ readonly type: Schema.String;
26
+ }>;
20
27
  'thread.started': Schema.Struct<{
21
28
  readonly threadId: Schema.String;
22
29
  readonly kind: Schema.String;
@@ -36,6 +43,8 @@ export declare const protocolCatalog: import("./catalog").EventCatalog<"runtime"
36
43
  'thread.cancelled': Schema.Struct<{
37
44
  readonly threadId: Schema.String;
38
45
  readonly reason: Schema.optional<Schema.String>;
46
+ /** The run's last seq before this cancellation began; a fork of the run resumes there. */
47
+ readonly resumeSeq: Schema.optional<Schema.Finite>;
39
48
  }>;
40
49
  'thread.cancel.requested': Schema.Struct<{
41
50
  readonly threadId: Schema.String;
@@ -138,7 +147,7 @@ export declare const protocolCatalog: import("./catalog").EventCatalog<"runtime"
138
147
  }>;
139
148
  export type ProtocolEvent = EventsOfCatalog<typeof protocolCatalog>;
140
149
  export type ProtocolEventInput = EventInputOf<typeof protocolCatalog>;
141
- export declare const PROTOCOL_TYPES: readonly ['runtime.run.started', 'runtime.run.completed', 'runtime.run.cancelled', 'runtime.thread.started', 'runtime.thread.completed', 'runtime.thread.failed', 'runtime.thread.cancelled', 'runtime.thread.cancel.requested', 'runtime.wait.registered', 'runtime.wait.satisfied', 'runtime.timer.set', 'runtime.timer.fired', 'runtime.effect.failed', 'runtime.effect.attempt.started', 'runtime.effect.queued', 'runtime.effect.dispatched', 'runtime.effect.worker.started', 'runtime.effect.heartbeat', 'runtime.effect.cancel.requested', 'runtime.effect.cancelled', 'runtime.effect.completed', 'runtime.effect.timed_out', 'runtime.effect.ambiguous', 'runtime.effect.retry.scheduled', 'runtime.snapshot.taken', 'runtime.signal.received'];
150
+ export declare const PROTOCOL_TYPES: readonly ['runtime.run.started', 'runtime.run.completed', 'runtime.run.cancelled', 'runtime.run.forked', 'runtime.fork.elided', 'runtime.thread.started', 'runtime.thread.completed', 'runtime.thread.failed', 'runtime.thread.cancelled', 'runtime.thread.cancel.requested', 'runtime.wait.registered', 'runtime.wait.satisfied', 'runtime.timer.set', 'runtime.timer.fired', 'runtime.effect.failed', 'runtime.effect.attempt.started', 'runtime.effect.queued', 'runtime.effect.dispatched', 'runtime.effect.worker.started', 'runtime.effect.heartbeat', 'runtime.effect.cancel.requested', 'runtime.effect.cancelled', 'runtime.effect.completed', 'runtime.effect.timed_out', 'runtime.effect.ambiguous', 'runtime.effect.retry.scheduled', 'runtime.snapshot.taken', 'runtime.signal.received'];
142
151
  export type ProtocolEventType = (typeof PROTOCOL_TYPES)[number];
143
152
  export declare function isProtocolType(type: string): type is ProtocolEventType;
144
153
  export type RunStartedPayload = Schema.Schema.Type<(typeof protocolCatalog.entries)['run.started']>;
@@ -20,6 +20,13 @@ export const protocolCatalog = defineEventCatalog('runtime', {
20
20
  'run.cancelled': Schema.Struct({
21
21
  reason: Schema.optional(Schema.String),
22
22
  }),
23
+ 'run.forked': Schema.Struct({
24
+ sourceRunId: Schema.String,
25
+ sourceSeq: Schema.Finite,
26
+ }),
27
+ 'fork.elided': Schema.Struct({
28
+ type: Schema.String,
29
+ }),
23
30
  'thread.started': Schema.Struct({
24
31
  threadId: Schema.String,
25
32
  kind: Schema.String,
@@ -39,6 +46,8 @@ export const protocolCatalog = defineEventCatalog('runtime', {
39
46
  'thread.cancelled': Schema.Struct({
40
47
  threadId: Schema.String,
41
48
  reason: Schema.optional(Schema.String),
49
+ /** The run's last seq before this cancellation began; a fork of the run resumes there. */
50
+ resumeSeq: Schema.optional(Schema.Finite),
42
51
  }),
43
52
  'thread.cancel.requested': Schema.Struct({
44
53
  threadId: Schema.String,
@@ -138,6 +147,8 @@ export const PROTOCOL_TYPES = [
138
147
  'runtime.run.started',
139
148
  'runtime.run.completed',
140
149
  'runtime.run.cancelled',
150
+ 'runtime.run.forked',
151
+ 'runtime.fork.elided',
141
152
  'runtime.thread.started',
142
153
  'runtime.thread.completed',
143
154
  'runtime.thread.failed',
@@ -1,11 +1,12 @@
1
- import type { EventEnvelope, EventsOf } from '@swirls/looms/core';
1
+ import type { EventsOf } from './compose';
2
+ import type { EventEnvelope } from './envelope';
2
3
  /** Looser event bound so catalog-inferred payloads (including Schema.Type) are accepted. */
3
4
  export type AnyEventEnvelope = EventEnvelope<string, any>;
4
5
  /**
5
- * Application-level type registry for Looms React/client stores.
6
+ * Application-level type registry for Looms.
6
7
  *
7
- * Augment this interface in your app to bind the event catalog used by
8
- * `useRunEvents`, `createLoomsStore`, and related hooks:
8
+ * Augment this interface once to bind your event union. `defineProjection` reducers and the
9
+ * `@swirls/looms/react` hooks and stores use it as their default event type:
9
10
  *
10
11
  * ```ts
11
12
  * declare module '@swirls/looms/react' {
@@ -15,7 +16,7 @@ export type AnyEventEnvelope = EventEnvelope<string, any>;
15
16
  * }
16
17
  * ```
17
18
  *
18
- * You may register either:
19
+ * Augmenting `@swirls/looms/core` works the same way. You may register either:
19
20
  * - `events`: an explicit event union
20
21
  * - `modules`: a module array / creator function (via `EventsOf`)
21
22
  * - `catalog`: an event catalog or catalog array (via `EventsOf`)
@@ -24,8 +25,8 @@ export interface LoomsRegister {
24
25
  }
25
26
  export type RegisteredEvent = LoomsRegister extends {
26
27
  events: infer E;
27
- } ? E & AnyEventEnvelope : LoomsRegister extends {
28
+ } ? Extract<E, AnyEventEnvelope> : LoomsRegister extends {
28
29
  modules: infer M;
29
- } ? EventsOf<M> & AnyEventEnvelope : LoomsRegister extends {
30
+ } ? Extract<EventsOf<M>, AnyEventEnvelope> : LoomsRegister extends {
30
31
  catalog: infer C;
31
- } ? EventsOf<C> & AnyEventEnvelope : EventEnvelope;
32
+ } ? Extract<EventsOf<C>, AnyEventEnvelope> : EventEnvelope;
@@ -49,6 +49,10 @@ export declare const ReplayStepSchema: Schema.Struct<{
49
49
  readonly idempotencyKey: Schema.NullOr<Schema.String>;
50
50
  readonly rootThreadId: Schema.String;
51
51
  }>>, never>;
52
+ readonly forkedFrom: Schema.withDecodingDefaultKey<Schema.NullOr<Schema.Struct<{
53
+ readonly runId: Schema.String;
54
+ readonly seq: Schema.Finite;
55
+ }>>, never>;
52
56
  readonly threads: Schema.$Record<Schema.String, Schema.Struct<{
53
57
  readonly threadId: Schema.String;
54
58
  readonly kind: Schema.String;
@@ -161,6 +165,10 @@ export declare const ReplayStepSchema: Schema.Struct<{
161
165
  readonly idempotencyKey: Schema.NullOr<Schema.String>;
162
166
  readonly rootThreadId: Schema.String;
163
167
  }>>, never>;
168
+ readonly forkedFrom: Schema.withDecodingDefaultKey<Schema.NullOr<Schema.Struct<{
169
+ readonly runId: Schema.String;
170
+ readonly seq: Schema.Finite;
171
+ }>>, never>;
164
172
  readonly threads: Schema.$Record<Schema.String, Schema.Struct<{
165
173
  readonly threadId: Schema.String;
166
174
  readonly kind: Schema.String;
@@ -21,14 +21,7 @@ export function shouldTakeSnapshot(events, every = DEFAULT_SNAPSHOT_EVERY) {
21
21
  if (durable.length === 0) {
22
22
  return false;
23
23
  }
24
- let lastSnap;
25
- for (let i = events.length - 1; i >= 0; i--) {
26
- const candidate = events[i];
27
- if (candidate?.type === 'runtime.snapshot.taken') {
28
- lastSnap = candidate;
29
- break;
30
- }
31
- }
24
+ const lastSnap = events.findLast((e) => e.type === 'runtime.snapshot.taken');
32
25
  const since = lastSnap ? durable.filter((e) => e.seq > lastSnap.seq).length : durable.length;
33
26
  return since >= every;
34
27
  }
@@ -66,17 +59,10 @@ export function buildSnapshotMarker(runId, cursor, stateHash, options) {
66
59
  }
67
60
  export function foldFromSnapshots(events, registry, options) {
68
61
  const runId = options?.runId ?? events[0]?.runId ?? 'unknown';
69
- let latestSnapIdx = -1;
70
- for (let i = events.length - 1; i >= 0; i--) {
71
- if (events[i]?.type === 'runtime.snapshot.taken') {
72
- latestSnapIdx = i;
73
- break;
74
- }
75
- }
76
- if (latestSnapIdx < 0) {
62
+ const snap = events.findLast((e) => e.type === 'runtime.snapshot.taken');
63
+ if (!snap) {
77
64
  return foldRun(events, registry, { runId });
78
65
  }
79
- const snap = events[latestSnapIdx];
80
66
  const decoded = Schema.decodeUnknownSync(SnapshotTakenPayloadSchema)(snap.payload);
81
67
  if (decoded.state !== undefined) {
82
68
  const trailing = events.filter((e) => e.seq > decoded.seq);
@@ -46,11 +46,17 @@ export interface RunStartIdentity {
46
46
  idempotencyKey: string | null;
47
47
  rootThreadId: string;
48
48
  }
49
+ /** The run and last sequence a fork copied its history from. */
50
+ export interface RunForkSource {
51
+ runId: string;
52
+ seq: number;
53
+ }
49
54
  export interface RunState {
50
55
  runId: string;
51
56
  status: RunStatus;
52
57
  rootThreadId: string | null;
53
58
  startIdentity: RunStartIdentity | null;
59
+ forkedFrom: RunForkSource | null;
54
60
  threads: {
55
61
  [threadId: string]: ThreadRecord;
56
62
  };
@@ -77,6 +83,10 @@ export declare const RunStateSchema: Schema.Struct<{
77
83
  readonly idempotencyKey: Schema.NullOr<Schema.String>;
78
84
  readonly rootThreadId: Schema.String;
79
85
  }>>, never>;
86
+ readonly forkedFrom: Schema.withDecodingDefaultKey<Schema.NullOr<Schema.Struct<{
87
+ readonly runId: Schema.String;
88
+ readonly seq: Schema.Finite;
89
+ }>>, never>;
80
90
  readonly threads: Schema.$Record<Schema.String, Schema.Struct<{
81
91
  readonly threadId: Schema.String;
82
92
  readonly kind: Schema.String;
@@ -178,4 +188,8 @@ export declare const RunStateSchema: Schema.Struct<{
178
188
  }>;
179
189
  export declare function emptyRunState(runId: string): RunState;
180
190
  export declare function isRunTerminal(state: RunState): boolean;
191
+ /** Every thread below `threadId`, in the order they were started. */
192
+ export declare function descendantThreadIds(state: RunState, threadId: string): string[];
193
+ /** The status a `runtime.run.completed` payload ends the run with: an error means it failed. */
194
+ export declare function completedRunStatus(payload: JsonValue): 'completed' | 'failed';
181
195
  export declare function isRunParked(state: RunState): boolean;
@@ -1,7 +1,8 @@
1
- import { Effect, Schema } from 'effect';
1
+ import { Effect, Predicate, Schema } from 'effect';
2
2
  import { RuntimeEffectSchema, WaitConditionSchema, } from './effects.js';
3
3
  import { JsonValueSchema } from './envelope.js';
4
4
  import { DEFAULT_DEFINITION_VERSION } from './module.js';
5
+ import { isTerminalStatus } from './thread.js';
5
6
  export const RunStateSchema = Schema.Struct({
6
7
  runId: Schema.String,
7
8
  status: Schema.Union([
@@ -20,6 +21,7 @@ export const RunStateSchema = Schema.Struct({
20
21
  idempotencyKey: Schema.NullOr(Schema.String),
21
22
  rootThreadId: Schema.String,
22
23
  })).pipe(Schema.withDecodingDefaultKey(Effect.succeed(null))),
24
+ forkedFrom: Schema.NullOr(Schema.Struct({ runId: Schema.String, seq: Schema.Finite })).pipe(Schema.withDecodingDefaultKey(Effect.succeed(null))),
23
25
  threads: Schema.Record(Schema.String, Schema.Struct({
24
26
  threadId: Schema.String,
25
27
  kind: Schema.String,
@@ -80,6 +82,7 @@ export function emptyRunState(runId) {
80
82
  status: 'running',
81
83
  rootThreadId: null,
82
84
  startIdentity: null,
85
+ forkedFrom: null,
83
86
  threads: {},
84
87
  waits: {},
85
88
  outstandingEffects: [],
@@ -89,7 +92,27 @@ export function emptyRunState(runId) {
89
92
  };
90
93
  }
91
94
  export function isRunTerminal(state) {
92
- return state.status === 'completed' || state.status === 'failed' || state.status === 'cancelled';
95
+ return isTerminalStatus(state.status);
96
+ }
97
+ /** Every thread below `threadId`, in the order they were started. */
98
+ export function descendantThreadIds(state, threadId) {
99
+ return Object.values(state.threads)
100
+ .filter((record) => {
101
+ let parentThreadId = record.parentThreadId;
102
+ while (parentThreadId) {
103
+ if (parentThreadId === threadId) {
104
+ return true;
105
+ }
106
+ parentThreadId = state.threads[parentThreadId]?.parentThreadId ?? null;
107
+ }
108
+ return false;
109
+ })
110
+ .map((record) => record.threadId);
111
+ }
112
+ /** The status a `runtime.run.completed` payload ends the run with: an error means it failed. */
113
+ export function completedRunStatus(payload) {
114
+ const error = Predicate.isObject(payload) ? payload.error : undefined;
115
+ return Predicate.isString(error) && error.length > 0 ? 'failed' : 'completed';
93
116
  }
94
117
  export function isRunParked(state) {
95
118
  if (isRunTerminal(state)) {
@@ -91,6 +91,7 @@ export interface StreamBounds {
91
91
  readonly tail: number;
92
92
  }
93
93
  export interface AppendOptions {
94
+ /** Fail unless the stream is at this tail. The batch is numbered from `expectedTail + 1`. */
94
95
  readonly expectedTail?: number;
95
96
  /**
96
97
  * Atomically claims an ingress command with the append. Reusing the key
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--color-black:#000;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-light:300;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--leading-relaxed:1.625;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:ui-sans-serif, system-ui, -apple-system, sans-serif;--default-mono-font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--color-border:var(--border)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:root{--background:oklch(16% .005 260);--foreground:oklch(93% .01 260);--card:oklch(19% .006 260);--card-foreground:oklch(93% .01 260);--primary:oklch(93% .01 260);--primary-foreground:oklch(20% .006 260);--secondary:oklch(24% .008 260);--secondary-foreground:oklch(93% .01 260);--muted:oklch(24% .008 260);--muted-foreground:oklch(68% .015 260);--accent:oklch(26% .01 260);--accent-foreground:oklch(95% .01 260);--destructive:oklch(65% .18 25);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.12);--ring:oklch(55% .02 260);--sidebar:oklch(18% .006 260);--sidebar-foreground:oklch(93% .01 260)}:where(.looms-debugger,.debugger-pop),:where(.looms-debugger,.debugger-pop) *,:where(.looms-debugger,.debugger-pop) :before,:where(.looms-debugger,.debugger-pop) :after{border-color:var(--color-border)}}@layer components;@layer utilities{.\@container{container-type:inline-size}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-y-0{inset-block:0}.top-0{top:0}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.right-0{right:0}.right-0\.5{right:calc(var(--spacing) * .5)}.bottom-3{bottom:calc(var(--spacing) * 3)}.left-0{left:0}.left-1\/2{left:50%}.left-2{left:calc(var(--spacing) * 2)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.-mx-1{margin-inline:calc(var(--spacing) * -1)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.my-1{margin-block:var(--spacing)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mr-1{margin-right:var(--spacing)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-auto{margin-left:auto}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.field-sizing-content{field-sizing:content}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-2\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-full{width:100%;height:100%}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-11{height:calc(var(--spacing) * 11)}.h-\[26px\]{height:26px}.h-\[45\%\]{height:45%}.h-full{height:100%}.h-px{height:1px}.max-h-\(--radix-dropdown-menu-content-available-height\){max-height:var(--radix-dropdown-menu-content-available-height)}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-80{max-height:calc(var(--spacing) * 80)}.min-h-0{min-height:0}.min-h-11{min-height:calc(var(--spacing) * 11)}.min-h-16{min-height:calc(var(--spacing) * 16)}.min-h-20{min-height:calc(var(--spacing) * 20)}.min-h-28{min-height:calc(var(--spacing) * 28)}.min-h-32{min-height:calc(var(--spacing) * 32)}.min-h-40{min-height:calc(var(--spacing) * 40)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-7{width:calc(var(--spacing) * 7)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-60{width:calc(var(--spacing) * 60)}.w-72{width:calc(var(--spacing) * 72)}.w-80{width:calc(var(--spacing) * 80)}.w-\[26rem\]{width:26rem}.w-\[calc\(100\%\+0\.5rem\)\]{width:calc(100% + .5rem)}.w-fit{width:fit-content}.w-full{width:100%}.w-px{width:1px}.max-w-60{max-width:calc(var(--spacing) * 60)}.max-w-64{max-width:calc(var(--spacing) * 64)}.max-w-full{max-width:100%}.min-w-0{min-width:0}.min-w-5{min-width:calc(var(--spacing) * 5)}.min-w-40{min-width:calc(var(--spacing) * 40)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-90{rotate:90deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.touch-none{touch-action:none}.resize-none{resize:none}.scroll-py-1{scroll-padding-block:var(--spacing)}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-rows-\[minmax\(0\,38\%\)_minmax\(0\,1fr\)\]{grid-template-rows:minmax(0,38%) minmax(0,1fr)}.flex-col{flex-direction:column}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0{gap:0}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:.25rem}.rounded-\[1px\]{border-radius:1px}.rounded-\[3px\]{border-radius:3px}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) * .8)}.rounded-sm{border-radius:calc(var(--radius) * .6)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-border,.border-border\/70{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/70{border-color:color-mix(in oklab, var(--border) 70%, transparent)}}.border-input{border-color:var(--input)}.border-t-transparent{border-top-color:#0000}.border-l-transparent{border-left-color:#0000}.bg-accent{background-color:var(--accent)}.bg-background,.bg-background\/40{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.bg-background\/40{background-color:color-mix(in oklab, var(--background) 40%, transparent)}}.bg-background\/60{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.bg-background\/60{background-color:color-mix(in oklab, var(--background) 60%, transparent)}}.bg-background\/95{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.bg-background\/95{background-color:color-mix(in oklab, var(--background) 95%, transparent)}}.bg-border{background-color:var(--border)}.bg-card,.bg-card\/60{background-color:var(--card)}@supports (color:color-mix(in lab, red, red)){.bg-card\/60{background-color:color-mix(in oklab, var(--card) 60%, transparent)}}.bg-card\/90{background-color:var(--card)}@supports (color:color-mix(in lab, red, red)){.bg-card\/90{background-color:color-mix(in oklab, var(--card) 90%, transparent)}}.bg-card\/95{background-color:var(--card)}@supports (color:color-mix(in lab, red, red)){.bg-card\/95{background-color:color-mix(in oklab, var(--card) 95%, transparent)}}.bg-current\/10{background-color:currentColor}@supports (color:color-mix(in lab, red, red)){.bg-current\/10{background-color:color-mix(in oklab, currentcolor 10%, transparent)}}.bg-foreground,.bg-foreground\/15{background-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.bg-foreground\/15{background-color:color-mix(in oklab, var(--foreground) 15%, transparent)}}.bg-foreground\/70{background-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.bg-foreground\/70{background-color:color-mix(in oklab, var(--foreground) 70%, transparent)}}.bg-primary{background-color:var(--primary)}.bg-secondary,.bg-secondary\/70{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.bg-secondary\/70{background-color:color-mix(in oklab, var(--secondary) 70%, transparent)}}.bg-sidebar{background-color:var(--sidebar)}.bg-status-cancelled{background-color:var(--status-cancelled)}.bg-status-completed{background-color:var(--status-completed)}.bg-status-failed,.bg-status-failed\/10{background-color:var(--status-failed)}@supports (color:color-mix(in lab, red, red)){.bg-status-failed\/10{background-color:color-mix(in oklab, var(--status-failed) 10%, transparent)}}.bg-status-running{background-color:var(--status-running)}.bg-status-waiting{background-color:var(--status-waiting)}.bg-transparent{background-color:#0000}.fill-current{fill:currentColor}.p-0{padding:0}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-px{padding:1px}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-px{padding-block:1px}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pr-0\.5{padding-right:calc(var(--spacing) * .5)}.pr-1{padding-right:var(--spacing)}.pr-1\.5{padding-right:calc(var(--spacing) * 1.5)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pb-1{padding-bottom:var(--spacing)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-0{padding-left:0}.pl-1{padding-left:var(--spacing)}.pl-1\.5{padding-left:calc(var(--spacing) * 1.5)}.pl-2\.5{padding-left:calc(var(--spacing) * 2.5)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-7{padding-left:calc(var(--spacing) * 7)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-\[-2px\]{vertical-align:-2px}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.font-sans{font-family:ui-sans-serif,system-ui,-apple-system,sans-serif}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.leading-3\.5{--tw-leading:calc(var(--spacing) * 3.5);line-height:calc(var(--spacing) * 3.5)}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.break-words{overflow-wrap:break-word}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-background{color:var(--background)}.text-border{color:var(--border)}.text-card-foreground{color:var(--card-foreground)}.text-foreground{color:var(--foreground)}.text-json-boolean{color:var(--json-boolean)}.text-json-key{color:var(--json-key)}.text-json-null{color:var(--json-null)}.text-json-number{color:var(--json-number)}.text-json-string{color:var(--json-string)}.text-muted-foreground,.text-muted-foreground\/60{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/60{color:color-mix(in oklab, var(--muted-foreground) 60%, transparent)}}.text-muted-foreground\/70{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/70{color:color-mix(in oklab, var(--muted-foreground) 70%, transparent)}}.text-muted-foreground\/80{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/80{color:color-mix(in oklab, var(--muted-foreground) 80%, transparent)}}.text-primary-foreground{color:var(--primary-foreground)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-status-cancelled{color:var(--status-cancelled)}.text-status-completed{color:var(--status-completed)}.text-status-failed{color:var(--status-failed)}.text-status-running{color:var(--status-running)}.text-status-waiting{color:var(--status-waiting)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-black\/30{--tw-shadow-color:#0000004d}@supports (color:color-mix(in lab, red, red)){.shadow-black\/30{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-black) 30%, transparent) var(--tw-shadow-alpha), transparent)}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-\[border-color\,box-shadow\]{transition-property:border-color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[transform\,background-color\,color\,opacity\]{transition-property:transform,background-color,color,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-150{--tw-duration:.15s;transition-duration:.15s}.ease-snappy{--tw-ease:var(--debugger-ease);transition-timing-function:var(--debugger-ease)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\/branch\:text-foreground:is(:where(.group\/branch):hover *){color:var(--foreground)}.group-hover\/json\:opacity-100:is(:where(.group\/json):hover *){opacity:1}}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:inset-y-0:after{content:var(--tw-content);inset-block:0}.after\:left-1\/2:after{content:var(--tw-content);left:50%}.after\:w-2:after{content:var(--tw-content);width:calc(var(--spacing) * 2)}.after\:-translate-x-1\/2:after{content:var(--tw-content);--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.focus-within\:border-ring\/70:focus-within{border-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-within\:border-ring\/70:focus-within{border-color:color-mix(in oklab, var(--ring) 70%, transparent)}}.focus-within\:ring-\[3px\]:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-within\:ring-ring\/25:focus-within{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-within\:ring-ring\/25:focus-within{--tw-ring-color:color-mix(in oklab, var(--ring) 25%, transparent)}}@media (hover:hover){.hover\:border-ring\/40:hover{border-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.hover\:border-ring\/40:hover{border-color:color-mix(in oklab, var(--ring) 40%, transparent)}}.hover\:bg-accent:hover,.hover\:bg-accent\/40:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/40:hover{background-color:color-mix(in oklab, var(--accent) 40%, transparent)}}.hover\:bg-accent\/50:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/50:hover{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.hover\:bg-accent\/60:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/60:hover{background-color:color-mix(in oklab, var(--accent) 60%, transparent)}}.hover\:bg-background\/40:hover{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-background\/40:hover{background-color:color-mix(in oklab, var(--background) 40%, transparent)}}.hover\:bg-background\/60:hover{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-background\/60:hover{background-color:color-mix(in oklab, var(--background) 60%, transparent)}}.hover\:bg-foreground\/25:hover{background-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-foreground\/25:hover{background-color:color-mix(in oklab, var(--foreground) 25%, transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--primary) 90%, transparent)}}.hover\:bg-status-failed\/15:hover{background-color:var(--status-failed)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-status-failed\/15:hover{background-color:color-mix(in oklab, var(--status-failed) 15%, transparent)}}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-status-failed:hover{color:var(--status-failed)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:bg-accent:focus{background-color:var(--accent)}.focus\:text-accent-foreground:focus{color:var(--accent-foreground)}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:opacity-100:focus-visible{opacity:1}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.active\:scale-\[0\.97\]:active{scale:.97}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.aria-pressed\:bg-accent[aria-pressed=true]{background-color:var(--accent)}.aria-pressed\:text-foreground[aria-pressed=true]{color:var(--foreground)}.aria-\[orientation\=vertical\]\:flex-col[aria-orientation=vertical]{flex-direction:column}.data-disabled\:pointer-events-none[data-disabled]{pointer-events:none}.data-disabled\:opacity-50[data-disabled]{opacity:.5}.data-\[disabled\=true\]\:pointer-events-none[data-disabled=true]{pointer-events:none}.data-\[disabled\=true\]\:opacity-50[data-disabled=true]{opacity:.5}.data-\[selected\=true\]\:bg-accent[data-selected=true]{background-color:var(--accent)}.data-\[selected\=true\]\:text-accent-foreground[data-selected=true]{color:var(--accent-foreground)}.data-\[separator\=active\]\:bg-ring[data-separator=active],.data-\[separator\=focus\]\:bg-ring[data-separator=focus],.data-\[separator\=hover\]\:bg-ring\/60[data-separator=hover]{background-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.data-\[separator\=hover\]\:bg-ring\/60[data-separator=hover]{background-color:color-mix(in oklab, var(--ring) 60%, transparent)}}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:var(--background)}.data-\[state\=active\]\:text-foreground[data-state=active]{color:var(--foreground)}.data-\[state\=active\]\:shadow-sm[data-state=active]{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.data-\[state\=checked\]\:bg-foreground[data-state=checked]{background-color:var(--foreground)}.data-\[state\=checked\]\:text-background[data-state=checked]{color:var(--background)}.data-\[state\=hidden\]\:opacity-0[data-state=hidden]{opacity:0}.data-\[state\=open\]\:border-ring\/60[data-state=open]{border-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.data-\[state\=open\]\:border-ring\/60[data-state=open]{border-color:color-mix(in oklab, var(--ring) 60%, transparent)}}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:var(--accent)}.data-\[state\=open\]\:text-foreground[data-state=open]{color:var(--foreground)}@media (width>=36rem){.min-\[36rem\]\:grid-cols-\[14rem_minmax\(0\,1fr\)\]{grid-template-columns:14rem minmax(0,1fr)}.min-\[36rem\]\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.min-\[36rem\]\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}}@container (width>=24rem){.\@sm\:ml-0{margin-left:0}.\@sm\:flex{display:flex}}@container (width>=28rem){.\@md\:flex{display:flex}.\@md\:max-w-64{max-width:calc(var(--spacing) * 64)}}@container (width>=32rem){.\@lg\:inline{display:inline}}.\[\&_\[cmdk-group-heading\]\]\:px-2 [cmdk-group-heading]{padding-inline:calc(var(--spacing) * 2)}.\[\&_\[cmdk-group-heading\]\]\:pt-2 [cmdk-group-heading]{padding-top:calc(var(--spacing) * 2)}.\[\&_\[cmdk-group-heading\]\]\:pb-1 [cmdk-group-heading]{padding-bottom:var(--spacing)}.\[\&_\[cmdk-group-heading\]\]\:text-\[11px\] [cmdk-group-heading]{font-size:11px}.\[\&_\[cmdk-group-heading\]\]\:font-medium [cmdk-group-heading]{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.\[\&_\[cmdk-group-heading\]\]\:text-muted-foreground [cmdk-group-heading]{color:var(--muted-foreground)}.\[\&_svg\]\:size-3 svg{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.\[\&_svg\]\:size-3\.5 svg{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.\[\&_svg\]\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&\>div\]\:block\!>div{display:block!important}}:root{--debugger-ease:cubic-bezier(.23, 1, .32, 1);--status-running:oklch(74% .12 240);--status-waiting:oklch(80% .14 85);--status-completed:oklch(76% .13 155);--status-failed:oklch(68% .18 25);--status-cancelled:oklch(62% .01 260);--json-key:oklch(80% .06 280);--json-string:oklch(80% .1 150);--json-number:oklch(80% .1 230);--json-boolean:oklch(82% .11 70);--json-null:oklch(60% .01 260)}@keyframes debugger-pop-in{0%{opacity:0;transform:scale(.97)}}@keyframes debugger-fade-in{0%{opacity:0}}.debugger-pop{transform-origin:var(--radix-popper-transform-origin);animation:debugger-pop-in .15s var(--debugger-ease)}.debugger-pop[data-instant]{animation:none}.debugger-float-in{transition:opacity .15s var(--debugger-ease), transform .15s var(--debugger-ease), scale .15s var(--debugger-ease), background-color .15s var(--debugger-ease)}@starting-style{.debugger-float-in{opacity:0;transform:translateY(4px)}}@media (prefers-reduced-motion:reduce){.debugger-pop{animation-name:debugger-fade-in}.debugger-float-in{transition-property:opacity}}.debugger-event-stream{container-type:inline-size}.debugger-event-offset,.debugger-event-causation,.debugger-event-thread{display:none}@container (width>=24rem){.debugger-event-offset{display:inline}}@container (width>=34rem){.debugger-event-thread{display:inline}}@container (width>=44rem){.debugger-event-causation{display:inline}}:root{--radius:.375rem}html,body,#root{height:100%}html,body{overscroll-behavior:none}body{margin:0}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}