@xfey/tutti 0.1.85 → 0.1.86

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 (24) hide show
  1. package/dist/server-shell/cli/cli.js +11 -3
  2. package/dist/server-shell/desktop-integration/entry-continuation.d.ts +31 -0
  3. package/dist/server-shell/desktop-integration/entry-continuation.js +81 -0
  4. package/dist/server-shell/desktop-integration/index.d.ts +1 -0
  5. package/dist/server-shell/desktop-integration/index.js +1 -0
  6. package/dist/server-shell/desktop-integration/protocol.d.ts +6 -0
  7. package/dist/server-shell/desktop-integration/protocol.js +30 -5
  8. package/dist/server-shell/local-console/server.js +12 -0
  9. package/dist/server-shell/local-console/session.d.ts +2 -0
  10. package/dist/server-shell/local-console/session.js +24 -3
  11. package/node_modules/@tutti/shared/dist/ids/index.d.ts +3 -0
  12. package/node_modules/@tutti/shared/dist/ids/index.js +2 -0
  13. package/node_modules/@tutti/shared/dist/schemas/api/desktop-entry-continuations.d.ts +75 -0
  14. package/node_modules/@tutti/shared/dist/schemas/api/desktop-entry-continuations.js +59 -0
  15. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +2 -0
  16. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -0
  17. package/node_modules/@tutti/shared/dist/schemas/domain/index.d.ts +1 -0
  18. package/node_modules/@tutti/shared/dist/schemas/domain/index.js +1 -0
  19. package/package.json +1 -1
  20. package/web/assets/{homepage-motion-scene-uE_guJiL.js → homepage-motion-scene-fY2v-V-b.js} +1 -1
  21. package/web/assets/index-B8Fj3PkC.js +69 -0
  22. package/web/assets/{index-BZNgSvWi.css → index-lNbWftd-.css} +1 -1
  23. package/web/index.html +2 -2
  24. package/web/assets/index-Lf1CEBa7.js +0 -69
@@ -8,7 +8,8 @@ import { resolveExistingProjectContext } from "./project-resolver.js";
8
8
  import { runProviderSetupTui } from "./provider-tui.js";
9
9
  import { runArchiveCommand, runDoctorCommand, runForgetCommand, runInviteCommand, runLogsCommand, runProviderStatusCommand, runPsManageCommand, runPsCommand, runStopCommand, listRuntimeProjects, } from "./runtime-commands.js";
10
10
  import { readCliVersion } from "./version.js";
11
- import { ensureDesktopIntegrationAutomatically, parseTuttiDesktopUrl, runDesktopIntegrationCommand, TUTTI_DESKTOP_PROJECTS_URL, TuttiDesktopProtocolError, } from "../desktop-integration/index.js";
11
+ import { ensureDesktopIntegrationAutomatically, executeDesktopOpenIntent, parseTuttiDesktopUrl, runDesktopIntegrationCommand, TUTTI_DESKTOP_PROJECTS_URL, TuttiDesktopProtocolError, } from "../desktop-integration/index.js";
12
+ import { resolveRelayUrl } from "./launch.js";
12
13
  import { ensureLocalConsole, openLocalConsoleBrowser, readLocalConsoleServiceStatus, restartLocalConsoleService, runLocalConsoleProcess, stopLocalConsoleService, } from "../local-console/index.js";
13
14
  import { runPackageUpdateCompletionProtocol, runPackageUpdateWorkerProtocol, } from "../local-console/package-update-process.js";
14
15
  import { recoverPackageUpdateForConsoleStartup } from "../local-console/package-update-recovery.js";
@@ -260,8 +261,9 @@ function runDesktopCommand(action) {
260
261
  }
