@xfey/tutti 0.1.97 → 0.1.99

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 (61) hide show
  1. package/README.md +2 -1
  2. package/dist/artifact-feedback/index.d.ts +19 -0
  3. package/dist/artifact-feedback/index.js +196 -0
  4. package/dist/chat-assistant/index.js +5 -4
  5. package/dist/collaboration-state/task-compile-context.d.ts +1 -1
  6. package/dist/control-plane/index.js +15 -3
  7. package/dist/control-plane/scratchpad-source-messages.js +2 -1
  8. package/dist/control-plane/task-source-context.js +3 -2
  9. package/dist/control-plane/worklist-terminal-feedback.js +4 -4
  10. package/dist/server-shell/http/routes/agent-context-references.js +8 -14
  11. package/dist/server-shell/http/routes/project-api/artifacts-routes.d.ts +2 -1
  12. package/dist/server-shell/http/routes/project-api/artifacts-routes.js +1 -0
  13. package/dist/server-shell/http/routes/project-api/messages-routes.d.ts +3 -1
  14. package/dist/server-shell/http/routes/project-api/messages-routes.js +61 -29
  15. package/dist/server-shell/http/routes/project-api/openapi-viewer-routes.d.ts +0 -2
  16. package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +8 -2
  17. package/dist/server-shell/http/routes/project-api/openapi.d.ts +8 -2
  18. package/dist/server-shell/http/routes/project-api/payload-validation.js +12 -0
  19. package/dist/server-shell/http/routes/project-api/reference-files.js +6 -17
  20. package/dist/server-shell/http/routes/project-api/schemas.d.ts +8 -2
  21. package/dist/server-shell/http/routes/project-api/schemas.js +2 -0
  22. package/dist/server-shell/http/routes/project-api/types.d.ts +1 -0
  23. package/dist/server-shell/http/routes/project-api/workspace-projections.js +1 -0
  24. package/dist/server-shell/http/routes/project-api.js +2 -2
  25. package/dist/workspace-ops/constants.d.ts +0 -1
  26. package/dist/workspace-ops/constants.js +0 -1
  27. package/dist/workspace-ops/index.d.ts +3 -2
  28. package/dist/workspace-ops/index.js +3 -2
  29. package/dist/workspace-ops/project-doc-templates.js +1 -1
  30. package/dist/workspace-ops/reference-files.js +3 -2
  31. package/dist/workspace-ops/reference-metadata.d.ts +2 -2
  32. package/dist/workspace-ops/reference-metadata.js +8 -22
  33. package/dist/workspace-ops/reference-summaries.js +11 -17
  34. package/dist/workspace-ops/reference-tree.d.ts +11 -0
  35. package/dist/workspace-ops/reference-tree.js +34 -0
  36. package/dist/workspace-ops/viewer-git.d.ts +1 -0
  37. package/dist/workspace-ops/viewer-git.js +11 -0
  38. package/node_modules/@tutti/shared/dist/schemas/api/artifact-feedback.d.ts +374 -0
  39. package/node_modules/@tutti/shared/dist/schemas/api/artifact-feedback.js +83 -0
  40. package/node_modules/@tutti/shared/dist/schemas/api/clarifications.d.ts +86 -0
  41. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +2 -1
  42. package/node_modules/@tutti/shared/dist/schemas/api/index.js +2 -1
  43. package/node_modules/@tutti/shared/dist/schemas/api/messages.d.ts +441 -2
  44. package/node_modules/@tutti/shared/dist/schemas/api/messages.js +17 -3
  45. package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +13 -1
  46. package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.d.ts +86 -5
  47. package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.js +0 -2
  48. package/package.json +1 -1
  49. package/prompts/procedures/context-sync.md +3 -3
  50. package/prompts/procedures/reference-file-summary.md +1 -1
  51. package/prompts/procedures/task-compile.md +2 -2
  52. package/prompts/prompt-flow-map.md +1 -1
  53. package/prompts/runs/task-execute.md +2 -2
  54. package/prompts/skills/read-references/SKILL.md +2 -2
  55. package/web/assets/homepage-motion-scene-BtMS4SCZ.js +1 -0
  56. package/web/assets/index-DtZ_5QLQ.js +69 -0
  57. package/web/assets/index-JY06YzFV.css +1 -0
  58. package/web/index.html +2 -2
  59. package/web/assets/homepage-motion-scene-lpr-1FjJ.js +0 -1
  60. package/web/assets/index-CQoq2PtU.js +0 -69
  61. package/web/assets/index-quWLFJgD.css +0 -1
