@xfey/tutti 0.1.73 → 0.1.75

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.
@@ -0,0 +1,7 @@
1
+ export type VisibleJoinUrlState = {
2
+ join_url?: string;
3
+ join_url_visibility?: "visible_once" | "not_recoverable";
4
+ join_token_expires_at?: string;
5
+ };
6
+ export declare function readFreshVisibleJoinUrl(state: VisibleJoinUrlState, now?: Date): string | undefined;
7
+ //# sourceMappingURL=join-url.d.ts.map
@@ -0,0 +1,15 @@
1
+ const JOIN_URL_REFRESH_GRACE_MS = 5 * 60 * 1000;
2
+ export function readFreshVisibleJoinUrl(state, now = new Date()) {
3
+ if (state.join_url === undefined || state.join_url_visibility !== "visible_once") {
4
+ return undefined;
5
+ }
6
+ if (state.join_token_expires_at === undefined) {
7
+ return state.join_url;
8
+ }
9
+ const expiresAt = new Date(state.join_token_expires_at).getTime();
10
+ if (!Number.isFinite(expiresAt) || expiresAt - now.getTime() <= JOIN_URL_REFRESH_GRACE_MS) {
11
+ return undefined;
12
+ }
13
+ return state.join_url;
14
+ }
15
+ //# sourceMappingURL=join-url.js.map
@@ -1,4 +1,5 @@
1
1
  import { createIdleExecutionStatusProjection, readActiveClarificationProjection, readMainChatMessageWindow, readReadStateSummary, readScratchpadProjection, readWorklistProjection, } from "../../../../collaboration-state/index.js";
2
+ import { readFreshVisibleJoinUrl } from "../../../cli/join-url.js";
2
3
  import { HOST_MAINLINE_BRANCH } from "./constants.js";
