@xfey/tutti 0.1.96 → 0.1.98
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 +5 -5
- package/dist/collaboration-state/index.js +4 -4
- package/dist/collaboration-state/scratchpad-source-state.d.ts +6 -1
- package/dist/collaboration-state/scratchpad-source-state.js +37 -6
- package/dist/collaboration-state/storage-types.d.ts +10 -0
- package/dist/collaboration-state/task-compile-context.d.ts +8 -3
- package/dist/collaboration-state/task-compile-context.js +91 -7
- package/dist/collaboration-state/types.d.ts +12 -0
- package/dist/collaboration-state/worklist.d.ts +2 -1
- package/dist/collaboration-state/worklist.js +6 -0
- package/dist/control-plane/clarification-commands.d.ts +12 -8
- package/dist/control-plane/clarification-commands.js +29 -10
- package/dist/control-plane/dispatch-intents.d.ts +104 -0
- package/dist/control-plane/dispatch-intents.js +276 -0
- package/dist/control-plane/follow-up-run.d.ts +1 -1
- package/dist/control-plane/follow-up-run.js +12 -4
- package/dist/control-plane/follow-up-start.d.ts +3 -1
- package/dist/control-plane/follow-up-start.js +7 -2
- package/dist/control-plane/formatters.d.ts +2 -0
- package/dist/control-plane/formatters.js +6 -0
- package/dist/control-plane/index.d.ts +9 -0
- package/dist/control-plane/index.js +274 -13
- package/dist/control-plane/intent-dispatcher.d.ts +52 -0
- package/dist/control-plane/intent-dispatcher.js +184 -0
- package/dist/control-plane/reference-summary-refresh.d.ts +4 -1
- package/dist/control-plane/reference-summary-refresh.js +39 -4
- package/dist/control-plane/run-dispatch-intents.d.ts +15 -0
- package/dist/control-plane/run-dispatch-intents.js +40 -0
- package/dist/control-plane/run-retry.d.ts +1 -1
- package/dist/control-plane/run-retry.js +14 -6
- package/dist/control-plane/run-scheduler.d.ts +1 -1
- package/dist/control-plane/run-scheduler.js +12 -4
- package/dist/control-plane/scratchpad-refresh-start.d.ts +10 -2
- package/dist/control-plane/scratchpad-refresh-start.js +57 -8
- package/dist/control-plane/startup-recovery.d.ts +2 -2
- package/dist/control-plane/startup-recovery.js +73 -3
- package/dist/control-plane/task-compile-continuation.d.ts +3 -1
- package/dist/control-plane/task-compile-continuation.js +14 -9
- package/dist/control-plane/task-compile-start.d.ts +33 -1
- package/dist/control-plane/task-compile-start.js +244 -26
- package/dist/control-plane/types.d.ts +4 -2
- package/dist/control-plane/worklist-terminal-feedback.js +4 -4
- package/dist/server-shell/http/routes/agent-context-references.js +8 -14
- package/dist/server-shell/http/routes/project-api/openapi-viewer-routes.d.ts +0 -2
- package/dist/server-shell/http/routes/project-api/reference-files.js +6 -17
- package/dist/workspace-ops/constants.d.ts +0 -1
- package/dist/workspace-ops/constants.js +0 -1
- package/dist/workspace-ops/index.d.ts +3 -2
- package/dist/workspace-ops/index.js +3 -2
- package/dist/workspace-ops/project-doc-templates.js +1 -1
- package/dist/workspace-ops/reference-files.js +3 -2
- package/dist/workspace-ops/reference-metadata.d.ts +2 -2
- package/dist/workspace-ops/reference-metadata.js +8 -22
- package/dist/workspace-ops/reference-summaries.js +11 -17
- package/dist/workspace-ops/reference-tree.d.ts +11 -0
- package/dist/workspace-ops/reference-tree.js +34 -0
- package/dist/workspace-ops/viewer-git.d.ts +1 -0
- package/dist/workspace-ops/viewer-git.js +11 -0
- package/migrations/0015_control_plane_intents.sql +115 -0
- package/migrations/README.md +2 -1
- package/node_modules/@tutti/shared/dist/ids/index.d.ts +3 -0
- package/node_modules/@tutti/shared/dist/ids/index.js +2 -0
- package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.d.ts +0 -5
- package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.js +0 -2
- package/package.json +1 -1
- package/prompts/procedures/context-sync.md +3 -3
- package/prompts/procedures/reference-file-summary.md +1 -1
- package/prompts/procedures/task-compile.md +2 -2
- package/prompts/prompt-flow-map.md +1 -1
- package/prompts/runs/task-execute.md +2 -2
- package/prompts/skills/read-references/SKILL.md +2 -2
- package/web/assets/{homepage-motion-scene-BFo4r4nz.js → homepage-motion-scene-_nsq44Ph.js} +1 -1
- package/web/assets/{index-CNIl4TF8.js → index-BtTlbKEP.js} +3 -3
- package/web/index.html +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
export { DEFAULT_VIEWER_MAX_BYTES, MAX_REFERENCE_UPLOAD_BYTES, MAX_VIEWER_MAX_BYTES, PROJECT_DOC_PATHS, REFERENCE_IMAGE_ASSET_CACHE_VERSION, REFERENCE_IMAGE_PREVIEW_MAX_EDGE_PX, REFERENCE_IMAGE_THUMBNAIL_MAX_EDGE_PX, REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH,
|
|
1
|
+
export { DEFAULT_VIEWER_MAX_BYTES, MAX_REFERENCE_UPLOAD_BYTES, MAX_VIEWER_MAX_BYTES, PROJECT_DOC_PATHS, REFERENCE_IMAGE_ASSET_CACHE_VERSION, REFERENCE_IMAGE_PREVIEW_MAX_EDGE_PX, REFERENCE_IMAGE_THUMBNAIL_MAX_EDGE_PX, REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, VIEWER_ASSET_READ_LIMIT_BYTES, VIEWER_HARD_READ_LIMIT_BYTES, WORKSPACE_OPS_MAINLINE_BRANCH, } from "./constants.js";
|
|
2
2
|
export { WorkspaceOpsError } from "./errors.js";
|
|
3
3
|
export { commitOwnedPaths, requireOwnedPathsWriteReady } from "./system-commits.js";
|
|
4
4
|
export { collectProjectSourceDiff, createAcceptedCheckpoint, inspectProjectWorkspace, recoverAcceptedCheckpoint, } from "./project-workspace.js";
|
|
5
5
|
export { initializeProjectDocs, readProjectDocsInitializationStatus, syncProjectDocs, } from "./project-docs.js";
|
|
6
6
|
export { uploadReferenceFile } from "./reference-files.js";
|
|
7
|
-
export { referenceFileCategoryForPath,
|
|
7
|
+
export { isReferenceFilePath, referenceFileCategoryForPath, referenceFolderGroupForPath, referenceMediaTypeForPath, } from "./reference-metadata.js";
|
|
8
|
+
export { readReferenceFileEntries } from "./reference-tree.js";
|
|
8
9
|
export { readReferenceSummaryEntries, readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
|
|
9
10
|
export { readViewerAsset, readViewerFile, readViewerSnapshot, readViewerTree } from "./viewer.js";
|
|
10
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -129,7 +129,7 @@ ${asBulletList([
|
|
|
129
129
|
...repoHints.directories.map((directory) => `Top-level directory: \`${directory}/\``),
|
|
130
130
|
...repoHints.root_files.map((file) => `Root file: \`${file}\``),
|
|
131
131
|
], "Repository structure is pending context sync.")}
|
|
132
|
-
-
|
|
132
|
+
- Shared reference materials maintained by project members and Tutti, when present, live under \`docs/reference/\`.
|
|
133
133
|
|
|
134
134
|
## Naming Conventions
|
|
135
135
|
|
|
@@ -110,7 +110,7 @@ function appendReferenceIndexEntry(options) {
|
|
|
110
110
|
? [
|
|
111
111
|
"# Reference Files",
|
|
112
112
|
"",
|
|
113
|
-
"
|
|
113
|
+
"Shared project reference files maintained by project members and Tutti.",
|
|
114
114
|
"",
|
|
115
115
|
"## Files",
|
|
116
116
|
"",
|
|
@@ -185,7 +185,8 @@ export function uploadReferenceFile(options) {
|
|
|
185
185
|
paths: [REFERENCE_INDEX_PATH, repoPath],
|
|
186
186
|
message: `Add reference file: ${safeName}`,
|
|
187
187
|
});
|
|
188
|
-
const resolvedCommitOid = commitOid ??
|
|
188
|
+
const resolvedCommitOid = commitOid ??
|
|
189
|
+
readViewerFile({ workspaceRoot: options.workspaceRoot, path: repoPath }).snapshot.head.oid;
|
|
189
190
|
const file = readViewerFile({
|
|
190
191
|
workspaceRoot: options.workspaceRoot,
|
|
191
192
|
path: repoPath,
|
|
@@ -9,7 +9,7 @@ export declare function classifyReferenceUpload(options: {
|
|
|
9
9
|
directoryPath: string;
|
|
10
10
|
};
|
|
11
11
|
export declare function referenceFileCategoryForPath(path: string): ReferenceFileCategory | undefined;
|
|
12
|
-
export declare function
|
|
13
|
-
export declare function
|
|
12
|
+
export declare function isReferenceFilePath(path: string): boolean;
|
|
13
|
+
export declare function referenceFolderGroupForPath(path: string): string | undefined;
|
|
14
14
|
export declare function referenceMediaTypeForPath(path: string): string | undefined;
|
|
15
15
|
//# sourceMappingURL=reference-metadata.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { extname
|
|
2
|
-
import { REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH,
|
|
1
|
+
import { extname } from "node:path";
|
|
2
|
+
import { REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, } from "./constants.js";
|
|
3
3
|
const REFERENCE_IMAGE_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".webp", ".gif"]);
|
|
4
4
|
const REFERENCE_IMAGE_MEDIA_TYPES = new Set(["image/png", "image/jpeg", "image/webp", "image/gif"]);
|
|
5
5
|
function normalizeMediaType(mediaType) {
|
|
@@ -54,33 +54,19 @@ export function referenceFileCategoryForPath(path) {
|
|
|
54
54
|
if (path.startsWith(`${REFERENCE_IMAGES_DIRECTORY_PATH}/`)) {
|
|
55
55
|
return "image";
|
|
56
56
|
}
|
|
57
|
-
if (path
|
|
58
|
-
return "file";
|
|
59
|
-
}
|
|
60
|
-
if (path.startsWith(`${REFERENCE_TUTTI_DIRECTORY_PATH}/`)) {
|
|
61
|
-
return "file";
|
|
62
|
-
}
|
|
63
|
-
if (posix.dirname(path) === REFERENCE_DIRECTORY_PATH && path !== REFERENCE_INDEX_PATH) {
|
|
57
|
+
if (isReferenceFilePath(path)) {
|
|
64
58
|
return "file";
|
|
65
59
|
}
|
|
66
60
|
return undefined;
|
|
67
61
|
}
|
|
68
|
-
export function
|
|
69
|
-
|
|
70
|
-
return "tutti_output";
|
|
71
|
-
}
|
|
72
|
-
if (path.startsWith(`${REFERENCE_FILES_DIRECTORY_PATH}/`) ||
|
|
73
|
-
path.startsWith(`${REFERENCE_IMAGES_DIRECTORY_PATH}/`) ||
|
|
74
|
-
(posix.dirname(path) === REFERENCE_DIRECTORY_PATH && path !== REFERENCE_INDEX_PATH)) {
|
|
75
|
-
return "human_upload";
|
|
76
|
-
}
|
|
77
|
-
return undefined;
|
|
62
|
+
export function isReferenceFilePath(path) {
|
|
63
|
+
return path !== REFERENCE_INDEX_PATH && path.startsWith(`${REFERENCE_DIRECTORY_PATH}/`);
|
|
78
64
|
}
|
|
79
|
-
export function
|
|
80
|
-
if (!path
|
|
65
|
+
export function referenceFolderGroupForPath(path) {
|
|
66
|
+
if (!isReferenceFilePath(path)) {
|
|
81
67
|
return undefined;
|
|
82
68
|
}
|
|
83
|
-
const rest = path.slice(
|
|
69
|
+
const rest = path.slice(REFERENCE_DIRECTORY_PATH.length + 1);
|
|
84
70
|
const [first, second] = rest.split("/");
|
|
85
71
|
if (first === undefined || first.length === 0 || second === undefined) {
|
|
86
72
|
return undefined;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { redactText } from "@tutti/shared/utils";
|
|
4
|
-
import {
|
|
4
|
+
import { REFERENCE_INDEX_PATH } from "./constants.js";
|
|
5
5
|
import { referenceFileCategoryForPath, referenceMediaTypeForPath } from "./reference-metadata.js";
|
|
6
|
+
import { readReferenceFileEntries } from "./reference-tree.js";
|
|
6
7
|
import { commitOwnedPaths, requireOwnedPathsWriteReady } from "./system-commits.js";
|
|
7
|
-
import { readViewerTree } from "./viewer.js";
|
|
8
8
|
const SUMMARY_SECTION_HEADING = "## Summaries";
|
|
9
9
|
const SUMMARY_BLOCK_START = "<!-- tutti-reference-summaries:v1";
|
|
10
10
|
const SUMMARY_BLOCK_END = "-->";
|
|
@@ -115,7 +115,7 @@ function readReferenceIndexContent(workspaceRoot) {
|
|
|
115
115
|
return [
|
|
116
116
|
"# Reference Files",
|
|
117
117
|
"",
|
|
118
|
-
"
|
|
118
|
+
"Shared project reference files maintained by project members and Tutti.",
|
|
119
119
|
"",
|
|
120
120
|
"## Files",
|
|
121
121
|
"",
|
|
@@ -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 (options.entry.blob_oid !== undefined &&
|
|
142
|
-
record.source_blob_oid !== options.entry.blob_oid) {
|
|
141
|
+
if (options.entry.blob_oid !== undefined && record.source_blob_oid !== options.entry.blob_oid) {
|
|
143
142
|
return {
|
|
144
143
|
status: "stale",
|
|
145
144
|
...base,
|
|
@@ -165,14 +164,8 @@ export function referenceSummaryProjectionForEntry(options) {
|
|
|
165
164
|
...(record.summary === undefined ? {} : { text: record.summary }),
|
|
166
165
|
};
|
|
167
166
|
}
|
|
168
|
-
function
|
|
169
|
-
|
|
170
|
-
workspaceRoot: options.workspaceRoot,
|
|
171
|
-
path: REFERENCE_DIRECTORY_PATH,
|
|
172
|
-
depth: 2,
|
|
173
|
-
...(options.now === undefined ? {} : { now: options.now }),
|
|
174
|
-
});
|
|
175
|
-
return tree.items
|
|
167
|
+
function readSummaryFileEntries(options) {
|
|
168
|
+
return readReferenceFileEntries({ workspaceRoot: options.workspaceRoot })
|
|
176
169
|
.filter((entry) => entry.kind === "file")
|
|
177
170
|
.filter((entry) => referenceFileCategoryForPath(entry.path) !== undefined)
|
|
178
171
|
.filter((entry) => entry.blob_oid !== undefined && entry.size_bytes !== undefined)
|
|
@@ -181,7 +174,7 @@ function readReferenceFileEntries(options) {
|
|
|
181
174
|
export function readReferenceSummaryEntries(options) {
|
|
182
175
|
const summaries = readReferenceSummaryIndex({ workspaceRoot: options.workspaceRoot });
|
|
183
176
|
const requested = options.paths === undefined ? undefined : new Set(options.paths);
|
|
184
|
-
return
|
|
177
|
+
return readSummaryFileEntries(options)
|
|
185
178
|
.filter((entry) => requested === undefined || requested.has(entry.path))
|
|
186
179
|
.map((entry) => {
|
|
187
180
|
const category = referenceFileCategoryForPath(entry.path) ?? "file";
|
|
@@ -239,7 +232,9 @@ function renderSummaryRecord(record) {
|
|
|
239
232
|
return rendered;
|
|
240
233
|
}
|
|
241
234
|
function renderSummariesSection(records) {
|
|
242
|
-
const items = records
|
|
235
|
+
const items = records
|
|
236
|
+
.map(renderSummaryRecord)
|
|
237
|
+
.sort((left, right) => left.path.localeCompare(right.path, "en", { sensitivity: "base" }));
|
|
243
238
|
const json = JSON.stringify({ items }, null, 2);
|
|
244
239
|
const lines = [
|
|
245
240
|
SUMMARY_SECTION_HEADING,
|
|
@@ -277,9 +272,8 @@ export function updateReferenceSummaries(options) {
|
|
|
277
272
|
}
|
|
278
273
|
existing.set(summary.path, rendered);
|
|
279
274
|
}
|
|
280
|
-
const currentPaths = new Set(
|
|
275
|
+
const currentPaths = new Set(readSummaryFileEntries({
|
|
281
276
|
workspaceRoot: options.workspaceRoot,
|
|
282
|
-
...(options.now === undefined ? {} : { now: options.now }),
|
|
283
277
|
}).map((entry) => entry.path));
|
|
284
278
|
const records = [...existing.values()].filter((record) => currentPaths.has(record.path));
|
|
285
279
|
const nextContent = `${removeSummarySection(existingContent)}\n\n${renderSummariesSection(records)}\n`;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ViewerTreeEntry } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Enumerate every committed regular file in the shared Reference directory.
|
|
4
|
+
* The generic Repo Viewer intentionally keeps its bounded depth contract; this
|
|
5
|
+
* Reference-specific reader is the single recursive source for the API,
|
|
6
|
+
* summaries, and agent context.
|
|
7
|
+
*/
|
|
8
|
+
export declare function readReferenceFileEntries(options: {
|
|
9
|
+
workspaceRoot: string;
|
|
10
|
+
}): ViewerTreeEntry[];
|
|
11
|
+
//# sourceMappingURL=reference-tree.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { REFERENCE_DIRECTORY_PATH } from "./constants.js";
|
|
3
|
+
import { WorkspaceOpsError } from "./errors.js";
|
|
4
|
+
import { entryKind, lsPath, lsTreeRecursive } from "./viewer-git.js";
|
|
5
|
+
import { isPathAllowedForProjection } from "./viewer-paths.js";
|
|
6
|
+
import { createViewerTreeEntry } from "./viewer-tree.js";
|
|
7
|
+
/**
|
|
8
|
+
* Enumerate every committed regular file in the shared Reference directory.
|
|
9
|
+
* The generic Repo Viewer intentionally keeps its bounded depth contract; this
|
|
10
|
+
* Reference-specific reader is the single recursive source for the API,
|
|
11
|
+
* summaries, and agent context.
|
|
12
|
+
*/
|
|
13
|
+
export function readReferenceFileEntries(options) {
|
|
14
|
+
const root = lsPath(options.workspaceRoot, REFERENCE_DIRECTORY_PATH);
|
|
15
|
+
if (root === null) {
|
|
16
|
+
throw new WorkspaceOpsError("not_found", "Reference directory was not found");
|
|
17
|
+
}
|
|
18
|
+
if (entryKind(root) !== "directory") {
|
|
19
|
+
throw new WorkspaceOpsError("validation_failed", "Reference path is not a directory");
|
|
20
|
+
}
|
|
21
|
+
return lsTreeRecursive(options.workspaceRoot, REFERENCE_DIRECTORY_PATH)
|
|
22
|
+
.filter((entry) => entryKind(entry) === "file")
|
|
23
|
+
.filter((entry) => isPathAllowedForProjection(entry.path))
|
|
24
|
+
.map((entry) => {
|
|
25
|
+
const relativePath = entry.path.slice(REFERENCE_DIRECTORY_PATH.length + 1);
|
|
26
|
+
return createViewerTreeEntry(entry, {
|
|
27
|
+
path: entry.path,
|
|
28
|
+
parentPath: posix.dirname(entry.path),
|
|
29
|
+
depth: relativePath.split("/").length,
|
|
30
|
+
});
|
|
31
|
+
})
|
|
32
|
+
.sort((left, right) => left.path.localeCompare(right.path, "en", { sensitivity: "base" }));
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=reference-tree.js.map
|
|
@@ -9,6 +9,7 @@ export type RawTreeEntry = {
|
|
|
9
9
|
export declare function readViewerSnapshot(options: WorkspaceViewerOptions): ViewerRepoSnapshot;
|
|
10
10
|
export declare function lsPath(workspaceRoot: string, normalizedPath: string): RawTreeEntry | null;
|
|
11
11
|
export declare function lsDirectoryChildren(workspaceRoot: string, normalizedPath: string): RawTreeEntry[];
|
|
12
|
+
export declare function lsTreeRecursive(workspaceRoot: string, normalizedPath: string): RawTreeEntry[];
|
|
12
13
|
export declare function entryKind(entry: RawTreeEntry): ViewerEntryKind;
|
|
13
14
|
export declare function requireFileEntry(options: {
|
|
14
15
|
workspaceRoot: string;
|
|
@@ -76,6 +76,17 @@ export function lsDirectoryChildren(workspaceRoot, normalizedPath) {
|
|
|
76
76
|
: `${WORKSPACE_OPS_MAINLINE_BRANCH}:${normalizedPath}`;
|
|
77
77
|
return lsTree(workspaceRoot, ["ls-tree", "-z", "-l", treeish]);
|
|
78
78
|
}
|
|
79
|
+
export function lsTreeRecursive(workspaceRoot, normalizedPath) {
|
|
80
|
+
return lsTree(workspaceRoot, [
|
|
81
|
+
"ls-tree",
|
|
82
|
+
"-r",
|
|
83
|
+
"-z",
|
|
84
|
+
"-l",
|
|
85
|
+
WORKSPACE_OPS_MAINLINE_BRANCH,
|
|
86
|
+
"--",
|
|
87
|
+
normalizedPath,
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
79
90
|
export function entryKind(entry) {
|
|
80
91
|
if (entry.mode === "040000" || entry.type === "tree") {
|
|
81
92
|
return "directory";
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
CREATE TABLE control_plane_intents (
|
|
2
|
+
intent_id TEXT PRIMARY KEY CHECK (
|
|
3
|
+
intent_id GLOB 'intent_[0-7][0-9A-HJKMNP-TV-Z][0-9A-HJKMNP-TV-Z][0-9A-HJKMNP-TV-Z]*'
|
|
4
|
+
AND length(intent_id) = 33
|
|
5
|
+
),
|
|
6
|
+
kind TEXT NOT NULL CHECK (
|
|
7
|
+
kind IN (
|
|
8
|
+
'task_compile_start',
|
|
9
|
+
'task_compile_continuation',
|
|
10
|
+
'task_bound_follow_up',
|
|
11
|
+
'scratchpad_refresh',
|
|
12
|
+
'reference_summary_refresh',
|
|
13
|
+
'run_dispatch'
|
|
14
|
+
)
|
|
15
|
+
),
|
|
16
|
+
owner_kind TEXT NOT NULL CHECK (
|
|
17
|
+
owner_kind IN (
|
|
18
|
+
'task_compile',
|
|
19
|
+
'clarification_round',
|
|
20
|
+
'scratchpad',
|
|
21
|
+
'reference_summary',
|
|
22
|
+
'task_run'
|
|
23
|
+
)
|
|
24
|
+
),
|
|
25
|
+
owner_ref TEXT NOT NULL CHECK (length(owner_ref) BETWEEN 1 AND 512),
|
|
26
|
+
dedupe_key TEXT NOT NULL UNIQUE CHECK (length(dedupe_key) BETWEEN 1 AND 512),
|
|
27
|
+
lane TEXT NOT NULL CHECK (lane IN ('foreground', 'scratchpad_background', 'run')),
|
|
28
|
+
priority INTEGER NOT NULL DEFAULT 100 CHECK (priority >= 0),
|
|
29
|
+
state TEXT NOT NULL DEFAULT 'pending' CHECK (
|
|
30
|
+
state IN ('pending', 'claimed', 'running', 'completed', 'failed', 'cancelled')
|
|
31
|
+
),
|
|
32
|
+
available_at TEXT NOT NULL,
|
|
33
|
+
claim_token TEXT CHECK (claim_token IS NULL OR length(claim_token) BETWEEN 1 AND 256),
|
|
34
|
+
lease_expires_at TEXT,
|
|
35
|
+
attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
|
|
36
|
+
last_error_code TEXT CHECK (
|
|
37
|
+
last_error_code IS NULL OR length(last_error_code) BETWEEN 1 AND 128
|
|
38
|
+
),
|
|
39
|
+
created_at TEXT NOT NULL,
|
|
40
|
+
updated_at TEXT NOT NULL,
|
|
41
|
+
completed_at TEXT,
|
|
42
|
+
CHECK (
|
|
43
|
+
(
|
|
44
|
+
state = 'pending'
|
|
45
|
+
AND claim_token IS NULL
|
|
46
|
+
AND lease_expires_at IS NULL
|
|
47
|
+
AND completed_at IS NULL
|
|
48
|
+
)
|
|
49
|
+
OR (
|
|
50
|
+
state IN ('claimed', 'running')
|
|
51
|
+
AND claim_token IS NOT NULL
|
|
52
|
+
AND lease_expires_at IS NOT NULL
|
|
53
|
+
AND completed_at IS NULL
|
|
54
|
+
)
|
|
55
|
+
OR (
|
|
56
|
+
state IN ('completed', 'failed', 'cancelled')
|
|
57
|
+
AND claim_token IS NULL
|
|
58
|
+
AND lease_expires_at IS NULL
|
|
59
|
+
AND completed_at IS NOT NULL
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
CREATE INDEX idx_control_plane_intents_dispatch
|
|
65
|
+
ON control_plane_intents (state, available_at ASC, priority ASC, created_at ASC, intent_id ASC);
|
|
66
|
+
|
|
67
|
+
CREATE INDEX idx_control_plane_intents_expired_claim
|
|
68
|
+
ON control_plane_intents (state, lease_expires_at ASC)
|
|
69
|
+
WHERE state IN ('claimed', 'running');
|
|
70
|
+
|
|
71
|
+
CREATE INDEX idx_control_plane_intents_owner
|
|
72
|
+
ON control_plane_intents (owner_kind, owner_ref, created_at ASC);
|
|
73
|
+
|
|
74
|
+
CREATE TABLE pending_task_compile_submissions (
|
|
75
|
+
id TEXT PRIMARY KEY CHECK (id = 'current'),
|
|
76
|
+
workflow_ref TEXT NOT NULL UNIQUE,
|
|
77
|
+
accepted_activity_ref TEXT NOT NULL,
|
|
78
|
+
requested_at TEXT NOT NULL,
|
|
79
|
+
source_window_after_created_at TEXT,
|
|
80
|
+
source_window_after_message_id TEXT,
|
|
81
|
+
source_window_through_created_at TEXT,
|
|
82
|
+
source_window_through_message_id TEXT,
|
|
83
|
+
CHECK (
|
|
84
|
+
(source_window_after_created_at IS NULL AND source_window_after_message_id IS NULL)
|
|
85
|
+
OR (
|
|
86
|
+
source_window_after_created_at IS NOT NULL
|
|
87
|
+
AND source_window_after_message_id IS NOT NULL
|
|
88
|
+
)
|
|
89
|
+
),
|
|
90
|
+
CHECK (
|
|
91
|
+
(source_window_through_created_at IS NULL AND source_window_through_message_id IS NULL)
|
|
92
|
+
OR (
|
|
93
|
+
source_window_through_created_at IS NOT NULL
|
|
94
|
+
AND source_window_through_message_id IS NOT NULL
|
|
95
|
+
)
|
|
96
|
+
),
|
|
97
|
+
CHECK (
|
|
98
|
+
source_window_after_created_at IS NULL
|
|
99
|
+
OR source_window_through_created_at IS NULL
|
|
100
|
+
OR source_window_through_created_at > source_window_after_created_at
|
|
101
|
+
OR (
|
|
102
|
+
source_window_through_created_at = source_window_after_created_at
|
|
103
|
+
AND source_window_through_message_id >= source_window_after_message_id
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
CREATE TRIGGER pending_task_compile_submissions_immutable
|
|
109
|
+
BEFORE UPDATE ON pending_task_compile_submissions
|
|
110
|
+
BEGIN
|
|
111
|
+
SELECT RAISE(ABORT, 'pending Task Compile submission is immutable');
|
|
112
|
+
END;
|
|
113
|
+
|
|
114
|
+
ALTER TABLE scratchpad_source_state
|
|
115
|
+
ADD COLUMN in_flight_intent_id TEXT REFERENCES control_plane_intents(intent_id);
|
package/migrations/README.md
CHANGED
|
@@ -27,10 +27,11 @@
|
|
|
27
27
|
- `0012_scratchpad_receipts.sql`:为当前 Scratchpad 增加 `submitted` 状态字段,并新增已提交 Scratchpad 小票历史表。
|
|
28
28
|
- `0013_scratchpad_receipt_sources.sql`:新增当前 Scratchpad snapshot 与 submitted receipt 的 source message id 引用表,供 Timeline Task Accepted 追溯原始聊天依据。
|
|
29
29
|
- `0014_scratchpad_task_compile_context.sql`:把 Scratchpad source state 收敛为纯主群聊周期 cursor,新增 durable active Task Compile Context 与完整 source refs,并把 Current Scratchpad / receipt sources 限定为主群聊。该开发阶段 migration 不迁移旧调试数据,已有本地开发数据库需要 reset / recreate。
|
|
30
|
+
- `0015_control_plane_intents.sql`:新增 Control Plane durable dispatch intent,保存 bounded kind / owner / dedupe / lane、pending-to-running claim lease 与 terminal 状态,为 Clarification、Task Compile、Scratchpad、Reference Summary 和 Run 提供可恢复的 runtime handoff;同时用 immutable pending Task Compile submission row 固化 context capture 前的 workflow / main-chat cursor boundary,不保存 prompt、消息正文、provider output、secret 或 host path。
|
|
30
31
|
|
|
31
32
|
## 当前实现状态
|
|
32
33
|
|
|
33
|
-
- `0001_init.sql` 至 `
|
|
34
|
+
- `0001_init.sql` 至 `0015_control_plane_intents.sql` 已存在,代表当前 host project SQLite schema contract。`0014` 明确采用开发数据库重建策略,不提供旧 Scratchpad source/cursor 数据兼容。
|
|
34
35
|
- SQLite adapter、migration runner、checksum 校验、store metadata 初始化、transaction helper 与 command recovery scan helper 已实现。
|
|
35
36
|
- 协作 repository 与 Control Plane 已实现第一批业务读写;Phase 7 首批已复用 `0001_init.sql` 中的 `tasks.latest_run_result_id`、`task_details.result_json` 与 `run_results` 表完成 Run result / checks / promotion 摘要持久化。Control Plane recovery resolver 与 task-bound continuation / retry 复用现有 schema;新 Run 的 accepted checkpoint 业务 truth 继续写入最终 Run result / task detail result,Git tag / commit trailer 承担 crash recovery evidence。Timeline 默认从 `tasks`、`run_results` 与历史主群聊 `refs.worklist_feedback` 投影任务级审计节点,当前 task terminal Chat feedback 写入 `refs.task_result` 消息;`project_timeline_events` 只保留缺少稳定 record 的轻量可观测性事件和历史 reconcile 兼容记录。project workspace、working diff 与 ignored runtime state 都不进入 SQLite truth。`provider_usage_events` 只保存 token 计数、调用来源、模型名、记录时间和可空 anchor,不保存 provider secret、prompt 或 raw response。store 基础设施本身已经可以创建并迁移 `tutti.sqlite`。
|
|
36
37
|
|
|
@@ -25,6 +25,7 @@ export declare const ID_PREFIXES: {
|
|
|
25
25
|
readonly hostConnection: "host_connection_";
|
|
26
26
|
readonly joinToken: "join_token_";
|
|
27
27
|
readonly notice: "notice_";
|
|
28
|
+
readonly controlPlaneIntent: "intent_";
|
|
28
29
|
};
|
|
29
30
|
export type IdPrefix = (typeof ID_PREFIXES)[keyof typeof ID_PREFIXES];
|
|
30
31
|
export type PrefixedId<TPrefix extends string> = `${TPrefix}${string}`;
|
|
@@ -53,6 +54,7 @@ export type RelayDesktopEntryContinuationRef = PrefixedId<typeof ID_PREFIXES.rel
|
|
|
53
54
|
export type HostConnectionRef = PrefixedId<typeof ID_PREFIXES.hostConnection>;
|
|
54
55
|
export type JoinTokenRef = PrefixedId<typeof ID_PREFIXES.joinToken>;
|
|
55
56
|
export type NoticeId = PrefixedId<typeof ID_PREFIXES.notice>;
|
|
57
|
+
export type ControlPlaneIntentId = PrefixedId<typeof ID_PREFIXES.controlPlaneIntent>;
|
|
56
58
|
export declare function createPrefixedId<const TPrefix extends IdPrefix>(prefix: TPrefix): PrefixedId<TPrefix>;
|
|
57
59
|
export declare function isUlidBody(value: string): boolean;
|
|
58
60
|
export declare function getPrefixedIdBody(value: string, prefix: IdPrefix): string | null;
|
|
@@ -85,4 +87,5 @@ export declare const createRelayDesktopEntryContinuationRef: () => RelayDesktopE
|
|
|
85
87
|
export declare const createHostConnectionRef: () => HostConnectionRef;
|
|
86
88
|
export declare const createJoinTokenRef: () => JoinTokenRef;
|
|
87
89
|
export declare const createNoticeId: () => NoticeId;
|
|
90
|
+
export declare const createControlPlaneIntentId: () => ControlPlaneIntentId;
|
|
88
91
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -27,6 +27,7 @@ export const ID_PREFIXES = {
|
|
|
27
27
|
hostConnection: "host_connection_",
|
|
28
28
|
joinToken: "join_token_",
|
|
29
29
|
notice: "notice_",
|
|
30
|
+
controlPlaneIntent: "intent_",
|
|
30
31
|
};
|
|
31
32
|
export function createPrefixedId(prefix) {
|
|
32
33
|
return `${prefix}${ulid()}`;
|
|
@@ -87,4 +88,5 @@ export const createRelayDesktopEntryContinuationRef = () => createPrefixedId(ID_
|
|
|
87
88
|
export const createHostConnectionRef = () => createPrefixedId(ID_PREFIXES.hostConnection);
|
|
88
89
|
export const createJoinTokenRef = () => createPrefixedId(ID_PREFIXES.joinToken);
|
|
89
90
|
export const createNoticeId = () => createPrefixedId(ID_PREFIXES.notice);
|
|
91
|
+
export const createControlPlaneIntentId = () => createPrefixedId(ID_PREFIXES.controlPlaneIntent);
|
|
90
92
|
//# sourceMappingURL=index.js.map
|
|
@@ -250,7 +250,6 @@ export declare const ReferenceDirectoryProjectionSchema: import("@sinclair/typeb
|
|
|
250
250
|
index_path: import("@sinclair/typebox").TLiteral<"docs/reference/README.md">;
|
|
251
251
|
files_path: import("@sinclair/typebox").TLiteral<"docs/reference/files">;
|
|
252
252
|
images_path: import("@sinclair/typebox").TLiteral<"docs/reference/images">;
|
|
253
|
-
tutti_path: import("@sinclair/typebox").TLiteral<"docs/reference/tutti">;
|
|
254
253
|
index_status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"available">, import("@sinclair/typebox").TLiteral<"missing">, import("@sinclair/typebox").TLiteral<"unreadable">]>;
|
|
255
254
|
index_unreadable_reason: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"restricted_path">, import("@sinclair/typebox").TLiteral<"secret_like">, import("@sinclair/typebox").TLiteral<"binary">, import("@sinclair/typebox").TLiteral<"unsupported_encoding">, import("@sinclair/typebox").TLiteral<"too_large">]>>;
|
|
256
255
|
}>;
|
|
@@ -266,7 +265,6 @@ export declare const ReferenceSummaryProjectionSchema: import("@sinclair/typebox
|
|
|
266
265
|
export declare const ReferenceFileProjectionSchema: import("@sinclair/typebox").TObject<{
|
|
267
266
|
path: import("@sinclair/typebox").TString;
|
|
268
267
|
name: import("@sinclair/typebox").TString;
|
|
269
|
-
source: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"human_upload">, import("@sinclair/typebox").TLiteral<"tutti_output">]>;
|
|
270
268
|
category: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"file">, import("@sinclair/typebox").TLiteral<"image">]>;
|
|
271
269
|
size_bytes: import("@sinclair/typebox").TInteger;
|
|
272
270
|
media_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -308,14 +306,12 @@ export declare const GetReferenceFilesResponseSchema: import("@sinclair/typebox"
|
|
|
308
306
|
index_path: import("@sinclair/typebox").TLiteral<"docs/reference/README.md">;
|
|
309
307
|
files_path: import("@sinclair/typebox").TLiteral<"docs/reference/files">;
|
|
310
308
|
images_path: import("@sinclair/typebox").TLiteral<"docs/reference/images">;
|
|
311
|
-
tutti_path: import("@sinclair/typebox").TLiteral<"docs/reference/tutti">;
|
|
312
309
|
index_status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"available">, import("@sinclair/typebox").TLiteral<"missing">, import("@sinclair/typebox").TLiteral<"unreadable">]>;
|
|
313
310
|
index_unreadable_reason: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"restricted_path">, import("@sinclair/typebox").TLiteral<"secret_like">, import("@sinclair/typebox").TLiteral<"binary">, import("@sinclair/typebox").TLiteral<"unsupported_encoding">, import("@sinclair/typebox").TLiteral<"too_large">]>>;
|
|
314
311
|
}>;
|
|
315
312
|
items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
316
313
|
path: import("@sinclair/typebox").TString;
|
|
317
314
|
name: import("@sinclair/typebox").TString;
|
|
318
|
-
source: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"human_upload">, import("@sinclair/typebox").TLiteral<"tutti_output">]>;
|
|
319
315
|
category: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"file">, import("@sinclair/typebox").TLiteral<"image">]>;
|
|
320
316
|
size_bytes: import("@sinclair/typebox").TInteger;
|
|
321
317
|
media_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -359,7 +355,6 @@ export declare const UploadReferenceFileResultSchema: import("@sinclair/typebox"
|
|
|
359
355
|
file: import("@sinclair/typebox").TObject<{
|
|
360
356
|
path: import("@sinclair/typebox").TString;
|
|
361
357
|
name: import("@sinclair/typebox").TString;
|
|
362
|
-
source: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"human_upload">, import("@sinclair/typebox").TLiteral<"tutti_output">]>;
|
|
363
358
|
category: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"file">, import("@sinclair/typebox").TLiteral<"image">]>;
|
|
364
359
|
size_bytes: import("@sinclair/typebox").TInteger;
|
|
365
360
|
media_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
@@ -164,7 +164,6 @@ export const ReferenceDirectoryProjectionSchema = Type.Object({
|
|
|
164
164
|
index_path: Type.Literal("docs/reference/README.md"),
|
|
165
165
|
files_path: Type.Literal("docs/reference/files"),
|
|
166
166
|
images_path: Type.Literal("docs/reference/images"),
|
|
167
|
-
tutti_path: Type.Literal("docs/reference/tutti"),
|
|
168
167
|
index_status: Type.Union([
|
|
169
168
|
Type.Literal("available"),
|
|
170
169
|
Type.Literal("missing"),
|
|
@@ -196,7 +195,6 @@ export const ReferenceSummaryProjectionSchema = Type.Object({
|
|
|
196
195
|
export const ReferenceFileProjectionSchema = Type.Object({
|
|
197
196
|
path: ViewerPathSchema,
|
|
198
197
|
name: NonEmptyStringSchema,
|
|
199
|
-
source: Type.Union([Type.Literal("human_upload"), Type.Literal("tutti_output")]),
|
|
200
198
|
category: ReferenceFileCategorySchema,
|
|
201
199
|
size_bytes: Type.Integer({ minimum: 0 }),
|
|
202
200
|
media_type: Type.Optional(NonEmptyStringSchema),
|
package/package.json
CHANGED
|
@@ -16,9 +16,9 @@ Use repository inspection and attached skills only when useful:
|
|
|
16
16
|
|
|
17
17
|
- Use `read-project-docs` for existing project documents and availability.
|
|
18
18
|
- Use `read-worklist` when repo state or completed formal tasks can explain the current implementation stage. Do not turn task results into a changelog.
|
|
19
|
-
- Use `read-references` only when a
|
|
19
|
+
- Use `read-references` only when a file in the shared project Reference space actually matters.
|
|
20
20
|
|
|
21
|
-
Reference
|
|
21
|
+
Reference creation events, file names, media types, paths, and summaries do not prove file contents. Read the relevant file before relying on it.
|
|
22
22
|
|
|
23
23
|
# Documentation Scope
|
|
24
24
|
|
|
@@ -62,5 +62,5 @@ Return only JSON matching this schema:
|
|
|
62
62
|
If no concrete documentation update is needed, return an empty `updates` array:
|
|
63
63
|
|
|
64
64
|
```json
|
|
65
|
-
{"summary":"Checked current docs against repository facts; no updates needed.","updates":[]}
|
|
65
|
+
{ "summary": "Checked current docs against repository facts; no updates needed.", "updates": [] }
|
|
66
66
|
```
|
|
@@ -36,9 +36,9 @@ You compile Tutti's Scratchpad into an append-only Worklist proposal for post-ba
|
|
|
36
36
|
Tutti can expose direct user-viewable outputs through two repo-backed surfaces when a task result is meant for project members to inspect:
|
|
37
37
|
|
|
38
38
|
- a single active visual artifact, declared by `tutti.artifact.json`, for previewable pages, apps, dashboards, or similar interactive outputs;
|
|
39
|
-
- generated files
|
|
39
|
+
- generated files in the shared `docs/reference/**` space, directly at the root or under a meaningful semantic subfolder, for reviewable files such as reports, notes, specs, exports, or similar outputs.
|
|
40
40
|
|
|
41
|
-
Treat these as delivery surfaces, not as task subjects by themselves.
|
|
41
|
+
Treat these as delivery surfaces, not as task subjects by themselves. Browser uploads continue to enter the Host-managed `docs/reference/files/` or `docs/reference/images/` partitions, `docs/reference/README.md` remains Host-owned, and stable project facts still belong in the relevant project docs or README-style files.
|
|
42
42
|
|
|
43
43
|
When the Scratchpad clearly asks for one of these direct deliverables, include a concise task `scope` item naming the expected surface. If a completion card should call out the result or generated file name, the scope may also mention `user_note_candidate`. Do not add artifact or generated-reference outputs solely to create feedback for ordinary implementation tasks.
|
|
44
44
|
|
|
@@ -377,7 +377,7 @@ Provider raw 输出:根对象只包含 `result`;`result` 内二选一输出
|
|
|
377
377
|
- Reference Files 不通过 built-in skill 暴露;若任务契约或 Project Docs 指向 `docs/reference/` 中资料,Codex 可直接读取相关 repo 文件正文。
|
|
378
378
|
- `goal / scope` 决定本次执行边界;`source_messages` 与 compile `clarification_rounds` 只提供该边界引用的精确材料,不自动扩展任务目标。
|
|
379
379
|
|
|
380
|
-
输出:根对象只包含 `result`;`result` 内四选一输出 `completed.{summary,user_note_candidate}`、`completed_no_repo_changes.{summary,user_note_candidate}`、`needs_human.{title,summary,request}` 或 `failed.summary`。`user_note_candidate` 是可选最终反馈候选,字段必填但可为 `null
|
|
380
|
+
输出:根对象只包含 `result`;`result` 内四选一输出 `completed.{summary,user_note_candidate}`、`completed_no_repo_changes.{summary,user_note_candidate}`、`needs_human.{title,summary,request}` 或 `failed.summary`。`user_note_candidate` 是可选最终反馈候选,字段必填但可为 `null`;生成给用户直接查看的文件应写入共享 `docs/reference/` 根目录或有意义的语义子目录,同时避开 Host-owned `README.md` 和通常由浏览器上传使用的 `files/`、`images/` 分区。`completed_no_repo_changes` 只用于任务契约不要求 repository file changes 的情况。`needs_human` payload 必须能直接作为 task-bound clarification request 使用:解释为什么 frozen contract 下无法安全继续,并提出一个具体、可回答、非 secret 的问题。
|
|
381
381
|
|
|
382
382
|
下游:Run pipeline 收集真实 Git diff 作为 `changed_paths`;`needs_human` 时 Control Plane 记录 `Run.needs_human`、打开 task-bound clarification 并把 task 迁回 `pending`;有 repo candidate 的 `completed` 结果先执行 Artifact candidate gate 与 checks,再在当前 `tutti/mainline` 创建 accepted commit + immutable activity tag;空 diff 的 `completed_no_repo_changes` 结果跳过 Artifact gate、checks 与 accepted checkpoint,记录 `promotion.status = not_attempted`。
|
|
383
383
|
|
|
@@ -33,9 +33,9 @@ For a continuation, the same task is already present in this conversation. The i
|
|
|
33
33
|
|
|
34
34
|
Use attached skills only when they help the task. `read-worklist` may clarify related formal work without expanding this task. `read-project-docs` may clarify architecture, setup, and maintenance rules. User skills may guide implementation but do not override the task, command policy, workspace policy, checks, or redaction rules.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Project members and Tutti share `docs/reference/**` as the member-viewable Reference space. Read a relevant source file before relying on it; do not infer its contents from a name, path, media type, upload message, or summary.
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
When this task needs to create an explicit reviewable deliverable, write it directly under `docs/reference/` or use a meaningful semantic subfolder such as `docs/reference/reports/`. Do not put temporary output, logs, internal notes, or canonical project documentation there. Do not overwrite unrelated existing References. `docs/reference/files/` and `docs/reference/images/` are normally reserved for Host-managed browser uploads, and `docs/reference/README.md` is Host-owned; do not modify them unless the task explicitly requires that exact existing file.
|
|
39
39
|
|
|
40
40
|
# Documentation
|
|
41
41
|
|
|
@@ -5,7 +5,7 @@ description: List and read bounded Tutti reference files when the turn has refer
|
|
|
5
5
|
|
|
6
6
|
# Read References
|
|
7
7
|
|
|
8
|
-
Use this skill when a Tutti app-server turn needs
|
|
8
|
+
Use this skill when a Tutti app-server turn needs material from the shared project Reference space. Files may have been uploaded by a project member or created by Tutti in an earlier Run.
|
|
9
9
|
|
|
10
10
|
When a Tutti context API runtime hint is present and includes `references:list`, list available references through:
|
|
11
11
|
|
|
@@ -19,7 +19,7 @@ When a listed text file is relevant and the hint includes `references:read`, rea
|
|
|
19
19
|
|
|
20
20
|
Read responses may include the same `summary` object alongside text or unavailable metadata.
|
|
21
21
|
|
|
22
|
-
Read only reference files that are relevant to the current task or question. Do not infer file contents from
|
|
22
|
+
Read only reference files that are relevant to the current task or question. Do not infer file contents from creation events, names, media types, paths, or summaries alone. If a file is unavailable, restricted, binary, too large, or unsupported, use the returned disposition instead of guessing.
|
|
23
23
|
|
|
24
24
|
This skill is read-only. Do not attempt to create, update, refresh, or write reference summaries from this skill.
|
|
25
25
|
|