@xfey/tutti 0.1.78 → 0.1.79
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/chat-assistant/index.d.ts +11 -1
- package/dist/chat-assistant/index.js +61 -7
- package/dist/checks/index.d.ts +22 -0
- package/dist/checks/index.js +110 -4
- package/dist/control-plane/follow-up-start.d.ts +1 -0
- package/dist/control-plane/follow-up-start.js +3 -1
- package/dist/control-plane/index.d.ts +6 -1
- package/dist/control-plane/index.js +72 -11
- package/dist/control-plane/procedure-logging.js +24 -67
- package/dist/control-plane/project-context-bootstrap.js +7 -1
- package/dist/control-plane/reference-summary-refresh.js +1 -1
- package/dist/control-plane/run-result-recording.js +2 -1
- package/dist/control-plane/task-compile-start.d.ts +1 -0
- package/dist/control-plane/task-compile-start.js +11 -1
- package/dist/control-plane/workflows/openai.d.ts +6 -0
- package/dist/control-plane/workflows/openai.js +16 -3
- package/dist/procedure-engine/index.d.ts +1 -0
- package/dist/procedure-engine/index.js +7 -1
- package/dist/process-tree.d.ts +25 -0
- package/dist/process-tree.js +121 -0
- package/dist/providers/openai/app-server/invocation-coordinator.d.ts +28 -0
- package/dist/providers/openai/app-server/invocation-coordinator.js +104 -0
- package/dist/providers/openai/app-server/invocation-lifecycle.d.ts +45 -0
- package/dist/providers/openai/app-server/invocation-lifecycle.js +104 -0
- package/dist/providers/openai/app-server/json-rpc.d.ts +1 -1
- package/dist/providers/openai/app-server/json-rpc.js +9 -16
- package/dist/providers/openai/app-server/read-only-procedure.d.ts +8 -2
- package/dist/providers/openai/app-server/read-only-procedure.js +63 -11
- package/dist/providers/openai/app-server/smoke-types.d.ts +4 -2
- package/dist/providers/openai/app-server/smoke.js +41 -12
- package/dist/providers/openai/app-server/stale-temp-cleanup.d.ts +17 -0
- package/dist/providers/openai/app-server/stale-temp-cleanup.js +130 -0
- package/dist/providers/openai/app-server/workspace-write-run.d.ts +8 -2
- package/dist/providers/openai/app-server/workspace-write-run.js +63 -11
- package/dist/providers/openai/chat-assistant.d.ts +6 -0
- package/dist/providers/openai/chat-assistant.js +12 -0
- package/dist/run-engine/index.js +2 -1
- package/dist/run-pipeline/artifact-applicability.js +2 -2
- package/dist/run-pipeline/openai.d.ts +9 -0
- package/dist/run-pipeline/openai.js +26 -26
- package/dist/run-pipeline/task-run-invocation.js +6 -0
- package/dist/runtime-failures.d.ts +3 -0
- package/dist/runtime-failures.js +22 -0
- package/dist/server-shell/cli/host-lifecycle.js +1 -1
- package/dist/server-shell/cli/host-project-runtime-lifecycle.d.ts +43 -0
- package/dist/server-shell/cli/host-project-runtime-lifecycle.js +54 -0
- package/dist/server-shell/cli/host-server-runtime.js +77 -14
- package/dist/server-shell/http/create-server.d.ts +3 -0
- package/dist/server-shell/http/create-server.js +10 -4
- package/package.json +1 -1
- package/web/assets/{homepage-motion-scene-sNI8fBH3.js → homepage-motion-scene-BFQnHtRi.js} +1 -1
- package/web/assets/index-C4cdSaSb.js +69 -0
- package/web/index.html +1 -1
- package/web/assets/index-d-q9yZ09.js +0 -69
|
@@ -251,13 +251,13 @@ export async function runArtifactCandidateGate(options) {
|
|
|
251
251
|
try {
|
|
252
252
|
applicability = await judgeApplicability(options.judge ?? createDefaultJudge(options), input);
|
|
253
253
|
}
|
|
254
|
-
catch
|
|
254
|
+
catch {
|
|
255
255
|
return gateFailure({
|
|
256
256
|
reasonCode: "artifact_applicability_failed",
|
|
257
257
|
summary: "Tutti could not determine whether this candidate requires an Artifact.",
|
|
258
258
|
guidance: "Retry when the Artifact applicability provider is available.",
|
|
259
259
|
source: "applicability_judge",
|
|
260
|
-
detail:
|
|
260
|
+
detail: "Artifact applicability could not be determined by the provider.",
|
|
261
261
|
correctable: false,
|
|
262
262
|
});
|
|
263
263
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ProjectId } from "@tutti/shared/ids";
|
|
2
2
|
import type { ApprovalRequestManager } from "../approvals/index.js";
|
|
3
|
+
import { type CheckProcessCoordinator } from "../checks/index.js";
|
|
3
4
|
import type { ControlPlaneLogger, RunPipelineResolution, RunPipelineRunner } from "../control-plane/index.js";
|
|
4
5
|
import type { ProviderUsageRecorder } from "../provider-usage/index.js";
|
|
5
6
|
import type { OpenAiStructuredOutputClient } from "../providers/openai/sdk-procedure-runner.js";
|
|
@@ -8,6 +9,8 @@ import { type ArtifactApplicabilityJudge } from "./artifact-applicability.js";
|
|
|
8
9
|
import { type OpenAiProviderConfig } from "../providers/openai/provider-config.js";
|
|
9
10
|
import { type CodexLinuxSandboxReadiness } from "../providers/openai/app-server/linux-sandbox-readiness.js";
|
|
10
11
|
import type { CodexAppServerAgentContextRuntime } from "../providers/openai/app-server/skills.js";
|
|
12
|
+
import type { CodexAppServerInvocationCoordinator } from "../providers/openai/app-server/invocation-coordinator.js";
|
|
13
|
+
import type { CodexAppServerLifecycleIncident } from "../providers/openai/app-server/invocation-lifecycle.js";
|
|
11
14
|
export { TASK_RUN_OUTPUT_SCHEMA } from "./task-run-output.js";
|
|
12
15
|
export type OpenAiRunPipelineRunnerOptions = {
|
|
13
16
|
config: OpenAiProviderConfig;
|
|
@@ -23,9 +26,12 @@ export type OpenAiRunPipelineRunnerOptions = {
|
|
|
23
26
|
requestTimeoutMs?: number;
|
|
24
27
|
turnTimeoutMs?: number;
|
|
25
28
|
checkTimeoutMs?: number;
|
|
29
|
+
checkProcessCoordinator?: CheckProcessCoordinator;
|
|
26
30
|
baseEnv?: NodeJS.ProcessEnv;
|
|
27
31
|
logger?: ControlPlaneLogger | undefined;
|
|
28
32
|
recordUsage?: ProviderUsageRecorder;
|
|
33
|
+
invocationCoordinator?: CodexAppServerInvocationCoordinator;
|
|
34
|
+
onLifecycleIncident?: (incident: CodexAppServerLifecycleIncident) => void;
|
|
29
35
|
artifactApplicabilityClient?: OpenAiStructuredOutputClient;
|
|
30
36
|
artifactApplicabilityJudge?: ArtifactApplicabilityJudge;
|
|
31
37
|
validateArtifactCandidate?: (options: ValidateCandidateArtifactOptions) => Promise<CandidateArtifactValidationResult>;
|
|
@@ -40,6 +46,9 @@ export type ProjectOpenAiRunPipelineRunnerOptions = {
|
|
|
40
46
|
approvalManager?: ApprovalRequestManager;
|
|
41
47
|
logger?: ControlPlaneLogger | undefined;
|
|
42
48
|
recordUsage?: ProviderUsageRecorder;
|
|
49
|
+
invocationCoordinator?: CodexAppServerInvocationCoordinator;
|
|
50
|
+
checkProcessCoordinator?: CheckProcessCoordinator;
|
|
51
|
+
onLifecycleIncident?: (incident: CodexAppServerLifecycleIncident) => void;
|
|
43
52
|
};
|
|
44
53
|
export declare function createOpenAiRunPipelineRunner(options: OpenAiRunPipelineRunnerOptions): RunPipelineRunner;
|
|
45
54
|
export declare function resolveProjectOpenAiRunPipelineRunner(options: ProjectOpenAiRunPipelineRunnerOptions): RunPipelineResolution;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createNodeNpmCheckPlan, executeCheckPlan } from "../checks/index.js";
|
|
1
|
+
import { createNodeNpmCheckPlan, executeCheckPlan, } from "../checks/index.js";
|
|
2
2
|
import { runArtifactCandidateGate, } from "./artifact-applicability.js";
|
|
3
3
|
import { checkSkipFields, checkStatus, checksSummary, completedWithoutRepoChanges, docsStatusForChangedPaths, failedBeforeChecks, failedFinishedResult, promotionNotAttempted, promotionNotPromoted, successfulRunSummary, } from "./result-projections.js";
|
|
4
4
|
import { runWorkspaceWriteTask } from "./task-run-invocation.js";
|
|
@@ -13,28 +13,16 @@ function isRecord(value) {
|
|
|
13
13
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
14
|
}
|
|
15
15
|
function summarizeProviderError(error) {
|
|
16
|
-
const
|
|
17
|
-
error.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
error.details.stderr_excerpt === undefined || error.details.stderr_excerpt.trim() === ""
|
|
24
|
-
? ""
|
|
25
|
-
: `stderr=${error.details.stderr_excerpt}`,
|
|
26
|
-
].filter((part) => part !== "");
|
|
27
|
-
const summary = diagnosticParts.length === 0
|
|
28
|
-
? error.message
|
|
29
|
-
: `${error.message} (${diagnosticParts.join("; ")})`;
|
|
30
|
-
const looksLikeSchemaError = summary.includes("invalid_json_schema") ||
|
|
31
|
-
summary.includes("Invalid schema") ||
|
|
32
|
-
summary.includes("response_format");
|
|
16
|
+
const looksLikeSchemaError = error.details.turn_error_code === "invalid_json_schema" ||
|
|
17
|
+
error.message.includes("invalid_json_schema") ||
|
|
18
|
+
error.message.includes("Invalid schema") ||
|
|
19
|
+
error.message.includes("response_format");
|
|
20
|
+
const errorCode = looksLikeSchemaError
|
|
21
|
+
? "codex_app_server_output_schema_invalid"
|
|
22
|
+
: `codex_app_server_${error.code}`;
|
|
33
23
|
return failedBeforeChecks({
|
|
34
|
-
summary
|
|
35
|
-
errorCode
|
|
36
|
-
? "codex_app_server_output_schema_invalid"
|
|
37
|
-
: `codex_app_server_${error.code}`,
|
|
24
|
+
summary: `Provider execution failed before checks. (${errorCode})`,
|
|
25
|
+
errorCode,
|
|
38
26
|
retryable: !looksLikeSchemaError &&
|
|
39
27
|
(error.code === "app_server_protocol_error" ||
|
|
40
28
|
error.code === "turn_timeout" ||
|
|
@@ -44,13 +32,13 @@ function summarizeProviderError(error) {
|
|
|
44
32
|
}
|
|
45
33
|
function summarizeWorkspaceOpsError(error, changedPaths) {
|
|
46
34
|
return failedBeforeChecks({
|
|
47
|
-
summary: error.
|
|
35
|
+
summary: `Workspace operation failed before checks. (workspace_ops_${error.code})`,
|
|
48
36
|
errorCode: `workspace_ops_${error.code}`,
|
|
49
37
|
retryable: error.code === "conflict",
|
|
50
38
|
...(changedPaths === undefined ? {} : { changedPaths }),
|
|
51
39
|
promotion: error.code === "conflict"
|
|
52
|
-
? promotionNotPromoted("mainline_not_promotable",
|
|
53
|
-
: promotionNotAttempted("workspace_ops_failed",
|
|
40
|
+
? promotionNotPromoted("mainline_not_promotable", "Workspace state could not be accepted safely.")
|
|
41
|
+
: promotionNotAttempted("workspace_ops_failed", "Workspace operation failed before promotion."),
|
|
54
42
|
});
|
|
55
43
|
}
|
|
56
44
|
function runLineageFields(input) {
|
|
@@ -359,6 +347,9 @@ async function runTaskAttempt(options, input) {
|
|
|
359
347
|
workspaceRoot: options.workspaceRoot,
|
|
360
348
|
plan: checkPlan,
|
|
361
349
|
...(options.checkTimeoutMs === undefined ? {} : { timeoutMs: options.checkTimeoutMs }),
|
|
350
|
+
...(options.checkProcessCoordinator === undefined
|
|
351
|
+
? {}
|
|
352
|
+
: { processCoordinator: options.checkProcessCoordinator }),
|
|
362
353
|
}), (result) => ({ checks_status: result.status, command_count: result.commands.length }));
|
|
363
354
|
if (checks.status === "failed") {
|
|
364
355
|
const result = failedFinishedResult({
|
|
@@ -441,7 +432,7 @@ async function runTaskAttempt(options, input) {
|
|
|
441
432
|
return summarizeWorkspaceOpsError(error, changedPaths);
|
|
442
433
|
}
|
|
443
434
|
return failedBeforeChecks({
|
|
444
|
-
summary:
|
|
435
|
+
summary: "Run pipeline failed before checks. (run_pipeline_failed)",
|
|
445
436
|
errorCode: "run_pipeline_failed",
|
|
446
437
|
retryable: false,
|
|
447
438
|
...(changedPaths === undefined ? {} : { changedPaths }),
|
|
@@ -529,6 +520,15 @@ export function resolveProjectOpenAiRunPipelineRunner(options) {
|
|
|
529
520
|
...(options.promptsRoot === undefined ? {} : { promptsRoot: options.promptsRoot }),
|
|
530
521
|
...(options.logger === undefined ? {} : { logger: options.logger }),
|
|
531
522
|
...(options.recordUsage === undefined ? {} : { recordUsage: options.recordUsage }),
|
|
523
|
+
...(options.invocationCoordinator === undefined
|
|
524
|
+
? {}
|
|
525
|
+
: { invocationCoordinator: options.invocationCoordinator }),
|
|
526
|
+
...(options.checkProcessCoordinator === undefined
|
|
527
|
+
? {}
|
|
528
|
+
: { checkProcessCoordinator: options.checkProcessCoordinator }),
|
|
529
|
+
...(options.onLifecycleIncident === undefined
|
|
530
|
+
? {}
|
|
531
|
+
: { onLifecycleIncident: options.onLifecycleIncident }),
|
|
532
532
|
...(process.platform === "linux"
|
|
533
533
|
? { codexSandboxReadiness: () => inspectCodexLinuxSandboxReadiness() }
|
|
534
534
|
: {}),
|
|
@@ -111,6 +111,12 @@ export async function runWorkspaceWriteTask(options, input) {
|
|
|
111
111
|
: { requestTimeoutMs: options.requestTimeoutMs }),
|
|
112
112
|
...(options.turnTimeoutMs === undefined ? {} : { turnTimeoutMs: options.turnTimeoutMs }),
|
|
113
113
|
...(options.baseEnv === undefined ? {} : { baseEnv: options.baseEnv }),
|
|
114
|
+
...(options.invocationCoordinator === undefined
|
|
115
|
+
? {}
|
|
116
|
+
: { invocationCoordinator: options.invocationCoordinator }),
|
|
117
|
+
...(options.onLifecycleIncident === undefined
|
|
118
|
+
? {}
|
|
119
|
+
: { onLifecycleIncident: options.onLifecycleIncident }),
|
|
114
120
|
runtimeTelemetry: {
|
|
115
121
|
activityRef: input.activity_ref,
|
|
116
122
|
stageId: "provider_task_run",
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function stableRuntimeFailureCode(error: unknown, fallback: string): string;
|
|
2
|
+
export declare function safeRuntimeFailureSummary(subject: "Procedure" | "Run", error: unknown, fallbackCode: "procedure_failed" | "run_failed"): string;
|
|
3
|
+
//# sourceMappingURL=runtime-failures.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const STABLE_FAILURE_CODE = /^[a-z][a-z0-9_]{0,63}$/u;
|
|
2
|
+
export function stableRuntimeFailureCode(error, fallback) {
|
|
3
|
+
if (typeof error === "object" &&
|
|
4
|
+
error !== null &&
|
|
5
|
+
"code" in error &&
|
|
6
|
+
typeof error.code === "string" &&
|
|
7
|
+
STABLE_FAILURE_CODE.test(error.code)) {
|
|
8
|
+
return error.code;
|
|
9
|
+
}
|
|
10
|
+
return fallback;
|
|
11
|
+
}
|
|
12
|
+
export function safeRuntimeFailureSummary(subject, error, fallbackCode) {
|
|
13
|
+
const code = stableRuntimeFailureCode(error, fallbackCode);
|
|
14
|
+
if (code === "process_lifecycle_failed" || code === "process_tree_not_terminated") {
|
|
15
|
+
return `${subject} stopped because the provider process could not close safely. Restart the Host before retrying. (${code})`;
|
|
16
|
+
}
|
|
17
|
+
if (code === "admission_unavailable" || code === "admission_closed") {
|
|
18
|
+
return `${subject} stopped because provider execution is unavailable while the Host is closing. Retry after the Host is ready. (${code})`;
|
|
19
|
+
}
|
|
20
|
+
return `${subject} failed because the runtime returned an internal error. Retry the action. (${code})`;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=runtime-failures.js.map
|
|
@@ -393,7 +393,7 @@ export function formatLaunchLifecycleResult(result, options = {}) {
|
|
|
393
393
|
}
|
|
394
394
|
export async function waitForForegroundHostShutdown(handle, processLike = process) {
|
|
395
395
|
const stop = () => {
|
|
396
|
-
void handle.close();
|
|
396
|
+
void handle.close().catch(() => undefined);
|
|
397
397
|
};
|
|
398
398
|
processLike.once("SIGINT", stop);
|
|
399
399
|
processLike.once("SIGTERM", stop);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
type ControlPlaneLifecycleOwner = {
|
|
2
|
+
beginShutdown: () => void;
|
|
3
|
+
waitForIdle: () => Promise<void>;
|
|
4
|
+
};
|
|
5
|
+
type ChatAssistantLifecycleOwner = {
|
|
6
|
+
stopAccepting: () => void;
|
|
7
|
+
waitForIdle: () => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
type InvocationLifecycleOwner = {
|
|
10
|
+
stopAccepting: () => void;
|
|
11
|
+
closeActive: () => Promise<void>;
|
|
12
|
+
waitForIdle: () => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
type CheckLifecycleOwner = {
|
|
15
|
+
stopAccepting: () => void;
|
|
16
|
+
terminateActive: () => Promise<void>;
|
|
17
|
+
waitForIdle: () => Promise<void>;
|
|
18
|
+
};
|
|
19
|
+
type ApprovalLifecycleOwner = {
|
|
20
|
+
clearPending: () => void;
|
|
21
|
+
dispose: () => void;
|
|
22
|
+
};
|
|
23
|
+
export declare class HostProjectRuntimeShutdownError extends Error {
|
|
24
|
+
readonly code: "drain_timeout";
|
|
25
|
+
constructor(code: "drain_timeout", message: string);
|
|
26
|
+
}
|
|
27
|
+
export declare class HostProjectRuntimeLifecycle {
|
|
28
|
+
private readonly options;
|
|
29
|
+
private closePromise;
|
|
30
|
+
constructor(options: {
|
|
31
|
+
controlPlane: ControlPlaneLifecycleOwner;
|
|
32
|
+
chatAssistant: ChatAssistantLifecycleOwner;
|
|
33
|
+
invocationCoordinator: InvocationLifecycleOwner;
|
|
34
|
+
checkProcessCoordinator: CheckLifecycleOwner;
|
|
35
|
+
approvalManager: ApprovalLifecycleOwner;
|
|
36
|
+
gracefulDrainMs?: number;
|
|
37
|
+
forcedDrainMs?: number;
|
|
38
|
+
});
|
|
39
|
+
close(): Promise<void>;
|
|
40
|
+
private closeOnce;
|
|
41
|
+
}
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=host-project-runtime-lifecycle.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export class HostProjectRuntimeShutdownError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(code, message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.name = "HostProjectRuntimeShutdownError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const DEFAULT_GRACEFUL_DRAIN_MS = 1_000;
|
|
10
|
+
const DEFAULT_FORCED_DRAIN_MS = 10_000;
|
|
11
|
+
function wait(delayMs) {
|
|
12
|
+
return new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
13
|
+
}
|
|
14
|
+
async function settlesWithin(promise, timeoutMs) {
|
|
15
|
+
return await Promise.race([
|
|
16
|
+
promise.then(() => true),
|
|
17
|
+
wait(timeoutMs).then(() => false),
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
export class HostProjectRuntimeLifecycle {
|
|
21
|
+
options;
|
|
22
|
+
closePromise;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.options = options;
|
|
25
|
+
}
|
|
26
|
+
close() {
|
|
27
|
+
this.closePromise ??= this.closeOnce();
|
|
28
|
+
return this.closePromise;
|
|
29
|
+
}
|
|
30
|
+
async closeOnce() {
|
|
31
|
+
this.options.controlPlane.beginShutdown();
|
|
32
|
+
this.options.chatAssistant.stopAccepting();
|
|
33
|
+
this.options.invocationCoordinator.stopAccepting();
|
|
34
|
+
this.options.checkProcessCoordinator.stopAccepting();
|
|
35
|
+
this.options.approvalManager.clearPending();
|
|
36
|
+
const waitForOwners = () => Promise.all([
|
|
37
|
+
this.options.chatAssistant.waitForIdle(),
|
|
38
|
+
this.options.controlPlane.waitForIdle(),
|
|
39
|
+
this.options.invocationCoordinator.waitForIdle(),
|
|
40
|
+
this.options.checkProcessCoordinator.waitForIdle(),
|
|
41
|
+
]).then(() => undefined);
|
|
42
|
+
if (!(await settlesWithin(waitForOwners(), this.options.gracefulDrainMs ?? DEFAULT_GRACEFUL_DRAIN_MS))) {
|
|
43
|
+
await Promise.all([
|
|
44
|
+
this.options.invocationCoordinator.closeActive(),
|
|
45
|
+
this.options.checkProcessCoordinator.terminateActive(),
|
|
46
|
+
]);
|
|
47
|
+
if (!(await settlesWithin(waitForOwners(), this.options.forcedDrainMs ?? DEFAULT_FORCED_DRAIN_MS))) {
|
|
48
|
+
throw new HostProjectRuntimeShutdownError("drain_timeout", "Host project runtime did not settle within the bounded shutdown window.");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.options.approvalManager.dispose();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=host-project-runtime-lifecycle.js.map
|
|
@@ -4,9 +4,12 @@ import { completeRelayUpload, resolveRelayUpload } from "@tutti/relay-client";
|
|
|
4
4
|
import { ApprovalRequestManager } from "../../approvals/index.js";
|
|
5
5
|
import { ArtifactPreviewManager } from "../../artifacts/index.js";
|
|
6
6
|
import { ReadOnlyChatAssistant } from "../../chat-assistant/index.js";
|
|
7
|
+
import { CheckProcessCoordinator } from "../../checks/index.js";
|
|
7
8
|
import { ensureInitialProjectWelcomeMessage } from "../../collaboration-state/index.js";
|
|
8
9
|
import { Phase5ControlPlane } from "../../control-plane/index.js";
|
|
9
10
|
import { resolveProjectOpenAiProcedureWorkflowRunner } from "../../control-plane/workflows/index.js";
|
|
11
|
+
import { cleanupStaleCodexAppServerTempRoots } from "../../providers/openai/app-server/stale-temp-cleanup.js";
|
|
12
|
+
import { CodexAppServerInvocationCoordinator } from "../../providers/openai/app-server/invocation-coordinator.js";
|
|
10
13
|
import { resolveProjectOpenAiReadOnlyChatAssistantModel } from "../../providers/openai/chat-assistant.js";
|
|
11
14
|
import { configureProjectOpenAiProvider, readOpenAiProviderConfigProjection, } from "../../providers/openai/index.js";
|
|
12
15
|
import { readProviderUsageProjection, recordProviderUsageEvent, } from "../../provider-usage/index.js";
|
|
@@ -18,6 +21,7 @@ import { readHostRepoProjection } from "../http/routes/project-api.js";
|
|
|
18
21
|
import { WorkspaceEventBus } from "../http/workspace-events.js";
|
|
19
22
|
import { createTrustedRelaySessionMetadataStore, } from "../session/relay-session-context.js";
|
|
20
23
|
import { LaunchError } from "./errors.js";
|
|
24
|
+
import { HostProjectRuntimeLifecycle } from "./host-project-runtime-lifecycle.js";
|
|
21
25
|
import { readCliVersion } from "./version.js";
|
|
22
26
|
import { relayStateFromLaunchStatus } from "./host-relay-status.js";
|
|
23
27
|
import { appendHostLogLine, readHostRegistrationSecret, createMachineRuntimeEndpointToken, deleteMachineRuntimeEndpoint, ensureHostLogFile, getHostLogFilePath, updateMachineProjectDisplayNameSnapshot, writeMachineRuntimeEndpoint, } from "./machine-local.js";
|
|
@@ -47,6 +51,15 @@ function createHostRuntimeLogger(options) {
|
|
|
47
51
|
},
|
|
48
52
|
};
|
|
49
53
|
}
|
|
54
|
+
function createLifecycleIncidentReporter(logger, consumer) {
|
|
55
|
+
return (incident) => {
|
|
56
|
+
logger.info({
|
|
57
|
+
consumer,
|
|
58
|
+
incident_code: incident.code,
|
|
59
|
+
error_code: incident.error_code,
|
|
60
|
+
}, "Codex app-server lifecycle incident");
|
|
61
|
+
};
|
|
62
|
+
}
|
|
50
63
|
function createAgentContextRuntime(options) {
|
|
51
64
|
return {
|
|
52
65
|
baseUrl: new URL(AGENT_CONTEXT_BASE_PATH, options.baseUrl).toString(),
|
|
@@ -214,10 +227,25 @@ export async function startForegroundHostServer(options) {
|
|
|
214
227
|
logFilePath,
|
|
215
228
|
now,
|
|
216
229
|
});
|
|
230
|
+
const procedureLifecycleIncident = createLifecycleIncidentReporter(controlPlaneLogger, "procedure");
|
|
231
|
+
const runLifecycleIncident = createLifecycleIncidentReporter(runPipelineLogger, "run");
|
|
232
|
+
const chatLifecycleIncident = createLifecycleIncidentReporter(controlPlaneLogger, "chat_assistant");
|
|
233
|
+
const staleTempCleanup = await cleanupStaleCodexAppServerTempRoots({
|
|
234
|
+
onIncident: (incident) => {
|
|
235
|
+
controlPlaneLogger.info({
|
|
236
|
+
consumer: "maintenance",
|
|
237
|
+
incident_code: incident.code,
|
|
238
|
+
error_code: incident.error_code,
|
|
239
|
+
}, "Codex app-server lifecycle incident");
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
controlPlaneLogger.info(staleTempCleanup, "Codex app-server stale temp cleanup completed");
|
|
217
243
|
const approvalManager = new ApprovalRequestManager({
|
|
218
244
|
events: workspaceEvents,
|
|
219
245
|
now,
|
|
220
246
|
});
|
|
247
|
+
const codexInvocationCoordinator = new CodexAppServerInvocationCoordinator();
|
|
248
|
+
const checkProcessCoordinator = new CheckProcessCoordinator();
|
|
221
249
|
const artifactPreviewManager = new ArtifactPreviewManager({
|
|
222
250
|
onStatusChange: () => {
|
|
223
251
|
workspaceEvents.publish({
|
|
@@ -254,6 +282,9 @@ export async function startForegroundHostServer(options) {
|
|
|
254
282
|
approvalManager,
|
|
255
283
|
logger: runPipelineLogger,
|
|
256
284
|
recordUsage,
|
|
285
|
+
invocationCoordinator: codexInvocationCoordinator,
|
|
286
|
+
checkProcessCoordinator,
|
|
287
|
+
onLifecycleIncident: runLifecycleIncident,
|
|
257
288
|
}),
|
|
258
289
|
resolveWorkflowRunner: () => resolveProjectOpenAiProcedureWorkflowRunner({
|
|
259
290
|
tuttiHome: options.preparation.tutti_home,
|
|
@@ -261,6 +292,8 @@ export async function startForegroundHostServer(options) {
|
|
|
261
292
|
workspaceRoot: options.preparation.workspace_root,
|
|
262
293
|
agentContext: agentContextRuntime,
|
|
263
294
|
recordUsage,
|
|
295
|
+
invocationCoordinator: codexInvocationCoordinator,
|
|
296
|
+
onLifecycleIncident: procedureLifecycleIncident,
|
|
264
297
|
}),
|
|
265
298
|
});
|
|
266
299
|
const chatAssistant = new ReadOnlyChatAssistant({
|
|
@@ -276,6 +309,8 @@ export async function startForegroundHostServer(options) {
|
|
|
276
309
|
workspaceRoot: options.preparation.workspace_root,
|
|
277
310
|
agentContext: agentContextRuntime,
|
|
278
311
|
recordUsage,
|
|
312
|
+
invocationCoordinator: codexInvocationCoordinator,
|
|
313
|
+
onLifecycleIncident: chatLifecycleIncident,
|
|
279
314
|
});
|
|
280
315
|
if (resolution.kind !== "ready") {
|
|
281
316
|
throw new Error("Provider is not configured.");
|
|
@@ -283,9 +318,17 @@ export async function startForegroundHostServer(options) {
|
|
|
283
318
|
return await resolution.model.answer(input);
|
|
284
319
|
},
|
|
285
320
|
},
|
|
321
|
+
waitForInspectionAvailability: () => controlPlane.waitForRepoInspectionIdle(),
|
|
286
322
|
onScratchpadSourceChanged: (message) => controlPlane.notifyScratchpadSourceChanged(message),
|
|
287
323
|
now,
|
|
288
324
|
});
|
|
325
|
+
const projectRuntimeLifecycle = new HostProjectRuntimeLifecycle({
|
|
326
|
+
controlPlane,
|
|
327
|
+
chatAssistant,
|
|
328
|
+
invocationCoordinator: codexInvocationCoordinator,
|
|
329
|
+
checkProcessCoordinator,
|
|
330
|
+
approvalManager,
|
|
331
|
+
});
|
|
289
332
|
let close = async () => { };
|
|
290
333
|
let relayConnectionManager;
|
|
291
334
|
const packageUpdateReadiness = () => packageUpdateReadinessFromExecutionStatus(controlPlane.getExecutionStatus());
|
|
@@ -372,6 +415,9 @@ export async function startForegroundHostServer(options) {
|
|
|
372
415
|
},
|
|
373
416
|
},
|
|
374
417
|
logger: { file: logFilePath },
|
|
418
|
+
lifecycle: {
|
|
419
|
+
close: () => projectRuntimeLifecycle.close(),
|
|
420
|
+
},
|
|
375
421
|
localControl,
|
|
376
422
|
now,
|
|
377
423
|
projectApi: {
|
|
@@ -456,30 +502,47 @@ export async function startForegroundHostServer(options) {
|
|
|
456
502
|
recoverInProgressCommands: true,
|
|
457
503
|
});
|
|
458
504
|
let resolveClosed;
|
|
459
|
-
|
|
505
|
+
let rejectClosed;
|
|
506
|
+
const closed = new Promise((resolve, reject) => {
|
|
460
507
|
resolveClosed = resolve;
|
|
508
|
+
rejectClosed = reject;
|
|
461
509
|
});
|
|
462
510
|
let closePromise;
|
|
463
511
|
close = () => {
|
|
464
512
|
closePromise ??= (async () => {
|
|
513
|
+
let closeError;
|
|
514
|
+
let appClosed = false;
|
|
465
515
|
try {
|
|
466
|
-
await relayConnectionManager?.stop();
|
|
467
|
-
await app.close();
|
|
468
|
-
}
|
|
469
|
-
finally {
|
|
470
516
|
try {
|
|
471
|
-
|
|
472
|
-
|
|
517
|
+
await relayConnectionManager?.stop();
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
closeError = error;
|
|
473
521
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
resolveClosed();
|
|
522
|
+
try {
|
|
523
|
+
await app.close();
|
|
524
|
+
appClosed = true;
|
|
525
|
+
}
|
|
526
|
+
catch (error) {
|
|
527
|
+
closeError ??= error;
|
|
481
528
|
}
|
|
529
|
+
if (appClosed) {
|
|
530
|
+
store.close();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
finally {
|
|
534
|
+
deleteMachineRuntimeEndpoint({
|
|
535
|
+
tuttiHome: options.preparation.tutti_home,
|
|
536
|
+
projectId: options.preparation.project_id,
|
|
537
|
+
expectedToken: token,
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
if (closeError !== undefined) {
|
|
541
|
+
const normalizedCloseError = closeError instanceof Error ? closeError : new Error("Host server close failed.");
|
|
542
|
+
rejectClosed(normalizedCloseError);
|
|
543
|
+
throw normalizedCloseError;
|
|
482
544
|
}
|
|
545
|
+
resolveClosed();
|
|
483
546
|
})();
|
|
484
547
|
return closePromise;
|
|
485
548
|
};
|
|
@@ -24,10 +24,11 @@ export function createHostServer(options = {}) {
|
|
|
24
24
|
if (options.projectApi !== undefined && options.projectApi !== false) {
|
|
25
25
|
const projectApiOptions = options.projectApi;
|
|
26
26
|
registerHostProjectApiRoutes(app, projectApiOptions);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
if (options.lifecycle === undefined) {
|
|
28
|
+
app.addHook("onClose", async () => {
|
|
29
|
+
await projectApiOptions.controlPlane?.dispose();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
31
32
|
if (options.agentContext !== false) {
|
|
32
33
|
registerAgentContextRoutes(app, {
|
|
33
34
|
project: projectApiOptions.project,
|
|
@@ -46,6 +47,11 @@ export function createHostServer(options = {}) {
|
|
|
46
47
|
});
|
|
47
48
|
}
|
|
48
49
|
}
|
|
50
|
+
if (options.lifecycle !== undefined) {
|
|
51
|
+
app.addHook("onClose", async () => {
|
|
52
|
+
await options.lifecycle?.close();
|
|
53
|
+
});
|
|
54
|
+
}
|
|
49
55
|
if (options.webStatic !== undefined && options.webStatic !== false) {
|
|
50
56
|
registerHostWebStaticRoutes(app, options.webStatic);
|
|
51
57
|
}
|
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-d-q9yZ09.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-C4cdSaSb.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};
|