@xfey/tutti 0.1.66 → 0.1.68
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/collaboration-state/index.d.ts +1 -1
- package/dist/collaboration-state/index.js +1 -1
- package/dist/collaboration-state/task-compile-context.d.ts +2 -1
- package/dist/collaboration-state/task-compile-context.js +8 -3
- package/dist/control-plane/index.d.ts +7 -0
- package/dist/control-plane/index.js +77 -3
- package/dist/control-plane/recent-references.d.ts +26 -0
- package/dist/control-plane/recent-references.js +94 -0
- package/dist/control-plane/reference-context-types.d.ts +12 -0
- package/dist/control-plane/reference-context-types.js +2 -0
- package/dist/control-plane/reference-summary-refresh.d.ts +5 -1
- package/dist/control-plane/reference-summary-refresh.js +181 -113
- package/dist/control-plane/run-start.js +12 -0
- package/dist/control-plane/task-compile-continuation.d.ts +2 -0
- package/dist/control-plane/task-compile-continuation.js +11 -0
- package/dist/control-plane/task-compile-start.d.ts +2 -0
- package/dist/control-plane/task-compile-start.js +113 -16
- package/dist/control-plane/types.d.ts +2 -0
- package/dist/control-plane/workflows/openai.js +7 -0
- package/dist/control-plane/workflows/types.d.ts +3 -0
- package/dist/run-pipeline/task-run-invocation.js +3 -0
- package/dist/workspace-ops/index.d.ts +1 -1
- package/dist/workspace-ops/index.js +1 -1
- package/dist/workspace-ops/reference-files.js +98 -34
- package/dist/workspace-ops/reference-summaries.d.ts +5 -0
- package/dist/workspace-ops/reference-summaries.js +6 -5
- package/package.json +2 -2
- package/prompts/README.md +1 -1
- package/prompts/procedures/README.md +1 -1
- package/prompts/procedures/task-compile.md +2 -1
- package/prompts/prompt-flow-map.md +9 -2
- package/prompts/runs/README.md +1 -1
- package/prompts/runs/task-continuation.md +3 -0
- package/prompts/runs/task-retry.md +3 -0
- package/prompts/runs/task-run.md +3 -0
- package/web/assets/{homepage-motion-scene-Doj_Soje.js → homepage-motion-scene-D2GZ8Nix.js} +1 -1
- package/web/assets/{index-DuT1ti0p.js → index-NsxRK6_d.js} +2 -2
- package/web/index.html +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExecutionRuntimeSnapshot, MessageProjection, RunResultProjection, TaskDetailProjection, WorklistProjection } from "@tutti/shared/schemas/api";
|
|
2
|
+
import type { RecentReferenceContext } from "../reference-context-types.js";
|
|
2
3
|
import type { ClarificationRequestPayload, TaskContractProjection } from "@tutti/shared/schemas/api";
|
|
3
4
|
import type { ProjectDocKey } from "@tutti/shared/schemas/api";
|
|
4
5
|
import type { ActivityRef, ClarificationRoundRef, ClarificationThreadRef, MessageId, TaskId, TaskModuleId, WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
@@ -80,6 +81,7 @@ export type TaskCompileWorkflowInput = {
|
|
|
80
81
|
workflow_ref: WorkflowInvocationRef;
|
|
81
82
|
scratchpad: ScratchpadWorkflowSnapshot;
|
|
82
83
|
worklist: WorklistProjection;
|
|
84
|
+
recent_references?: RecentReferenceContext[];
|
|
83
85
|
clarification_rounds?: Array<{
|
|
84
86
|
request_payload: ClarificationRequestPayload;
|
|
85
87
|
answer_messages: TaskCompilePromptClarificationMessage[];
|
|
@@ -113,6 +115,7 @@ export type TaskCompilePromptInput = {
|
|
|
113
115
|
}>;
|
|
114
116
|
}>;
|
|
115
117
|
};
|
|
118
|
+
recent_references?: RecentReferenceContext[];
|
|
116
119
|
clarification_rounds?: Array<{
|
|
117
120
|
request: {
|
|
118
121
|
title?: string;
|
|
@@ -6,6 +6,9 @@ function taskContractRunInput(input) {
|
|
|
6
6
|
title: input.task.title,
|
|
7
7
|
goal: input.task_detail.detail.contract.goal,
|
|
8
8
|
scope: input.task_detail.detail.contract.scope,
|
|
9
|
+
...(input.recent_references === undefined || input.recent_references.length === 0
|
|
10
|
+
? {}
|
|
11
|
+
: { recent_references: input.recent_references }),
|
|
9
12
|
};
|
|
10
13
|
}
|
|
11
14
|
function initialTaskRunInput(input) {
|
|
@@ -5,7 +5,7 @@ export { collectProjectSourceDiff, createAcceptedCheckpoint, inspectProjectWorks
|
|
|
5
5
|
export { initializeProjectDocs, readProjectDocsInitializationStatus, syncProjectDocs, } from "./project-docs.js";
|
|
6
6
|
export { uploadReferenceFile } from "./reference-files.js";
|
|
7
7
|
export { referenceFileCategoryForPath, referenceFileSourceForPath, referenceMediaTypeForPath, referenceTuttiGroupForPath, } from "./reference-metadata.js";
|
|
8
|
-
export { readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
|
|
8
|
+
export { readReferenceSummaryEntries, readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
|
|
9
9
|
export { readViewerAsset, readViewerFile, readViewerSnapshot, readViewerTree } from "./viewer.js";
|
|
10
10
|
export type { WorkspaceOpsErrorCode } from "./errors.js";
|
|
11
11
|
export type { AcceptedCheckpointRecoveryResult, AcceptedCheckpointResult, CreateAcceptedCheckpointOptions, InitializeProjectDocsOptions, InitializeProjectDocsResult, ProjectDocsInitializationContext, ProjectDocsInitializationDocument, ProjectDocsInitializationStatus, ProjectWorkspaceInspection, ReadViewerAssetOptions, ReadViewerFileOptions, ReadViewerTreeOptions, ReferenceFileCategory, ReferenceSummaryProjection, ReferenceSummaryRecord, ReferenceSummaryStatus, ReferenceSummaryTarget, RunDiffSummary, SyncProjectDocsResult, SyncProjectDocsUpdate, UpdateReferenceSummariesOptions, UpdateReferenceSummariesResult, UploadReferenceFileOptions, UploadReferenceFileResult, ViewerAssetResult, ViewerAssetVariant, ViewerEntryKind, ViewerFileContent, ViewerFileResult, ViewerRepoSnapshot, ViewerTreeEntry, ViewerTreeResult, WorkspaceViewerOptions, } from "./types.js";
|
|
@@ -5,6 +5,6 @@ export { collectProjectSourceDiff, createAcceptedCheckpoint, inspectProjectWorks
|
|
|
5
5
|
export { initializeProjectDocs, readProjectDocsInitializationStatus, syncProjectDocs, } from "./project-docs.js";
|
|
6
6
|
export { uploadReferenceFile } from "./reference-files.js";
|
|
7
7
|
export { referenceFileCategoryForPath, referenceFileSourceForPath, referenceMediaTypeForPath, referenceTuttiGroupForPath, } from "./reference-metadata.js";
|
|
8
|
-
export { readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
|
|
8
|
+
export { readReferenceSummaryEntries, readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
|
|
9
9
|
export { readViewerAsset, readViewerFile, readViewerSnapshot, readViewerTree } from "./viewer.js";
|
|
10
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -6,40 +6,102 @@ import { WorkspaceOpsError } from "./errors.js";
|
|
|
6
6
|
import { classifyReferenceUpload } from "./reference-metadata.js";
|
|
7
7
|
import { commitOwnedPaths, requireOwnedPathsWriteReady } from "./system-commits.js";
|
|
8
8
|
import { readViewerFile } from "./viewer.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
if (raw.length === 0) {
|
|
9
|
+
const MAX_REFERENCE_FILE_NAME_BYTES = 240;
|
|
10
|
+
const WINDOWS_RESERVED_FILE_STEMS = /^(?:con|prn|aux|nul|clock\$|com[1-9]|lpt[1-9])$/iu;
|
|
11
|
+
const WINDOWS_INVALID_FILE_NAME_CHARACTERS = /[<>:"|?*]/u;
|
|
12
|
+
function normalizeReferenceFileName(fileName) {
|
|
13
|
+
if (fileName.length === 0 || fileName.trim().length === 0) {
|
|
15
14
|
throw new WorkspaceOpsError("validation_failed", "Reference file name cannot be empty");
|
|
16
15
|
}
|
|
17
|
-
if (
|
|
16
|
+
if (fileName !== fileName.trim()) {
|
|
17
|
+
throw new WorkspaceOpsError("validation_failed", "Reference file name must not have leading or trailing whitespace");
|
|
18
|
+
}
|
|
19
|
+
const normalized = fileName.normalize("NFC");
|
|
20
|
+
if (normalized.includes("/") || normalized.includes("\\")) {
|
|
18
21
|
throw new WorkspaceOpsError("validation_failed", "Reference file name must not include directories");
|
|
19
22
|
}
|
|
20
|
-
|
|
23
|
+
if (WINDOWS_INVALID_FILE_NAME_CHARACTERS.test(normalized)) {
|
|
24
|
+
throw new WorkspaceOpsError("validation_failed", "Reference file name contains a platform-reserved character");
|
|
25
|
+
}
|
|
26
|
+
if (normalized.endsWith(".") || /^\.+$/u.test(normalized)) {
|
|
27
|
+
throw new WorkspaceOpsError("validation_failed", "Reference file name must not end with a dot or consist only of dots");
|
|
28
|
+
}
|
|
29
|
+
const reservedStem = normalized.split(".", 1)[0] ?? normalized;
|
|
30
|
+
if (WINDOWS_RESERVED_FILE_STEMS.test(reservedStem)) {
|
|
31
|
+
throw new WorkspaceOpsError("validation_failed", "Reference file name is reserved by the platform");
|
|
32
|
+
}
|
|
33
|
+
if (Buffer.byteLength(normalized, "utf8") > MAX_REFERENCE_FILE_NAME_BYTES) {
|
|
34
|
+
throw new WorkspaceOpsError("validation_failed", `Reference file name cannot exceed ${MAX_REFERENCE_FILE_NAME_BYTES} UTF-8 bytes`);
|
|
35
|
+
}
|
|
36
|
+
const rawClassification = classifyViewerPath(normalized);
|
|
21
37
|
if (rawClassification.kind === "rejected") {
|
|
22
38
|
throw new WorkspaceOpsError("validation_failed", `Reference file name is rejected: ${rawClassification.reason_code}`, { reason_code: rawClassification.reason_code });
|
|
23
39
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
function truncateUtf8(value, maxBytes) {
|
|
43
|
+
let result = "";
|
|
44
|
+
let bytes = 0;
|
|
45
|
+
for (const character of value) {
|
|
46
|
+
const characterBytes = Buffer.byteLength(character, "utf8");
|
|
47
|
+
if (bytes + characterBytes > maxBytes) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
result += character;
|
|
51
|
+
bytes += characterBytes;
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function conflictFileName(fileName, suffix) {
|
|
56
|
+
const extension = extname(fileName);
|
|
57
|
+
const stem = extension.length === 0 ? fileName : fileName.slice(0, -extension.length);
|
|
58
|
+
const marker = `-${suffix}`;
|
|
59
|
+
const maxStemBytes = MAX_REFERENCE_FILE_NAME_BYTES -
|
|
60
|
+
Buffer.byteLength(marker, "utf8") -
|
|
61
|
+
Buffer.byteLength(extension, "utf8");
|
|
62
|
+
if (maxStemBytes <= 0) {
|
|
63
|
+
throw new WorkspaceOpsError("validation_failed", "Reference file name is too long to resolve a path conflict");
|
|
64
|
+
}
|
|
65
|
+
const boundedStem = truncateUtf8(stem, maxStemBytes).replace(/[.\s]+$/u, "");
|
|
66
|
+
if (boundedStem.length === 0) {
|
|
67
|
+
throw new WorkspaceOpsError("validation_failed", "Reference file name cannot be disambiguated safely");
|
|
68
|
+
}
|
|
69
|
+
return `${boundedStem}${marker}${extension}`;
|
|
70
|
+
}
|
|
71
|
+
function commandSuffixes(commandId) {
|
|
72
|
+
const normalized = commandId.toLowerCase().replace(/[^a-z0-9]/gu, "");
|
|
73
|
+
const lengths = [8, 12, 16, 24];
|
|
74
|
+
return [...new Set(lengths.map((length) => normalized.slice(-length)).filter(Boolean))];
|
|
75
|
+
}
|
|
76
|
+
function sameFileContent(path, content) {
|
|
77
|
+
return existsSync(path) && readFileSync(path).equals(content);
|
|
78
|
+
}
|
|
79
|
+
function resolveReferenceFileName(options) {
|
|
80
|
+
const originalPath = join(options.workspaceRoot, ...options.directoryPath.split("/"), options.fileName);
|
|
81
|
+
if (!existsSync(originalPath) || sameFileContent(originalPath, options.content)) {
|
|
82
|
+
return options.fileName;
|
|
83
|
+
}
|
|
84
|
+
for (const suffix of commandSuffixes(options.commandId)) {
|
|
85
|
+
const candidate = conflictFileName(options.fileName, suffix);
|
|
86
|
+
const candidatePath = join(options.workspaceRoot, ...options.directoryPath.split("/"), candidate);
|
|
87
|
+
if (!existsSync(candidatePath) || sameFileContent(candidatePath, options.content)) {
|
|
88
|
+
return candidate;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
throw new WorkspaceOpsError("conflict", "Reference file name conflicts with an existing upload");
|
|
92
|
+
}
|
|
93
|
+
function requireSafeReferencePath(directoryPath, fileName) {
|
|
94
|
+
const path = `${directoryPath}/${fileName}`;
|
|
38
95
|
const classification = classifyViewerPath(path);
|
|
39
96
|
if (classification.kind === "rejected") {
|
|
40
97
|
throw new WorkspaceOpsError("validation_failed", `Reference file path is rejected: ${classification.reason_code}`, { reason_code: classification.reason_code });
|
|
41
98
|
}
|
|
42
|
-
|
|
99
|
+
}
|
|
100
|
+
function markdownLinkLabel(value) {
|
|
101
|
+
return value.replaceAll("[", "\\[").replaceAll("]", "\\]");
|
|
102
|
+
}
|
|
103
|
+
function markdownLinkPath(value) {
|
|
104
|
+
return value.split("/").map(encodeURIComponent).join("/");
|
|
43
105
|
}
|
|
44
106
|
function appendReferenceIndexEntry(options) {
|
|
45
107
|
const indexPath = join(options.workspaceRoot, "docs", "reference", "README.md");
|
|
@@ -63,10 +125,10 @@ function appendReferenceIndexEntry(options) {
|
|
|
63
125
|
content = `${content.trimEnd()}\n\n## Images\n\n`;
|
|
64
126
|
}
|
|
65
127
|
const relativePath = posix.relative(REFERENCE_DIRECTORY_PATH, options.repoPath);
|
|
66
|
-
const link = `./${relativePath}`;
|
|
128
|
+
const link = `./${markdownLinkPath(relativePath)}`;
|
|
67
129
|
const note = options.note?.trim();
|
|
68
130
|
const description = note === undefined || note.length === 0 ? "" : ` - ${note}`;
|
|
69
|
-
const line = `- [${options.fileName}](${link})${description}\n`;
|
|
131
|
+
const line = `- [${markdownLinkLabel(options.fileName)}](${link})${description}\n`;
|
|
70
132
|
if (content.includes(`](${link})`)) {
|
|
71
133
|
writeFileSync(indexPath, content, "utf8");
|
|
72
134
|
return;
|
|
@@ -89,24 +151,26 @@ export function uploadReferenceFile(options) {
|
|
|
89
151
|
if (options.content.byteLength > MAX_REFERENCE_UPLOAD_BYTES) {
|
|
90
152
|
throw new WorkspaceOpsError("validation_failed", `Reference file content cannot exceed ${MAX_REFERENCE_UPLOAD_BYTES} bytes`);
|
|
91
153
|
}
|
|
92
|
-
const
|
|
154
|
+
const normalizedName = normalizeReferenceFileName(options.fileName);
|
|
93
155
|
const classification = classifyReferenceUpload({
|
|
94
|
-
fileName:
|
|
156
|
+
fileName: normalizedName,
|
|
95
157
|
content: options.content,
|
|
96
158
|
...(options.mediaType === undefined ? {} : { mediaType: options.mediaType }),
|
|
97
159
|
});
|
|
160
|
+
const safeName = resolveReferenceFileName({
|
|
161
|
+
workspaceRoot: options.workspaceRoot,
|
|
162
|
+
directoryPath: classification.directoryPath,
|
|
163
|
+
fileName: normalizedName,
|
|
164
|
+
commandId: options.commandId,
|
|
165
|
+
content: options.content,
|
|
166
|
+
});
|
|
167
|
+
requireSafeReferencePath(classification.directoryPath, safeName);
|
|
98
168
|
const referenceDirectory = join(options.workspaceRoot, ...classification.directoryPath.split("/"));
|
|
99
169
|
const repoPath = `${classification.directoryPath}/${safeName}`;
|
|
100
170
|
const filesystemPath = join(referenceDirectory, safeName);
|
|
101
171
|
requireOwnedPathsWriteReady(options.workspaceRoot, [REFERENCE_INDEX_PATH, repoPath]);
|
|
102
172
|
mkdirSync(referenceDirectory, { recursive: true });
|
|
103
|
-
if (existsSync(filesystemPath)) {
|
|
104
|
-
const existing = readFileSync(filesystemPath);
|
|
105
|
-
if (!existing.equals(options.content)) {
|
|
106
|
-
throw new WorkspaceOpsError("conflict", "Reference file path already exists with different content");
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
173
|
+
if (!existsSync(filesystemPath)) {
|
|
110
174
|
writeFileSync(filesystemPath, options.content);
|
|
111
175
|
}
|
|
112
176
|
appendReferenceIndexEntry({
|
|
@@ -7,6 +7,11 @@ export declare function referenceSummaryProjectionForEntry(options: {
|
|
|
7
7
|
entry: ViewerTreeEntry;
|
|
8
8
|
summaries: ReferenceSummaryIndex;
|
|
9
9
|
}): ReferenceSummaryProjection;
|
|
10
|
+
export declare function readReferenceSummaryEntries(options: {
|
|
11
|
+
workspaceRoot: string;
|
|
12
|
+
paths?: string[];
|
|
13
|
+
now?: () => Date;
|
|
14
|
+
}): ReferenceSummaryTarget[];
|
|
10
15
|
export declare function readReferenceSummaryTargets(options: {
|
|
11
16
|
workspaceRoot: string;
|
|
12
17
|
paths?: string[];
|
|
@@ -138,8 +138,7 @@ export function referenceSummaryProjectionForEntry(options) {
|
|
|
138
138
|
...(record.source_blob_oid === undefined ? {} : { source_blob_oid: record.source_blob_oid }),
|
|
139
139
|
...(record.read_paths === undefined ? {} : { read_paths: record.read_paths }),
|
|
140
140
|
};
|
|
141
|
-
if (
|
|
142
|
-
options.entry.blob_oid !== undefined &&
|
|
141
|
+
if (options.entry.blob_oid !== undefined &&
|
|
143
142
|
record.source_blob_oid !== options.entry.blob_oid) {
|
|
144
143
|
return {
|
|
145
144
|
status: "stale",
|
|
@@ -179,7 +178,7 @@ function readReferenceFileEntries(options) {
|
|
|
179
178
|
.filter((entry) => entry.blob_oid !== undefined && entry.size_bytes !== undefined)
|
|
180
179
|
.sort((left, right) => left.path.localeCompare(right.path, "en", { sensitivity: "base" }));
|
|
181
180
|
}
|
|
182
|
-
export function
|
|
181
|
+
export function readReferenceSummaryEntries(options) {
|
|
183
182
|
const summaries = readReferenceSummaryIndex({ workspaceRoot: options.workspaceRoot });
|
|
184
183
|
const requested = options.paths === undefined ? undefined : new Set(options.paths);
|
|
185
184
|
return readReferenceFileEntries(options)
|
|
@@ -198,8 +197,10 @@ export function readReferenceSummaryTargets(options) {
|
|
|
198
197
|
: { media_type: referenceMediaTypeForPath(entry.path) }),
|
|
199
198
|
summary,
|
|
200
199
|
};
|
|
201
|
-
})
|
|
202
|
-
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
export function readReferenceSummaryTargets(options) {
|
|
203
|
+
return readReferenceSummaryEntries(options).filter((target) => target.summary.status !== "available");
|
|
203
204
|
}
|
|
204
205
|
function removeSummarySection(content) {
|
|
205
206
|
const headingPattern = /(^|\n)## Summaries\n/u;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xfey/tutti",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.68",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@fastify/cors": "^11.2.0",
|
|
30
30
|
"@fastify/static": "^9.1.3",
|
|
31
31
|
"@fastify/websocket": "^11.2.0",
|
|
32
|
-
"@openai/codex": "^0.
|
|
32
|
+
"@openai/codex": "^0.147.0",
|
|
33
33
|
"@sinclair/typebox": "^0.34.49",
|
|
34
34
|
"@tutti/relay-client": "0.0.0",
|
|
35
35
|
"@tutti/shared": "0.0.0",
|
package/prompts/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Prompt / skill 改造后的 live 实验计划与记录见 [prompt-flow-experimen
|
|
|
15
15
|
|
|
16
16
|
- `procedures/`:`scratchpad_refresh`、`project_brief_refresh`、`task_compile`、`project_context_bootstrap`、`context_sync`、`reference_summary_refresh`、`follow_up_check` 等 Procedure / workflow prompt。
|
|
17
17
|
- `artifacts/`:候选实现完成后的 transient Artifact applicability 判断;只接收 bounded task / diff / repo evidence,不写回 Task contract 或 repo。
|
|
18
|
-
- `runs/`:正式 task `Run`、task-bound continuation 与 pipeline self-correction retry 等 Run pipeline prompt;provider transient retry 不新增 prompt,而是复用失败 attempt 的同一 prompt family。所有 Run prompt都以持久 project workspace为 cwd contract,不设计 promotion reconcile prompt。
|
|
18
|
+
- `runs/`:正式 task `Run`、task-bound continuation 与 pipeline self-correction retry 等 Run pipeline prompt;task contract 可附带 receipt-derived compact `recent_references`,两类 retry 都保留它。provider transient retry 不新增 prompt,而是复用失败 attempt 的同一 prompt family。所有 Run prompt都以持久 project workspace为 cwd contract,不设计 promotion reconcile prompt。
|
|
19
19
|
- `codex/`:Codex app-server smoke 等 adapter / spike prompt。
|
|
20
20
|
- `skills/`:Tutti packaged built-in Codex skills;由 server-side app-server skill selection 选择,不在 Web Skills 页面展示,也不保存 user skills。
|
|
21
21
|
- `chat-assistant.md`:主群聊与 clarification round 内 `@tutti` 只读项目问答 prompt;它不是 Procedure / Run prompt。
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
`project_context_bootstrap` 的 provider path 只让 Codex app-server read-only adapter 生成缺失文档内容;如果该计划不可用,Control Plane 会回退到本地保守模板。
|
|
16
16
|
`project_context_bootstrap` 的 read-only 输入只包含项目名、非空时的 `missing_docs` 与刷新后的 Scratchpad;prompt 会要求 app-server 只读探索仓库,并可通过 `read-project-docs` / `read-references` skill 按需读取现有文档和参考文件。输出只包含 `documents[].doc_key/content`,固定 path 由 Control Plane 后处理生成。
|
|
17
|
-
`task_compile` 的 read-only 输入只包含 durable context 固定的五字段 Scratchpad、当前 Worklist 和可选完整有序 `clarification_rounds`;
|
|
17
|
+
`task_compile` 的 read-only 输入只包含 durable context 固定的五字段 Scratchpad、当前 Worklist、可选 compact `recent_references` 和可选完整有序 `clarification_rounds`;reference 项只含 path、最终 name 与 available/unavailable summary,不含 blob/message/workflow audit fields。每次 continuation 仍读取同一 pinned Scratchpad 与 source set,不读取并行变化的 Current Scratchpad或 boundary 后的新上传;later round 可以纠正 earlier round,明确撤回时允许空 proposal 正常结束。prompt 暴露 `read-project-docs` / `read-worklist` / `read-references` skills 供 app-server 必要时读取项目上下文文件、既有任务 contract / latest result 或相关 reference 正文;Scratchpad 和 Worklist 紧凑视图仍以直接输入为准,不通过 skill 重读 Scratchpad。provider raw output 使用 `{ result: ... }` 互斥分支;proposal 分支用 `module_ref` 指向新模块或既有模块,task 只输出 `title / goal / scope`,runner adapter 再映射为 Control Plane 内部 proposal:`goal` 同时作为内部 task summary 和 contract goal,`scope` 作为内部 contract scope。
|
|
18
18
|
`context_sync` 没有 provider-facing direct input;workflow ref、activity ref、触发原因、安全元数据、checked paths、skipped paths 和 open questions 都不进入 prompt,只用于运行时追踪、调度或审计。prompt 说明通用文档同步目标、目标项目文档落点和 canonical docs 职责,由 app-server 主动探索 repo,并通过 `read-project-docs` / `read-worklist` / `read-references` skill 按需读取现有文档、正式任务上下文和参考文件。Worklist / task result 只作为阶段性完成背景和稳定结果线索,不写成长文档里的逐任务流水。
|
|
19
19
|
`context_sync` prompt 只返回 `summary` 与 `updates[].path/content`;空 `updates` 表示无需同步,非空 `updates` 由 Control Plane 调用 `workspace-ops` 做 path policy、mainline clean 检查、文件写入和 Git commit。
|
|
20
20
|
`project_brief_refresh` 只走 OpenAI SDK structured output,不使用 Codex app-server,不读取 repo 或 skills。它接收四个 baseline Project Docs 的 bounded source 内容与状态,输出 `product_summary / tech_summary / structure_summary / principles_summary`,由 Control Plane 写入 host-local `project_brief` projection;Project Docs 创建、同步、被成功 Run promotion 修改,或 provider setup 后需要 backfill 时可以触发。provider 不可用、source 不可用、brief 已经 fresh 或刷新失败都不影响 Project Docs 写入结果。
|
|
@@ -20,13 +20,14 @@ You compile Tutti's Scratchpad into an append-only Worklist proposal for post-ba
|
|
|
20
20
|
|
|
21
21
|
- `scratchpad` is the immutable five-field snapshot pinned when this task_compile workflow was submitted. It has already removed message ids, timestamps, activity refs, and refresh state.
|
|
22
22
|
- `worklist.modules[]` is the current formal Worklist. Module `id` values are the only valid existing module keys. Module names and task titles are historical anchors for resolving short references in the current Scratchpad.
|
|
23
|
+
- `recent_references`, when present, identifies human-uploaded files from the same pinned Scratchpad cycle and provides a terminal summary status for each source.
|
|
23
24
|
- `clarification_rounds`, when present, contains every sealed workflow-bound clarification round for this same pinned Scratchpad, ordered from earliest to latest. Each round keeps its request separate from its ordered submitted answer messages.
|
|
24
25
|
- Later clarification rounds may add to or correct earlier rounds. Interpret them chronologically without discarding the earlier context.
|
|
25
26
|
- Concurrent main-chat discussion and the mutable Current Scratchpad are intentionally absent. Never assume that a short clarification answer applies to a newer chat direction, and never use skills to find concurrent chat to complete this workflow.
|
|
26
27
|
- Treat the provided Scratchpad and Worklist as authoritative. Do not use skills to reread them.
|
|
27
28
|
- Use `read-worklist` only when an existing task's contract or latest result would clarify the current task's subject, boundary, or delivery relationship. Do not duplicate tasks already covered by the Worklist.
|
|
28
29
|
- Use `read-project-docs` or `read-references` only when task scope, acceptance, product intent, technical stack, repo structure, agent working rules, or reference contents matter and are not clear from direct input.
|
|
29
|
-
-
|
|
30
|
+
- Use recent references when they materially inform the proposed work, and read the source when its summary is insufficient to freeze the task contract.
|
|
30
31
|
- Preserve user-provided non-secret details when they are needed to execute or accept the task. Do not generalize them into vague labels.
|
|
31
32
|
- Do not use web search, credentials, provider internals, raw logs, or Tutti runtime/internal paths.
|
|
32
33
|
|
|
@@ -53,6 +53,7 @@ Provider validation 也使用 OpenAI Responses API,但它只是启动前 crede
|
|
|
53
53
|
- 2026-07-29:新增 `artifacts/applicability.md` transient judge;Run / reconcile candidate 在 checks 前执行 Artifact gate。`task-retry` correction block 增加必填 redacted / bounded diagnostic,`promotion_failure` 改为完整对象或显式 `null`。
|
|
54
54
|
- 2026-08-01:Run pipeline 完成持久 project workspace cutover;本条取代上述历史记录中的 attempt workspace cleanup、fresh run workspace、result commit / fast-forward promotion 与 reconcile candidate 语义。initial、continuation、provider transient retry 和 self-correction 现在复用同一项目目录;candidate Artifact、checks 与正式 preview 共享目录身份,通过 gate 后创建 accepted commit + immutable activity tag。
|
|
55
55
|
- 2026-08-10:Scratchpad / task compile 上下文边界完成重构。Scratchpad 只从当前主群聊周期完整重建,输入收敛为 `project_brief? / worklist / active_task_compile? / messages`;Submit 固定 durable Task Compile Context,bootstrap / compile / continuation 复用 pinned snapshot,continuation 使用完整 `clarification_rounds`,receipt / sources 从 context 生成,clarification 不再回写 Scratchpad。
|
|
56
|
+
- 2026-08-12:Submit 在 Task Compile 前等待 pinned-cycle references 对当前 blob 形成 summary terminal;Task Compile 与对应 Run 接收 compact `recent_references`,initial / continuation / provider retry / self-correction 保留同一 source set。
|
|
56
57
|
|
|
57
58
|
后续逐项讨论时,默认从尚未在本节标为已完成的环节继续推进,避免重复分析已经收口的 prompt。
|
|
58
59
|
|
|
@@ -275,6 +276,7 @@ Submit gate 在缺失 baseline context files 且当前主群聊周期存在尚
|
|
|
275
276
|
|
|
276
277
|
- `workflow_input_json.scratchpad`:当前 workflow-owned Task Compile Context 固定的五个业务字段:`topic / background_summary / current_consensus / open_questions / task_changes`。初次 compile 和所有 continuation 都读取同一 snapshot。
|
|
277
278
|
- `workflow_input_json.worklist.modules[]`:当前正式 Worklist 的紧凑模块视图,仅包含模块 `id / name / optional summary / archived` 与任务 `title / summary / status`;模块名和任务标题作为短指代解析的历史锚点。
|
|
279
|
+
- `workflow_input_json.recent_references`:可选当前 pinned Scratchpad cycle human uploads,按 source message 顺序稳定生成;每项只含 repo-relative `path`、最终 `name` 与对应 source blob 的 `available.text` 或 `unavailable.reason`,不含 blob oid、message id 或 workflow audit fields。
|
|
278
280
|
- `workflow_input_json.clarification_rounds`:可选 workflow-bound continuation 上下文,按 round index 包含截至当前 sealed round 的全部 `request` 和 submitted answer messages;answer message 只包含 `role / optional author_display_name / text`。opening/card refs 被排除,later round 可修正 earlier round,但不得丢失较早轮次。
|
|
279
281
|
- 可通过 `read-project-docs` / `read-worklist` / `read-references` skills 按需读取当前项目上下文文件正文、既有任务 contract / latest result 或相关 reference 正文,用于理解产品目标、技术栈、结构、agent 工作规则、阶段性任务背景或用户提供的参考资料。
|
|
280
282
|
- 不通过 skill 重读 Scratchpad;Worklist 紧凑视图以直接输入为准,task detail 只在需要理解既有任务细节时读取。
|
|
@@ -297,8 +299,8 @@ Provider raw 输出:根对象只包含 `result`;`result` 内二选一输出
|
|
|
297
299
|
- Project Docs 缺失通常不会进入本环节,因为 Submit gate 会先通过 `project_context_bootstrap` 与 `workspace-ops.initializeProjectDocs` 补齐缺失 baseline paths。gate 检查的是固定路径存在性,不保证内容质量。
|
|
298
300
|
- Project Docs unreadable / unavailable 应是少见状态,通常来自编码或二进制异常、path policy、repo snapshot / viewer、IO 或 scope 配置问题。模型应在 Scratchpad / Worklist 与其他允许证据足够时继续任务化;只有无法定义目标、范围、约束或验收时才请求 workflow-bound clarification。
|
|
299
301
|
- Project Docs 中的 `To be confirmed.` 等占位是开放上下文,不是阻塞项,也不能当作已确认事实。
|
|
300
|
-
-
|
|
301
|
-
-
|
|
302
|
+
- `recent_references` 的 summary 只提供定位和压缩,不证明全部正文事实;当相关 summary 不足以冻结 task contract 时,应通过 `read-references` 按 path 读取 source。
|
|
303
|
+
- 当前不增加独立 reference context expansion workflow、Task reference dependency schema 或 proposal reference paths。
|
|
302
304
|
|
|
303
305
|
### 文档同步计划 `context_sync`
|
|
304
306
|
|
|
@@ -347,6 +349,8 @@ Provider raw 输出:根对象只包含 `result`;`result` 内二选一输出
|
|
|
347
349
|
|
|
348
350
|
当前改造结论:
|
|
349
351
|
|
|
352
|
+
- 单个协调 Procedure 以并发度 `2` 运行隔离 target turns;单文件失败有界重试并形成 terminal unavailable,同批完成后一次写 index,再重新扫描 `missing / stale` 直到 drain。
|
|
353
|
+
- 活动期间的新上传通过 pending/rescan 并入同一 single-flight;Submit 可加入既有 summary activity,并在 pinned references terminal 后续接 Task Compile,不启动第二个 foreground writer。
|
|
350
354
|
- 原始 path、blob、media type、workflow refs 和 activity refs 不进入 prompt,避免上下文浪费和路径泄露。
|
|
351
355
|
- summary 模型只看到临时目录中的一个复制文件,不会顺手探索目标项目目录或做项目理解。
|
|
352
356
|
- prompt 只说明任务、只读/no-network 边界、secret-like content 处理和输出 schema 示例。
|
|
@@ -363,6 +367,7 @@ Provider raw 输出:根对象只包含 `result`;`result` 内二选一输出
|
|
|
363
367
|
- `run_input_json.title`:短任务标题,用于快速定位任务意图。
|
|
364
368
|
- `run_input_json.goal`:正式任务目标。
|
|
365
369
|
- `run_input_json.scope`:正式任务边界,同时承接关键约束、非目标、假设和可观察验收信号。
|
|
370
|
+
- `run_input_json.recent_references?`:由 task 的 Task Compile receipt sources 恢复的本轮 human uploads;每项只含 path、最终 name 与 available/unavailable summary,必要时 Run 仍按 path 核对原文件。
|
|
366
371
|
- 不传入 `context_entry_json`、task id、task summary、workflow / activity refs、Run lineage、dispatch context 或 project workspace 绝对路径。
|
|
367
372
|
- 通过 `workspace_write_run` selection 可读取 Project Docs 与 Worklist,并可加载所有 enabled user skills;存在 user skills 时,app-server `skills/list` 会先收到当前项目 `<TUTTI_HOME>/projects/<project_id>/skills` extra user root。
|
|
368
373
|
- Reference Files 不通过 built-in skill 暴露;若任务契约或 Project Docs 指向 `docs/reference/` 中资料,Codex 可直接读取相关 repo 文件正文。
|
|
@@ -392,6 +397,7 @@ provider transient retry:如果本环节的 Codex app-server workspace-write t
|
|
|
392
397
|
当前输入:
|
|
393
398
|
|
|
394
399
|
- `run_input_json.title` / `goal` / `scope`:同初次 Task Run,是 frozen task contract 的完整 provider-facing 表达。
|
|
400
|
+
- `run_input_json.recent_references?`:与 initial Run 相同的 receipt-derived source set;task-bound continuation 不读取后续上传。
|
|
395
401
|
- `run_input_json.continuation.previous_run`:上一 Run 的 needs-human summary 与原 clarification request payload,说明为什么暂停。
|
|
396
402
|
- `run_input_json.continuation.clarification.resolved_rounds[]`:截至当前 round 的已提交 task-bound clarification rounds;每轮包含 request payload 和人类回答消息原文。
|
|
397
403
|
- `run_input_json.continuation.follow_up_check`:`resume` 判断的简短 summary,用于说明为什么本次可继续,但不能替代人类回答原文。
|
|
@@ -425,6 +431,7 @@ provider transient retry:continuation 的 retryable app-server failure 只在
|
|
|
425
431
|
当前输入:
|
|
426
432
|
|
|
427
433
|
- `run_input_json.title` / `goal` / `scope`:同一 frozen task contract。
|
|
434
|
+
- `run_input_json.recent_references?`:与原 attempt 相同的 receipt-derived source set;pipeline self-correction 与其 provider transient retry 均保留。
|
|
428
435
|
- `run_input_json.correction.summary`:上一 attempt 的 bounded failure summary。
|
|
429
436
|
- `run_input_json.correction.reason_code`:Run pipeline 生成的 feedback 短码,来源包括 Artifact gate、checks 前后无 candidate diff、checks 失败或 accepted-checkpoint failure。
|
|
430
437
|
- `run_input_json.correction.guidance`:Run pipeline 根据 feedback reason 生成的本次 retry 直接修正目标。
|
package/prompts/runs/README.md
CHANGED
|
@@ -8,7 +8,7 @@ These templates are used by task `Run` execution.
|
|
|
8
8
|
Templates in this directory may describe task contracts, repo evidence, check expectations, artifact declaration rules, and documentation update responsibilities. They must never include provider credentials or host-local secret material.
|
|
9
9
|
|
|
10
10
|
`task-run.md` allows `needs_human` only for human requirement decisions, non-secret context, or risk confirmation. Unusable candidates, ordinary missing diffs, or repo/tooling errors that prevent implementation should be returned as `failed` so the Run does not open task-bound clarification incorrectly. If the task contract does not require repository file changes, the output can use `completed_no_repo_changes`; otherwise a completed implementation is expected to produce a candidate diff. If the candidate is complete but Codex self-validation commands are unavailable or blocked, the task-run output should still be `completed`; Tutti checks are the authoritative validation gate.
|
|
11
|
-
Initial `task-run.md`, active `task-continuation.md`, and active pipeline `task-retry.md` receive
|
|
11
|
+
Initial `task-run.md`, active `task-continuation.md`, and active pipeline `task-retry.md` receive the compact task contract fields `title / goal / scope` plus optional receipt-derived `recent_references`; each reference includes only path, final name and available/unavailable summary. Continuation adds the required `continuation` block, and pipeline self-correction retry adds the required `correction` block with the previous failure summary, machine-generated reason code, correction guidance, a required redacted / bounded diagnostic, and `promotion_failure` as either a complete object or explicit `null`. Provider transient retry and self-correction both preserve the same reference context. Provider-facing prompts do not receive task ids, task summaries, Run lineage, workflow anchors, blob ids, message ids, changed paths, docs status, checks status, or the safety audit context entry.
|
|
12
12
|
All three Run templates use a slim mutually exclusive structured output schema under `result`: exactly one of `completed.{summary,user_note_candidate}`, `completed_no_repo_changes.{summary,user_note_candidate}`, `needs_human.{title,summary,request}`, or `failed.summary`. The `summary` is a concise, human-readable result note for project members who may not inspect the code. Completed branches also require `user_note_candidate`, which is either a short user-facing final-card sentence or `null`; it must not repeat `summary` or include file paths. Checks, docs, promotion, changed paths, and other Tutti status stay in structured fields derived by the Run pipeline. They do not ask Codex to self-report docs status or changed paths; both come from Run pipeline Git diff and derived projection.
|
|
13
13
|
Run templates describe `docs/reference/` as a user-visible file exchange area. Human uploads remain under `docs/reference/files/` and `docs/reference/images/`; `docs/reference/tutti/**` is for Tutti-generated files intended for direct member review in References, not temporary output, internal notes, logs, or canonical project documentation. Generated user-visible files must be written under `docs/reference/tutti/`, with `docs/reference/tutti/<meaningful-folder>/...` used when the folder name should be shown as a References UI group. Generated files under `docs/reference/tutti/` are discovered from promoted changed paths, rendered by References automatically, and may be listed in completed task result cards.
|
|
14
14
|
Initial `task-run.md`, active `task-continuation.md`, and active pipeline `task-retry.md` also instruct Codex to write or update the single active `tutti.artifact.json` manifest only when the task creates or updates a member-viewable visual artifact. Each template includes the complete strict static and server JSON shapes: every behavior field is required, `network` is always an explicit boolean, and server `script / ready_path / port` fields are forbidden. A server package instead declares the fixed `artifact:preview` npm script in its own `package.json` and listens on the injected `HOST / PORT`. The manifest remains repo truth and is not reported through the structured output schema.
|
|
@@ -23,6 +23,7 @@ Fields:
|
|
|
23
23
|
- `title`: short task title for orientation.
|
|
24
24
|
- `goal`: formal task outcome to implement.
|
|
25
25
|
- `scope`: formal task boundary. Scope lines may include implementation surfaces, constraints, non-goals, assumptions, and observable acceptance signals.
|
|
26
|
+
- `recent_references`, when present: human-uploaded files from the Task Compile source cycle, with a terminal summary status for each source.
|
|
26
27
|
- `continuation`: previous Run pause reason, submitted clarification answers, and the `follow_up_check.resume` summary.
|
|
27
28
|
|
|
28
29
|
# Continuation Context
|
|
@@ -60,6 +61,8 @@ Use attached skills only when they help the current task:
|
|
|
60
61
|
|
|
61
62
|
Human-uploaded reference material is kept in the repository under `docs/reference/`. If the task contract, project docs, or clarification answer makes a reference file relevant, read the actual repo file before relying on it. Do not infer reference contents from names, upload messages, media types, or paths.
|
|
62
63
|
|
|
64
|
+
When the task is grounded in reference material, verify the implementation against the relevant source rather than relying on its summary alone.
|
|
65
|
+
|
|
63
66
|
`docs/reference/` is a user-visible file exchange area:
|
|
64
67
|
|
|
65
68
|
- Human uploads live under `docs/reference/files/` and `docs/reference/images/`.
|
|
@@ -23,6 +23,7 @@ Fields:
|
|
|
23
23
|
- `title`: short task title for orientation.
|
|
24
24
|
- `goal`: formal task outcome to implement.
|
|
25
25
|
- `scope`: formal task boundary. Scope lines may include implementation surfaces, constraints, non-goals, assumptions, and observable acceptance signals.
|
|
26
|
+
- `recent_references`, when present: human-uploaded files from the Task Compile source cycle, with a terminal summary status for each source.
|
|
26
27
|
- `correction`: bounded pipeline feedback from the previous attempt and the immediate retry guidance.
|
|
27
28
|
|
|
28
29
|
# Correction Context
|
|
@@ -68,6 +69,8 @@ Use attached skills only when they help the current task:
|
|
|
68
69
|
|
|
69
70
|
Human-uploaded reference material is kept in the repository under `docs/reference/`. If the task contract, project docs, or correction context makes a reference file relevant, read the actual repo file before relying on it. Do not infer reference contents from names, upload messages, media types, or paths.
|
|
70
71
|
|
|
72
|
+
When the task is grounded in reference material, verify the implementation against the relevant source rather than relying on its summary alone.
|
|
73
|
+
|
|
71
74
|
`docs/reference/` is a user-visible file exchange area:
|
|
72
75
|
|
|
73
76
|
- Human uploads live under `docs/reference/files/` and `docs/reference/images/`.
|
package/prompts/runs/task-run.md
CHANGED
|
@@ -23,6 +23,7 @@ Fields:
|
|
|
23
23
|
- `title`: short task title for orientation.
|
|
24
24
|
- `goal`: formal task outcome to implement.
|
|
25
25
|
- `scope`: formal task boundary. Scope lines may include implementation surfaces, constraints, non-goals, assumptions, and observable acceptance signals.
|
|
26
|
+
- `recent_references`, when present: human-uploaded files from the Task Compile source cycle, with a terminal summary status for each source.
|
|
26
27
|
|
|
27
28
|
# Execution Boundary
|
|
28
29
|
|
|
@@ -47,6 +48,8 @@ Use attached skills only when they help the current task:
|
|
|
47
48
|
|
|
48
49
|
Human-uploaded reference material is kept in the repository under `docs/reference/`. If the task contract or project docs make a reference file relevant, read the actual repo file before relying on it. Do not infer reference contents from names, upload messages, media types, or paths.
|
|
49
50
|
|
|
51
|
+
When the task is grounded in reference material, verify the implementation against the relevant source rather than relying on its summary alone.
|
|
52
|
+
|
|
50
53
|
`docs/reference/` is a user-visible file exchange area:
|
|
51
54
|
|
|
52
55
|
- Human uploads live under `docs/reference/files/` and `docs/reference/images/`.
|
|
@@ -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-DuT1ti0p.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:`Execution progress`})]})}),(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-NsxRK6_d.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:`Execution progress`})]})}),(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};
|