@xfey/tutti 0.1.17 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/collaboration-state/run-recording.js +3 -0
  2. package/dist/collaboration-state/run-results.js +3 -0
  3. package/dist/collaboration-state/types.d.ts +1 -0
  4. package/dist/control-plane/index.js +3 -0
  5. package/dist/control-plane/types.d.ts +1 -0
  6. package/dist/control-plane/worklist-terminal-feedback.d.ts +1 -0
  7. package/dist/control-plane/worklist-terminal-feedback.js +109 -0
  8. package/dist/run-pipeline/openai.js +6 -0
  9. package/dist/run-pipeline/promotion-reconcile.d.ts +2 -2
  10. package/dist/run-pipeline/promotion-reconcile.js +3 -0
  11. package/dist/run-pipeline/result-projections.d.ts +1 -0
  12. package/dist/run-pipeline/result-projections.js +3 -0
  13. package/dist/run-pipeline/task-run-output.d.ts +9 -3
  14. package/dist/run-pipeline/task-run-output.js +24 -4
  15. package/dist/server-shell/http/routes/project-api/openapi-execution-routes.d.ts +1 -0
  16. package/dist/server-shell/http/routes/project-api/openapi-viewer-routes.d.ts +2 -0
  17. package/dist/server-shell/http/routes/project-api/openapi.d.ts +1 -0
  18. package/dist/server-shell/http/routes/project-api/reference-files.js +9 -3
  19. package/dist/workspace-ops/constants.d.ts +1 -0
  20. package/dist/workspace-ops/constants.js +1 -0
  21. package/dist/workspace-ops/index.d.ts +2 -2
  22. package/dist/workspace-ops/index.js +2 -2
  23. package/dist/workspace-ops/reference-metadata.d.ts +2 -0
  24. package/dist/workspace-ops/reference-metadata.js +26 -1
  25. package/node_modules/@tutti/shared/dist/schemas/api/clarifications.d.ts +9 -0
  26. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -1
  27. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -1
  28. package/node_modules/@tutti/shared/dist/schemas/api/messages.d.ts +52 -0
  29. package/node_modules/@tutti/shared/dist/schemas/api/messages.js +10 -0
  30. package/node_modules/@tutti/shared/dist/schemas/api/runtime-events.d.ts +1 -0
  31. package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +2 -1
  32. package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.d.ts +14 -0
  33. package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.js +2 -0
  34. package/node_modules/@tutti/shared/dist/schemas/api/work-items.d.ts +3 -0
  35. package/node_modules/@tutti/shared/dist/schemas/api/work-items.js +2 -0
  36. package/package.json +1 -1
  37. package/prompts/prompt-flow-map.md +2 -2
  38. package/prompts/runs/README.md +2 -1
  39. package/prompts/runs/task-continuation.md +8 -2
  40. package/prompts/runs/task-retry.md +8 -2
  41. package/prompts/runs/task-run.md +8 -2
  42. package/web/assets/index-4JInvPEN.js +29 -0
  43. package/web/assets/index-P5uZBm0s.css +1 -0
  44. package/web/index.html +2 -2
  45. package/web/assets/index-BhNJQ717.js +0 -29
  46. package/web/assets/index-mXkNKFjm.css +0 -1
@@ -29,6 +29,9 @@ export function recordRunResult(db, input) {
29
29
  };
