@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.
- package/dist/server-shell/cli/join-url.d.ts +7 -0
- package/dist/server-shell/cli/join-url.js +15 -0
- package/dist/server-shell/http/routes/project-api/workspace-projections.js +3 -16
- package/dist/server-shell/http/validation.js +1 -0
- package/dist/server-shell/local-console/project-service.d.ts +9 -3
- package/dist/server-shell/local-console/project-service.js +134 -68
- package/dist/server-shell/local-console/server.js +1 -0
- package/node_modules/@tutti/relay-client/dist/host-control.d.ts +14 -0
- package/node_modules/@tutti/relay-client/dist/host-control.js +53 -0
- package/node_modules/@tutti/shared/dist/schemas/api/primitives.d.ts +2 -2
- package/node_modules/@tutti/shared/dist/schemas/api/primitives.js +1 -0
- package/package.json +1 -1
- package/web/assets/{homepage-motion-scene-BFtd7PRa.js → homepage-motion-scene-Dn91ywLW.js} +1 -1
- package/web/assets/index-B8qhmh35.js +69 -0
- package/web/index.html +1 -1
- package/web/assets/index-l-bfO_Si.js +0 -69
|
@@ -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 =
|
|
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" ||
|
|
61
|
+
if (relayState.status !== "connected" || readFreshVisibleJoinUrl(relayState, now) !== undefined) {
|
|
75
62
|
return buildWorkspaceProjection(options, relayState, now);
|
|
76
63
|
}
|
|
77
64
|
try {
|
|
@@ -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
|
-
|
|
41
|
-
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
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
|
-
|
|
405
|
-
|
|
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
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
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
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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
|
-
|
|
461
|
-
|
|
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 +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};
|