@xfey/tutti 0.1.14 → 0.1.15

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 (48) hide show
  1. package/dist/control-plane/workflows/openai.d.ts +1 -0
  2. package/dist/control-plane/workflows/openai.js +5 -0
  3. package/dist/providers/openai/app-server/read-only-procedure.d.ts +1 -0
  4. package/dist/providers/openai/app-server/read-only-procedure.js +3 -1
  5. package/dist/providers/openai/app-server/skills.d.ts +2 -2
  6. package/dist/providers/openai/app-server/skills.js +8 -7
  7. package/dist/providers/openai/app-server/workspace-write-run.d.ts +1 -0
  8. package/dist/providers/openai/app-server/workspace-write-run.js +4 -2
  9. package/dist/providers/openai/chat-assistant.d.ts +1 -0
  10. package/dist/providers/openai/chat-assistant.js +3 -0
  11. package/dist/run-pipeline/openai.d.ts +1 -0
  12. package/dist/run-pipeline/openai.js +2 -0
  13. package/dist/run-pipeline/task-run-invocation.js +1 -0
  14. package/dist/server-shell/cli/host-server-runtime.js +16 -1
  15. package/dist/server-shell/cli/project-identity.d.ts +3 -0
  16. package/dist/server-shell/cli/project-identity.js +24 -0
  17. package/dist/server-shell/http/routes/agent-context-shared.d.ts +1 -0
  18. package/dist/server-shell/http/routes/agent-context-shared.js +4 -0
  19. package/dist/server-shell/http/routes/agent-context-skills-routes.js +3 -3
  20. package/dist/server-shell/http/routes/project-api/invalidations.d.ts +1 -0
  21. package/dist/server-shell/http/routes/project-api/invalidations.js +4 -1
  22. package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +8 -0
  23. package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.js +14 -1
  24. package/dist/server-shell/http/routes/project-api/openapi.d.ts +8 -0
  25. package/dist/server-shell/http/routes/project-api/payload-validation.d.ts +2 -1
  26. package/dist/server-shell/http/routes/project-api/payload-validation.js +7 -0
  27. package/dist/server-shell/http/routes/project-api/schemas.d.ts +8 -0
  28. package/dist/server-shell/http/routes/project-api/schemas.js +1 -0
  29. package/dist/server-shell/http/routes/project-api/skills-helpers.d.ts +1 -0
  30. package/dist/server-shell/http/routes/project-api/skills-helpers.js +4 -1
  31. package/dist/server-shell/http/routes/project-api/skills-routes.js +5 -5
  32. package/dist/server-shell/http/routes/project-api/system-routes.js +66 -4
  33. package/dist/server-shell/http/routes/project-api/types.d.ts +2 -0
  34. package/dist/skills/index.d.ts +7 -6
  35. package/dist/skills/index.js +18 -21
  36. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -1
  37. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -1
  38. package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +5 -1
  39. package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.d.ts +18 -0
  40. package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.js +15 -0
  41. package/package.json +1 -1
  42. package/prompts/prompt-flow-map.md +5 -5
  43. package/prompts/skills/read-user-skills/SKILL.md +1 -1
  44. package/web/assets/index-CohZfGSh.css +1 -0
  45. package/web/assets/index-YQvFdpG8.js +29 -0
  46. package/web/index.html +8 -2
  47. package/web/assets/index-Cm_uyHbH.js +0 -29
  48. package/web/assets/index-DIQpGeKY.css +0 -1
@@ -1,11 +1,11 @@
1
- import { UpdateProjectDisplayNameBodySchema, UpdateProjectDisplayNameResponseSchema, } from "@tutti/shared/schemas/api";
1
+ import { UpdateProjectDescriptionBodySchema, UpdateProjectDescriptionResponseSchema, UpdateProjectDisplayNameBodySchema, UpdateProjectDisplayNameResponseSchema, } from "@tutti/shared/schemas/api";
2
2
  import { BootstrapResponseSchema, GetEventsRequestSchema, OpenApiDocumentProjectionSchema, ProviderConfigProjectionSchema, ProviderUsageProjectionSchema, SessionResponseSchema, WorkspaceResponseSchema, } from "./schemas.js";
3
3
  import { executeIdempotentCommand } from "../../../command-idempotency/index.js";
4
4
  import { HOST_PROJECT_API_BASE_PATH } from "./constants.js";
5
5
  import { openWorkspaceEventStream } from "./events-stream.js";
6
- import { projectDisplayNameInvalidates } from "./invalidations.js";
6
+ import { projectMetadataInvalidates } from "./invalidations.js";
7
7
  import { buildHostProjectOpenApiDocument } from "./openapi.js";
8
- import { requireValidProjectDisplayNamePayload } from "./payload-validation.js";
8
+ import { requireValidProjectDescriptionPayload, requireValidProjectDisplayNamePayload, } from "./payload-validation.js";
9
9
  import { requireHostProjectSession, requireProjectStore, } from "./session-requirements.js";
10
10
  import { buildBootstrapSnapshots, resolveWorkspaceProjection, } from "./workspace-projections.js";
11
11
  function updateProjectDisplayName(options, payload) {
@@ -24,6 +24,27 @@ function updateProjectDisplayName(options, payload) {
24
24
  result: { project: { display_name: nextName } },
25
25
  };
26
26
  }