30
30
  if (input.result.result_kind === "finished") {
31
31
  detailResult.outcome = input.result.outcome;
32
+ if (input.result.user_note_candidate !== undefined) {
33
+ detailResult.user_note_candidate = input.result.user_note_candidate;
34
+ }
32
35
  detailResult.checks = input.result.checks;
33
36
  detailResult.docs = input.result.docs;
34
37
  if (input.result.skip_reason_code !== undefined) {
@@ -38,6 +38,9 @@ export function mapRunResultRow(row) {
38
38
  result_kind: "finished",
39
39
  outcome: result.outcome === "failed" ? "failed" : "completed",
40
40
  summary: typeof result.summary === "string" ? result.summary : "",
41
+ ...(typeof result.user_note_candidate === "string"
42
+ ? { user_note_candidate: result.user_note_candidate }
43
+ : {}),
41
44
  checks: result.checks === "failed" || result.checks === "skipped" ? result.checks : "passed",
42
45
  docs: result.docs === "checked_no_change" ||
43
46
  result.docs === "not_checked" ||
@@ -120,6 +120,7 @@ export type RecordRunResultInput = {
120
120
  summary: string;
121
121
  checks: "passed" | "failed" | "skipped";
122
122
  docs: "updated" | "checked_no_change" | "not_checked" | "sync_deferred";
123
+ user_note_candidate?: string;
123
124
  skip_reason_code?: TaskDetailResultProjection["skip_reason_code"];
124
125
  skip_reason_summary?: string;
125
126
  external_side_effects?: TaskDetailResultProjection["external_side_effects"];
@@ -313,6 +313,9 @@ export class Phase5ControlPlane {
313
313
  emitWorklistCompletedFeedback({
314
314
  store: this.store,
315
315
  events: this.events,
316
+ ...(this.projectContext === undefined
317
+ ? {}
318
+ : { workspaceRoot: this.projectContext.workspaceRoot }),
316
319
  now: this.now,
317
320
  });
318
321
  this.maybeStartContextSyncAfterWorklistCompletion();
@@ -123,6 +123,7 @@ export type RunPipelineResult = RunPipelineResultMetadata & ({
123
123
  result_kind: "finished";
124
124
  outcome: "completed" | "failed";
125
125
  summary: string;
126
+ user_note_candidate?: string;
126
127
  checks: "passed" | "failed" | "skipped";
127
128
  docs: "updated" | "checked_no_change" | "not_checked" | "sync_deferred";
128
129
  skip_reason_code?: NonNullable<TaskDetailProjection["detail"]["result"]["skip_reason_code"]>;
@@ -5,6 +5,7 @@ import type { WorkspaceEventBus } from "../server-shell/http/workspace-events.js
5
5
  type EmitWorklistFeedbackInput = {
6
6
  store: HostProjectStore;
7
7
  events: WorkspaceEventBus;
8
+ workspaceRoot?: string;
8
9
  now: () => Date;
9
10
  };
10
11
  export declare function emitWorklistCompletedFeedback(input: EmitWorklistFeedbackInput): MessageProjection | null;
@@ -1,3 +1,4 @@
1
+ import { readViewerFile, referenceFileSourceForPath, referenceMediaTypeForPath, referenceTuttiGroupForPath, } from "../workspace-ops/index.js";
1
2
  import { createMainChatAgentMessage, hasMainChatWorklistFeedbackMessage, readCompletedWorklistFeedbackTaskIds, readTaskDetailProjection, readWorklistProjection, } from "../collaboration-state/index.js";
2
3
  import { mainChatInvalidates } from "./invalidations.js";
3
4
  const BODY_ITEM_LIMIT = 12;
@@ -27,6 +28,100 @@ function feedbackItemFromEntry(entry) {
27
28
  }
28
29
  return item;
29
30
  }
31
+ function userNoteCandidateFromEntry(entry) {
32
+ const trimmed = (entry.detail?.detail.result.user_note_candidate ?? "").trim();
33
+ return trimmed.length === 0 ? undefined : trimmed;
34
+ }
35
+ function normalizedUserNoteLine(value) {
36
+ return value.replace(/\s+/gu, " ").trim();
37
+ }
38
+ function finalNoteForCompletedEntries(entries) {
39
+ const notes = entries
40
+ .map(userNoteCandidateFromEntry)
41
+ .filter((note) => note !== undefined)
42
+ .map(normalizedUserNoteLine)
43
+ .filter((note) => note.length > 0);
44
+ if (notes.length === 0) {
45
+ return undefined;
46
+ }
47
+ if (entries.length === 1) {
48
+ return notes[0];
49
+ }
50
+ return `Completed work across ${entries.length} tasks: ${notes.join(" ")}`;
51
+ }
52
+ function shouldInspectGeneratedFiles(entry) {
53
+ const result = entry.detail?.detail.result;
54
+ return (result?.result_kind === "finished" &&
55
+ result.outcome === "completed" &&
56
+ result.promotion?.status === "promoted" &&
57
+ Array.isArray(result.changed_paths));
58
+ }
59
+ function generatedFileProjection(file) {
60
+ const projection = {
61
+ path: file.path,
62
+ name: file.name,
63
+ size_bytes: file.size_bytes,
64
+ };
65
+ const group = referenceTuttiGroupForPath(file.path);
66
+ if (group !== undefined) {
67
+ projection.group = group;
68
+ }
69
+ const mediaType = referenceMediaTypeForPath(file.path);
70
+ if (mediaType !== undefined) {
71
+ projection.media_type = mediaType;
72
+ }
73
+ return projection;
74
+ }
75
+ function readGeneratedFile(input) {
76
+ if (referenceFileSourceForPath(input.path) !== "tutti_output") {
77
+ return null;
78
+ }
79
+ try {
80
+ const file = readViewerFile({
81
+ workspaceRoot: input.workspaceRoot,
82
+ path: input.path,
83
+ maxBytes: 1,
84
+ now: input.now,
85
+ });
86
+ return generatedFileProjection(file.file);
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ }
92
+ function generatedFilesForCompletedEntries(input, entries) {
93
+ const workspaceRoot = input.workspaceRoot;
94
+ if (workspaceRoot === undefined) {
95
+ return [];
96
+ }
97
+ const paths = new Set();
98
+ for (const entry of entries) {
99
+ if (!shouldInspectGeneratedFiles(entry)) {
100
+ continue;
101
+ }
102
+ for (const path of entry.detail?.detail.result.changed_paths ?? []) {
103
+ if (referenceFileSourceForPath(path) === "tutti_output") {
104
+ paths.add(path);
105
+ }
106
+ }
107
+ }
108
+ return [...paths]
109
+ .map((path) => readGeneratedFile({
110
+ workspaceRoot,
111
+ path,
112
+ now: input.now,
113
+ }))
114
+ .filter((file) => file !== null)
115
+ .sort((left, right) => {
116
+ const groupOrder = (left.group ?? "").localeCompare(right.group ?? "", "en", {
117
+ sensitivity: "base",
118
+ });
119
+ if (groupOrder !== 0) {
120
+ return groupOrder;
121
+ }
122
+ return left.name.localeCompare(right.name, "en", { sensitivity: "base" });
123
+ });
124
+ }
30
125
  function feedbackCounters(entries) {
31
126
  const completed = entries.filter((entry) => entry.task.status === "done").length;
32
127
  const failed = entries.filter((entry) => entry.task.status === "failed").length;
@@ -51,6 +146,16 @@ function taskCountLabel(count) {
51
146
  }
52
147
  function markdownFallback(feedback) {
53
148
  const lines = [feedback.title, ""];
149
+ if (feedback.final_note !== undefined && feedback.final_note.trim().length > 0) {
150
+ lines.push(feedback.final_note.trim(), "");
151
+ }
152
+ if (feedback.generated_files !== undefined && feedback.generated_files.length > 0) {
153
+ lines.push("Generated files:");
154
+ for (const file of feedback.generated_files) {
155
+ lines.push(`- ${file.name}`);
156
+ }
157
+ lines.push("");
158
+ }
54
159
  const visibleItems = feedback.items.slice(0, BODY_ITEM_LIMIT);
55
160
  for (const item of visibleItems) {
56
161
  const prefix = item.status === "done" ? "- Done" : "- Failed";
@@ -102,6 +207,8 @@ export function emitWorklistCompletedFeedback(input) {
102
207
  return null;
103
208
  }
104
209
  const items = newCompletedEntries.map(feedbackItemFromEntry);
210
+ const finalNote = finalNoteForCompletedEntries(newCompletedEntries);
211
+ const generatedFiles = generatedFilesForCompletedEntries(input, newCompletedEntries);
105
212
  const feedback = {
106
213
  kind: "worklist_terminal",
107
214
  status: "completed",
@@ -110,6 +217,8 @@ export function emitWorklistCompletedFeedback(input) {
110
217
  feedback_key: completedFeedbackKey(items),
111
218
  counters: feedbackCounters(newCompletedEntries),
112
219
  items,
220
+ ...(finalNote === undefined ? {} : { final_note: finalNote }),
221
+ ...(generatedFiles.length === 0 ? {} : { generated_files: generatedFiles }),
113
222
  };
114
223
  return publishFeedbackMessage(input, feedback);
115
224
  }
@@ -332,6 +332,9 @@ async function runTaskAttempt(options, input) {
332
332
  if (changedPaths.length === 0 && taskOutput.decision === "completed_no_repo_changes") {
333
333
  return completedWithoutRepoChanges({
334
334
  summary: taskOutput.summary,
335
+ ...(taskOutput.user_note_candidate === undefined
336
+ ? {}
337
+ : { userNoteCandidate: taskOutput.user_note_candidate }),
335
338
  });
336
339
  }
337
340
  if (changedPaths.length === 0) {
@@ -424,6 +427,9 @@ async function runTaskAttempt(options, input) {
424
427
  checks,
425
428
  completion: "Promotion complete.",
426
429
  }),
430
+ ...(taskOutput.user_note_candidate === undefined
431
+ ? {}
432
+ : { user_note_candidate: taskOutput.user_note_candidate }),
427
433
  checks: checkStatus(checks),
428
434
  docs,
429
435
  ...checkSkipFields(checks),
@@ -1,12 +1,12 @@
1
1
  import type { RunPipelineInput, RunPipelineResult } from "../control-plane/index.js";
2
2
  import { type ResultCommit, type RunWorkspaceHandle } from "../workspace-ops/index.js";
3
3
  import type { OpenAiRunPipelineRunnerOptions } from "./openai.js";
4
- import type { TaskRunOutput } from "./task-run-output.js";
4
+ import type { CompletedNoRepoChangesTaskRunOutput, CompletedTaskRunOutput } from "./task-run-output.js";
5
5
  export declare function runPromotionReconcile(input: {
6
6
  options: OpenAiRunPipelineRunnerOptions;
7
7
  pipelineInput: RunPipelineInput;
8
8
  runHandle: RunWorkspaceHandle;
9
- taskOutput: TaskRunOutput;
9
+ taskOutput: CompletedTaskRunOutput | CompletedNoRepoChangesTaskRunOutput;
10
10
  sourceCommit: ResultCommit;
11
11
  changedPaths: string[];
12
12
  }): Promise<RunPipelineResult>;
@@ -93,6 +93,9 @@ export async function runPromotionReconcile(input) {
93
93
  checks,
94
94
  completion: "Promotion reconciled and complete.",
95
95
  }),
96
+ ...(input.taskOutput.user_note_candidate === undefined
97
+ ? {}
98
+ : { user_note_candidate: input.taskOutput.user_note_candidate }),
96
99
  checks: checkStatus(checks),
97
100
  docs,
98
101
  ...checkSkipFields(checks),
@@ -35,5 +35,6 @@ export declare function failedBeforeChecks(input: {
35
35
  }): RunPipelineResult;
36
36
  export declare function completedWithoutRepoChanges(input: {
37
37
  summary: string;
38
+ userNoteCandidate?: string;
38
39
  }): RunPipelineResult;
39
40
  //# sourceMappingURL=result-projections.d.ts.map
@@ -104,6 +104,9 @@ export function completedWithoutRepoChanges(input) {
104
104
  result_kind: "finished",
105
105
  outcome: "completed",
106
106
  summary: input.summary,
107
+ ...(input.userNoteCandidate === undefined
108
+ ? {}
109
+ : { user_note_candidate: input.userNoteCandidate }),
107
110
  checks: "skipped",
108
111
  docs: "checked_no_change",
109
112
  skip_reason_code: "validation_not_applicable",
@@ -5,10 +5,12 @@ export type InitialTaskRunOutput = {
5
5
  result: {
6
6
  completed: {
7
7
  summary: string;
8
+ user_note_candidate: string | null;
8
9
  };
9
10
  } | {
10
11
  completed_no_repo_changes: {
11
12
  summary: string;
13
+ user_note_candidate: string | null;
12
14
  };
13
15
  } | {
14
16
  needs_human: ClarificationRequestPayload;
@@ -18,13 +20,17 @@ export type InitialTaskRunOutput = {
18
20
  };
19
21
  };
20
22
  };
21
- export type TaskRunOutput = {
23
+ export type CompletedTaskRunOutput = {
22
24
  decision: "completed";
23
25
  summary: string;
24
- } | {
26
+ user_note_candidate?: string;
27
+ };
28
+ export type CompletedNoRepoChangesTaskRunOutput = {
25
29
  decision: "completed_no_repo_changes";
26
30
  summary: string;
27
- } | {
31
+ user_note_candidate?: string;
32
+ };
33
+ export type TaskRunOutput = CompletedTaskRunOutput | CompletedNoRepoChangesTaskRunOutput | {
28
34
  decision: "needs_human";
29
35
  summary: string;
30
36
  clarification_request_payload: ClarificationRequestPayload;
@@ -22,10 +22,13 @@ export const TASK_RUN_OUTPUT_SCHEMA = {
22
22
  properties: {
23
23
  completed: {
24
24
  type: "object",
25
- required: ["summary"],
25
+ required: ["summary", "user_note_candidate"],
26
26
  additionalProperties: false,
27
27
  properties: {
28
28
  summary: { type: "string" },
29
+ user_note_candidate: {
30
+ anyOf: [{ type: "string" }, { type: "null" }],
31
+ },
29
32
  },
30
33
  },
31
34
  },
@@ -37,10 +40,13 @@ export const TASK_RUN_OUTPUT_SCHEMA = {
37
40
  properties: {
38
41
  completed_no_repo_changes: {
39
42
  type: "object",
40
- required: ["summary"],
43
+ required: ["summary", "user_note_candidate"],
41
44
  additionalProperties: false,
42
45
  properties: {
43
46
  summary: { type: "string" },
47
+ user_note_candidate: {
48
+ anyOf: [{ type: "string" }, { type: "null" }],
49
+ },
44
50
  },
45
51
  },
46
52
  },
@@ -96,6 +102,16 @@ function isSummaryRecord(value) {
96
102
  Object.keys(value).every((key) => key === "summary") &&
97
103
  typeof value.summary === "string");
98
104
  }
105
+ function isCompletedRecord(value) {
106
+ return (isRecord(value) &&
107
+ Object.keys(value).every((key) => key === "summary" || key === "user_note_candidate") &&
108
+ typeof value.summary === "string" &&
109
+ (typeof value.user_note_candidate === "string" || value.user_note_candidate === null));
110
+ }
111
+ function normalizedUserNoteCandidate(value) {
112
+ const trimmed = (value ?? "").trim();
113
+ return trimmed.length === 0 ? undefined : trimmed;
114
+ }
99
115
  export function isInitialTaskRunOutput(value) {
100
116
  if (!isRecord(value) || !isRecord(value.result) || Object.keys(value).length !== 1) {
101
117
  return false;
@@ -105,10 +121,10 @@ export function isInitialTaskRunOutput(value) {
105
121
  return false;
106
122
  }
107
123
  if ("completed" in value.result) {
108
- return isSummaryRecord(value.result.completed);
124
+ return isCompletedRecord(value.result.completed);
109
125
  }
110
126
  if ("completed_no_repo_changes" in value.result) {
111
- return isSummaryRecord(value.result.completed_no_repo_changes);
127
+ return isCompletedRecord(value.result.completed_no_repo_changes);
112
128
  }
113
129
  if ("needs_human" in value.result) {
114
130
  return isTaskRunClarificationRequestPayload(value.result.needs_human);
@@ -120,15 +136,19 @@ export function isInitialTaskRunOutput(value) {
120
136
  }
121
137
  export function normalizeTaskRunOutput(output) {
122
138
  if ("completed" in output.result) {
139
+ const userNoteCandidate = normalizedUserNoteCandidate(output.result.completed.user_note_candidate);
123
140
  return {
124
141
  decision: "completed",
125
142
  summary: output.result.completed.summary,
143
+ ...(userNoteCandidate === undefined ? {} : { user_note_candidate: userNoteCandidate }),
126
144
  };
127
145
  }
128
146
  if ("completed_no_repo_changes" in output.result) {
147
+ const userNoteCandidate = normalizedUserNoteCandidate(output.result.completed_no_repo_changes.user_note_candidate);
129
148
  return {
130
149
  decision: "completed_no_repo_changes",
131
150
  summary: output.result.completed_no_repo_changes.summary,
151
+ ...(userNoteCandidate === undefined ? {} : { user_note_candidate: userNoteCandidate }),
132
152
  };
133
153
  }
134
154
  if ("needs_human" in output.result) {
@@ -78,6 +78,7 @@ export declare const HOST_PROJECT_EXECUTION_OPENAPI_ROUTES: ({
78
78
  finished_at: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
79
79
  }>>>;
80
80
  changed_paths: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
81
+ user_note_candidate: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
81
82
  promotion: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
82
83
  status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"promoted">, import("@sinclair/typebox").TLiteral<"not_promoted">, import("@sinclair/typebox").TLiteral<"not_attempted">]>;
83
84
  summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -283,12 +283,14 @@ export declare const HOST_PROJECT_VIEWER_OPENAPI_ROUTES: ({
283
283
  index_path: import("@sinclair/typebox").TLiteral<"docs/reference/README.md">;
284
284
  files_path: import("@sinclair/typebox").TLiteral<"docs/reference/files">;
285
285
  images_path: import("@sinclair/typebox").TLiteral<"docs/reference/images">;
286
+ tutti_path: import("@sinclair/typebox").TLiteral<"docs/reference/tutti">;
286
287
  index_status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"available">, import("@sinclair/typebox").TLiteral<"missing">, import("@sinclair/typebox").TLiteral<"unreadable">]>;
287
288
  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">]>>;
288
289
  }>;
289
290
  items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
290
291
  path: import("@sinclair/typebox").TString;
291
292
  name: import("@sinclair/typebox").TString;
293
+ source: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"human_upload">, import("@sinclair/typebox").TLiteral<"tutti_output">]>;
292
294
  category: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"file">, import("@sinclair/typebox").TLiteral<"image">]>;
293
295
  size_bytes: import("@sinclair/typebox").TInteger;
294
296
  media_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -701,6 +701,7 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
701
701
  finished_at: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
702
702
  }>>>;
703
703
  changed_paths: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
704
+ user_note_candidate: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
704
705
  promotion: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
705
706
  status: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"promoted">, import("@sinclair/typebox").TLiteral<"not_promoted">, import("@sinclair/typebox").TLiteral<"not_attempted">]>;
706
707
  summary: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -1,4 +1,4 @@
1
- import { REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, VIEWER_HARD_READ_LIMIT_BYTES, WorkspaceOpsError, readViewerFile, readViewerSnapshot, readViewerTree, readReferenceSummaryIndex, referenceFileCategoryForPath, referenceMediaTypeForPath, referenceSummaryProjectionForEntry, } from "../../../../workspace-ops/index.js";
1
+ import { REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, REFERENCE_TUTTI_DIRECTORY_PATH, VIEWER_HARD_READ_LIMIT_BYTES, WorkspaceOpsError, readViewerFile, readViewerSnapshot, readViewerTree, readReferenceSummaryIndex, referenceFileCategoryForPath, referenceFileSourceForPath, referenceMediaTypeForPath, referenceSummaryProjectionForEntry, } from "../../../../workspace-ops/index.js";
2
2
  import { paginateViewerItems, viewerPageLimit } from "./viewer-projections.js";
3
3
  function unreadableReasonForReferenceContent(content) {
4
4
  if (content.kind === "text") {
@@ -34,6 +34,7 @@ export function toReferenceFileProjection(options) {
34
34
  path: options.entry.path,
35
35
  name: options.entry.name,
36
36
  category,
37
+ source: referenceFileSourceForPath(options.entry.path) ?? "human_upload",
37
38
  size_bytes: options.entry.size_bytes ?? 0,
38
39
  text_read: referenceTextReadProjection(options.workspaceRoot, options.entry, options.now),
39
40
  summary: referenceSummaryProjectionForEntry({
@@ -64,6 +65,7 @@ function referenceDirectoryProjection(options) {
64
65
  index_path: REFERENCE_INDEX_PATH,
65
66
  files_path: REFERENCE_FILES_DIRECTORY_PATH,
66
67
  images_path: REFERENCE_IMAGES_DIRECTORY_PATH,
68
+ tutti_path: REFERENCE_TUTTI_DIRECTORY_PATH,
67
69
  index_status: "missing",
68
70
  };
69
71
  }
@@ -80,6 +82,7 @@ function referenceDirectoryProjection(options) {
80
82
  index_path: REFERENCE_INDEX_PATH,
81
83
  files_path: REFERENCE_FILES_DIRECTORY_PATH,
82
84
  images_path: REFERENCE_IMAGES_DIRECTORY_PATH,
85
+ tutti_path: REFERENCE_TUTTI_DIRECTORY_PATH,
83
86
  index_status: "available",
84
87
  };
85
88
  }
@@ -89,6 +92,7 @@ function referenceDirectoryProjection(options) {
89
92
  index_path: REFERENCE_INDEX_PATH,
90
93
  files_path: REFERENCE_FILES_DIRECTORY_PATH,
91
94
  images_path: REFERENCE_IMAGES_DIRECTORY_PATH,
95
+ tutti_path: REFERENCE_TUTTI_DIRECTORY_PATH,
92
96
  index_status: "unreadable",
93
97
  index_unreadable_reason: file.content.reason,
94
98
  };
@@ -101,6 +105,7 @@ function referenceDirectoryProjection(options) {
101
105
  index_path: REFERENCE_INDEX_PATH,
102
106
  files_path: REFERENCE_FILES_DIRECTORY_PATH,
103
107
  images_path: REFERENCE_IMAGES_DIRECTORY_PATH,
108
+ tutti_path: REFERENCE_TUTTI_DIRECTORY_PATH,
104
109
  index_status: "missing",
105
110
  };
106
111
  }
@@ -119,7 +124,7 @@ export function readReferenceFilesResponse(options, query) {
119
124
  tree = readViewerTree({
120
125
  workspaceRoot,
121
126
  path: REFERENCE_DIRECTORY_PATH,
122
- depth: 2,
127
+ depth: 3,
123
128
  ...(now === undefined ? {} : { now }),
124
129
  });
125
130
  }
@@ -147,7 +152,7 @@ export function readReferenceFilesResponse(options, query) {
147
152
  .filter((entry) => entry.kind === "file")
148
153
  .filter((entry) => includeIndex || entry.path !== REFERENCE_INDEX_PATH)
149
154
  .filter((entry) => entry.path === REFERENCE_INDEX_PATH ||
150
- referenceFileCategoryForPath(entry.path) !== undefined)
155
+ referenceFileSourceForPath(entry.path) !== undefined)
151
156
  .sort((left, right) => {
152
157
  const leftCategory = referenceFileCategoryForPath(left.path) ?? "file";
153
158
  const rightCategory = referenceFileCategoryForPath(right.path) ?? "file";
@@ -197,6 +202,7 @@ export function referenceFileMessageRef(file) {
197
202
  const ref = {
198
203
  path: file.path,
199
204
  name: file.name,
205
+ source: file.source,
200
206
  category: file.category,
201
207
  size_bytes: file.size_bytes,
202
208
  text_read: file.text_read,
@@ -5,6 +5,7 @@ export declare const VIEWER_HARD_READ_LIMIT_BYTES: number;
5
5
  export declare const REFERENCE_DIRECTORY_PATH: "docs/reference";
6
6
  export declare const REFERENCE_FILES_DIRECTORY_PATH: "docs/reference/files";
7
7
  export declare const REFERENCE_IMAGES_DIRECTORY_PATH: "docs/reference/images";
8
+ export declare const REFERENCE_TUTTI_DIRECTORY_PATH: "docs/reference/tutti";
8
9
  export declare const REFERENCE_INDEX_PATH: "docs/reference/README.md";
9
10
  export declare const MAX_REFERENCE_UPLOAD_BYTES: number;
10
11
  export declare const VIEWER_ASSET_READ_LIMIT_BYTES: number;
@@ -5,6 +5,7 @@ export const VIEWER_HARD_READ_LIMIT_BYTES = 5 * 1024 * 1024;
5
5
  export const REFERENCE_DIRECTORY_PATH = "docs/reference";
6
6
  export const REFERENCE_FILES_DIRECTORY_PATH = "docs/reference/files";
7
7
  export const REFERENCE_IMAGES_DIRECTORY_PATH = "docs/reference/images";
8
+ export const REFERENCE_TUTTI_DIRECTORY_PATH = "docs/reference/tutti";
8
9
  export const REFERENCE_INDEX_PATH = "docs/reference/README.md";
9
10
  export const MAX_REFERENCE_UPLOAD_BYTES = 10 * 1024 * 1024;
10
11
  export const VIEWER_ASSET_READ_LIMIT_BYTES = MAX_REFERENCE_UPLOAD_BYTES;
@@ -1,8 +1,8 @@
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";
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, REFERENCE_TUTTI_DIRECTORY_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 { initializeProjectDocs, readProjectDocsInitializationStatus, syncProjectDocs, } from "./project-docs.js";
4
4
  export { uploadReferenceFile } from "./reference-files.js";
5
- export { referenceFileCategoryForPath, referenceMediaTypeForPath } from "./reference-metadata.js";
5
+ export { referenceFileCategoryForPath, referenceFileSourceForPath, referenceMediaTypeForPath, referenceTuttiGroupForPath, } from "./reference-metadata.js";
6
6
  export { readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
7
7
  export { applyRunResultToMergeWorkspace, cleanupMergeWorkspace, cleanupRunWorkspace, cleanupStaleRunWorkspaces, collectMergeDiff, collectRunDiff, createMergeCandidateCommit, createResultCommit, prepareMergeWorkspace, prepareRunWorkspace, promoteMergeCandidate, promoteRunResult, } from "./run-workspaces.js";
8
8
  export { readViewerAsset, readViewerFile, readViewerSnapshot, readViewerTree } from "./viewer.js";
@@ -1,8 +1,8 @@
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";
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, REFERENCE_TUTTI_DIRECTORY_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 { initializeProjectDocs, readProjectDocsInitializationStatus, syncProjectDocs, } from "./project-docs.js";
4
4
  export { uploadReferenceFile } from "./reference-files.js";
5
- export { referenceFileCategoryForPath, referenceMediaTypeForPath } from "./reference-metadata.js";
5
+ export { referenceFileCategoryForPath, referenceFileSourceForPath, referenceMediaTypeForPath, referenceTuttiGroupForPath, } from "./reference-metadata.js";
6
6
  export { readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
7
7
  export { applyRunResultToMergeWorkspace, cleanupMergeWorkspace, cleanupRunWorkspace, cleanupStaleRunWorkspaces, collectMergeDiff, collectRunDiff, createMergeCandidateCommit, createResultCommit, prepareMergeWorkspace, prepareRunWorkspace, promoteMergeCandidate, promoteRunResult, } from "./run-workspaces.js";
8
8
  export { readViewerAsset, readViewerFile, readViewerSnapshot, readViewerTree } from "./viewer.js";
@@ -9,5 +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 referenceFileSourceForPath(path: string): "human_upload" | "tutti_output" | undefined;
13
+ export declare function referenceTuttiGroupForPath(path: string): string | undefined;
12
14
  export declare function referenceMediaTypeForPath(path: string): string | undefined;
13
15
  //# sourceMappingURL=reference-metadata.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { extname, posix } from "node:path";
2
- import { REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, } from "./constants.js";
2
+ import { REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, REFERENCE_TUTTI_DIRECTORY_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) {
@@ -57,11 +57,36 @@ export function referenceFileCategoryForPath(path) {
57
57
  if (path.startsWith(`${REFERENCE_FILES_DIRECTORY_PATH}/`)) {
58
58
  return "file";
59
59
  }
60
+ if (path.startsWith(`${REFERENCE_TUTTI_DIRECTORY_PATH}/`)) {
61
+ return "file";
62
+ }
60
63
  if (posix.dirname(path) === REFERENCE_DIRECTORY_PATH && path !== REFERENCE_INDEX_PATH) {
61
64
  return "file";
62
65
  }
63
66
  return undefined;
64
67
  }
68
+ export function referenceFileSourceForPath(path) {
69
+ if (path.startsWith(`${REFERENCE_TUTTI_DIRECTORY_PATH}/`)) {
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;
78
+ }
79
+ export function referenceTuttiGroupForPath(path) {
80
+ if (!path.startsWith(`${REFERENCE_TUTTI_DIRECTORY_PATH}/`)) {
81
+ return undefined;
82
+ }
83
+ const rest = path.slice(REFERENCE_TUTTI_DIRECTORY_PATH.length + 1);
84
+ const [first, second] = rest.split("/");
85
+ if (first === undefined || first.length === 0 || second === undefined) {
86
+ return undefined;
87
+ }
88
+ return first;
89
+ }
65
90
  export function referenceMediaTypeForPath(path) {
66
91
  const extension = extname(path).toLowerCase();
67
92
  switch (extension) {
@@ -516,6 +516,7 @@ export declare const SendClarificationRoundMessageResultSchema: import("@sinclai
516
516
  reference_file: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
517
517
  path: import("@sinclair/typebox").TString;
518
518
  name: import("@sinclair/typebox").TString;
519
+ source: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"human_upload">, import("@sinclair/typebox").TLiteral<"tutti_output">]>;
519
520
  category: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"file">, import("@sinclair/typebox").TLiteral<"image">]>;
520
521
  blob_oid: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
521
522
  media_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -544,6 +545,14 @@ export declare const SendClarificationRoundMessageResultSchema: import("@sinclai
544
545
  module_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
545
546
  latest_run_result_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
546
547
  }>>;
548
+ final_note: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
549
+ generated_files: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
550
+ path: import("@sinclair/typebox").TString;
551
+ name: import("@sinclair/typebox").TString;
552
+ group: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
553
+ size_bytes: import("@sinclair/typebox").TInteger;
554
+ media_type: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
555
+ }>>>;
547
556
  primary_task_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
548
557
  }>>;
549
558
  }>>;
@@ -6,7 +6,7 @@ export { ProviderUsageBreakdownProjectionSchema, ProviderUsageCategorySchema, Pr
6
6
  export { ProjectTimelineItemKindSchema, ProjectTimelineItemSchema, ProjectTimelineItemStatusSchema, ProjectTimelineResponseSchema, } from "./project-timeline.js";
7
7
  export { MAX_REFERENCE_STAGED_UPLOAD_BYTES, MAX_SKILL_ZIP_STAGED_UPLOAD_BYTES, MAX_STAGED_UPLOAD_BYTES, PresignedUploadPutSchema, ReferenceFileStartRelayUploadPayloadSchema, ReferenceStagedUploadReferenceProperties, RelayUploadProjectionSchema, RelayUploadPurposeSchema, Sha256DigestSchema, SkillZipStartRelayUploadPayloadSchema, SkillZipStagedUploadReferenceProperties, StagedUploadReferenceProperties, StagedUploadReferenceSchema, StartRelayUploadBodySchema, StartRelayUploadDispositionSchema, StartRelayUploadPayloadSchema, StartRelayUploadResponseSchema, StartRelayUploadResultSchema, maxStagedUploadBytesForPurpose, } from "./uploads.js";
8
8
  export { MarkReadBodySchema, MarkReadDispositionSchema, MarkReadPayloadSchema, MarkReadResponseSchema, MarkReadResultSchema, ReadStateScopeProjectionSchema, ReadStateScopeSchema, ReadStateSummaryProjectionSchema, } from "./read-state.js";
9
- export { GetMessagesRequestSchema, MessageAuthorSchema, MessageCreatedEventPayloadSchema, MessageKindSchema, MessageProjectionSchema, MessageReferenceFileRefSchema, MessageRefsSchema, MessageScopeSchema, MessageWindowSchema, ReferenceFileCategorySchema, SendMainChatMessageBodySchema, SendMainChatMessageCreatedDispositionSchema, SendMainChatMessageDispositionSchema, SendMainChatMessagePayloadSchema, SendMainChatMessageResponseSchema, SendMainChatMessageResultSchema, WorklistFeedbackItemSchema, WorklistFeedbackRefSchema, } from "./messages.js";
9
+ export { GetMessagesRequestSchema, MessageAuthorSchema, MessageCreatedEventPayloadSchema, MessageKindSchema, MessageProjectionSchema, MessageReferenceFileRefSchema, MessageRefsSchema, MessageScopeSchema, MessageWindowSchema, ReferenceFileCategorySchema, SendMainChatMessageBodySchema, SendMainChatMessageCreatedDispositionSchema, SendMainChatMessageDispositionSchema, SendMainChatMessagePayloadSchema, SendMainChatMessageResponseSchema, SendMainChatMessageResultSchema, WorklistFeedbackItemSchema, WorklistFeedbackGeneratedFileSchema, WorklistFeedbackRefSchema, } from "./messages.js";
10
10
  export { CheckSkipReasonCodeSchema, ExternalSideEffectSummaryProjectionSchema, GetRecoverySummariesRequestSchema, GetRecoverySummariesResponseSchema, GetRecoverySummaryResponseSchema, RecoverySummaryProjectionSchema, ResultAnchorSchema, RunLineageSchema, RunResultProjectionSchema, ScratchpadProjectionSchema, ScratchpadReceiptProjectionSchema, TaskContractProjectionSchema, TaskDetailProjectionSchema, TaskDetailResultProjectionSchema, TaskModuleProjectionSchema, TaskProjectionSchema, TaskRunResultsPageSchema, TaskStatusSchema, WorklistProjectionSchema, } from "./work-items.js";
11
11
  export { ActiveApprovalProjectionSchema, ApprovalCommandProjectionSchema, ApprovalDecisionKindSchema, ApprovalDecisionOptionProjectionSchema, ApprovalDecisionToneSchema, ApprovalFileChangeProjectionSchema, ApprovalPermissionsProjectionSchema, ApprovalRequestKindSchema, ApprovalRequestProjectionSchema, ApprovalResolutionOutcomeSchema, ApprovalResolutionProjectionSchema, DecideApprovalBodySchema, DecideApprovalDispositionSchema, DecideApprovalPayloadSchema, DecideApprovalResponseSchema, DecideApprovalResultSchema, } from "./approvals.js";
12
12
  export { ActiveClarificationProjectionSchema, ClarificationChangedEventPayloadSchema, ClarificationOwnerProjectionSchema, ClarificationRequestPayloadSchema, ClarificationRoundProjectionSchema, ClarificationRoundSummaryProjectionSchema, ClarificationSuccessorRefSchema, ClarificationThreadProjectionSchema, ContextRefSchema, GetClarificationRoundMessagesRequestSchema, GetClarificationRoundResponseSchema, GetClarificationThreadResponseSchema, HumanInteractionPayloadSchema, HumanRequestPayloadSchema, SendClarificationRoundMessageBodySchema, SendClarificationRoundMessageDispositionSchema, SendClarificationRoundMessagePayloadSchema, SendClarificationRoundMessageResponseSchema, SendClarificationRoundMessageResultSchema, SubmitClarificationRoundBodySchema, SubmitClarificationRoundDispositionSchema, SubmitClarificationRoundPayloadSchema, SubmitClarificationRoundResponseSchema, SubmitClarificationRoundResultSchema, } from "./clarifications.js";