@@ -585,7 +585,7 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
585
585
  };
586
586
  readonly capabilities: {
587
587
  readonly type: "object";
588
- readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification"];
588
+ readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification", "artifact_feedback"];
589
589
  readonly additionalProperties: false;
590
590
  readonly properties: {
591
591
  readonly sse: {
@@ -616,6 +616,9 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
616
616
  readonly clarification: {
617
617
  readonly type: "boolean";
618
618
  };
619
+ readonly artifact_feedback: {
620
+ readonly type: "boolean";
621
+ };
619
622
  };
620
623
  };
621
624
  };
@@ -776,7 +779,7 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
776
779
  };
777
780
  readonly capabilities: {
778
781
  readonly type: "object";
779
- readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification"];
782
+ readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification", "artifact_feedback"];
780
783
  readonly additionalProperties: false;
781
784
  readonly properties: {
782
785
  readonly sse: {
@@ -807,6 +810,9 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
807
810
  readonly clarification: {
808
811
  readonly type: "boolean";
809
812
  };
813
+ readonly artifact_feedback: {
814
+ readonly type: "boolean";
815
+ };
810
816
  };
811
817
  };
812
818
  };
@@ -1868,7 +1868,7 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
1868
1868
  };
1869
1869
  readonly capabilities: {
1870
1870
  readonly type: "object";
1871
- readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification"];
1871
+ readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification", "artifact_feedback"];
1872
1872
  readonly additionalProperties: false;
1873
1873
  readonly properties: {
1874
1874
  readonly sse: {
@@ -1899,6 +1899,9 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
1899
1899
  readonly clarification: {
1900
1900
  readonly type: "boolean";
1901
1901
  };
1902
+ readonly artifact_feedback: {
1903
+ readonly type: "boolean";
1904
+ };
1902
1905
  };
1903
1906
  };
1904
1907
  };
@@ -2059,7 +2062,7 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
2059
2062
  };
2060
2063
  readonly capabilities: {
2061
2064
  readonly type: "object";
2062
- readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification"];
2065
+ readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification", "artifact_feedback"];
2063
2066
  readonly additionalProperties: false;
2064
2067
  readonly properties: {
2065
2068
  readonly sse: {
@@ -2090,6 +2093,9 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
2090
2093
  readonly clarification: {
2091
2094
  readonly type: "boolean";
2092
2095
  };
2096
+ readonly artifact_feedback: {
2097
+ readonly type: "boolean";
2098
+ };
2093
2099
  };
2094
2100
  };
2095
2101
  };
@@ -1,3 +1,4 @@
1
+ import { ArtifactFeedbackValidationError, normalizeArtifactFeedbackCommand, } from "../../../../artifact-feedback/index.js";
1
2
  import { HostProjectBadRequestError, HostProjectValidationError } from "./errors.js";