27
+ function updateProjectDescription(options, payload) {
28
+ const currentDescription = options.project.description ?? "";
29
+ const nextDescription = payload.description;
30
+ if (currentDescription === nextDescription) {
31
+ return {
32
+ disposition: { kind: "unchanged" },
33
+ result: { project: { description: currentDescription } },
34
+ };
35
+ }
36
+ options.updateProjectDescription?.(nextDescription);
37
+ if (nextDescription.length === 0) {
38
+ delete options.project.description;
39
+ }
40
+ else {
41
+ options.project.description = nextDescription;
42
+ }
43
+ return {
44
+ disposition: { kind: "updated" },
45
+ result: { project: { description: nextDescription } },
46
+ };
47
+ }
27
48
  export function registerSystemRoutes(app, { options, workspaceEvents, }) {
28
49
  app.get(`${HOST_PROJECT_API_BASE_PATH}/openapi.json`, {
29
50
  schema: {
@@ -97,7 +118,7 @@ export function registerSystemRoutes(app, { options, workspaceEvents, }) {
97
118
  ...(options.now === undefined ? {} : { now: options.now }),
98
119
  execute: () => updateProjectDisplayName(options, payload),
99
120
  });
100
- const invalidates = projectDisplayNameInvalidates();
121
+ const invalidates = projectMetadataInvalidates();
101
122
  const response = {
102
123
  command_id: execution.command_id,
103
124
  disposition: execution.disposition,
@@ -118,6 +139,47 @@ export function registerSystemRoutes(app, { options, workspaceEvents, }) {
118
139
  }
119
140
  return response;
120
141
  });
142
+ app.post(`${HOST_PROJECT_API_BASE_PATH}/workspace/project-description`, {
143
+ schema: {
144
+ body: UpdateProjectDescriptionBodySchema,
145
+ response: {
146
+ 200: UpdateProjectDescriptionResponseSchema,
147
+ },
148
+ },
149
+ }, (request) => {
150
+ requireHostProjectSession(request, options);
151
+ const store = requireProjectStore(options);
152
+ const payload = requireValidProjectDescriptionPayload(request.body.payload);
153
+ const execution = executeIdempotentCommand({
154
+ db: store.db,
155
+ command_id: request.body.command_id,
156
+ command_name: "workspace.update_project_description",
157
+ target_ref: `project:${options.project.project_id}`,
158
+ payload,
159
+ ...(options.now === undefined ? {} : { now: options.now }),
160
+ execute: () => updateProjectDescription(options, payload),
161
+ });
162
+ const invalidates = projectMetadataInvalidates();
163
+ const response = {
164
+ command_id: execution.command_id,
165
+ disposition: execution.disposition,
166
+ invalidates,
167
+ };
168
+ if (execution.result !== undefined) {
169
+ response.result = execution.result;
170
+ }
171
+ if (!execution.replayed) {
172
+ workspaceEvents.publish({
173
+ event_type: "query.invalidate",
174
+ payload: {
175
+ reason: "bulk_state_change",
176
+ message: "Project description changed.",
177
+ },
178
+ invalidates,
179
+ });
180
+ }
181
+ return response;
182
+ });
121
183
  app.get(`${HOST_PROJECT_API_BASE_PATH}/bootstrap`, {
122
184
  schema: {
123
185
  response: {
@@ -75,6 +75,7 @@ export type HostProjectApiRouteOptions = {
75
75
  project: {
76
76
  project_id: ProjectId;
77
77
  display_name: string;
78
+ description?: string;
78
79
  identity_source: "git_config";
79
80
  };
80
81
  server: {
@@ -98,6 +99,7 @@ export type HostProjectApiRouteOptions = {
98
99
  capabilities?: Partial<Omit<HostProjectApiCapabilities, "browser_secret_write">>;
99
100
  getRepo?: () => HostRepoProjection;
100
101
  updateProjectDisplayName?: (displayName: string) => void;
102
+ updateProjectDescription?: (description: string) => void;
101
103
  resolveStagedUpload?: (uploadId: RelayUploadProjection["upload_id"]) => Promise<ResolvedStagedUpload>;
102
104
  workspaceOps?: {
103
105
  workspaceRoot: string;
@@ -1,3 +1,4 @@
1
+ import type { ProjectId } from "@tutti/shared/ids";
1
2
  import type { SkillDetailProjection, SkillProjection } from "@tutti/shared/schemas/api";
2
3
  import { type UserSkillImportPlan } from "./zip-import.js";
3
4
  export { MAX_SKILL_DIRECTORY_DEPTH, MAX_SKILL_FILE_BYTES, MAX_SKILL_FILE_COUNT, MAX_SKILL_TOTAL_UNCOMPRESSED_BYTES, MAX_SKILL_ZIP_BYTES, SKILL_MD_FILE_NAME, USER_SKILLS_DIRECTORY_NAME, } from "./constants.js";
@@ -25,17 +26,17 @@ export type UserSkillImportResult = {
25
26
  disposition: UserSkillImportDisposition;
26
27
  skill: SkillDetailProjection;
27
28
  };
28
- export declare function getUserSkillsRoot(tuttiHome: string): string;
29
- export declare function listUserSkills(tuttiHome: string): SkillProjection[];
30
- export declare function readUserSkill(tuttiHome: string, skillName: string): SkillDetailProjection;
29
+ export declare function getProjectUserSkillsRoot(tuttiHome: string, projectId: ProjectId): string;
30
+ export declare function listUserSkills(userSkillsRoot: string): SkillProjection[];
31
+ export declare function readUserSkill(userSkillsRoot: string, skillName: string): SkillDetailProjection;
31
32
  export declare function importUserSkillZip(options: {
32
- tuttiHome: string;
33
+ userSkillsRoot: string;
33
34
  zipBuffer: Buffer;
34
35
  fileName: string;
35
36
  }): Promise<UserSkillImportResult>;
36
37
  export declare function commitUserSkillImport(options: {
37
- tuttiHome: string;
38
+ userSkillsRoot: string;
38
39
  plan: UserSkillImportPlan;
39
40
  }): UserSkillImportResult;
40
- export declare function deleteUserSkill(tuttiHome: string, skillName: string): UserSkillDeleteDisposition;
41
+ export declare function deleteUserSkill(userSkillsRoot: string, skillName: string): UserSkillDeleteDisposition;
41
42
  //# sourceMappingURL=index.d.ts.map
@@ -9,8 +9,8 @@ export { MAX_SKILL_DIRECTORY_DEPTH, MAX_SKILL_FILE_BYTES, MAX_SKILL_FILE_COUNT,
9
9
  export { SkillServiceError } from "./errors.js";
10
10
  export { isValidSkillName, parseSkillMarkdown } from "./metadata.js";
11
11
  export { prepareUserSkillZipImport } from "./zip-import.js";
12
- export function getUserSkillsRoot(tuttiHome) {
13
- return join(tuttiHome, USER_SKILLS_DIRECTORY_NAME);
12
+ export function getProjectUserSkillsRoot(tuttiHome, projectId) {
13
+ return join(tuttiHome, "projects", projectId, USER_SKILLS_DIRECTORY_NAME);
14
14
  }
15
15
  function assertValidSkillName(skillName) {
16
16
  if (!isValidSkillName(skillName)) {
@@ -24,11 +24,10 @@ function ensureInside(parent, child) {
24
24
  throw new SkillServiceError("validation_failed", "Skill path is invalid");
25
25
  }
26
26
  }
27
- function skillDirectory(tuttiHome, skillName) {
27
+ function skillDirectory(userSkillsRoot, skillName) {
28
28
  assertValidSkillName(skillName);
29
- const root = getUserSkillsRoot(tuttiHome);
30
- const directory = join(root, skillName);
31
- ensureInside(root, directory);
29
+ const directory = join(userSkillsRoot, skillName);
30
+ ensureInside(userSkillsRoot, directory);
32
31
  return directory;
33
32
  }
34
33
  function readSkillMarkdown(filePath) {
@@ -63,18 +62,17 @@ function readSkillProjection(directory) {
63
62
  updatedAt: stat.mtime.toISOString(),
64
63
  });
65
64
  }
66
- export function listUserSkills(tuttiHome) {
67
- const root = getUserSkillsRoot(tuttiHome);
68
- if (!existsSync(root)) {
65
+ export function listUserSkills(userSkillsRoot) {
66
+ if (!existsSync(userSkillsRoot)) {
69
67
  return [];
70
68
  }
71
69
  const items = [];
72
- for (const entry of readdirSync(root, { withFileTypes: true })) {
70
+ for (const entry of readdirSync(userSkillsRoot, { withFileTypes: true })) {
73
71
  if (!entry.isDirectory() || !isValidSkillName(entry.name)) {
74
72
  continue;
75
73
  }
76
74
  try {
77
- const projection = readSkillProjection(join(root, entry.name));
75
+ const projection = readSkillProjection(join(userSkillsRoot, entry.name));
78
76
  if (projection.name === entry.name) {
79
77
  items.push(projection);
80
78
  }
@@ -85,8 +83,8 @@ export function listUserSkills(tuttiHome) {
85
83
  }
86
84
  return items.sort((left, right) => left.name.localeCompare(right.name));
87
85
  }
88
- export function readUserSkill(tuttiHome, skillName) {
89
- const directory = skillDirectory(tuttiHome, skillName);
86
+ export function readUserSkill(userSkillsRoot, skillName) {
87
+ const directory = skillDirectory(userSkillsRoot, skillName);
90
88
  const skillMdPath = join(directory, SKILL_MD_FILE_NAME);
91
89
  if (!existsSync(skillMdPath)) {
92
90
  throw new SkillServiceError("skill_not_found", "Skill does not exist");
@@ -110,19 +108,18 @@ export async function importUserSkillZip(options) {
110
108
  fileName: options.fileName,
111
109
  });
112
110
  return commitUserSkillImport({
113
- tuttiHome: options.tuttiHome,
111
+ userSkillsRoot: options.userSkillsRoot,
114
112
  plan,
115
113
  });
116
114
  }
117
115
  export function commitUserSkillImport(options) {
118
116
  const candidate = options.plan;
119
- const root = getUserSkillsRoot(options.tuttiHome);
120
- mkdirSync(root, { recursive: true, mode: 0o700 });
121
- const destination = skillDirectory(options.tuttiHome, candidate.skillName);
117
+ mkdirSync(options.userSkillsRoot, { recursive: true, mode: 0o700 });
118
+ const destination = skillDirectory(options.userSkillsRoot, candidate.skillName);
122
119
  const existed = existsSync(destination);
123
120
  const tempParent = mkdtempSync(join(tmpdir(), "tutti-skill-import-"));
124
121
  const tempSkillRoot = join(tempParent, candidate.skillName);
125
- const backupPath = join(root, `.trash-${candidate.skillName}-${process.pid}-${Date.now()}`);
122
+ const backupPath = join(options.userSkillsRoot, `.trash-${candidate.skillName}-${process.pid}-${Date.now()}`);
126
123
  try {
127
124
  writeCandidateFiles(tempSkillRoot, candidate);
128
125
  if (existed) {
@@ -154,11 +151,11 @@ export function commitUserSkillImport(options) {
154
151
  kind: existed ? "replaced" : "created",
155
152
  skill_name: candidate.skillName,
156
153
  },
157
- skill: readUserSkill(options.tuttiHome, candidate.skillName),
154
+ skill: readUserSkill(options.userSkillsRoot, candidate.skillName),
158
155
  };
159
156
  }
160
- export function deleteUserSkill(tuttiHome, skillName) {
161
- const directory = skillDirectory(tuttiHome, skillName);
157
+ export function deleteUserSkill(userSkillsRoot, skillName) {
158
+ const directory = skillDirectory(userSkillsRoot, skillName);
162
159
  if (!existsSync(directory)) {
163
160
  return { kind: "not_found", skill_name: skillName };
164
161
  }
@@ -14,5 +14,5 @@ export { GetProjectDocRequestSchema, GetProjectDocResponseSchema, GetProjectDocs
14
14
  export { ArtifactKindSchema, ArtifactManifestPathSchema, ArtifactManifestSchema, ArtifactPreviewCommandPayloadSchema, ArtifactPreviewCommandResultSchema, ArtifactPreviewProjectionSchema, ArtifactPreviewStatusSchema, ArtifactServerManifestSchema, ArtifactStaticManifestSchema, ArtifactSummaryProjectionSchema, ArtifactTitleSchema, ArtifactProjectionSchema, GetArtifactsResponseSchema, HeartbeatArtifactPreviewBodySchema, HeartbeatArtifactPreviewDispositionSchema, HeartbeatArtifactPreviewResponseSchema, StartArtifactPreviewBodySchema, StartArtifactPreviewDispositionSchema, StartArtifactPreviewResponseSchema, StopArtifactPreviewBodySchema, StopArtifactPreviewDispositionSchema, StopArtifactPreviewResponseSchema, } from "./artifacts.js";
15
15
  export { DeleteSkillBodySchema, DeleteSkillDispositionSchema, DeleteSkillPayloadSchema, DeleteSkillResponseSchema, GetSkillParamsSchema, GetSkillResponseSchema, GetSkillsResponseSchema, ImportSkillZipBodySchema, ImportSkillZipDispositionSchema, ImportSkillZipPayloadSchema, ImportSkillZipResponseSchema, ImportSkillZipResultSchema, SkillDetailProjectionSchema, SkillNameSchema, SkillProjectionSchema, } from "./skills.js";
16
16
  export { ActivityEventProjectionSchema, ActivityEventSsePayloadSchema, ApprovalChangedEventPayloadSchema, ActivityProjectionSchema, ConnectionReadyEventPayloadSchema, ExecutionActivitySummarySchema, ExecutionStatusChangedEventPayloadSchema, ExecutionStatusKindSchema, ExecutionStatusProjectionSchema, ProcedureLaneSchema, ProviderConfigChangedEventPayloadSchema, QueryInvalidateEventPayloadSchema, ScratchpadUpdatedEventPayloadSchema, TaskDetailUpdatedEventPayloadSchema, TaskUpdatedEventPayloadSchema, WorklistChangedEventPayloadSchema, WorkspaceRecoveredEventPayloadSchema, } from "./runtime-events.js";
17
- export { ContextSyncBodySchema, ContextSyncDispositionSchema, ContextSyncPayloadSchema, ContextSyncResponseSchema, ContextSyncResultSchema, InitializeProjectDocsBodySchema, InitializeProjectDocsDispositionSchema, InitializeProjectDocsPayloadSchema, InitializeProjectDocsResponseSchema, InitializeProjectDocsResultSchema, ProjectDocsProcedureStartResultSchema, RefreshScratchpadDispositionSchema, RefreshScratchpadResultSchema, RunSchedulerNowBodySchema, RunSchedulerNowDispositionSchema, RunSchedulerNowPayloadSchema, RunSchedulerNowResponseSchema, SubmitWorklistBodySchema, SubmitWorklistDispositionSchema, SubmitWorklistPayloadSchema, SubmitWorklistResponseSchema, SubmitWorklistResultSchema, UpdateProjectDisplayNameBodySchema, UpdateProjectDisplayNameDispositionSchema, UpdateProjectDisplayNamePayloadSchema, UpdateProjectDisplayNameResponseSchema, UpdateProjectDisplayNameResultSchema, } from "./workspace-commands.js";
17
+ export { ContextSyncBodySchema, ContextSyncDispositionSchema, ContextSyncPayloadSchema, ContextSyncResponseSchema, ContextSyncResultSchema, InitializeProjectDocsBodySchema, InitializeProjectDocsDispositionSchema, InitializeProjectDocsPayloadSchema, InitializeProjectDocsResponseSchema, InitializeProjectDocsResultSchema, ProjectDocsProcedureStartResultSchema, RefreshScratchpadDispositionSchema, RefreshScratchpadResultSchema, RunSchedulerNowBodySchema, RunSchedulerNowDispositionSchema, RunSchedulerNowPayloadSchema, RunSchedulerNowResponseSchema, SubmitWorklistBodySchema, SubmitWorklistDispositionSchema, SubmitWorklistPayloadSchema, SubmitWorklistResponseSchema, SubmitWorklistResultSchema, UpdateProjectDescriptionBodySchema, UpdateProjectDescriptionDispositionSchema, UpdateProjectDescriptionPayloadSchema, UpdateProjectDescriptionResponseSchema, UpdateProjectDescriptionResultSchema, UpdateProjectDisplayNameBodySchema, UpdateProjectDisplayNameDispositionSchema, UpdateProjectDisplayNamePayloadSchema, UpdateProjectDisplayNameResponseSchema, UpdateProjectDisplayNameResultSchema, } from "./workspace-commands.js";
18
18
  //# sourceMappingURL=index.d.ts.map
@@ -13,5 +13,5 @@ export { GetProjectDocRequestSchema, GetProjectDocResponseSchema, GetProjectDocs
13
13
  export { ArtifactKindSchema, ArtifactManifestPathSchema, ArtifactManifestSchema, ArtifactPreviewCommandPayloadSchema, ArtifactPreviewCommandResultSchema, ArtifactPreviewProjectionSchema, ArtifactPreviewStatusSchema, ArtifactServerManifestSchema, ArtifactStaticManifestSchema, ArtifactSummaryProjectionSchema, ArtifactTitleSchema, ArtifactProjectionSchema, GetArtifactsResponseSchema, HeartbeatArtifactPreviewBodySchema, HeartbeatArtifactPreviewDispositionSchema, HeartbeatArtifactPreviewResponseSchema, StartArtifactPreviewBodySchema, StartArtifactPreviewDispositionSchema, StartArtifactPreviewResponseSchema, StopArtifactPreviewBodySchema, StopArtifactPreviewDispositionSchema, StopArtifactPreviewResponseSchema, } from "./artifacts.js";
14
14
  export { DeleteSkillBodySchema, DeleteSkillDispositionSchema, DeleteSkillPayloadSchema, DeleteSkillResponseSchema, GetSkillParamsSchema, GetSkillResponseSchema, GetSkillsResponseSchema, ImportSkillZipBodySchema, ImportSkillZipDispositionSchema, ImportSkillZipPayloadSchema, ImportSkillZipResponseSchema, ImportSkillZipResultSchema, SkillDetailProjectionSchema, SkillNameSchema, SkillProjectionSchema, } from "./skills.js";
15
15
  export { ActivityEventProjectionSchema, ActivityEventSsePayloadSchema, ApprovalChangedEventPayloadSchema, ActivityProjectionSchema, ConnectionReadyEventPayloadSchema, ExecutionActivitySummarySchema, ExecutionStatusChangedEventPayloadSchema, ExecutionStatusKindSchema, ExecutionStatusProjectionSchema, ProcedureLaneSchema, ProviderConfigChangedEventPayloadSchema, QueryInvalidateEventPayloadSchema, ScratchpadUpdatedEventPayloadSchema, TaskDetailUpdatedEventPayloadSchema, TaskUpdatedEventPayloadSchema, WorklistChangedEventPayloadSchema, WorkspaceRecoveredEventPayloadSchema, } from "./runtime-events.js";
16
- export { ContextSyncBodySchema, ContextSyncDispositionSchema, ContextSyncPayloadSchema, ContextSyncResponseSchema, ContextSyncResultSchema, InitializeProjectDocsBodySchema, InitializeProjectDocsDispositionSchema, InitializeProjectDocsPayloadSchema, InitializeProjectDocsResponseSchema, InitializeProjectDocsResultSchema, ProjectDocsProcedureStartResultSchema, RefreshScratchpadDispositionSchema, RefreshScratchpadResultSchema, RunSchedulerNowBodySchema, RunSchedulerNowDispositionSchema, RunSchedulerNowPayloadSchema, RunSchedulerNowResponseSchema, SubmitWorklistBodySchema, SubmitWorklistDispositionSchema, SubmitWorklistPayloadSchema, SubmitWorklistResponseSchema, SubmitWorklistResultSchema, UpdateProjectDisplayNameBodySchema, UpdateProjectDisplayNameDispositionSchema, UpdateProjectDisplayNamePayloadSchema, UpdateProjectDisplayNameResponseSchema, UpdateProjectDisplayNameResultSchema, } from "./workspace-commands.js";
16
+ export { ContextSyncBodySchema, ContextSyncDispositionSchema, ContextSyncPayloadSchema, ContextSyncResponseSchema, ContextSyncResultSchema, InitializeProjectDocsBodySchema, InitializeProjectDocsDispositionSchema, InitializeProjectDocsPayloadSchema, InitializeProjectDocsResponseSchema, InitializeProjectDocsResultSchema, ProjectDocsProcedureStartResultSchema, RefreshScratchpadDispositionSchema, RefreshScratchpadResultSchema, RunSchedulerNowBodySchema, RunSchedulerNowDispositionSchema, RunSchedulerNowPayloadSchema, RunSchedulerNowResponseSchema, SubmitWorklistBodySchema, SubmitWorklistDispositionSchema, SubmitWorklistPayloadSchema, SubmitWorklistResponseSchema, SubmitWorklistResultSchema, UpdateProjectDescriptionBodySchema, UpdateProjectDescriptionDispositionSchema, UpdateProjectDescriptionPayloadSchema, UpdateProjectDescriptionResponseSchema, UpdateProjectDescriptionResultSchema, UpdateProjectDisplayNameBodySchema, UpdateProjectDisplayNameDispositionSchema, UpdateProjectDisplayNamePayloadSchema, UpdateProjectDisplayNameResponseSchema, UpdateProjectDisplayNameResultSchema, } from "./workspace-commands.js";
17
17
  //# sourceMappingURL=index.js.map
@@ -14,7 +14,7 @@ import type { GetProjectDocRequestSchema, GetProjectDocResponseSchema, GetProjec
14
14
  import type { ArtifactKindSchema, ArtifactManifestPathSchema, ArtifactManifestSchema, ArtifactPreviewCommandPayloadSchema, ArtifactPreviewCommandResultSchema, ArtifactPreviewProjectionSchema, ArtifactPreviewStatusSchema, ArtifactProjectionSchema, ArtifactServerManifestSchema, ArtifactStaticManifestSchema, ArtifactSummaryProjectionSchema, GetArtifactsResponseSchema, HeartbeatArtifactPreviewDispositionSchema, StartArtifactPreviewDispositionSchema, StopArtifactPreviewDispositionSchema } from "./artifacts.js";
15
15
  import type { DeleteSkillDispositionSchema, DeleteSkillPayloadSchema, GetSkillParamsSchema, GetSkillResponseSchema, GetSkillsResponseSchema, ImportSkillZipDispositionSchema, ImportSkillZipPayloadSchema, ImportSkillZipResultSchema, SkillDetailProjectionSchema, SkillNameSchema, SkillProjectionSchema } from "./skills.js";
16
16
  import type { ActivityEventProjectionSchema, ActivityEventSsePayloadSchema, ApprovalChangedEventPayloadSchema, ActivityProjectionSchema, ConnectionReadyEventPayloadSchema, ExecutionActivitySummarySchema, ExecutionRuntimeActionSchema, ExecutionRuntimeSnapshotSchema, ExecutionRuntimeTokenUsageSchema, ExecutionStatusChangedEventPayloadSchema, ExecutionStatusKindSchema, ExecutionStatusProjectionSchema, ProcedureLaneSchema, ProviderConfigChangedEventPayloadSchema, QueryInvalidateEventPayloadSchema, ScratchpadUpdatedEventPayloadSchema, TaskDetailUpdatedEventPayloadSchema, TaskUpdatedEventPayloadSchema, WorklistChangedEventPayloadSchema, WorkspaceRecoveredEventPayloadSchema } from "./runtime-events.js";
17
- import type { ContextSyncDispositionSchema, ContextSyncPayloadSchema, ContextSyncResultSchema, InitializeProjectDocsDispositionSchema, InitializeProjectDocsPayloadSchema, InitializeProjectDocsResultSchema, RefreshScratchpadDispositionSchema, RefreshScratchpadResultSchema, RunSchedulerNowDispositionSchema, RunSchedulerNowPayloadSchema, SubmitWorklistDispositionSchema, SubmitWorklistPayloadSchema, SubmitWorklistResultSchema, UpdateProjectDisplayNameDispositionSchema, UpdateProjectDisplayNamePayloadSchema, UpdateProjectDisplayNameResultSchema } from "./workspace-commands.js";
17
+ import type { ContextSyncDispositionSchema, ContextSyncPayloadSchema, ContextSyncResultSchema, InitializeProjectDocsDispositionSchema, InitializeProjectDocsPayloadSchema, InitializeProjectDocsResultSchema, RefreshScratchpadDispositionSchema, RefreshScratchpadResultSchema, RunSchedulerNowDispositionSchema, RunSchedulerNowPayloadSchema, SubmitWorklistDispositionSchema, SubmitWorklistPayloadSchema, SubmitWorklistResultSchema, UpdateProjectDescriptionDispositionSchema, UpdateProjectDescriptionPayloadSchema, UpdateProjectDescriptionResultSchema, UpdateProjectDisplayNameDispositionSchema, UpdateProjectDisplayNamePayloadSchema, UpdateProjectDisplayNameResultSchema } from "./workspace-commands.js";
18
18
  export type CursorPageRequest = Static<typeof CursorPageRequestSchema>;
19
19
  export type CursorPage<TItem> = {
20
20
  items: TItem[];
@@ -216,6 +216,10 @@ export type UpdateProjectDisplayNamePayload = Static<typeof UpdateProjectDisplay
216
216
  export type UpdateProjectDisplayNameDisposition = Static<typeof UpdateProjectDisplayNameDispositionSchema>;
217
217
  export type UpdateProjectDisplayNameResult = Static<typeof UpdateProjectDisplayNameResultSchema>;
218
218
  export type UpdateProjectDisplayNameResponse = CommandResponse<UpdateProjectDisplayNameDisposition, UpdateProjectDisplayNameResult>;
219
+ export type UpdateProjectDescriptionPayload = Static<typeof UpdateProjectDescriptionPayloadSchema>;
220
+ export type UpdateProjectDescriptionDisposition = Static<typeof UpdateProjectDescriptionDispositionSchema>;
221
+ export type UpdateProjectDescriptionResult = Static<typeof UpdateProjectDescriptionResultSchema>;
222
+ export type UpdateProjectDescriptionResponse = CommandResponse<UpdateProjectDescriptionDisposition, UpdateProjectDescriptionResult>;
219
223
  export type InitializeProjectDocsPayload = Static<typeof InitializeProjectDocsPayloadSchema>;
220
224
  export type InitializeProjectDocsDisposition = Static<typeof InitializeProjectDocsDispositionSchema>;
221
225
  export type InitializeProjectDocsResult = Static<typeof InitializeProjectDocsResultSchema>;
@@ -121,6 +121,24 @@ export declare const UpdateProjectDisplayNameResultSchema: import("@sinclair/typ
121
121
  }>;
122
122
  export declare const UpdateProjectDisplayNameBodySchema: import("@sinclair/typebox").TSchema;
123
123
  export declare const UpdateProjectDisplayNameResponseSchema: import("@sinclair/typebox").TSchema;
124
+ export declare const UpdateProjectDescriptionPayloadSchema: import("@sinclair/typebox").TObject<{
125
+ description: import("@sinclair/typebox").TString;
126
+ }>;
127
+ export declare const UpdateProjectDescriptionDispositionSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
128
+ kind: import("@sinclair/typebox").TLiteral<"updated">;
129
+ }>, import("@sinclair/typebox").TObject<{
130
+ kind: import("@sinclair/typebox").TLiteral<"unchanged">;
131
+ }>, import("@sinclair/typebox").TObject<{
132
+ kind: import("@sinclair/typebox").TLiteral<"interrupted">;
133
+ retry_with_new_command_id: import("@sinclair/typebox").TLiteral<true>;
134
+ }>]>;
135
+ export declare const UpdateProjectDescriptionResultSchema: import("@sinclair/typebox").TObject<{
136
+ project: import("@sinclair/typebox").TObject<{
137
+ description: import("@sinclair/typebox").TString;
138
+ }>;
139
+ }>;
140
+ export declare const UpdateProjectDescriptionBodySchema: import("@sinclair/typebox").TSchema;
141
+ export declare const UpdateProjectDescriptionResponseSchema: import("@sinclair/typebox").TSchema;
124
142
  export declare const InitializeProjectDocsPayloadSchema: import("@sinclair/typebox").TObject<{}>;
125
143
  export declare const InitializeProjectDocsDispositionSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
126
144
  kind: import("@sinclair/typebox").TLiteral<"created">;
@@ -99,6 +99,21 @@ export const UpdateProjectDisplayNameResultSchema = Type.Object({
99
99
  }, { additionalProperties: false });
100
100
  export const UpdateProjectDisplayNameBodySchema = commandEnvelopeSchema(UpdateProjectDisplayNamePayloadSchema);
101
101
  export const UpdateProjectDisplayNameResponseSchema = commandResponseWithResultSchema(UpdateProjectDisplayNameDispositionSchema, UpdateProjectDisplayNameResultSchema);
102
+ export const UpdateProjectDescriptionPayloadSchema = Type.Object({
103
+ description: Type.String({ maxLength: 160 }),
104
+ }, { additionalProperties: false });
105
+ export const UpdateProjectDescriptionDispositionSchema = Type.Union([
106
+ Type.Object({ kind: Type.Literal("updated") }, { additionalProperties: false }),
107
+ Type.Object({ kind: Type.Literal("unchanged") }, { additionalProperties: false }),
108
+ InterruptedCommandDispositionSchema,
109
+ ]);
110
+ export const UpdateProjectDescriptionResultSchema = Type.Object({
111
+ project: Type.Object({
112
+ description: Type.String({ maxLength: 160 }),
113
+ }, { additionalProperties: false }),
114
+ }, { additionalProperties: false });
115
+ export const UpdateProjectDescriptionBodySchema = commandEnvelopeSchema(UpdateProjectDescriptionPayloadSchema);
116
+ export const UpdateProjectDescriptionResponseSchema = commandResponseWithResultSchema(UpdateProjectDescriptionDispositionSchema, UpdateProjectDescriptionResultSchema);
102
117
  export const InitializeProjectDocsPayloadSchema = Type.Object({}, { additionalProperties: false });
103
118
  export const InitializeProjectDocsDispositionSchema = Type.Union([
104
119
  Type.Object({ kind: Type.Literal("created") }, { additionalProperties: false }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfey/tutti",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -24,8 +24,8 @@ Provider validation 也使用 OpenAI Responses API,但它只是启动前 crede
24
24
  - `project_context_bootstrap`:已对齐为 Codex app-server read-only + `read-project-docs` / `read-references` skills;只生成缺失 baseline context files 计划,写入仍归 `workspace-ops`。
25
25
  - `task_compile`:已对齐为 Codex app-server read-only + `read-project-docs` / `read-worklist` / `read-references` skills;Scratchpad / Worklist 紧凑视图仍作为直接权威输入,Project Docs / Worklist detail / References 仅在必要时按需读取;任务化 readiness 内聚在该 workflow 中,不新增独立 gate。
26
26
  - `context_sync`:已对齐为 Codex app-server read-only + `read-project-docs` / `read-worklist` / `read-references` skills;provider-facing direct input 为空,让 app-server 只读探索 repo,并输出 `summary` 与 `updates[].path/content`。
27
- - `workspace_write_run`:已对齐为 workspace-write + 精简 task contract 输入 + Project Docs / Worklist skills + user skills;存在 user skills 时通过 `skills/list.perCwdExtraUserRoots` 预热 `<TUTTI_HOME>/skills`;Reference Files 不再通过 built-in skill 暴露,若任务或项目文档指向 `docs/reference/` 中资料,Codex 可直接读取相关 repo 文件。
28
- - `follow_up_run`:已对齐为 workspace-write + 精简 task contract 输入 + continuation block + Project Docs / Worklist skills + user skills;存在 user skills 时同样预热 `<TUTTI_HOME>/skills` extra root;Reference Files 不再通过 built-in skill 暴露,若任务、项目文档或 clarification answer 指向 `docs/reference/` 中资料,Codex 可直接读取相关 repo 文件。
27
+ - `workspace_write_run`:已对齐为 workspace-write + 精简 task contract 输入 + Project Docs / Worklist skills + user skills;存在 user skills 时通过 `skills/list.perCwdExtraUserRoots` 预热当前项目 `<TUTTI_HOME>/projects/<project_id>/skills`;Reference Files 不再通过 built-in skill 暴露,若任务或项目文档指向 `docs/reference/` 中资料,Codex 可直接读取相关 repo 文件。
28
+ - `follow_up_run`:已对齐为 workspace-write + 精简 task contract 输入 + continuation block + Project Docs / Worklist skills + user skills;存在 user skills 时同样预热当前项目 `<TUTTI_HOME>/projects/<project_id>/skills` extra root;Reference Files 不再通过 built-in skill 暴露,若任务、项目文档或 clarification answer 指向 `docs/reference/` 中资料,Codex 可直接读取相关 repo 文件。
29
29
  - `pipeline_self_correction`:已对齐为 workspace-write + 精简 task contract 输入 + 精简 correction block;使用 `runs/task-retry.md` 和 `workspace_write_run` selection,在同一 active Run 记录终态前处理 no candidate diff、checks 失败、checks 修改候选或 deterministic promotion reconcile 失败等可自纠 feedback。
30
30
  - `follow_up_check`:保持 OpenAI SDK structured output;已收敛为只判断上游 `Run.needs_human` 的 task-bound answer,不接入 skill,不重查代码或协作上下文;provider-facing input 只保留精简 task contract、previous Run pause reason、原 clarification request 和 answers,provider raw output 使用 `{ result: ... }` 互斥分支,failed-task retry 从 active path 移除。
31
31
  - `reference_summary_refresh`:已对齐为 Codex app-server read-only + 单文件临时 `cwd`;workflow / activity refs、原始 path、blob、media type 和 file metadata 只留在 Control Plane 内部,不进入 prompt;provider raw output 使用 `{ result: ... }` 互斥分支,只输出 `summarized.summary` 或 `unavailable.reason`。
@@ -354,7 +354,7 @@ Provider raw 输出:根对象只包含 `result`;`result` 内二选一输出
354
354
  - `run_input_json.goal`:正式任务目标。
355
355
  - `run_input_json.scope`:正式任务边界,同时承接关键约束、非目标、假设和可观察验收信号。
356
356
  - 不传入 `context_entry_json`、task id、task summary、workflow / activity refs、Run lineage、dispatch context 或 run workspace 绝对路径。
357
- - 通过 `workspace_write_run` selection 可读取 Project Docs 与 Worklist,并可加载所有 enabled user skills;存在 user skills 时,app-server `skills/list` 会先收到 `<TUTTI_HOME>/skills` extra user root。
357
+ - 通过 `workspace_write_run` selection 可读取 Project Docs 与 Worklist,并可加载所有 enabled user skills;存在 user skills 时,app-server `skills/list` 会先收到当前项目 `<TUTTI_HOME>/projects/<project_id>/skills` extra user root。
358
358
  - Reference Files 不通过 built-in skill 暴露;若任务契约或 Project Docs 指向 `docs/reference/` 中资料,Codex 可直接读取相关 repo 文件正文。
359
359
  - 不直接读取主群聊或 Scratchpad;这些不作为 hidden scope。
360
360
 
@@ -386,7 +386,7 @@ provider transient retry:如果本环节的 Codex app-server workspace-write t
386
386
  - `run_input_json.continuation.clarification.resolved_rounds[]`:截至当前 round 的已提交 task-bound clarification rounds;每轮包含 request payload 和人类回答消息原文。
387
387
  - `run_input_json.continuation.follow_up_check`:`resume` 判断的简短 summary,用于说明为什么本次可继续,但不能替代人类回答原文。
388
388
  - 不传入 `context_entry_json`、task id、task summary、workflow / activity refs、Run lineage、dispatch context 或 run workspace 绝对路径。
389
- - 通过 `follow_up_run` selection 可读取 Project Docs 与 Worklist,并可加载所有 enabled user skills;存在 user skills 时,app-server `skills/list` 会先收到 `<TUTTI_HOME>/skills` extra user root。
389
+ - 通过 `follow_up_run` selection 可读取 Project Docs 与 Worklist,并可加载所有 enabled user skills;存在 user skills 时,app-server `skills/list` 会先收到当前项目 `<TUTTI_HOME>/projects/<project_id>/skills` extra user root。
390
390
  - Reference Files 不通过 built-in skill 暴露;若任务契约、Project Docs 或 clarification answer 指向 `docs/reference/` 中资料,Codex 可直接读取相关 repo 文件正文。
391
391
  - 不直接读取主群聊或 Scratchpad;这些不作为 hidden scope。
392
392
 
@@ -420,7 +420,7 @@ provider transient retry:continuation 的 retryable app-server failure 只重
420
420
  - `run_input_json.correction.guidance`:Run pipeline 根据 feedback reason 生成的本次 retry 直接修正目标。
421
421
  - `run_input_json.correction.promotion_failure?`:仅 promotion / promotion-reconcile 未能 promotion 时出现,包含机器生成 reason code 和短摘要。
422
422
  - 不传入 `context_entry_json`、task id、task summary、workflow / activity refs、Run lineage、dispatch context 或 run workspace 绝对路径。
423
- - 通过 `workspace_write_run` selection 可读取 Project Docs 与 Worklist,并可加载所有 enabled user skills;存在 user skills 时,app-server `skills/list` 会先收到 `<TUTTI_HOME>/skills` extra user root。
423
+ - 通过 `workspace_write_run` selection 可读取 Project Docs 与 Worklist,并可加载所有 enabled user skills;存在 user skills 时,app-server `skills/list` 会先收到当前项目 `<TUTTI_HOME>/projects/<project_id>/skills` extra user root。
424
424
 
425
425
  输出:同初次 Task Run 的 `{ result: ... }` 互斥分支 schema。retry 不自报 `docs` 或 `changed_paths`。
426
426
 
@@ -5,7 +5,7 @@ description: List and read Tutti user skills when the turn has skills scopes.
5
5
 
6
6
  # Read User Skills
7
7
 
8
- Use this skill when a Tutti app-server turn needs to answer questions about host machine-local user skills.
8
+ Use this skill when a Tutti app-server turn needs to answer questions about the current project's host machine-local user skills.
9
9
 
10
10
  When a Tutti context API runtime hint is present and includes `skills:list`, list available user skills through:
11
11