261
262
  async function runDesktopOpenCommand(value) {
262
263
  const desktopUrl = value ?? TUTTI_DESKTOP_PROJECTS_URL;
264
+ let intent;
263
265
  try {
264
- parseTuttiDesktopUrl(desktopUrl);
266
+ intent = parseTuttiDesktopUrl(desktopUrl);
265
267
  }
266
268
  catch (error) {
267
269
  if (error instanceof TuttiDesktopProtocolError) {
@@ -272,7 +274,13 @@ async function runDesktopOpenCommand(value) {
272
274
  const cliEntrypoint = process.argv[1];
273
275
  const cwd = cliEntrypoint === undefined ? process.cwd() : dirname(resolve(cliEntrypoint));
274
276
  const url = await ensureUserLocalConsole({ source: "desktop", cwd });
275
- if (!openLocalConsoleBrowser(url)) {
277
+ const result = await executeDesktopOpenIntent({
278
+ intent,
279
+ accessUrl: url,
280
+ relayUrl: resolveRelayUrl(process.env),
281
+ openBrowser: openLocalConsoleBrowser,
282
+ });
283
+ if (result.kind === "browser_unavailable") {
276
284
  throw new LaunchError("desktop_open_failed", "The Local Console started, but no desktop browser opener is available.", "Run `tutti` from a terminal to print a one-time browser URL.");
277
285
  }
278
286
  }
@@ -0,0 +1,31 @@
1
+ import { type SealedDesktopEntryPayload } from "@tutti/shared/schemas/api";
2
+ import type { TuttiDesktopIntent } from "./protocol.js";
3
+ export type DesktopEntryContinuationIntent = Extract<TuttiDesktopIntent, {
4
+ kind: "projects-continuation";
5
+ }>;
6
+ export type DesktopEntryCompletionFetch = (input: string | URL, init: RequestInit) => Promise<Response>;
7
+ export declare function sealDesktopEntryAccessUrl(accessUrl: string, payloadKey: string, options?: {
8
+ createIv?: () => Buffer;
9
+ }): SealedDesktopEntryPayload;
10
+ export declare function completeDesktopEntryContinuation(options: {
11
+ intent: DesktopEntryContinuationIntent;
12
+ accessUrl: string;
13
+ relayUrl: string;
14
+ fetchImpl?: DesktopEntryCompletionFetch;
15
+ signal?: AbortSignal;
16
+ }): Promise<void>;
17
+ export type ExecuteDesktopOpenResult = {
18
+ kind: "continued";
19
+ } | {
20
+ kind: "browser_opened";
21
+ } | {
22
+ kind: "browser_unavailable";
23
+ };
24
+ export declare function executeDesktopOpenIntent(options: {
25
+ intent: TuttiDesktopIntent;
26
+ accessUrl: string;
27
+ relayUrl: string;
28
+ complete?: typeof completeDesktopEntryContinuation;
29
+ openBrowser: (url: string) => boolean;
30
+ }): Promise<ExecuteDesktopOpenResult>;
31
+ //# sourceMappingURL=entry-continuation.d.ts.map
@@ -0,0 +1,81 @@
1
+ import { createCipheriv, randomBytes } from "node:crypto";
2
+ import { DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH, } from "@tutti/shared/schemas/api";
3
+ const DESKTOP_ENTRY_COMPLETION_PATH = "/desktop-control/v1/entry-continuations/complete";
4
+ const DESKTOP_ENTRY_COMPLETION_TIMEOUT_MS = 5_000;
5
+ function decodePayloadKey(value) {
6
+ if (value.length !== DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH || !/^[A-Za-z0-9_-]+$/u.test(value)) {
7
+ throw new Error("Desktop entry payload key is invalid.");
8
+ }
9
+ const key = Buffer.from(value, "base64url");
10
+ if (key.length !== 32) {
11
+ throw new Error("Desktop entry payload key is invalid.");
12
+ }
13
+ return key;
14
+ }
15
+ export function sealDesktopEntryAccessUrl(accessUrl, payloadKey, options = {}) {
16
+ const iv = (options.createIv ?? (() => randomBytes(12)))();
17
+ if (iv.length !== 12) {
18
+ throw new Error("Desktop entry payload IV is invalid.");
19
+ }
20
+ const cipher = createCipheriv("aes-256-gcm", decodePayloadKey(payloadKey), iv);
21
+ const ciphertext = Buffer.concat([
22
+ cipher.update(accessUrl, "utf8"),
23
+ cipher.final(),
24
+ cipher.getAuthTag(),
25
+ ]);
26
+ return {
27
+ iv: iv.toString("base64url"),
28
+ ciphertext: ciphertext.toString("base64url"),
29
+ };
30
+ }
31
+ function completionUrl(relayUrl) {
32
+ const relay = new URL(relayUrl);
33
+ const localHttp = relay.protocol === "http:" &&
34
+ (relay.hostname === "127.0.0.1" || relay.hostname === "localhost");
35
+ if (relay.protocol !== "https:" && !localHttp) {
36
+ throw new Error("Desktop entry continuation requires HTTPS or a loopback Relay.");
37
+ }
38
+ return new URL(DESKTOP_ENTRY_COMPLETION_PATH, relay.origin);
39
+ }
40
+ export async function completeDesktopEntryContinuation(options) {
41
+ const fetchImpl = options.fetchImpl ?? fetch;
42
+ const response = await fetchImpl(completionUrl(options.relayUrl), {
43
+ method: "POST",
44
+ headers: {
45
+ accept: "application/json",
46
+ authorization: `Bearer ${options.intent.completionToken}`,
47
+ "content-type": "application/json",
48
+ },
49
+ body: JSON.stringify({
50
+ continuation_ref: options.intent.continuationRef,
51
+ sealed_payload: sealDesktopEntryAccessUrl(options.accessUrl, options.intent.payloadKey),
52
+ }),
53
+ signal: options.signal ?? AbortSignal.timeout(DESKTOP_ENTRY_COMPLETION_TIMEOUT_MS),
54
+ });
55
+ if (!response.ok) {
56
+ throw new Error("Relay did not accept the desktop entry continuation.");
57
+ }
58
+ const body = (await response.json());
59
+ if (body.status !== "accepted") {
60
+ throw new Error("Relay returned an invalid desktop entry continuation response.");
61
+ }
62
+ }
63
+ export async function executeDesktopOpenIntent(options) {
64
+ if (options.intent.kind === "projects-continuation") {
65
+ try {
66
+ await (options.complete ?? completeDesktopEntryContinuation)({
67
+ intent: options.intent,
68
+ accessUrl: options.accessUrl,
69
+ relayUrl: options.relayUrl,
70
+ });
71
+ return { kind: "continued" };
72
+ }
73
+ catch {
74
+ // The legacy browser opener remains the bounded availability fallback.
75
+ }
76
+ }
77
+ return options.openBrowser(options.accessUrl)
78
+ ? { kind: "browser_opened" }
79
+ : { kind: "browser_unavailable" };
80
+ }
81
+ //# sourceMappingURL=entry-continuation.js.map
@@ -1,3 +1,4 @@
1
+ export * from "./entry-continuation.js";
1
2
  export * from "./manager.js";
2
3
  export * from "./platform.js";
3
4
  export * from "./protocol.js";
@@ -1,3 +1,4 @@
1
+ export * from "./entry-continuation.js";
1
2
  export * from "./manager.js";
2
3
  export * from "./platform.js";
3
4
  export * from "./protocol.js";
@@ -1,6 +1,12 @@
1
+ import { type RelayDesktopEntryContinuationRef } from "@tutti/shared/ids";
1
2
  export declare const TUTTI_DESKTOP_PROJECTS_URL = "tutti://projects";
2
3
  export type TuttiDesktopIntent = {
3
4
  kind: "projects";
5
+ } | {
6
+ kind: "projects-continuation";
7
+ continuationRef: RelayDesktopEntryContinuationRef;
8
+ completionToken: string;
9
+ payloadKey: string;
4
10
  };
5
11
  export declare class TuttiDesktopProtocolError extends Error {
6
12
  constructor();
@@ -1,7 +1,9 @@
1
+ import { ID_PREFIXES, isPrefixedId, } from "@tutti/shared/ids";
2
+ import { DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH, DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH, } from "@tutti/shared/schemas/api";
1
3
  export const TUTTI_DESKTOP_PROJECTS_URL = "tutti://projects";
2
4
  export class TuttiDesktopProtocolError extends Error {
3
5
  constructor() {
4
- super("Only the fixed tutti://projects desktop destination is supported.");
6
+ super("The Tutti desktop destination is invalid.");
5
7
  this.name = "TuttiDesktopProtocolError";
6
8
  }
7
9
  }
@@ -13,16 +15,39 @@ export function parseTuttiDesktopUrl(value) {
13
15
  catch {
14
16
  throw new TuttiDesktopProtocolError();
15
17
  }
16
- if (url.protocol !== "tutti:" ||
18
+ const baseInvalid = url.protocol !== "tutti:" ||
17
19
  url.hostname !== "projects" ||
18
20
  (url.pathname !== "" && url.pathname !== "/") ||
19
21
  url.username !== "" ||
20
22
  url.password !== "" ||
21
23
  url.port !== "" ||
22
- url.search !== "" ||
23
- url.hash !== "") {
24
+ url.hash !== "";
25
+ if (baseInvalid) {
24
26
  throw new TuttiDesktopProtocolError();
25
27
  }
26
- return { kind: "projects" };
28
+ if (url.search === "") {
29
+ return { kind: "projects" };
30
+ }
31
+ const parameters = url.searchParams;
32
+ if (parameters.size !== 3 ||
33
+ parameters.getAll("continuation").length !== 1 ||
34
+ parameters.getAll("completion_token").length !== 1 ||
35
+ parameters.getAll("payload_key").length !== 1) {
36
+ throw new TuttiDesktopProtocolError();
37
+ }
38
+ const continuationRef = parameters.get("continuation") ?? "";
39
+ const completionToken = parameters.get("completion_token") ?? "";
40
+ const payloadKey = parameters.get("payload_key") ?? "";
41
+ if (!isPrefixedId(continuationRef, ID_PREFIXES.relayDesktopEntryContinuation) ||
42
+ !new RegExp(`^[A-Za-z0-9_-]{${DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH}}$`, "u").test(completionToken) ||
43
+ !new RegExp(`^[A-Za-z0-9_-]{${DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH}}$`, "u").test(payloadKey)) {
44
+ throw new TuttiDesktopProtocolError();
45
+ }
46
+ return {
47
+ kind: "projects-continuation",
48
+ continuationRef,
49
+ completionToken,
50
+ payloadKey,
51
+ };
27
52
  }
28
53
  //# sourceMappingURL=protocol.js.map
@@ -273,6 +273,7 @@ export function createLocalConsoleServer(options) {
273
273
  const session = requireSession(request);
274
274
  const packageUpdateCompletion = options.getPackageUpdateCompletion?.();
275
275
  return {
276
+ account_gate: { status: session.accountReady ? "ready" : "required" },
276
277
  csrf_token: session.csrfToken,
277
278
  version: options.runtime?.version ?? readCliVersion(),
278
279
  invocation: session.context.source === "terminal"
@@ -288,6 +289,17 @@ export function createLocalConsoleServer(options) {
288
289
  : { package_update_completion: packageUpdateCompletion }),
289
290
  };
290
291
  });
292
+ app.post(`${LOCAL_CONSOLE_API_BASE}/account-continuations`, (request) => {
293
+ const session = requireSession(request, true);
294
+ if (request.body !== undefined) {
295
+ throw new LocalConsoleHttpError(400, "bad_request", "Account continuation does not accept browser-controlled input.");
296
+ }
297
+ const continuation = sessions.issueAccountContinuation(session.context);
298
+ return {
299
+ access_token: continuation.token,
300
+ expires_at: continuation.expires_at,
301
+ };
302
+ });
291
303
  app.get(`${LOCAL_CONSOLE_API_BASE}/package-update`, {
292
304
  schema: {
293
305
  querystring: {
@@ -11,6 +11,7 @@ export type ExchangedLocalConsoleSession = {
11
11
  expires_at: string;
12
12
  };
13
13
  export type ReadLocalConsoleSession = {
14
+ accountReady: boolean;
14
15
  csrfToken: string;
15
16
  context: LocalConsoleInvocationContext;
16
17
  };
@@ -20,6 +21,7 @@ export declare class LocalConsoleSessionRegistry {
20
21
  now?: () => Date;
21
22
  });
22
23
  issueAccessToken(context: LocalConsoleInvocationContext): IssuedLocalConsoleAccessToken;
24
+ issueAccountContinuation(context: LocalConsoleInvocationContext): IssuedLocalConsoleAccessToken;
23
25
  exchangeAccessToken(token: string, existingSessionToken?: string): ExchangedLocalConsoleSession | null;
24
26
  readSession(token: string | undefined, contextToken?: string): ReadLocalConsoleSession | null;
25
27
  }
@@ -1,6 +1,7 @@
1
1
  import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
2
  export const LOCAL_CONSOLE_SESSION_COOKIE = "tutti_local_console_session";
3
3
  const ACCESS_TOKEN_TTL_MS = 60_000;
4
+ const ACCOUNT_CONTINUATION_TTL_MS = 15 * 60_000;
4
5
  const SESSION_TTL_MS = 12 * 60 * 60 * 1_000;
5
6
  function createSecret() {
6
7
  return randomBytes(32).toString("base64url");
@@ -23,13 +24,28 @@ export class LocalConsoleSessionRegistry {
23
24
  this.#now = options.now ?? (() => new Date());
24
25
  }
25
26
  issueAccessToken(context) {
27
+ return this.#issueAccessToken({
28
+ accountReady: false,
29
+ context,
30
+ ttlMs: ACCESS_TOKEN_TTL_MS,
31
+ });
32
+ }
33
+ issueAccountContinuation(context) {
34
+ return this.#issueAccessToken({
35
+ accountReady: true,
36
+ context,
37
+ ttlMs: ACCOUNT_CONTINUATION_TTL_MS,
38
+ });
39
+ }
40
+ #issueAccessToken(options) {
26
41
  this.#purgeExpired();
27
42
  const token = createSecret();
28
- const expiresAt = this.#now().getTime() + ACCESS_TOKEN_TTL_MS;
43
+ const expiresAt = this.#now().getTime() + options.ttlMs;
29
44
  this.#accessTokens.set(hashSecret(token), {
45
+ accountReady: options.accountReady,
30
46
  hash: hashSecret(token),
31
47
  expiresAt,
32
- context,
48
+ context: options.context,
33
49
  });
34
50
  return { token, expires_at: new Date(expiresAt).toISOString() };
35
51
  }
@@ -82,6 +98,7 @@ export class LocalConsoleSessionRegistry {
82
98
  const contextHash = hashSecret(contextToken);
83
99
  session.defaultContextHash = contextHash;
84
100
  this.#contexts.set(contextHash, {
101
+ accountReady: accessToken.accountReady,
85
102
  hash: contextHash,
86
103
  expiresAt: session.expiresAt,
87
104
  sessionHash,
@@ -113,7 +130,11 @@ export class LocalConsoleSessionRegistry {
113
130
  (contextToken !== undefined && !secretEquals(contextToken, context.hash))) {
114
131
  return null;
115
132
  }
116
- return { csrfToken: session.csrfToken, context: context.context };
133
+ return {
134
+ accountReady: context.accountReady,
135
+ csrfToken: session.csrfToken,
136
+ context: context.context,
137
+ };
117
138
  }
118
139
  #purgeExpired() {
119
140
  const now = this.#now().getTime();
@@ -21,6 +21,7 @@ export declare const ID_PREFIXES: {
21
21
  readonly relayClientSession: "relay_client_session_";
22
22
  readonly relayUpload: "relay_upload_";
23
23
  readonly relayAuthChallenge: "relay_auth_challenge_";
24
+ readonly relayDesktopEntryContinuation: "relay_desktop_entry_continuation_";
24
25
  readonly hostConnection: "host_connection_";
25
26
  readonly joinToken: "join_token_";
26
27
  readonly notice: "notice_";
@@ -48,6 +49,7 @@ export type RelayAccountSessionRef = PrefixedId<typeof ID_PREFIXES.relayAccountS
48
49
  export type RelayClientSessionId = PrefixedId<typeof ID_PREFIXES.relayClientSession>;
49
50
  export type RelayUploadRef = PrefixedId<typeof ID_PREFIXES.relayUpload>;
50
51
  export type RelayAuthChallengeRef = PrefixedId<typeof ID_PREFIXES.relayAuthChallenge>;
52
+ export type RelayDesktopEntryContinuationRef = PrefixedId<typeof ID_PREFIXES.relayDesktopEntryContinuation>;
51
53
  export type HostConnectionRef = PrefixedId<typeof ID_PREFIXES.hostConnection>;
52
54
  export type JoinTokenRef = PrefixedId<typeof ID_PREFIXES.joinToken>;
53
55
  export type NoticeId = PrefixedId<typeof ID_PREFIXES.notice>;
@@ -79,6 +81,7 @@ export declare const createRelayAccountSessionRef: () => RelayAccountSessionRef;
79
81
  export declare const createRelayClientSessionId: () => RelayClientSessionId;
80
82
  export declare const createRelayUploadRef: () => RelayUploadRef;
81
83
  export declare const createRelayAuthChallengeRef: () => RelayAuthChallengeRef;
84
+ export declare const createRelayDesktopEntryContinuationRef: () => RelayDesktopEntryContinuationRef;
82
85
  export declare const createHostConnectionRef: () => HostConnectionRef;
83
86
  export declare const createJoinTokenRef: () => JoinTokenRef;
84
87
  export declare const createNoticeId: () => NoticeId;
@@ -23,6 +23,7 @@ export const ID_PREFIXES = {
23
23
  relayClientSession: "relay_client_session_",
24
24
  relayUpload: "relay_upload_",
25
25
  relayAuthChallenge: "relay_auth_challenge_",
26
+ relayDesktopEntryContinuation: "relay_desktop_entry_continuation_",
26
27
  hostConnection: "host_connection_",
27
28
  joinToken: "join_token_",
28
29
  notice: "notice_",
@@ -82,6 +83,7 @@ export const createRelayAccountSessionRef = () => createPrefixedId(ID_PREFIXES.r
82
83
  export const createRelayClientSessionId = () => createPrefixedId(ID_PREFIXES.relayClientSession);
83
84
  export const createRelayUploadRef = () => createPrefixedId(ID_PREFIXES.relayUpload);
84
85
  export const createRelayAuthChallengeRef = () => createPrefixedId(ID_PREFIXES.relayAuthChallenge);
86
+ export const createRelayDesktopEntryContinuationRef = () => createPrefixedId(ID_PREFIXES.relayDesktopEntryContinuation);
85
87
  export const createHostConnectionRef = () => createPrefixedId(ID_PREFIXES.hostConnection);
86
88
  export const createJoinTokenRef = () => createPrefixedId(ID_PREFIXES.joinToken);
87
89
  export const createNoticeId = () => createPrefixedId(ID_PREFIXES.notice);
@@ -0,0 +1,75 @@
1
+ import type { Static } from "@sinclair/typebox";
2
+ import type { RelayDesktopEntryContinuationRef } from "../../ids/index.js";
3
+ export declare const DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH = 43;
4
+ export declare const DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH = 43;
5
+ export declare const DESKTOP_ENTRY_SEALED_IV_LENGTH = 16;
6
+ export declare const MAX_DESKTOP_ENTRY_SEALED_CIPHERTEXT_LENGTH = 4096;
7
+ export declare const DesktopEntryCompletionTokenSchema: import("@sinclair/typebox").TString;
8
+ export declare const DesktopEntryPayloadKeySchema: import("@sinclair/typebox").TString;
9
+ export declare const SealedDesktopEntryPayloadSchema: import("@sinclair/typebox").TObject<{
10
+ iv: import("@sinclair/typebox").TString;
11
+ ciphertext: import("@sinclair/typebox").TString;
12
+ }>;
13
+ export declare const CreateDesktopEntryContinuationResponseSchema: import("@sinclair/typebox").TObject<{
14
+ continuation_ref: import("@sinclair/typebox").TString;
15
+ completion_token: import("@sinclair/typebox").TString;
16
+ expires_at: import("@sinclair/typebox").TString;
17
+ }>;
18
+ export declare const DesktopEntryContinuationPendingProjectionSchema: import("@sinclair/typebox").TObject<{
19
+ continuation_ref: import("@sinclair/typebox").TString;
20
+ status: import("@sinclair/typebox").TLiteral<"pending">;
21
+ expires_at: import("@sinclair/typebox").TString;
22
+ }>;
23
+ export declare const DesktopEntryContinuationReadyProjectionSchema: import("@sinclair/typebox").TObject<{
24
+ continuation_ref: import("@sinclair/typebox").TString;
25
+ status: import("@sinclair/typebox").TLiteral<"ready">;
26
+ sealed_payload: import("@sinclair/typebox").TObject<{
27
+ iv: import("@sinclair/typebox").TString;
28
+ ciphertext: import("@sinclair/typebox").TString;
29
+ }>;
30
+ expires_at: import("@sinclair/typebox").TString;
31
+ }>;
32
+ export declare const GetDesktopEntryContinuationResponseSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
33
+ continuation_ref: import("@sinclair/typebox").TString;
34
+ status: import("@sinclair/typebox").TLiteral<"pending">;
35
+ expires_at: import("@sinclair/typebox").TString;
36
+ }>, import("@sinclair/typebox").TObject<{
37
+ continuation_ref: import("@sinclair/typebox").TString;
38
+ status: import("@sinclair/typebox").TLiteral<"ready">;
39
+ sealed_payload: import("@sinclair/typebox").TObject<{
40
+ iv: import("@sinclair/typebox").TString;
41
+ ciphertext: import("@sinclair/typebox").TString;
42
+ }>;
43
+ expires_at: import("@sinclair/typebox").TString;
44
+ }>]>;
45
+ export declare const CompleteDesktopEntryContinuationBodySchema: import("@sinclair/typebox").TObject<{
46
+ continuation_ref: import("@sinclair/typebox").TString;
47
+ sealed_payload: import("@sinclair/typebox").TObject<{
48
+ iv: import("@sinclair/typebox").TString;
49
+ ciphertext: import("@sinclair/typebox").TString;
50
+ }>;
51
+ }>;
52
+ export declare const CompleteDesktopEntryContinuationResponseSchema: import("@sinclair/typebox").TObject<{
53
+ status: import("@sinclair/typebox").TLiteral<"accepted">;
54
+ }>;
55
+ export type SealedDesktopEntryPayload = Static<typeof SealedDesktopEntryPayloadSchema>;
56
+ export type CreateDesktopEntryContinuationResponse = {
57
+ continuation_ref: RelayDesktopEntryContinuationRef;
58
+ completion_token: string;
59
+ expires_at: string;
60
+ };
61
+ export type GetDesktopEntryContinuationResponse = {
62
+ continuation_ref: RelayDesktopEntryContinuationRef;
63
+ status: "pending";
64
+ expires_at: string;
65
+ } | {
66
+ continuation_ref: RelayDesktopEntryContinuationRef;
67
+ status: "ready";
68
+ sealed_payload: SealedDesktopEntryPayload;
69
+ expires_at: string;
70
+ };
71
+ export type CompleteDesktopEntryContinuationBody = {
72
+ continuation_ref: RelayDesktopEntryContinuationRef;
73
+ sealed_payload: SealedDesktopEntryPayload;
74
+ };
75
+ //# sourceMappingURL=desktop-entry-continuations.d.ts.map
@@ -0,0 +1,59 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { RelayDesktopEntryContinuationRefSchema } from "../domain/index.js";
3
+ export const DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH = 43;
4
+ export const DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH = 43;
5
+ export const DESKTOP_ENTRY_SEALED_IV_LENGTH = 16;
6
+ export const MAX_DESKTOP_ENTRY_SEALED_CIPHERTEXT_LENGTH = 4_096;
7
+ const Base64UrlTokenSchema = Type.String({
8
+ pattern: "^[A-Za-z0-9_-]+$",
9
+ });
10
+ export const DesktopEntryCompletionTokenSchema = Type.String({
11
+ ...Base64UrlTokenSchema,
12
+ minLength: DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH,
13
+ maxLength: DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH,
14
+ });
15
+ export const DesktopEntryPayloadKeySchema = Type.String({
16
+ ...Base64UrlTokenSchema,
17
+ minLength: DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH,
18
+ maxLength: DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH,
19
+ });
20
+ export const SealedDesktopEntryPayloadSchema = Type.Object({
21
+ iv: Type.String({
22
+ ...Base64UrlTokenSchema,
23
+ minLength: DESKTOP_ENTRY_SEALED_IV_LENGTH,
24
+ maxLength: DESKTOP_ENTRY_SEALED_IV_LENGTH,
25
+ }),
26
+ ciphertext: Type.String({
27
+ ...Base64UrlTokenSchema,
28
+ minLength: 24,
29
+ maxLength: MAX_DESKTOP_ENTRY_SEALED_CIPHERTEXT_LENGTH,
30
+ }),
31
+ }, { additionalProperties: false });
32
+ export const CreateDesktopEntryContinuationResponseSchema = Type.Object({
33
+ continuation_ref: RelayDesktopEntryContinuationRefSchema,
34
+ completion_token: DesktopEntryCompletionTokenSchema,
35
+ expires_at: Type.String({ minLength: 1 }),
36
+ }, { additionalProperties: false });
37
+ export const DesktopEntryContinuationPendingProjectionSchema = Type.Object({
38
+ continuation_ref: RelayDesktopEntryContinuationRefSchema,
39
+ status: Type.Literal("pending"),
40
+ expires_at: Type.String({ minLength: 1 }),
41
+ }, { additionalProperties: false });
42
+ export const DesktopEntryContinuationReadyProjectionSchema = Type.Object({
43
+ continuation_ref: RelayDesktopEntryContinuationRefSchema,
44
+ status: Type.Literal("ready"),
45
+ sealed_payload: SealedDesktopEntryPayloadSchema,
46
+ expires_at: Type.String({ minLength: 1 }),
47
+ }, { additionalProperties: false });
48
+ export const GetDesktopEntryContinuationResponseSchema = Type.Union([
49
+ DesktopEntryContinuationPendingProjectionSchema,
50
+ DesktopEntryContinuationReadyProjectionSchema,
51
+ ]);
52
+ export const CompleteDesktopEntryContinuationBodySchema = Type.Object({
53
+ continuation_ref: RelayDesktopEntryContinuationRefSchema,
54
+ sealed_payload: SealedDesktopEntryPayloadSchema,
55
+ }, { additionalProperties: false });
56
+ export const CompleteDesktopEntryContinuationResponseSchema = Type.Object({
57
+ status: Type.Literal("accepted"),
58
+ }, { additionalProperties: false });
59
+ //# sourceMappingURL=desktop-entry-continuations.js.map
@@ -1,5 +1,7 @@
1
1
  export * from "./openapi.js";
2
2
  export type * from "./types.js";
3
+ export { CompleteDesktopEntryContinuationBodySchema, CompleteDesktopEntryContinuationResponseSchema, CreateDesktopEntryContinuationResponseSchema, DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH, DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH, DESKTOP_ENTRY_SEALED_IV_LENGTH, DesktopEntryCompletionTokenSchema, DesktopEntryContinuationPendingProjectionSchema, DesktopEntryContinuationReadyProjectionSchema, DesktopEntryPayloadKeySchema, GetDesktopEntryContinuationResponseSchema, MAX_DESKTOP_ENTRY_SEALED_CIPHERTEXT_LENGTH, SealedDesktopEntryPayloadSchema, } from "./desktop-entry-continuations.js";
4
+ export type { CompleteDesktopEntryContinuationBody, CreateDesktopEntryContinuationResponse, GetDesktopEntryContinuationResponse, SealedDesktopEntryPayload, } from "./desktop-entry-continuations.js";
3
5
  export { ApiErrorCodeSchema, ApiErrorResponseSchema, CommandDispositionBaseSchema, CursorPageRequestSchema, DEFAULT_SSE_REPLAY_WINDOW_POLICY, InterruptedCommandDispositionSchema, QueryInvalidationHintSchema, RelayInvalidationHintSchema, RelaySseEventTypeSchema, SseReplayWindowPolicySchema, WorkspaceSseEventTypeSchema, commandEnvelopeSchema, commandResponseSchema, commandResponseWithResultSchema, cursorPageSchema, relaySseEventSchema, timelineWindowSchema, workspaceSseEventSchema, } from "./primitives.js";
4
6
  export { GetProviderModelsResponseSchema, MAX_PROVIDER_MODEL_NAME_LENGTH, ProviderConfigInvalidReasonCodeSchema, ProviderConfigProjectionSchema, ProviderModelDiscoveryUnavailableReasonSchema, ProviderModelNameSchema, ProviderModelValidationFailureReasonSchema, ProviderUnavailableReasonCodeSchema, ProjectProviderUnavailableReasonSchema, UpdateProviderDefaultModelBodySchema, UpdateProviderDefaultModelDispositionSchema, UpdateProviderDefaultModelPayloadSchema, UpdateProviderDefaultModelResponseSchema, } from "./provider-config.js";
5
7
  export { ProviderUsageBreakdownProjectionSchema, ProviderUsageCategorySchema, ProviderUsageModelSummaryProjectionSchema, ProviderUsageProjectionSchema, ProviderUsageSourceSummaryProjectionSchema, } from "./provider-usage.js";
@@ -1,4 +1,5 @@
1
1
  export * from "./openapi.js";
2
+ export { CompleteDesktopEntryContinuationBodySchema, CompleteDesktopEntryContinuationResponseSchema, CreateDesktopEntryContinuationResponseSchema, DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH, DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH, DESKTOP_ENTRY_SEALED_IV_LENGTH, DesktopEntryCompletionTokenSchema, DesktopEntryContinuationPendingProjectionSchema, DesktopEntryContinuationReadyProjectionSchema, DesktopEntryPayloadKeySchema, GetDesktopEntryContinuationResponseSchema, MAX_DESKTOP_ENTRY_SEALED_CIPHERTEXT_LENGTH, SealedDesktopEntryPayloadSchema, } from "./desktop-entry-continuations.js";
2
3
  export { ApiErrorCodeSchema, ApiErrorResponseSchema, CommandDispositionBaseSchema, CursorPageRequestSchema, DEFAULT_SSE_REPLAY_WINDOW_POLICY, InterruptedCommandDispositionSchema, QueryInvalidationHintSchema, RelayInvalidationHintSchema, RelaySseEventTypeSchema, SseReplayWindowPolicySchema, WorkspaceSseEventTypeSchema, commandEnvelopeSchema, commandResponseSchema, commandResponseWithResultSchema, cursorPageSchema, relaySseEventSchema, timelineWindowSchema, workspaceSseEventSchema, } from "./primitives.js";
3
4
  export { GetProviderModelsResponseSchema, MAX_PROVIDER_MODEL_NAME_LENGTH, ProviderConfigInvalidReasonCodeSchema, ProviderConfigProjectionSchema, ProviderModelDiscoveryUnavailableReasonSchema, ProviderModelNameSchema, ProviderModelValidationFailureReasonSchema, ProviderUnavailableReasonCodeSchema, ProjectProviderUnavailableReasonSchema, UpdateProviderDefaultModelBodySchema, UpdateProviderDefaultModelDispositionSchema, UpdateProviderDefaultModelPayloadSchema, UpdateProviderDefaultModelResponseSchema, } from "./provider-config.js";
4
5
  export { ProviderUsageBreakdownProjectionSchema, ProviderUsageCategorySchema, ProviderUsageModelSummaryProjectionSchema, ProviderUsageProjectionSchema, ProviderUsageSourceSummaryProjectionSchema, } from "./provider-usage.js";
@@ -24,6 +24,7 @@ export declare const RelayAccountSessionRefSchema: TString;
24
24
  export declare const RelayClientSessionIdSchema: TString;
25
25
  export declare const RelayUploadRefSchema: TString;
26
26
  export declare const RelayAuthChallengeRefSchema: TString;
27
+ export declare const RelayDesktopEntryContinuationRefSchema: TString;
27
28
  export declare const HostConnectionRefSchema: TString;
28
29
  export declare const JoinTokenRefSchema: TString;
29
30
  export declare const WorkflowKindSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"project_context_bootstrap">, import("@sinclair/typebox").TLiteral<"scratchpad_refresh">, import("@sinclair/typebox").TLiteral<"task_compile">, import("@sinclair/typebox").TLiteral<"context_sync">, import("@sinclair/typebox").TLiteral<"reference_summary_refresh">, import("@sinclair/typebox").TLiteral<"recovery_check">, import("@sinclair/typebox").TLiteral<"follow_up_check">]>;
@@ -35,6 +35,7 @@ export const RelayAccountSessionRefSchema = prefixedIdSchema(ID_PREFIXES.relayAc
35
35
  export const RelayClientSessionIdSchema = prefixedIdSchema(ID_PREFIXES.relayClientSession, "RelayClientSessionId");
36
36
  export const RelayUploadRefSchema = prefixedIdSchema(ID_PREFIXES.relayUpload, "RelayUploadRef");
37
37
  export const RelayAuthChallengeRefSchema = prefixedIdSchema(ID_PREFIXES.relayAuthChallenge, "RelayAuthChallengeRef");
38
+ export const RelayDesktopEntryContinuationRefSchema = prefixedIdSchema(ID_PREFIXES.relayDesktopEntryContinuation, "RelayDesktopEntryContinuationRef");
38
39
  export const HostConnectionRefSchema = prefixedIdSchema(ID_PREFIXES.hostConnection, "HostConnectionRef");
39
40
  export const JoinTokenRefSchema = prefixedIdSchema(ID_PREFIXES.joinToken, "JoinTokenRef");
40
41
  export const WorkflowKindSchema = Type.Union([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfey/tutti",
3
- "version": "0.1.85",
3
+ "version": "0.1.86",
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-Lf1CEBa7.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)}}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-B8Fj3PkC.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)}}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};