2
3
  export function requireValidMessageWindowRequest(query) {
3
4
  if (query.before !== undefined && query.after !== undefined) {
@@ -9,6 +10,17 @@ export function requireValidMessageWindowRequest(query) {
9
10
  return query;
10
11
  }
11
12
  export function requireValidSendMainChatPayload(payload) {
13
+ if ("artifact_feedback" in payload) {
14
+ try {
15
+ return { artifact_feedback: normalizeArtifactFeedbackCommand(payload.artifact_feedback) };
16
+ }
17
+ catch (error) {
18
+ if (error instanceof ArtifactFeedbackValidationError) {
19
+ throw new HostProjectValidationError(error.message);
20
+ }
21
+ throw error;
22
+ }
23
+ }
12
24
  if (payload.body.trim() === "") {
13
25
  throw new HostProjectValidationError("Message body cannot be empty");
14
26
  }
@@ -1,4 +1,4 @@
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";
1
+ import { REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, VIEWER_HARD_READ_LIMIT_BYTES, WorkspaceOpsError, readReferenceFileEntries, readReferenceSummaryIndex, readViewerFile, readViewerSnapshot, referenceFileCategoryForPath, 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,7 +34,6 @@ 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",
38
37
  size_bytes: options.entry.size_bytes ?? 0,
39
38
  text_read: referenceTextReadProjection(options.workspaceRoot, options.entry, options.now),
40
39
  summary: referenceSummaryProjectionForEntry({
@@ -65,7 +64,6 @@ function referenceDirectoryProjection(options) {
65
64
  index_path: REFERENCE_INDEX_PATH,
66
65
  files_path: REFERENCE_FILES_DIRECTORY_PATH,
67
66
  images_path: REFERENCE_IMAGES_DIRECTORY_PATH,
68
- tutti_path: REFERENCE_TUTTI_DIRECTORY_PATH,
69
67
  index_status: "missing",
70
68
  };
71
69
  }
@@ -82,7 +80,6 @@ function referenceDirectoryProjection(options) {
82
80
  index_path: REFERENCE_INDEX_PATH,
83
81
  files_path: REFERENCE_FILES_DIRECTORY_PATH,
84
82
  images_path: REFERENCE_IMAGES_DIRECTORY_PATH,
85
- tutti_path: REFERENCE_TUTTI_DIRECTORY_PATH,
86
83
  index_status: "available",
87
84
  };
88
85
  }
@@ -92,7 +89,6 @@ function referenceDirectoryProjection(options) {
92
89
  index_path: REFERENCE_INDEX_PATH,
93
90
  files_path: REFERENCE_FILES_DIRECTORY_PATH,
94
91
  images_path: REFERENCE_IMAGES_DIRECTORY_PATH,
95
- tutti_path: REFERENCE_TUTTI_DIRECTORY_PATH,
96
92
  index_status: "unreadable",
97
93
  index_unreadable_reason: file.content.reason,
98
94
  };
@@ -105,7 +101,6 @@ function referenceDirectoryProjection(options) {
105
101
  index_path: REFERENCE_INDEX_PATH,
106
102
  files_path: REFERENCE_FILES_DIRECTORY_PATH,
107
103
  images_path: REFERENCE_IMAGES_DIRECTORY_PATH,
108
- tutti_path: REFERENCE_TUTTI_DIRECTORY_PATH,
109
104
  index_status: "missing",
110
105
  };
111
106
  }
@@ -119,14 +114,9 @@ export function readReferenceFilesResponse(options, query) {
119
114
  workspaceRoot,
120
115
  ...(now === undefined ? {} : { now }),
121
116
  });
122
- let tree;
117
+ let entries;
123
118
  try {
124
- tree = readViewerTree({
125
- workspaceRoot,
126
- path: REFERENCE_DIRECTORY_PATH,
127
- depth: 3,
128
- ...(now === undefined ? {} : { now }),
129
- });
119
+ entries = readReferenceFileEntries({ workspaceRoot });
130
120
  }
131
121
  catch (error) {
132
122
  if (error instanceof WorkspaceOpsError && error.code === "not_found") {
@@ -148,11 +138,10 @@ export function readReferenceFilesResponse(options, query) {
148
138
  }
149
139
  const includeIndex = query.include_index ?? false;
150
140
  const summaryIndex = readReferenceSummaryIndex({ workspaceRoot });
151
- const referenceItems = tree.items
152
- .filter((entry) => entry.kind === "file")
141
+ const referenceItems = entries
153
142
  .filter((entry) => includeIndex || entry.path !== REFERENCE_INDEX_PATH)
154
143
  .filter((entry) => entry.path === REFERENCE_INDEX_PATH ||
155
- referenceFileSourceForPath(entry.path) !== undefined)
144
+ referenceFileCategoryForPath(entry.path) !== undefined)
156
145
  .sort((left, right) => {
157
146
  const leftCategory = referenceFileCategoryForPath(left.path) ?? "file";
158
147
  const rightCategory = referenceFileCategoryForPath(right.path) ?? "file";
@@ -202,7 +191,7 @@ export function referenceFileMessageRef(file) {
202
191
  const ref = {
203
192
  path: file.path,
204
193
  name: file.name,
205
- source: file.source,
194
+ source: "human_upload",
206
195
  category: file.category,
207
196
  size_bytes: file.size_bytes,
208
197
  text_read: file.text_read,
@@ -560,7 +560,7 @@ export declare const WorkspaceResponseSchema: {
560
560
  };
561
561
  readonly capabilities: {
562
562
  readonly type: "object";
563
- readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification"];
563
+ readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification", "artifact_feedback"];
564
564
  readonly additionalProperties: false;
565
565
  readonly properties: {
566
566
  readonly sse: {
@@ -591,6 +591,9 @@ export declare const WorkspaceResponseSchema: {
591
591
  readonly clarification: {
592
592
  readonly type: "boolean";
593
593
  };
594
+ readonly artifact_feedback: {
595
+ readonly type: "boolean";
596
+ };
594
597
  };
595
598
  };
596
599
  };
@@ -740,7 +743,7 @@ export declare const BootstrapResponseSchema: {
740
743
  };
741
744
  readonly capabilities: {
742
745
  readonly type: "object";
743
- readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification"];
746
+ readonly required: readonly ["sse", "relay_join", "repo_viewer", "provider_config_query", "provider_model_update", "browser_secret_write", "task_auto_scheduler", "task_run_now_scheduler", "clarification", "artifact_feedback"];
744
747
  readonly additionalProperties: false;
745
748
  readonly properties: {
746
749
  readonly sse: {
@@ -771,6 +774,9 @@ export declare const BootstrapResponseSchema: {
771
774
  readonly clarification: {
772
775
  readonly type: "boolean";
773
776
  };
777
+ readonly artifact_feedback: {
778
+ readonly type: "boolean";
779
+ };
774
780
  };
775
781
  };
776
782
  };
@@ -316,6 +316,7 @@ export const WorkspaceResponseSchema = {
316
316
  "task_auto_scheduler",
317
317
  "task_run_now_scheduler",
318
318
  "clarification",
319
+ "artifact_feedback",
319
320
  ],
320
321
  additionalProperties: false,
321
322
  properties: {
@@ -328,6 +329,7 @@ export const WorkspaceResponseSchema = {
328
329
  task_auto_scheduler: { type: "boolean" },
329
330
  task_run_now_scheduler: { type: "boolean" },
330
331
  clarification: { type: "boolean" },
332
+ artifact_feedback: { type: "boolean" },
331
333
  },
332
334
  },
333
335
  },
@@ -72,6 +72,7 @@ export type HostProjectApiCapabilities = {
72
72
  task_auto_scheduler: boolean;
73
73
  task_run_now_scheduler: boolean;
74
74
  clarification: boolean;
75
+ artifact_feedback: boolean;
75
76
  };
76
77
  export type HostProviderModelService = {
77
78
  discover: () => Promise<GetProviderModelsResponse>;
@@ -13,6 +13,7 @@ function defaultCapabilities(options) {
13
13
  task_auto_scheduler: overrides?.task_auto_scheduler ?? false,
14
14
  task_run_now_scheduler: overrides?.task_run_now_scheduler ?? true,
15
15
  clarification: overrides?.clarification ?? false,
16
+ artifact_feedback: overrides?.artifact_feedback ?? true,
16
17
  };
17
18
  }
18
19
  function providerSummary(providerConfig) {
@@ -23,8 +23,8 @@ export function registerHostProjectApiRoutes(app, options) {
23
23
  registerViewerRoutes(app, options);
24
24
  registerReferenceFilesRoutes(app, { options, workspaceEvents });
25
25
  registerSkillRoutes(app, { options, workspaceEvents });
26
- registerArtifactsRoutes(app, { options, workspaceEvents });
27
- registerMessagesRoutes(app, { options, workspaceEvents });
26
+ const artifactPreviewManager = registerArtifactsRoutes(app, { options, workspaceEvents });
27
+ registerMessagesRoutes(app, { options, workspaceEvents, artifactPreviewManager });
28
28
  registerWorkflowRoutes(app, options);
29
29
  registerReadStateRoutes(app, { options, workspaceEvents });
30
30
  registerClarificationRoutes(app, options);
@@ -5,7 +5,6 @@ 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";
9
8
  export declare const REFERENCE_INDEX_PATH: "docs/reference/README.md";
10
9
  export declare const MAX_REFERENCE_UPLOAD_BYTES: number;
11
10
  export declare const VIEWER_ASSET_READ_LIMIT_BYTES: number;
@@ -5,7 +5,6 @@ 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";
9
8
  export const REFERENCE_INDEX_PATH = "docs/reference/README.md";
10
9
  export const MAX_REFERENCE_UPLOAD_BYTES = 10 * 1024 * 1024;
11
10
  export const VIEWER_ASSET_READ_LIMIT_BYTES = MAX_REFERENCE_UPLOAD_BYTES;
@@ -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, REFERENCE_TUTTI_DIRECTORY_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, 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, referenceFileSourceForPath, referenceMediaTypeForPath, referenceTuttiGroupForPath, } from "./reference-metadata.js";
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
  export type { WorkspaceOpsErrorCode } from "./errors.js";
@@ -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, REFERENCE_TUTTI_DIRECTORY_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, 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, referenceFileSourceForPath, referenceMediaTypeForPath, referenceTuttiGroupForPath, } from "./reference-metadata.js";
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
- - Human-uploaded reference materials, when present, live under \`docs/reference/\`.
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
- "Human-uploaded project reference files.",
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 ?? readViewerFile({ workspaceRoot: options.workspaceRoot, path: repoPath }).snapshot.head.oid;
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 referenceFileSourceForPath(path: string): "human_upload" | "tutti_output" | undefined;
13
- export declare function referenceTuttiGroupForPath(path: string): string | undefined;
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, posix } from "node:path";
2
- import { REFERENCE_DIRECTORY_PATH, REFERENCE_FILES_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, REFERENCE_TUTTI_DIRECTORY_PATH, } from "./constants.js";
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.startsWith(`${REFERENCE_FILES_DIRECTORY_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 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;
62
+ export function isReferenceFilePath(path) {
63
+ return path !== REFERENCE_INDEX_PATH && path.startsWith(`${REFERENCE_DIRECTORY_PATH}/`);
78
64
  }
79
- export function referenceTuttiGroupForPath(path) {
80
- if (!path.startsWith(`${REFERENCE_TUTTI_DIRECTORY_PATH}/`)) {
65
+ export function referenceFolderGroupForPath(path) {
66
+ if (!isReferenceFilePath(path)) {
81
67
  return undefined;
82
68
  }
83
- const rest = path.slice(REFERENCE_TUTTI_DIRECTORY_PATH.length + 1);
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 { REFERENCE_DIRECTORY_PATH, REFERENCE_INDEX_PATH, } from "./constants.js";
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
- "Human-uploaded project reference files.",
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 readReferenceFileEntries(options) {
169
- const tree = readViewerTree({
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 readReferenceFileEntries(options)
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.map(renderSummaryRecord).sort((left, right) => left.path.localeCompare(right.path, "en", { sensitivity: "base" }));
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(readReferenceFileEntries({
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";