3
4
  function defaultCapabilities(overrides) {
4
5
  return {
@@ -21,27 +22,13 @@ function providerSummary(providerConfig) {
21
22
  provider: providerConfig.provider,
22
23
  };
23
24
  }
24
- const JOIN_URL_REFRESH_GRACE_MS = 5 * 60 * 1000;
25
- function isFreshVisibleJoinUrl(relayState, now) {
26
- if (relayState.join_url === undefined || relayState.join_url_visibility !== "visible_once") {
27
- return false;
28
- }
29
- if (relayState.join_token_expires_at === undefined) {
30
- return true;
31
- }
32
- const expiresAt = new Date(relayState.join_token_expires_at).getTime();
33
- if (!Number.isFinite(expiresAt)) {
34
- return false;
35
- }
36
- return expiresAt - now.getTime() > JOIN_URL_REFRESH_GRACE_MS;
37
- }
38
25
  function workspaceRelayProjection(relayState, now) {
39
26
  const projection = {
40
27
  status: relayState.status,
41
28
  relay_url: relayState.relay_url,
42
29
  join_token_reusable: relayState.join_token_reusable,
43
30
  };
44
- const visibleJoinUrl = isFreshVisibleJoinUrl(relayState, now) ? relayState.join_url : undefined;
31
+ const visibleJoinUrl = readFreshVisibleJoinUrl(relayState, now);
45
32
  if (visibleJoinUrl !== undefined) {
46
33
  projection.join_url = visibleJoinUrl;
47
34
  }
@@ -71,7 +58,7 @@ export function buildWorkspaceProjection(options, relayState = options.relay.get
71
58
  export async function resolveWorkspaceProjection(options) {
72
59
  const now = options.now?.() ?? new Date();
73
60
  const relayState = options.relay.getState();
74
- if (relayState.status !== "connected" || isFreshVisibleJoinUrl(relayState, now)) {
61
+ if (relayState.status !== "connected" || readFreshVisibleJoinUrl(relayState, now) !== undefined) {
75
62
  return buildWorkspaceProjection(options, relayState, now);
76
63
  }
77
64
  try {
@@ -13,6 +13,7 @@ const API_ERROR_CODES = new Set([
13
13
  "provider_model_unavailable",
14
14
  "provider_network_error",
15
15
  "relay_session_invalid",
16
+ "project_membership_required",
16
17
  "command_replay_mismatch",
17
18
  "repo_snapshot_unavailable",
18
19
  "host_unavailable",
@@ -12,7 +12,6 @@ export type LocalConsoleProject = {
12
12
  provider_status: "configured" | "not_configured" | "invalid";
13
13
  provider_model?: string;
14
14
  relay_project_ref?: RelayProjectRef;
15
- join_url?: string;
16
15
  open_url?: string;
17
16
  relay_connection_status?: string;
18
17
  created_at?: string;
@@ -37,8 +36,14 @@ export type LocalConsoleLaunchResult = {
37
36
  };
38
37
  export type LocalConsoleOpenResult = {
39
38
  project: LocalConsoleProject;
40
- open_url: string;
41
- disposition: "opened_current" | "updated" | "deferred_busy" | "deferred_unsupported" | "deferred_unavailable";
39
+ handoff: {
40
+ kind: "project_open";
41
+ url: string;
42
+ } | {
43
+ kind: "project_join";
44
+ url: string;
45
+ };
46
+ host_update: "not_needed" | "updated" | "deferred_busy" | "deferred_unsupported" | "deferred_unavailable";
42
47
  };
43
48
  export declare class LocalConsoleProjectError extends Error {
44
49
  readonly code: string;
@@ -57,6 +62,7 @@ export declare class LocalConsoleProjectService {
57
62
  fetchImpl?: FetchLike;
58
63
  validateProviderCredential?: OpenAiProviderCredentialValidator;
59
64
  operations?: LocalConsoleOperationCoordinator;
65
+ now?: () => Date;
60
66
  });
61
67
  listProjects(context: LocalConsoleInvocationContext): Promise<LocalConsoleProject[]>;
62
68
  discoverModels(input: {
@@ -1,13 +1,16 @@
1
1
  import { existsSync, statSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
+ import { readRelayProjectMembershipState } from "@tutti/relay-client";
3
4
  import { relayProjectRouteSegment } from "@tutti/shared/ids";
4
5
  import { configureProjectOpenAiProvider, discoverOpenAiModels, isOpenAiApiKey, readOpenAiProviderConfigProjection, validateOpenAiCredential, } from "../../providers/openai/index.js";
5
6
  import { formatCliErrorReason, LaunchError } from "../cli/errors.js";
6
7
  import { createRuntimeEndpointProbe, waitForHostShutdown, } from "../cli/host-runtime-endpoint.js";
7
8
  import { prepareLaunchProject, resolveLaunchLocalContext, resolveRelayUrl } from "../cli/launch.js";
8
- import { requestHostLocalIdleShutdown, rotateHostLocalInvite, } from "../cli/local-control-client.js";
9
+ import { readHostLocalLaunchStatus, requestHostLocalIdleShutdown, rotateHostLocalInvite, } from "../cli/local-control-client.js";
10
+ import { readFreshVisibleJoinUrl } from "../cli/join-url.js";
9
11
  import { readHostRegistrationSecret, readMachineProjectBinding, readMachineRuntimeEndpoint, } from "../cli/machine-local.js";
10
12
  import { spawnDetachedHost, waitForManagedHostReady } from "../cli/managed-host.js";
13
+ import { relayStatusFromLocalStatus } from "../cli/host-relay-status.js";
11
14
  import { resolveManagedProjectContext } from "../cli/project-resolver.js";
12
15
  import { listRuntimeProjects, runStopCommand, } from "../cli/runtime-commands.js";
13
16
  import { readCliVersion } from "../cli/version.js";
@@ -94,7 +97,6 @@ function projectFromRuntimeRow(row, providerStatus, providerModel, metadata) {
94
97
  provider_status: providerStatus,
95
98
  ...(providerModel === undefined ? {} : { provider_model: providerModel }),
96
99
  ...(row.relay_project_ref === undefined ? {} : { relay_project_ref: row.relay_project_ref }),
97
- ...(row.join_url === undefined ? {} : { join_url: row.join_url }),
98
100
  ...(openUrl === undefined ? {} : { open_url: openUrl }),
99
101
  ...(row.relay_connection_status === undefined
100
102
  ? {}
@@ -156,12 +158,14 @@ export class LocalConsoleProjectService {
156
158
  #fetchImpl;
157
159
  #validateProviderCredential;
158
160
  #operations;
161
+ #now;
159
162
  #launches = new Map();
160
163
  constructor(options) {
161
164
  this.#tuttiHome = resolve(options.tuttiHome);
162
165
  this.#serviceEnvironment = options.serviceEnvironment ?? process.env;
163
166
  this.#fetchImpl = options.fetchImpl ?? fetch;
164
167
  this.#operations = options.operations ?? new LocalConsoleOperationCoordinator();
168
+ this.#now = options.now ?? (() => new Date());
165
169
  this.#validateProviderCredential =
166
170
  options.validateProviderCredential ?? validateOpenAiCredential;
167
171
  }
@@ -387,80 +391,142 @@ export class LocalConsoleProjectService {
387
391
  if (current.open_url === undefined) {
388
392
  throw new LocalConsoleProjectError("project_open_unavailable", "This project does not have a Relay destination yet.");
389
393
  }
390
- if (current.update_required !== true) {
391
- return {
392
- project: current,
393
- open_url: current.open_url,
394
- disposition: "opened_current",
395
- };
396
- }
397
- let managed;
398
- try {
399
- managed = resolveManagedProjectContext({
400
- target: projectId,
401
- ...this.#operationOptions(context),
402
- });
394
+ const updated = await this.#updateHostForOpen(current, projectId, context);
395
+ if (updated.project.open_url === undefined) {
396
+ throw new LocalConsoleProjectError("project_open_unavailable", "This project does not have a Relay destination yet.");
403
397
  }
404
- catch (error) {
405
- throw this.#normalizeError(error);
398
+ return {
399
+ project: updated.project,
400
+ handoff: await this.#resolveOpenHandoff(updated.project, updated.project.open_url, projectId, context),
401
+ host_update: updated.hostUpdate,
402
+ };
403
+ });
404
+ }
405
+ async #updateHostForOpen(current, projectId, context) {
406
+ if (current.update_required !== true) {
407
+ return { project: current, hostUpdate: "not_needed" };
408
+ }
409
+ let managed;
410
+ try {
411
+ managed = resolveManagedProjectContext({
412
+ target: projectId,
413
+ ...this.#operationOptions(context),
414
+ });
415
+ }
416
+ catch (error) {
417
+ throw this.#normalizeError(error);
418
+ }
419
+ if (!managed.workspace_exists ||
420
+ managed.runtime_endpoint === null ||
421
+ managed.provider_config.status !== "configured") {
422
+ return { project: current, hostUpdate: "deferred_unavailable" };
423
+ }
424
+ let shutdownDisposition;
425
+ try {
426
+ shutdownDisposition = await requestHostLocalIdleShutdown({
427
+ endpoint: managed.runtime_endpoint,
428
+ fetchImpl: this.#fetchImpl,
429
+ });
430
+ }
431
+ catch {
432
+ return { project: current, hostUpdate: "deferred_unavailable" };
433
+ }
434
+ if (shutdownDisposition !== "accepted") {
435
+ return {
436
+ project: current,
437
+ hostUpdate: shutdownDisposition === "busy" ? "deferred_busy" : "deferred_unsupported",
438
+ };
439
+ }
440
+ try {
441
+ await waitForHostShutdown({
442
+ endpoint: managed.runtime_endpoint,
443
+ probeRuntimeEndpoint: createRuntimeEndpointProbe(this.#fetchImpl),
444
+ shutdownWaitMs: OPEN_UPDATE_SHUTDOWN_WAIT_MS,
445
+ });
446
+ await this.#startManagedHost({
447
+ workspaceRoot: managed.workspace_root,
448
+ tuttiHome: managed.tutti_home,
449
+ projectId: managed.project_id,
450
+ env: this.#operationOptions(context).env,
451
+ inviteMode: "preserve",
452
+ });
453
+ const project = await this.#readProject(projectId, context);
454
+ if (project.open_url === undefined) {
455
+ throw new LocalConsoleProjectError("project_open_unavailable", "The updated project does not have a Relay destination.");
406
456
  }
407
- if (!managed.workspace_exists ||
408
- managed.runtime_endpoint === null ||
409
- managed.provider_config.status !== "configured") {
410
- return {
411
- project: current,
412
- open_url: current.open_url,
413
- disposition: "deferred_unavailable",
414
- };
457
+ return { project, hostUpdate: "updated" };
458
+ }
459
+ catch (error) {
460
+ throw this.#normalizeError(error);
461
+ }
462
+ }
463
+ async #resolveOpenHandoff(project, openUrl, projectId, context) {
464
+ const projectOpen = () => ({
465
+ kind: "project_open",
466
+ url: openUrl,
467
+ });
468
+ let runtimeEndpoint;
469
+ let relay;
470
+ try {
471
+ const managed = resolveManagedProjectContext({
472
+ target: projectId,
473
+ ...this.#operationOptions(context),
474
+ });
475
+ if (managed.runtime_endpoint === null || project.relay_project_ref === undefined) {
476
+ return projectOpen();
415
477
  }
416
- let shutdownDisposition;
417
- try {
418
- shutdownDisposition = await requestHostLocalIdleShutdown({
419
- endpoint: managed.runtime_endpoint,
420
- fetchImpl: this.#fetchImpl,
421
- });
478
+ const status = await readHostLocalLaunchStatus({
479
+ endpoint: managed.runtime_endpoint,
480
+ fetchImpl: this.#fetchImpl,
481
+ });
482
+ const resolvedRelay = relayStatusFromLocalStatus(status);
483
+ if (resolvedRelay === undefined ||
484
+ resolvedRelay.relay_project_ref !== project.relay_project_ref) {
485
+ return projectOpen();
422
486
  }
423
- catch {
424
- return {
425
- project: current,
426
- open_url: current.open_url,
427
- disposition: "deferred_unavailable",
428
- };
487
+ const relayUrl = managed.binding?.relay_url ?? relayUrlFromJoinUrl(openUrl);
488
+ if (relayUrl === undefined) {
489
+ return projectOpen();
429
490
  }
430
- if (shutdownDisposition !== "accepted") {
431
- return {
432
- project: current,
433
- open_url: current.open_url,
434
- disposition: shutdownDisposition === "busy" ? "deferred_busy" : "deferred_unsupported",
435
- };
491
+ const credential = readHostRegistrationSecret(managed.tutti_home, managed.project_id);
492
+ const membership = await readRelayProjectMembershipState({
493
+ relayUrl,
494
+ projectId: managed.project_id,
495
+ relayProjectRef: resolvedRelay.relay_project_ref,
496
+ hostConnectionRef: resolvedRelay.host_connection_ref,
497
+ hostRegistrationSecret: credential.secret,
498
+ fetch: this.#fetchImpl,
499
+ });
500
+ if (membership.membership_state === "established") {
501
+ return projectOpen();
436
502
  }
437
- try {
438
- await waitForHostShutdown({
439
- endpoint: managed.runtime_endpoint,
440
- probeRuntimeEndpoint: createRuntimeEndpointProbe(this.#fetchImpl),
441
- shutdownWaitMs: OPEN_UPDATE_SHUTDOWN_WAIT_MS,
442
- });
443
- await this.#startManagedHost({
444
- workspaceRoot: managed.workspace_root,
445
- tuttiHome: managed.tutti_home,
446
- projectId: managed.project_id,
447
- env: this.#operationOptions(context).env,
448
- inviteMode: "preserve",
449
- });
450
- const updated = await this.#readProject(projectId, context);
451
- if (updated.open_url === undefined) {
452
- throw new LocalConsoleProjectError("project_open_unavailable", "The updated project does not have a Relay destination.");
453
- }
454
- return {
455
- project: updated,
456
- open_url: updated.open_url,
457
- disposition: "updated",
458
- };
503
+ runtimeEndpoint = managed.runtime_endpoint;
504
+ relay = resolvedRelay;
505
+ }
506
+ catch {
507
+ return projectOpen();
508
+ }
509
+ try {
510
+ const currentJoinUrl = readFreshVisibleJoinUrl(relay, this.#now());
511
+ if (currentJoinUrl !== undefined) {
512
+ return { kind: "project_join", url: currentJoinUrl };
459
513
  }
460
- catch (error) {
461
- throw this.#normalizeError(error);
514
+ const refreshed = await rotateHostLocalInvite({
515
+ endpoint: runtimeEndpoint,
516
+ fetchImpl: this.#fetchImpl,
517
+ });
518
+ const refreshedRelay = relayStatusFromLocalStatus(refreshed);
519
+ const refreshedJoinUrl = refreshedRelay === undefined
520
+ ? undefined
521
+ : readFreshVisibleJoinUrl(refreshedRelay, this.#now());
522
+ if (refreshedJoinUrl === undefined) {
523
+ throw new LocalConsoleProjectError("project_join_unavailable", "This project still needs its first member, but a fresh invitation could not be created.");
462
524
  }
463
- });
525
+ return { kind: "project_join", url: refreshedJoinUrl };
526
+ }
527
+ catch (error) {
528
+ throw this.#normalizeError(error);
529
+ }
464
530
  }
465
531
  async refreshInvite(projectId, context) {
466
532
  return await this.#operations.runProjectOperation(async () => {
@@ -75,6 +75,7 @@ export function createLocalConsoleServer(options) {
75
75
  const projects = new LocalConsoleProjectService({
76
76
  tuttiHome,
77
77
  operations,
78
+ ...(options.now === undefined ? {} : { now: options.now }),
78
79
  ...(options.env === undefined ? {} : { serviceEnvironment: options.env }),
79
80
  });
80
81
  const packageUpdates = options.packageUpdateService ??
@@ -92,6 +92,10 @@ export type ArchiveRelayProjectResponse = {
92
92
  retry_with_new_command_id: true;
93
93
  };
94
94
  };
95
+ export type RelayProjectMembershipState = "empty" | "established";
96
+ export type ReadRelayProjectMembershipStateResponse = {
97
+ membership_state: RelayProjectMembershipState;
98
+ };
95
99
  export type RelayUploadProjection = {
96
100
  upload_id: RelayUploadRef;
97
101
  relay_project_ref: RelayProjectRef;
@@ -158,6 +162,15 @@ export type ArchiveRelayProjectOptions = {
158
162
  fetch?: RelayHostControlFetch;
159
163
  timeoutMs?: number;
160
164
  };
165
+ export type ReadRelayProjectMembershipStateOptions = {
166
+ relayUrl: string;
167
+ projectId: ProjectId;
168
+ relayProjectRef: RelayProjectRef;
169
+ hostConnectionRef: HostConnectionRef;
170
+ hostRegistrationSecret: string;
171
+ fetch?: RelayHostControlFetch;
172
+ timeoutMs?: number;
173
+ };
161
174
  export type ResolveRelayUploadOptions = {
162
175
  relayUrl: string;
163
176
  projectId: ProjectId;
@@ -182,6 +195,7 @@ export declare class RelayHostControlClientError extends Error {
182
195
  export declare function registerRelayHostConnection(options: RegisterRelayHostConnectionOptions): Promise<RegisterRelayHostConnectionResponse>;
183
196
  export declare function refreshRelayJoinToken(options: RefreshRelayJoinTokenOptions): Promise<RefreshRelayJoinTokenResponse>;
184
197
  export declare function archiveRelayProject(options: ArchiveRelayProjectOptions): Promise<ArchiveRelayProjectResponse>;
198
+ export declare function readRelayProjectMembershipState(options: ReadRelayProjectMembershipStateOptions): Promise<ReadRelayProjectMembershipStateResponse>;
185
199
  export declare function resolveRelayUpload(options: ResolveRelayUploadOptions): Promise<ResolveRelayUploadResponse>;
186
200
  export declare function completeRelayUpload(options: CompleteRelayUploadOptions): Promise<CompleteRelayUploadResponse>;
187
201
  //# sourceMappingURL=host-control.d.ts.map
@@ -23,6 +23,9 @@ function joinTokenUrl(relayUrl) {
23
23
  function archiveProjectUrl(relayUrl) {
24
24
  return new URL("/host-control/v1/projects/archive", relayUrl);
25
25
  }
26
+ function projectMembershipStateUrl(relayUrl) {
27
+ return new URL("/host-control/v1/projects/membership-state", relayUrl);
28
+ }
26
29
  function uploadResolveUrl(relayUrl) {
27
30
  return new URL("/host-control/v1/uploads/resolve", relayUrl);
28
31
  }
@@ -98,6 +101,20 @@ function createArchiveRelayProjectPayload(options) {
98
101
  },
99
102
  };
100
103
  }
104
+ function createReadRelayProjectMembershipStatePayload(options) {
105
+ return {
106
+ project_identity: {
107
+ source: "git_config",
108
+ project_id: options.projectId,
109
+ },
110
+ host_auth: {
111
+ kind: "host_registration_secret_v1",
112
+ secret: options.hostRegistrationSecret,
113
+ },
114
+ relay_project_ref: options.relayProjectRef,
115
+ host_connection_ref: options.hostConnectionRef,
116
+ };
117
+ }
101
118
  function createResolveRelayUploadPayload(options) {
102
119
  return {
103
120
  project_identity: {
@@ -180,6 +197,14 @@ function assertArchiveRelayProjectResponse(value) {
180
197
  }
181
198
  return value;
182
199
  }
200
+ function assertReadRelayProjectMembershipStateResponse(value) {
201
+ if (!isRecord(value) ||
202
+ Object.keys(value).length !== 1 ||
203
+ (value.membership_state !== "empty" && value.membership_state !== "established")) {
204
+ throw new RelayHostControlClientError("relay_registration_failed", "Relay project membership state response is invalid", false);
205
+ }
206
+ return value;
207
+ }
183
208
  function assertResolveRelayUploadResponse(value) {
184
209
  if (!isRecord(value) || !isRecord(value.upload) || !isRecord(value.get)) {
185
210
  throw new RelayHostControlClientError("relay_registration_failed", "Relay upload resolve response is invalid", false);
@@ -290,6 +315,34 @@ export async function archiveRelayProject(options) {
290
315
  }
291
316
  return assertArchiveRelayProjectResponse(await response.json());
292
317
  }
318
+ export async function readRelayProjectMembershipState(options) {
319
+ const fetchImpl = options.fetch ?? fetch;
320
+ let response;
321
+ try {
322
+ response = await fetchWithTimeout(fetchImpl, projectMembershipStateUrl(options.relayUrl), {
323
+ method: "POST",
324
+ headers: {
325
+ accept: "application/json",
326
+ "content-type": "application/json",
327
+ },
328
+ body: JSON.stringify(createReadRelayProjectMembershipStatePayload(options)),
329
+ }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
330
+ }
331
+ catch {
332
+ throw new RelayHostControlClientError("relay_unavailable", `Cannot reach Relay at ${options.relayUrl}`, true);
333
+ }
334
+ if (!response.ok) {
335
+ let relayErrorCode;
336
+ try {
337
+ relayErrorCode = relayErrorCodeFromBody(await response.json());
338
+ }
339
+ catch {
340
+ relayErrorCode = undefined;
341
+ }
342
+ throw new RelayHostControlClientError(response.status >= 500 ? "relay_unavailable" : "relay_registration_failed", `Relay project membership state failed with HTTP ${response.status}`, response.status >= 500, response.status, relayErrorCode);
343
+ }
344
+ return assertReadRelayProjectMembershipStateResponse(await response.json());
345
+ }
293
346
  export async function resolveRelayUpload(options) {
294
347
  const fetchImpl = options.fetch ?? fetch;
295
348
  const response = await (async () => {
@@ -72,10 +72,10 @@ export declare const InterruptedCommandDispositionSchema: import("@sinclair/type
72
72
  export declare function commandEnvelopeSchema<TPayload extends TSchema>(payload: TPayload): TSchema;
73
73
  export declare function commandResponseSchema<TDisposition extends TSchema>(disposition: TDisposition): TSchema;
74
74
  export declare function commandResponseWithResultSchema<TDisposition extends TSchema, TResult extends TSchema>(disposition: TDisposition, result: TResult): TSchema;
75
- export declare const ApiErrorCodeSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"bad_request">, import("@sinclair/typebox").TLiteral<"unauthorized">, import("@sinclair/typebox").TLiteral<"forbidden">, import("@sinclair/typebox").TLiteral<"not_found">, import("@sinclair/typebox").TLiteral<"conflict">, import("@sinclair/typebox").TLiteral<"validation_failed">, import("@sinclair/typebox").TLiteral<"provider_not_configured">, import("@sinclair/typebox").TLiteral<"provider_auth_invalid">, import("@sinclair/typebox").TLiteral<"provider_quota_or_billing_required">, import("@sinclair/typebox").TLiteral<"provider_rate_limited">, import("@sinclair/typebox").TLiteral<"provider_model_unavailable">, import("@sinclair/typebox").TLiteral<"provider_network_error">, import("@sinclair/typebox").TLiteral<"relay_session_invalid">, import("@sinclair/typebox").TLiteral<"command_replay_mismatch">, import("@sinclair/typebox").TLiteral<"repo_snapshot_unavailable">, import("@sinclair/typebox").TLiteral<"host_unavailable">, import("@sinclair/typebox").TLiteral<"internal_error">]>;
75
+ export declare const ApiErrorCodeSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"bad_request">, import("@sinclair/typebox").TLiteral<"unauthorized">, import("@sinclair/typebox").TLiteral<"forbidden">, import("@sinclair/typebox").TLiteral<"not_found">, import("@sinclair/typebox").TLiteral<"conflict">, import("@sinclair/typebox").TLiteral<"validation_failed">, import("@sinclair/typebox").TLiteral<"provider_not_configured">, import("@sinclair/typebox").TLiteral<"provider_auth_invalid">, import("@sinclair/typebox").TLiteral<"provider_quota_or_billing_required">, import("@sinclair/typebox").TLiteral<"provider_rate_limited">, import("@sinclair/typebox").TLiteral<"provider_model_unavailable">, import("@sinclair/typebox").TLiteral<"provider_network_error">, import("@sinclair/typebox").TLiteral<"relay_session_invalid">, import("@sinclair/typebox").TLiteral<"project_membership_required">, import("@sinclair/typebox").TLiteral<"command_replay_mismatch">, import("@sinclair/typebox").TLiteral<"repo_snapshot_unavailable">, import("@sinclair/typebox").TLiteral<"host_unavailable">, import("@sinclair/typebox").TLiteral<"internal_error">]>;
76
76
  export declare const ApiErrorResponseSchema: import("@sinclair/typebox").TObject<{
77
77
  error: import("@sinclair/typebox").TObject<{
78
- code: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"bad_request">, import("@sinclair/typebox").TLiteral<"unauthorized">, import("@sinclair/typebox").TLiteral<"forbidden">, import("@sinclair/typebox").TLiteral<"not_found">, import("@sinclair/typebox").TLiteral<"conflict">, import("@sinclair/typebox").TLiteral<"validation_failed">, import("@sinclair/typebox").TLiteral<"provider_not_configured">, import("@sinclair/typebox").TLiteral<"provider_auth_invalid">, import("@sinclair/typebox").TLiteral<"provider_quota_or_billing_required">, import("@sinclair/typebox").TLiteral<"provider_rate_limited">, import("@sinclair/typebox").TLiteral<"provider_model_unavailable">, import("@sinclair/typebox").TLiteral<"provider_network_error">, import("@sinclair/typebox").TLiteral<"relay_session_invalid">, import("@sinclair/typebox").TLiteral<"command_replay_mismatch">, import("@sinclair/typebox").TLiteral<"repo_snapshot_unavailable">, import("@sinclair/typebox").TLiteral<"host_unavailable">, import("@sinclair/typebox").TLiteral<"internal_error">]>;
78
+ code: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"bad_request">, import("@sinclair/typebox").TLiteral<"unauthorized">, import("@sinclair/typebox").TLiteral<"forbidden">, import("@sinclair/typebox").TLiteral<"not_found">, import("@sinclair/typebox").TLiteral<"conflict">, import("@sinclair/typebox").TLiteral<"validation_failed">, import("@sinclair/typebox").TLiteral<"provider_not_configured">, import("@sinclair/typebox").TLiteral<"provider_auth_invalid">, import("@sinclair/typebox").TLiteral<"provider_quota_or_billing_required">, import("@sinclair/typebox").TLiteral<"provider_rate_limited">, import("@sinclair/typebox").TLiteral<"provider_model_unavailable">, import("@sinclair/typebox").TLiteral<"provider_network_error">, import("@sinclair/typebox").TLiteral<"relay_session_invalid">, import("@sinclair/typebox").TLiteral<"project_membership_required">, import("@sinclair/typebox").TLiteral<"command_replay_mismatch">, import("@sinclair/typebox").TLiteral<"repo_snapshot_unavailable">, import("@sinclair/typebox").TLiteral<"host_unavailable">, import("@sinclair/typebox").TLiteral<"internal_error">]>;
79
79
  message: import("@sinclair/typebox").TString;
80
80
  retryable: import("@sinclair/typebox").TBoolean;
81
81
  details: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
@@ -102,6 +102,7 @@ export const ApiErrorCodeSchema = Type.Union([
102
102
  Type.Literal("provider_model_unavailable"),
103
103
  Type.Literal("provider_network_error"),
104
104
  Type.Literal("relay_session_invalid"),
105
+ Type.Literal("project_membership_required"),
105
106
  Type.Literal("command_replay_mismatch"),
106
107
  Type.Literal("repo_snapshot_unavailable"),
107
108
  Type.Literal("host_unavailable"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfey/tutti",
3
- "version": "0.1.73",
3
+ "version": "0.1.75",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1 +1 @@
1
- import{C as e,S as t,_ as n,a as r,b as i,c as a,d as o,f as s,g as c,h as l,i as u,l as d,m as f,n as p,o as m,p as h,r as g,s as _,t as v,u as y,v as b,w as x,x as S,y as C}from"./index-l-bfO_Si.js";var w=e(`mouse-pointer-2`,[[`path`,{d:`M4.037 4.688a.495.495 0 0 1 .651-.651l16 6.5a.5.5 0 0 1-.063.947l-6.124 1.58a2 2 0 0 0-1.438 1.435l-1.579 6.126a.5.5 0 0 1-.947.063z`,key:`edeuup`}]]),T=e(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]),E=x();function D(e){return{"--reveal":e}}function O(e,t,n){let r=(e,t)=>Number.parseInt(e.slice(t,t+2),16),i=i=>Math.round(r(e,i)+(r(t,i)-r(e,i))*n).toString(16).padStart(2,`0`);return`#${i(1)}${i(3)}${i(5)}`}function k(e){let t=r((e-p.runEnd)/(p.executionComplete-p.runEnd));return t+t*t-t*t*t}function A({progress:e,children:t,className:n=``}){return(0,E.jsx)(`div`,{className:`scene-reveal ${n}`,style:D(e),children:t})}function j({progress:e,author:t,avatar:n,tone:r,timestamp:i,online:a=!1,assets:o,children:s}){return(0,E.jsxs)(`article`,{className:`scene-message`,style:D(e),children:[(0,E.jsx)(`span`,{className:`scene-avatar is-${r} ${n===`tutti`?`is-tutti`:``} ${a?`is-online`:``}`,"aria-hidden":`true`,children:n===`tutti`?(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:o.tuttiAvatarSrc,alt:``}):(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:o.humanAvatars[n],alt:``})}),(0,E.jsxs)(`div`,{className:`scene-message-copy`,children:[(0,E.jsxs)(`header`,{children:[(0,E.jsx)(`strong`,{children:t}),(0,E.jsx)(`span`,{children:i})]}),(0,E.jsx)(`p`,{children:s})]})]})}function M({time:e,assets:r}){let i=e>=p.artifactLive,a=e>=p.artifactClick,o=e>=p.runEnd&&e<p.executionComplete,u=d(e,p.runEnd,19.2),f=d(e,p.artifactLive,30.92);return(0,E.jsxs)(`aside`,{className:`scene-sidebar`,children:[(0,E.jsx)(`button`,{className:`scene-brand`,type:`button`,"aria-label":`Tutti`,tabIndex:-1,children:(0,E.jsx)(`img`,{src:r.logoSrc,alt:``})}),(0,E.jsxs)(`div`,{className:`scene-nav-stack`,children:[(0,E.jsxs)(`nav`,{className:`scene-nav`,"aria-label":`Workspace pages`,children:[(0,E.jsx)(`button`,{className:a?``:`is-active`,type:`button`,"aria-label":`Chat`,tabIndex:-1,children:(0,E.jsx)(c,{"aria-hidden":`true`})}),(0,E.jsx)(`button`,{type:`button`,"aria-label":`Worklist`,tabIndex:-1,children:(0,E.jsx)(b,{"aria-hidden":`true`})}),(0,E.jsxs)(`button`,{className:a?`is-active`:``,type:`button`,"aria-label":`Artifacts`,tabIndex:-1,children:[(0,E.jsx)(l,{"aria-hidden":`true`}),i?(0,E.jsx)(`span`,{className:`scene-live-pill`,style:D(f),children:`Live`}):null]}),(0,E.jsx)(`button`,{type:`button`,"aria-label":`References`,tabIndex:-1,children:(0,E.jsx)(C,{"aria-hidden":`true`})}),(0,E.jsx)(`button`,{type:`button`,"aria-label":`Skills`,tabIndex:-1,children:(0,E.jsx)(s,{"aria-hidden":`true`})}),(0,E.jsx)(`button`,{type:`button`,"aria-label":`Timeline`,tabIndex:-1,children:(0,E.jsx)(t,{"aria-hidden":`true`})})]}),o?(0,E.jsx)(`button`,{className:`scene-status-entry is-running`,style:D(u),type:`button`,"aria-label":`Task running`,tabIndex:-1,children:(0,E.jsx)(n,{"aria-hidden":`true`})}):null]}),(0,E.jsx)(`button`,{className:`scene-settings`,type:`button`,"aria-label":`Settings`,tabIndex:-1,children:(0,E.jsx)(h,{"aria-hidden":`true`})})]})}function N({time:e,assets:t}){let n=d(e,30.35,30.92);return(0,E.jsxs)(`section`,{className:`scene-panel scene-chat-panel`,children:[(0,E.jsxs)(`header`,{className:`scene-panel-header`,children:[(0,E.jsx)(`span`,{className:`scene-icon-tile`,children:(0,E.jsx)(c,{"aria-hidden":`true`})}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{children:`Morrow Studio`}),(0,E.jsx)(`p`,{children:`Ceramics storefront`})]}),(0,E.jsxs)(`span`,{className:`scene-members`,"aria-hidden":`true`,children:[(0,E.jsx)(`i`,{className:`is-green`,children:(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:t.humanAvatars.fey,alt:``})}),(0,E.jsx)(`i`,{className:`is-blue`,children:(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:t.humanAvatars.avery,alt:``})}),(0,E.jsx)(`i`,{className:`is-yellow`,children:(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:t.humanAvatars.jun,alt:``})})]})]}),(0,E.jsxs)(`div`,{className:`scene-chat-stream`,children:[(0,E.jsx)(j,{progress:d(e,1.35,2.05),author:`Fey`,avatar:`fey`,tone:`green`,timestamp:`10:12`,online:!0,assets:t,children:`🏺 Let's build an online shop for our ceramics studio.`}),(0,E.jsx)(j,{progress:d(e,2.65,3.35),author:`Avery`,avatar:`avery`,tone:`blue`,timestamp:`10:13`,online:!0,assets:t,children:`✨ Keep it warm, minimal, and editorial.`}),(0,E.jsx)(j,{progress:d(e,3.95,4.65),author:`Jun`,avatar:`jun`,tone:`yellow`,timestamp:`10:14`,online:!0,assets:t,children:`🎨 Let people preview every piece in different glazes.`}),(0,E.jsx)(j,{progress:d(e,5.25,5.95),author:`Tutti`,avatar:`tutti`,tone:`green`,timestamp:`10:15`,assets:t,children:`Got it — I'll put it together. ✨`}),(0,E.jsxs)(`article`,{className:`scene-task-result`,style:D(n),children:[(0,E.jsx)(`span`,{className:`scene-task-result-rail`,"aria-hidden":`true`}),(0,E.jsx)(`span`,{className:`scene-task-result-icon`,"aria-hidden":`true`,children:(0,E.jsx)(S,{})}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`span`,{children:`Task completed`}),(0,E.jsx)(`strong`,{children:`Build ceramics storefront`}),(0,E.jsx)(`small`,{children:`Storefront`}),(0,E.jsx)(`p`,{children:`Warm editorial shopping and glaze previews are ready in Artifacts.`})]}),(0,E.jsx)(i,{className:`scene-task-result-chevron`,"aria-hidden":`true`})]})]}),(0,E.jsxs)(`div`,{className:`scene-composer`,"aria-hidden":`true`,children:[(0,E.jsx)(`span`,{children:`Write a message`}),(0,E.jsx)(T,{})]})]})}function P({progress:e,icon:t,children:n}){return(0,E.jsxs)(`div`,{className:`scene-scratchpad-row`,style:D(e),children:[(0,E.jsx)(`span`,{"aria-hidden":`true`,children:t}),(0,E.jsx)(`p`,{children:n})]})}function F({time:e}){return(0,E.jsxs)(`section`,{className:`scene-panel scene-scratchpad-panel`,style:{"--scratchpad-collapse":d(e,p.runEnd,19.18)},children:[(0,E.jsxs)(`header`,{className:`scene-panel-header`,children:[(0,E.jsx)(`span`,{className:`scene-icon-tile`,children:(0,E.jsx)(v,{"aria-hidden":`true`})}),(0,E.jsx)(`h2`,{children:`Scratchpad`})]}),(0,E.jsxs)(`div`,{className:`scene-scratchpad-body`,children:[(0,E.jsxs)(A,{progress:d(e,8.95,10),className:`scene-scratchpad-intro`,children:[(0,E.jsx)(`h3`,{children:`Ceramics storefront`}),(0,E.jsx)(`p`,{children:`A warm, editorial storefront for a small-batch studio, centered on tactile product discovery.`})]}),(0,E.jsx)(A,{progress:d(e,9.85,10.65),className:`scene-scratchpad-label`,children:`Confirmed`}),(0,E.jsx)(P,{progress:d(e,10.4,11.25),icon:(0,E.jsx)(S,{}),children:`Product-first editorial layout with generous space`}),(0,E.jsx)(P,{progress:d(e,11.2,12.05),icon:(0,E.jsx)(S,{}),children:`Warm neutrals with quiet serif headlines`}),(0,E.jsx)(P,{progress:d(e,12,12.85),icon:(0,E.jsx)(S,{}),children:`Keep the collection small, curated, and story-led`}),(0,E.jsx)(A,{progress:d(e,12.75,13.55),className:`scene-scratchpad-label`,children:`Requested feature`}),(0,E.jsx)(P,{progress:d(e,13.3,14.2),icon:(0,E.jsx)(o,{}),children:`Preview every piece in clay, sage, and ink glazes`})]}),(0,E.jsxs)(`footer`,{className:`scene-scratchpad-footer`,style:D(d(e,15.7,16.8)),children:[(0,E.jsxs)(`span`,{className:`scene-writing-mark`,children:[(0,E.jsx)(`strong`,{children:`Updated`}),(0,E.jsx)(`span`,{children:`just now`})]}),(0,E.jsxs)(`button`,{className:`scene-run-button`,type:`button`,tabIndex:-1,children:[(0,E.jsx)(f,{"aria-hidden":`true`}),(0,E.jsx)(`span`,{children:`Run`})]})]})]})}function I(e,t){let n=Math.max(0,Math.floor((e-t)*50/5)*5);return`${Math.floor(n/60)}m${(n%60).toString().padStart(2,`0`)}s`}function L({time:e,scoreSrc:t}){let r=d(e,18.92,19.2),i=_(e),a=i.id===`complete`,o={prepare:p.runEnd,implement:p.executionPrepareEnd,validate:p.executionImplementEnd,update:p.executionValidateEnd,complete:p.executionComplete}[i.id],s=d(e,o,o+.32),c=k(e);return(0,E.jsx)(`div`,{className:`scene-execution`,style:{"--reveal":r,"--stage-reveal":s},children:(0,E.jsxs)(`article`,{className:`homepage-motion-panel homepage-motion-execution-panel homepage-motion-execution-card is-score-${a?`complete`:`running`}`,children:[(0,E.jsx)(`header`,{className:`homepage-motion-panel-header`,children:(0,E.jsxs)(`div`,{className:`homepage-motion-panel-title`,children:[(0,E.jsx)(`span`,{className:`scene-icon-tile`,"aria-hidden":`true`,children:(0,E.jsx)(y,{})}),(0,E.jsx)(`h3`,{children:`Tutti is working on`})]})}),(0,E.jsxs)(`div`,{className:`homepage-motion-execution-body`,children:[(0,E.jsxs)(`div`,{className:`homepage-motion-execution-step homepage-motion-execution-stage is-${a?`complete`:`running`} has-marker`,children:[(0,E.jsx)(`span`,{className:`homepage-motion-execution-marker ${a?`is-done`:`is-running`}`,"aria-hidden":`true`,children:a?(0,E.jsx)(S,{}):(0,E.jsx)(n,{})}),(0,E.jsx)(`span`,{className:`homepage-motion-execution-step-content homepage-motion-execution-stage-copy`,children:(0,E.jsxs)(`span`,{className:`homepage-motion-execution-step-title`,children:[(0,E.jsx)(`span`,{className:`homepage-motion-execution-step-label`,children:i.label}),a?null:(0,E.jsx)(`span`,{className:`homepage-motion-execution-step-elapsed`,children:` (${I(e,o)})`})]})},i.id)]}),(0,E.jsx)(`div`,{className:`homepage-motion-running-score ${a?`is-complete`:``}`,role:`img`,"aria-label":`Ode to Joy score phrase`,children:(0,E.jsx)(`div`,{className:`homepage-motion-score-passage`,style:{"--score-translate-x":`${-395.3*c}px`},"aria-hidden":`true`,children:(0,E.jsx)(`img`,{src:t,alt:``,draggable:!1})})})]})]})})}function R({color:e,variant:t=`vase`,className:n=``}){let r={"--ceramic-color":e};return t===`cup`?(0,E.jsxs)(`svg`,{className:`ceramic-object is-cup ${n}`,viewBox:`0 0 260 260`,style:r,"aria-hidden":`true`,children:[(0,E.jsx)(`path`,{className:`ceramic-main`,d:`M54 64h132l-9 126c-2 26-20 42-46 42h-22c-26 0-44-16-46-42Z`}),(0,E.jsx)(`path`,{className:`ceramic-outline`,d:`M186 92h18c34 0 34 72 1 76h-27`}),(0,E.jsx)(`ellipse`,{className:`ceramic-rim`,cx:`120`,cy:`64`,rx:`66`,ry:`13`}),(0,E.jsx)(`path`,{className:`ceramic-highlight`,d:`M78 90c5 62 4 91 20 114`})]}):t===`bowl`?(0,E.jsxs)(`svg`,{className:`ceramic-object is-bowl ${n}`,viewBox:`0 0 300 220`,style:r,"aria-hidden":`true`,children:[(0,E.jsx)(`ellipse`,{className:`ceramic-rim`,cx:`150`,cy:`55`,rx:`116`,ry:`24`}),(0,E.jsx)(`path`,{className:`ceramic-main`,d:`M34 55c8 82 45 132 116 132S258 137 266 55c-42 25-190 25-232 0Z`}),(0,E.jsx)(`path`,{className:`ceramic-highlight`,d:`M72 82c18 45 40 70 70 82`}),(0,E.jsx)(`path`,{className:`ceramic-base`,d:`M112 185h76`})]}):(0,E.jsxs)(`svg`,{className:`ceramic-object is-vase ${n}`,viewBox:`0 0 320 420`,style:r,"aria-hidden":`true`,children:[(0,E.jsx)(`path`,{className:`ceramic-main`,d:`M116 56c7 38-17 61-36 96-31 56-28 157 5 199 33 42 117 42 150 0 33-42 36-143 5-199-19-35-43-58-36-96Z`}),(0,E.jsx)(`ellipse`,{className:`ceramic-rim`,cx:`160`,cy:`56`,rx:`44`,ry:`12`}),(0,E.jsx)(`ellipse`,{className:`ceramic-base`,cx:`160`,cy:`365`,rx:`66`,ry:`13`}),(0,E.jsx)(`path`,{className:`ceramic-highlight`,d:`M108 153c-25 64-23 145 1 185`})]})}function z({time:e}){let t=d(e,p.artifactClick,33.25),n=d(e,34.25,34.52),r=d(e,34.88,35.15),i=d(e,35.55,35.82),a=g(e),o=O(`#d9cbb4`,`#c56f4f`,n);e>=34.88&&(o=O(`#c56f4f`,`#6f9275`,r)),e>=35.55&&(o=O(`#6f9275`,`#243a46`,i));let s=e>=35.55?`ink`:e>=34.88?`sage`:e>=34.25?`clay`:null,c={"--artifact-scroll":a};return(0,E.jsxs)(`section`,{className:`scene-panel scene-artifact-panel`,style:D(t),children:[(0,E.jsxs)(`header`,{className:`scene-panel-header`,children:[(0,E.jsx)(`span`,{className:`scene-icon-tile`,children:(0,E.jsx)(l,{"aria-hidden":`true`})}),(0,E.jsx)(`h2`,{children:`Artifacts`}),(0,E.jsx)(`span`,{className:`scene-ready-tag`,children:`Ready`})]}),(0,E.jsx)(`div`,{className:`scene-artifact-canvas`,children:(0,E.jsxs)(`div`,{className:`artifact-page-frame`,style:c,children:[(0,E.jsxs)(`div`,{className:`artifact-page-nav`,children:[(0,E.jsx)(`strong`,{children:`Morrow`}),(0,E.jsx)(`span`,{children:`Objects · Journal · Studio`})]}),(0,E.jsxs)(`section`,{className:`artifact-hero`,children:[(0,E.jsxs)(`div`,{className:`artifact-hero-copy`,children:[(0,E.jsx)(`span`,{className:`artifact-eyebrow`,children:`Hand-finished in small batches`}),(0,E.jsx)(`h3`,{children:`Objects for slower days.`}),(0,E.jsx)(`p`,{children:`Quiet forms, warm glazes, and useful pieces made to live with.`}),(0,E.jsx)(`button`,{type:`button`,tabIndex:-1,children:`Explore the collection`})]}),(0,E.jsxs)(`div`,{className:`artifact-hero-object`,children:[(0,E.jsx)(R,{color:o}),(0,E.jsxs)(`div`,{className:`artifact-glaze-picker`,"aria-label":`Glaze preview`,children:[(0,E.jsx)(`span`,{children:`Glaze`}),(0,E.jsx)(`i`,{className:s===`clay`?`is-active is-clay`:`is-clay`}),(0,E.jsx)(`i`,{className:s===`sage`?`is-active is-sage`:`is-sage`}),(0,E.jsx)(`i`,{className:s===`ink`?`is-active is-ink`:`is-ink`})]})]})]}),(0,E.jsxs)(`section`,{className:`artifact-collection`,children:[(0,E.jsxs)(`header`,{children:[(0,E.jsx)(`span`,{children:`Selected pieces`}),(0,E.jsx)(`p`,{children:`Everyday forms shaped for the rituals around them.`})]}),(0,E.jsxs)(`div`,{className:`artifact-product-grid`,children:[(0,E.jsxs)(`article`,{children:[(0,E.jsx)(R,{color:`#b9785f`,variant:`cup`}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`strong`,{children:`Low cup`}),(0,E.jsx)(`span`,{children:`Rust glaze`})]})]}),(0,E.jsxs)(`article`,{children:[(0,E.jsx)(R,{color:`#819283`,variant:`vase`}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`strong`,{children:`Field vase`}),(0,E.jsx)(`span`,{children:`Sage glaze`})]})]}),(0,E.jsxs)(`article`,{children:[(0,E.jsx)(R,{color:`#d5c7af`,variant:`bowl`}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`strong`,{children:`Gather bowl`}),(0,E.jsx)(`span`,{children:`Flax glaze`})]})]})]})]}),(0,E.jsxs)(`section`,{className:`artifact-studio`,children:[(0,E.jsx)(`span`,{children:`Made by hand · Meant for every day`}),(0,E.jsx)(`h3`,{children:`Useful things can still feel special.`}),(0,E.jsx)(`p`,{children:`We make a small number of considered objects, slowly and close to home.`}),(0,E.jsx)(`button`,{type:`button`,tabIndex:-1,children:`Visit the studio`})]}),(0,E.jsxs)(`footer`,{className:`artifact-page-footer`,children:[(0,E.jsx)(`strong`,{children:`Morrow Ceramics`}),(0,E.jsx)(`span`,{className:`artifact-built-with`,children:`Built with Tutti.`}),(0,E.jsx)(`span`,{children:`Small batch · Est. 2026`})]})]})})]})}function B(e,t,n){return e+(t-e)*n}function V(e,t,n,r,i){let a=d(e,t,n,m);return{x:B(r.x,i.x,a),y:B(r.y,i.y,a)}}function H(e,t,n){return e<t||e>n?0:Math.sin(Math.PI*((e-t)/(n-t)))}function U(e){if(e>=p.runCursorStart&&e<18.92){let t=V(e,p.runCursorStart,p.runCursorArrive,{x:86,y:76},{x:94.25,y:94.2});return{visible:!0,x:t.x,y:t.y,clickPulse:H(e,p.runClickStart,p.runEnd)}}if(e>=31&&e<33.45){let t=V(e,31,32.22,{x:50,y:58},{x:4,y:22.85});return{visible:!0,x:t.x,y:t.y,clickPulse:H(e,32.28,32.6)}}if(e>=33.45&&e<35.95){let t={x:87.27,y:66.35},n={x:88.95,y:66.35},r={x:90.64,y:66.35},i;return i=e<34.15?V(e,33.45,34.15,{x:4,y:22.85},t):e<34.78?V(e,34.5,34.78,t,n):e<35.45?V(e,35.15,35.45,n,r):r,{visible:!0,x:i.x,y:i.y,clickPulse:Math.max(H(e,34.15,34.4),H(e,34.78,35.03),H(e,35.45,35.7))}}return{visible:!1,x:50,y:50,clickPulse:0}}function W({time:e,assets:t}){let n=u(e),r=U(e),i=a(e),o=d(e,.08,1.05,m);return(0,E.jsx)(`div`,{className:`motion-scene`,role:`img`,"aria-label":`Tutti workflow animation from team discussion to a generated ceramics storefront`,style:{opacity:i,visibility:i<=.001?`hidden`:`visible`},children:(0,E.jsxs)(`div`,{className:`motion-stage`,style:{opacity:o,transform:`translate(50%, 50%) scale(${n.scale}) translate(${-n.centerX*100}%, ${-n.centerY*100}%)`},children:[(0,E.jsx)(M,{time:e,assets:t}),(0,E.jsxs)(`div`,{className:`scene-workspace-layer`,children:[(0,E.jsx)(N,{time:e,assets:t}),(0,E.jsx)(F,{time:e}),(0,E.jsx)(L,{time:e,scoreSrc:t.scoreSrc})]}),(0,E.jsx)(z,{time:e}),(0,E.jsxs)(`span`,{className:`scene-cursor ${r.visible?`is-visible`:``}`,style:{left:`${r.x}%`,top:`${r.y}%`,"--click-pulse":r.clickPulse},"aria-hidden":`true`,children:[(0,E.jsx)(w,{}),(0,E.jsx)(`i`,{})]})]})})}export{W as HomepageMotionScene};
1
+ import{C as e,S as t,_ as n,a as r,b as i,c as a,d as o,f as s,g as c,h as l,i as u,l as d,m as f,n as p,o as m,p as h,r as g,s as _,t as v,u as y,v as b,w as x,x as S,y as C}from"./index-B8qhmh35.js";var w=e(`mouse-pointer-2`,[[`path`,{d:`M4.037 4.688a.495.495 0 0 1 .651-.651l16 6.5a.5.5 0 0 1-.063.947l-6.124 1.58a2 2 0 0 0-1.438 1.435l-1.579 6.126a.5.5 0 0 1-.947.063z`,key:`edeuup`}]]),T=e(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]),E=x();function D(e){return{"--reveal":e}}function O(e,t,n){let r=(e,t)=>Number.parseInt(e.slice(t,t+2),16),i=i=>Math.round(r(e,i)+(r(t,i)-r(e,i))*n).toString(16).padStart(2,`0`);return`#${i(1)}${i(3)}${i(5)}`}function k(e){let t=r((e-p.runEnd)/(p.executionComplete-p.runEnd));return t+t*t-t*t*t}function A({progress:e,children:t,className:n=``}){return(0,E.jsx)(`div`,{className:`scene-reveal ${n}`,style:D(e),children:t})}function j({progress:e,author:t,avatar:n,tone:r,timestamp:i,online:a=!1,assets:o,children:s}){return(0,E.jsxs)(`article`,{className:`scene-message`,style:D(e),children:[(0,E.jsx)(`span`,{className:`scene-avatar is-${r} ${n===`tutti`?`is-tutti`:``} ${a?`is-online`:``}`,"aria-hidden":`true`,children:n===`tutti`?(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:o.tuttiAvatarSrc,alt:``}):(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:o.humanAvatars[n],alt:``})}),(0,E.jsxs)(`div`,{className:`scene-message-copy`,children:[(0,E.jsxs)(`header`,{children:[(0,E.jsx)(`strong`,{children:t}),(0,E.jsx)(`span`,{children:i})]}),(0,E.jsx)(`p`,{children:s})]})]})}function M({time:e,assets:r}){let i=e>=p.artifactLive,a=e>=p.artifactClick,o=e>=p.runEnd&&e<p.executionComplete,u=d(e,p.runEnd,19.2),f=d(e,p.artifactLive,30.92);return(0,E.jsxs)(`aside`,{className:`scene-sidebar`,children:[(0,E.jsx)(`button`,{className:`scene-brand`,type:`button`,"aria-label":`Tutti`,tabIndex:-1,children:(0,E.jsx)(`img`,{src:r.logoSrc,alt:``})}),(0,E.jsxs)(`div`,{className:`scene-nav-stack`,children:[(0,E.jsxs)(`nav`,{className:`scene-nav`,"aria-label":`Workspace pages`,children:[(0,E.jsx)(`button`,{className:a?``:`is-active`,type:`button`,"aria-label":`Chat`,tabIndex:-1,children:(0,E.jsx)(c,{"aria-hidden":`true`})}),(0,E.jsx)(`button`,{type:`button`,"aria-label":`Worklist`,tabIndex:-1,children:(0,E.jsx)(b,{"aria-hidden":`true`})}),(0,E.jsxs)(`button`,{className:a?`is-active`:``,type:`button`,"aria-label":`Artifacts`,tabIndex:-1,children:[(0,E.jsx)(l,{"aria-hidden":`true`}),i?(0,E.jsx)(`span`,{className:`scene-live-pill`,style:D(f),children:`Live`}):null]}),(0,E.jsx)(`button`,{type:`button`,"aria-label":`References`,tabIndex:-1,children:(0,E.jsx)(C,{"aria-hidden":`true`})}),(0,E.jsx)(`button`,{type:`button`,"aria-label":`Skills`,tabIndex:-1,children:(0,E.jsx)(s,{"aria-hidden":`true`})}),(0,E.jsx)(`button`,{type:`button`,"aria-label":`Timeline`,tabIndex:-1,children:(0,E.jsx)(t,{"aria-hidden":`true`})})]}),o?(0,E.jsx)(`button`,{className:`scene-status-entry is-running`,style:D(u),type:`button`,"aria-label":`Task running`,tabIndex:-1,children:(0,E.jsx)(n,{"aria-hidden":`true`})}):null]}),(0,E.jsx)(`button`,{className:`scene-settings`,type:`button`,"aria-label":`Settings`,tabIndex:-1,children:(0,E.jsx)(h,{"aria-hidden":`true`})})]})}function N({time:e,assets:t}){let n=d(e,30.35,30.92);return(0,E.jsxs)(`section`,{className:`scene-panel scene-chat-panel`,children:[(0,E.jsxs)(`header`,{className:`scene-panel-header`,children:[(0,E.jsx)(`span`,{className:`scene-icon-tile`,children:(0,E.jsx)(c,{"aria-hidden":`true`})}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{children:`Morrow Studio`}),(0,E.jsx)(`p`,{children:`Ceramics storefront`})]}),(0,E.jsxs)(`span`,{className:`scene-members`,"aria-hidden":`true`,children:[(0,E.jsx)(`i`,{className:`is-green`,children:(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:t.humanAvatars.fey,alt:``})}),(0,E.jsx)(`i`,{className:`is-blue`,children:(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:t.humanAvatars.avery,alt:``})}),(0,E.jsx)(`i`,{className:`is-yellow`,children:(0,E.jsx)(`img`,{className:`scene-avatar-image`,src:t.humanAvatars.jun,alt:``})})]})]}),(0,E.jsxs)(`div`,{className:`scene-chat-stream`,children:[(0,E.jsx)(j,{progress:d(e,1.35,2.05),author:`Fey`,avatar:`fey`,tone:`green`,timestamp:`10:12`,online:!0,assets:t,children:`🏺 Let's build an online shop for our ceramics studio.`}),(0,E.jsx)(j,{progress:d(e,2.65,3.35),author:`Avery`,avatar:`avery`,tone:`blue`,timestamp:`10:13`,online:!0,assets:t,children:`✨ Keep it warm, minimal, and editorial.`}),(0,E.jsx)(j,{progress:d(e,3.95,4.65),author:`Jun`,avatar:`jun`,tone:`yellow`,timestamp:`10:14`,online:!0,assets:t,children:`🎨 Let people preview every piece in different glazes.`}),(0,E.jsx)(j,{progress:d(e,5.25,5.95),author:`Tutti`,avatar:`tutti`,tone:`green`,timestamp:`10:15`,assets:t,children:`Got it — I'll put it together. ✨`}),(0,E.jsxs)(`article`,{className:`scene-task-result`,style:D(n),children:[(0,E.jsx)(`span`,{className:`scene-task-result-rail`,"aria-hidden":`true`}),(0,E.jsx)(`span`,{className:`scene-task-result-icon`,"aria-hidden":`true`,children:(0,E.jsx)(S,{})}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`span`,{children:`Task completed`}),(0,E.jsx)(`strong`,{children:`Build ceramics storefront`}),(0,E.jsx)(`small`,{children:`Storefront`}),(0,E.jsx)(`p`,{children:`Warm editorial shopping and glaze previews are ready in Artifacts.`})]}),(0,E.jsx)(i,{className:`scene-task-result-chevron`,"aria-hidden":`true`})]})]}),(0,E.jsxs)(`div`,{className:`scene-composer`,"aria-hidden":`true`,children:[(0,E.jsx)(`span`,{children:`Write a message`}),(0,E.jsx)(T,{})]})]})}function P({progress:e,icon:t,children:n}){return(0,E.jsxs)(`div`,{className:`scene-scratchpad-row`,style:D(e),children:[(0,E.jsx)(`span`,{"aria-hidden":`true`,children:t}),(0,E.jsx)(`p`,{children:n})]})}function F({time:e}){return(0,E.jsxs)(`section`,{className:`scene-panel scene-scratchpad-panel`,style:{"--scratchpad-collapse":d(e,p.runEnd,19.18)},children:[(0,E.jsxs)(`header`,{className:`scene-panel-header`,children:[(0,E.jsx)(`span`,{className:`scene-icon-tile`,children:(0,E.jsx)(v,{"aria-hidden":`true`})}),(0,E.jsx)(`h2`,{children:`Scratchpad`})]}),(0,E.jsxs)(`div`,{className:`scene-scratchpad-body`,children:[(0,E.jsxs)(A,{progress:d(e,8.95,10),className:`scene-scratchpad-intro`,children:[(0,E.jsx)(`h3`,{children:`Ceramics storefront`}),(0,E.jsx)(`p`,{children:`A warm, editorial storefront for a small-batch studio, centered on tactile product discovery.`})]}),(0,E.jsx)(A,{progress:d(e,9.85,10.65),className:`scene-scratchpad-label`,children:`Confirmed`}),(0,E.jsx)(P,{progress:d(e,10.4,11.25),icon:(0,E.jsx)(S,{}),children:`Product-first editorial layout with generous space`}),(0,E.jsx)(P,{progress:d(e,11.2,12.05),icon:(0,E.jsx)(S,{}),children:`Warm neutrals with quiet serif headlines`}),(0,E.jsx)(P,{progress:d(e,12,12.85),icon:(0,E.jsx)(S,{}),children:`Keep the collection small, curated, and story-led`}),(0,E.jsx)(A,{progress:d(e,12.75,13.55),className:`scene-scratchpad-label`,children:`Requested feature`}),(0,E.jsx)(P,{progress:d(e,13.3,14.2),icon:(0,E.jsx)(o,{}),children:`Preview every piece in clay, sage, and ink glazes`})]}),(0,E.jsxs)(`footer`,{className:`scene-scratchpad-footer`,style:D(d(e,15.7,16.8)),children:[(0,E.jsxs)(`span`,{className:`scene-writing-mark`,children:[(0,E.jsx)(`strong`,{children:`Updated`}),(0,E.jsx)(`span`,{children:`just now`})]}),(0,E.jsxs)(`button`,{className:`scene-run-button`,type:`button`,tabIndex:-1,children:[(0,E.jsx)(f,{"aria-hidden":`true`}),(0,E.jsx)(`span`,{children:`Run`})]})]})]})}function I(e,t){let n=Math.max(0,Math.floor((e-t)*50/5)*5);return`${Math.floor(n/60)}m${(n%60).toString().padStart(2,`0`)}s`}function L({time:e,scoreSrc:t}){let r=d(e,18.92,19.2),i=_(e),a=i.id===`complete`,o={prepare:p.runEnd,implement:p.executionPrepareEnd,validate:p.executionImplementEnd,update:p.executionValidateEnd,complete:p.executionComplete}[i.id],s=d(e,o,o+.32),c=k(e);return(0,E.jsx)(`div`,{className:`scene-execution`,style:{"--reveal":r,"--stage-reveal":s},children:(0,E.jsxs)(`article`,{className:`homepage-motion-panel homepage-motion-execution-panel homepage-motion-execution-card is-score-${a?`complete`:`running`}`,children:[(0,E.jsx)(`header`,{className:`homepage-motion-panel-header`,children:(0,E.jsxs)(`div`,{className:`homepage-motion-panel-title`,children:[(0,E.jsx)(`span`,{className:`scene-icon-tile`,"aria-hidden":`true`,children:(0,E.jsx)(y,{})}),(0,E.jsx)(`h3`,{children:`Tutti is working on`})]})}),(0,E.jsxs)(`div`,{className:`homepage-motion-execution-body`,children:[(0,E.jsxs)(`div`,{className:`homepage-motion-execution-step homepage-motion-execution-stage is-${a?`complete`:`running`} has-marker`,children:[(0,E.jsx)(`span`,{className:`homepage-motion-execution-marker ${a?`is-done`:`is-running`}`,"aria-hidden":`true`,children:a?(0,E.jsx)(S,{}):(0,E.jsx)(n,{})}),(0,E.jsx)(`span`,{className:`homepage-motion-execution-step-content homepage-motion-execution-stage-copy`,children:(0,E.jsxs)(`span`,{className:`homepage-motion-execution-step-title`,children:[(0,E.jsx)(`span`,{className:`homepage-motion-execution-step-label`,children:i.label}),a?null:(0,E.jsx)(`span`,{className:`homepage-motion-execution-step-elapsed`,children:` (${I(e,o)})`})]})},i.id)]}),(0,E.jsx)(`div`,{className:`homepage-motion-running-score ${a?`is-complete`:``}`,role:`img`,"aria-label":`Ode to Joy score phrase`,children:(0,E.jsx)(`div`,{className:`homepage-motion-score-passage`,style:{"--score-translate-x":`${-395.3*c}px`},"aria-hidden":`true`,children:(0,E.jsx)(`img`,{src:t,alt:``,draggable:!1})})})]})]})})}function R({color:e,variant:t=`vase`,className:n=``}){let r={"--ceramic-color":e};return t===`cup`?(0,E.jsxs)(`svg`,{className:`ceramic-object is-cup ${n}`,viewBox:`0 0 260 260`,style:r,"aria-hidden":`true`,children:[(0,E.jsx)(`path`,{className:`ceramic-main`,d:`M54 64h132l-9 126c-2 26-20 42-46 42h-22c-26 0-44-16-46-42Z`}),(0,E.jsx)(`path`,{className:`ceramic-outline`,d:`M186 92h18c34 0 34 72 1 76h-27`}),(0,E.jsx)(`ellipse`,{className:`ceramic-rim`,cx:`120`,cy:`64`,rx:`66`,ry:`13`}),(0,E.jsx)(`path`,{className:`ceramic-highlight`,d:`M78 90c5 62 4 91 20 114`})]}):t===`bowl`?(0,E.jsxs)(`svg`,{className:`ceramic-object is-bowl ${n}`,viewBox:`0 0 300 220`,style:r,"aria-hidden":`true`,children:[(0,E.jsx)(`ellipse`,{className:`ceramic-rim`,cx:`150`,cy:`55`,rx:`116`,ry:`24`}),(0,E.jsx)(`path`,{className:`ceramic-main`,d:`M34 55c8 82 45 132 116 132S258 137 266 55c-42 25-190 25-232 0Z`}),(0,E.jsx)(`path`,{className:`ceramic-highlight`,d:`M72 82c18 45 40 70 70 82`}),(0,E.jsx)(`path`,{className:`ceramic-base`,d:`M112 185h76`})]}):(0,E.jsxs)(`svg`,{className:`ceramic-object is-vase ${n}`,viewBox:`0 0 320 420`,style:r,"aria-hidden":`true`,children:[(0,E.jsx)(`path`,{className:`ceramic-main`,d:`M116 56c7 38-17 61-36 96-31 56-28 157 5 199 33 42 117 42 150 0 33-42 36-143 5-199-19-35-43-58-36-96Z`}),(0,E.jsx)(`ellipse`,{className:`ceramic-rim`,cx:`160`,cy:`56`,rx:`44`,ry:`12`}),(0,E.jsx)(`ellipse`,{className:`ceramic-base`,cx:`160`,cy:`365`,rx:`66`,ry:`13`}),(0,E.jsx)(`path`,{className:`ceramic-highlight`,d:`M108 153c-25 64-23 145 1 185`})]})}function z({time:e}){let t=d(e,p.artifactClick,33.25),n=d(e,34.25,34.52),r=d(e,34.88,35.15),i=d(e,35.55,35.82),a=g(e),o=O(`#d9cbb4`,`#c56f4f`,n);e>=34.88&&(o=O(`#c56f4f`,`#6f9275`,r)),e>=35.55&&(o=O(`#6f9275`,`#243a46`,i));let s=e>=35.55?`ink`:e>=34.88?`sage`:e>=34.25?`clay`:null,c={"--artifact-scroll":a};return(0,E.jsxs)(`section`,{className:`scene-panel scene-artifact-panel`,style:D(t),children:[(0,E.jsxs)(`header`,{className:`scene-panel-header`,children:[(0,E.jsx)(`span`,{className:`scene-icon-tile`,children:(0,E.jsx)(l,{"aria-hidden":`true`})}),(0,E.jsx)(`h2`,{children:`Artifacts`}),(0,E.jsx)(`span`,{className:`scene-ready-tag`,children:`Ready`})]}),(0,E.jsx)(`div`,{className:`scene-artifact-canvas`,children:(0,E.jsxs)(`div`,{className:`artifact-page-frame`,style:c,children:[(0,E.jsxs)(`div`,{className:`artifact-page-nav`,children:[(0,E.jsx)(`strong`,{children:`Morrow`}),(0,E.jsx)(`span`,{children:`Objects · Journal · Studio`})]}),(0,E.jsxs)(`section`,{className:`artifact-hero`,children:[(0,E.jsxs)(`div`,{className:`artifact-hero-copy`,children:[(0,E.jsx)(`span`,{className:`artifact-eyebrow`,children:`Hand-finished in small batches`}),(0,E.jsx)(`h3`,{children:`Objects for slower days.`}),(0,E.jsx)(`p`,{children:`Quiet forms, warm glazes, and useful pieces made to live with.`}),(0,E.jsx)(`button`,{type:`button`,tabIndex:-1,children:`Explore the collection`})]}),(0,E.jsxs)(`div`,{className:`artifact-hero-object`,children:[(0,E.jsx)(R,{color:o}),(0,E.jsxs)(`div`,{className:`artifact-glaze-picker`,"aria-label":`Glaze preview`,children:[(0,E.jsx)(`span`,{children:`Glaze`}),(0,E.jsx)(`i`,{className:s===`clay`?`is-active is-clay`:`is-clay`}),(0,E.jsx)(`i`,{className:s===`sage`?`is-active is-sage`:`is-sage`}),(0,E.jsx)(`i`,{className:s===`ink`?`is-active is-ink`:`is-ink`})]})]})]}),(0,E.jsxs)(`section`,{className:`artifact-collection`,children:[(0,E.jsxs)(`header`,{children:[(0,E.jsx)(`span`,{children:`Selected pieces`}),(0,E.jsx)(`p`,{children:`Everyday forms shaped for the rituals around them.`})]}),(0,E.jsxs)(`div`,{className:`artifact-product-grid`,children:[(0,E.jsxs)(`article`,{children:[(0,E.jsx)(R,{color:`#b9785f`,variant:`cup`}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`strong`,{children:`Low cup`}),(0,E.jsx)(`span`,{children:`Rust glaze`})]})]}),(0,E.jsxs)(`article`,{children:[(0,E.jsx)(R,{color:`#819283`,variant:`vase`}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`strong`,{children:`Field vase`}),(0,E.jsx)(`span`,{children:`Sage glaze`})]})]}),(0,E.jsxs)(`article`,{children:[(0,E.jsx)(R,{color:`#d5c7af`,variant:`bowl`}),(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`strong`,{children:`Gather bowl`}),(0,E.jsx)(`span`,{children:`Flax glaze`})]})]})]})]}),(0,E.jsxs)(`section`,{className:`artifact-studio`,children:[(0,E.jsx)(`span`,{children:`Made by hand · Meant for every day`}),(0,E.jsx)(`h3`,{children:`Useful things can still feel special.`}),(0,E.jsx)(`p`,{children:`We make a small number of considered objects, slowly and close to home.`}),(0,E.jsx)(`button`,{type:`button`,tabIndex:-1,children:`Visit the studio`})]}),(0,E.jsxs)(`footer`,{className:`artifact-page-footer`,children:[(0,E.jsx)(`strong`,{children:`Morrow Ceramics`}),(0,E.jsx)(`span`,{className:`artifact-built-with`,children:`Built with Tutti.`}),(0,E.jsx)(`span`,{children:`Small batch · Est. 2026`})]})]})})]})}function B(e,t,n){return e+(t-e)*n}function V(e,t,n,r,i){let a=d(e,t,n,m);return{x:B(r.x,i.x,a),y:B(r.y,i.y,a)}}function H(e,t,n){return e<t||e>n?0:Math.sin(Math.PI*((e-t)/(n-t)))}function U(e){if(e>=p.runCursorStart&&e<18.92){let t=V(e,p.runCursorStart,p.runCursorArrive,{x:86,y:76},{x:94.25,y:94.2});return{visible:!0,x:t.x,y:t.y,clickPulse:H(e,p.runClickStart,p.runEnd)}}if(e>=31&&e<33.45){let t=V(e,31,32.22,{x:50,y:58},{x:4,y:22.85});return{visible:!0,x:t.x,y:t.y,clickPulse:H(e,32.28,32.6)}}if(e>=33.45&&e<35.95){let t={x:87.27,y:66.35},n={x:88.95,y:66.35},r={x:90.64,y:66.35},i;return i=e<34.15?V(e,33.45,34.15,{x:4,y:22.85},t):e<34.78?V(e,34.5,34.78,t,n):e<35.45?V(e,35.15,35.45,n,r):r,{visible:!0,x:i.x,y:i.y,clickPulse:Math.max(H(e,34.15,34.4),H(e,34.78,35.03),H(e,35.45,35.7))}}return{visible:!1,x:50,y:50,clickPulse:0}}function W({time:e,assets:t}){let n=u(e),r=U(e),i=a(e),o=d(e,.08,1.05,m);return(0,E.jsx)(`div`,{className:`motion-scene`,role:`img`,"aria-label":`Tutti workflow animation from team discussion to a generated ceramics storefront`,style:{opacity:i,visibility:i<=.001?`hidden`:`visible`},children:(0,E.jsxs)(`div`,{className:`motion-stage`,style:{opacity:o,transform:`translate(50%, 50%) scale(${n.scale}) translate(${-n.centerX*100}%, ${-n.centerY*100}%)`},children:[(0,E.jsx)(M,{time:e,assets:t}),(0,E.jsxs)(`div`,{className:`scene-workspace-layer`,children:[(0,E.jsx)(N,{time:e,assets:t}),(0,E.jsx)(F,{time:e}),(0,E.jsx)(L,{time:e,scoreSrc:t.scoreSrc})]}),(0,E.jsx)(z,{time:e}),(0,E.jsxs)(`span`,{className:`scene-cursor ${r.visible?`is-visible`:``}`,style:{left:`${r.x}%`,top:`${r.y}%`,"--click-pulse":r.clickPulse},"aria-hidden":`true`,children:[(0,E.jsx)(w,{}),(0,E.jsx)(`i`,{})]})]})})}export{W as HomepageMotionScene};