@xfey/tutti 0.1.13 → 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.
- package/dist/control-plane/workflows/openai.d.ts +1 -0
- package/dist/control-plane/workflows/openai.js +5 -0
- package/dist/providers/openai/app-server/read-only-procedure.d.ts +1 -0
- package/dist/providers/openai/app-server/read-only-procedure.js +3 -1
- package/dist/providers/openai/app-server/runtime-telemetry.js +4 -5
- package/dist/providers/openai/app-server/skills.d.ts +2 -2
- package/dist/providers/openai/app-server/skills.js +8 -7
- package/dist/providers/openai/app-server/workspace-write-run.d.ts +1 -0
- package/dist/providers/openai/app-server/workspace-write-run.js +4 -2
- package/dist/providers/openai/chat-assistant.d.ts +1 -0
- package/dist/providers/openai/chat-assistant.js +3 -0
- package/dist/run-pipeline/openai.d.ts +1 -0
- package/dist/run-pipeline/openai.js +2 -0
- package/dist/run-pipeline/task-run-invocation.js +1 -0
- package/dist/server-shell/cli/host-server-runtime.js +16 -1
- package/dist/server-shell/cli/project-identity.d.ts +3 -0
- package/dist/server-shell/cli/project-identity.js +24 -0
- package/dist/server-shell/http/routes/agent-context-shared.d.ts +1 -0
- package/dist/server-shell/http/routes/agent-context-shared.js +4 -0
- package/dist/server-shell/http/routes/agent-context-skills-routes.js +3 -3
- package/dist/server-shell/http/routes/project-api/invalidations.d.ts +1 -0
- package/dist/server-shell/http/routes/project-api/invalidations.js +4 -1
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.js +14 -1
- package/dist/server-shell/http/routes/project-api/openapi.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/payload-validation.d.ts +2 -1
- package/dist/server-shell/http/routes/project-api/payload-validation.js +7 -0
- package/dist/server-shell/http/routes/project-api/schemas.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/schemas.js +1 -0
- package/dist/server-shell/http/routes/project-api/skills-helpers.d.ts +1 -0
- package/dist/server-shell/http/routes/project-api/skills-helpers.js +4 -1
- package/dist/server-shell/http/routes/project-api/skills-routes.js +5 -5
- package/dist/server-shell/http/routes/project-api/system-routes.js +66 -4
- package/dist/server-shell/http/routes/project-api/types.d.ts +2 -0
- package/dist/skills/index.d.ts +7 -6
- package/dist/skills/index.js +18 -21
- package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -1
- package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -1
- package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +5 -1
- package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.d.ts +18 -0
- package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.js +15 -0
- package/package.json +1 -1
- package/prompts/prompt-flow-map.md +5 -5
- package/prompts/skills/read-user-skills/SKILL.md +1 -1
- package/web/assets/index-CohZfGSh.css +1 -0
- package/web/assets/index-YQvFdpG8.js +29 -0
- package/web/index.html +8 -2
- package/web/assets/index-CDUT1Etl.js +0 -29
- package/web/assets/index-DIQpGeKY.css +0 -1
|
@@ -7,6 +7,7 @@ import { readOpenAiApiKeyCredential } from "../../providers/openai/credential-st
|
|
|
7
7
|
import { resolveOpenAiProviderConfig, } from "../../providers/openai/provider-config.js";
|
|
8
8
|
import { SCRATCHPAD_REFRESH_OUTPUT_SCHEMA, TASK_COMPILE_OUTPUT_SCHEMA, PROJECT_CONTEXT_BOOTSTRAP_OUTPUT_SCHEMA, CONTEXT_SYNC_OUTPUT_SCHEMA, PROJECT_BRIEF_REFRESH_OUTPUT_SCHEMA, FOLLOW_UP_CHECK_OUTPUT_SCHEMA, REFERENCE_FILE_SUMMARY_OUTPUT_SCHEMA, isContextSyncWorkflowOutput, isFollowUpCheckStructuredOutput, isProjectBriefRefreshWorkflowOutput, isProjectContextBootstrapWorkflowOutput, isReferenceFileSummaryStructuredOutput, isScratchpadRefreshStructuredOutput, isTaskCompileStructuredOutput, } from "./structured-output.js";
|
|
9
9
|
import { runCodexAppServerReadOnlyProcedure } from "../../providers/openai/app-server/read-only-procedure.js";
|
|
10
|
+
import { getProjectUserSkillsRoot } from "../../skills/index.js";
|
|
10
11
|
function readOnlyAppServerOptions(options, prompt, outputSchema, skillSelectionName) {
|
|
11
12
|
if (options.readOnlyAppServer === undefined) {
|
|
12
13
|
throw new Error("Codex app-server read-only Procedure adapter is not configured");
|
|
@@ -36,6 +37,9 @@ function readOnlyAppServerOptions(options, prompt, outputSchema, skillSelectionN
|
|
|
36
37
|
...(options.readOnlyAppServer.tuttiHome === undefined
|
|
37
38
|
? {}
|
|
38
39
|
: { tuttiHome: options.readOnlyAppServer.tuttiHome }),
|
|
40
|
+
...(options.readOnlyAppServer.userSkillsRoot === undefined
|
|
41
|
+
? {}
|
|
42
|
+
: { userSkillsRoot: options.readOnlyAppServer.userSkillsRoot }),
|
|
39
43
|
...(options.readOnlyAppServer.builtInSkillsRoot === undefined
|
|
40
44
|
? {}
|
|
41
45
|
: { builtInSkillsRoot: options.readOnlyAppServer.builtInSkillsRoot }),
|
|
@@ -421,6 +425,7 @@ export function resolveProjectOpenAiProcedureWorkflowRunner(options) {
|
|
|
421
425
|
apiKey: credential.secret,
|
|
422
426
|
workspaceRoot: options.workspaceRoot,
|
|
423
427
|
tuttiHome: options.tuttiHome,
|
|
428
|
+
userSkillsRoot: getProjectUserSkillsRoot(options.tuttiHome, options.projectId),
|
|
424
429
|
...(options.agentContext === undefined ? {} : { agentContext: options.agentContext }),
|
|
425
430
|
},
|
|
426
431
|
...(options.recordUsage === undefined ? {} : { recordUsage: options.recordUsage }),
|
|
@@ -16,6 +16,7 @@ export type CodexAppServerReadOnlyProcedureInput<TOutput> = {
|
|
|
16
16
|
webSearchMode?: CodexAppServerWebSearchMode;
|
|
17
17
|
skillSelectionName?: CodexAppServerSkillSelectionName;
|
|
18
18
|
tuttiHome?: string;
|
|
19
|
+
userSkillsRoot?: string;
|
|
19
20
|
builtInSkillsRoot?: string;
|
|
20
21
|
agentContext?: CodexAppServerAgentContextRuntime;
|
|
21
22
|
strictLeakCheck?: boolean;
|
|
@@ -81,7 +81,7 @@ export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
|
81
81
|
try {
|
|
82
82
|
skillInputs = resolveCodexAppServerSkillInputs({
|
|
83
83
|
...(options.skillSelectionName === undefined ? {} : { selectionName: options.skillSelectionName }),
|
|
84
|
-
...(options.
|
|
84
|
+
...(options.userSkillsRoot === undefined ? {} : { userSkillsRoot: options.userSkillsRoot }),
|
|
85
85
|
...(options.builtInSkillsRoot === undefined
|
|
86
86
|
? {}
|
|
87
87
|
: { builtInSkillsRoot: options.builtInSkillsRoot }),
|
|
@@ -100,6 +100,7 @@ export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
|
100
100
|
options.workspaceRoot,
|
|
101
101
|
options.appServerCwd ?? "",
|
|
102
102
|
options.tuttiHome ?? "",
|
|
103
|
+
options.userSkillsRoot ?? "",
|
|
103
104
|
options.builtInSkillsRoot ?? "",
|
|
104
105
|
]));
|
|
105
106
|
}
|
|
@@ -145,6 +146,7 @@ export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
|
145
146
|
appServerCwd,
|
|
146
147
|
...readablePaths,
|
|
147
148
|
options.tuttiHome ?? "",
|
|
149
|
+
options.userSkillsRoot ?? "",
|
|
148
150
|
options.builtInSkillsRoot ?? "",
|
|
149
151
|
...(contextRuntimeHint?.sensitiveValues ?? []),
|
|
150
152
|
...skillInputs.map((skill) => skill.path),
|
|
@@ -20,10 +20,12 @@ function actionFromNotification(notification) {
|
|
|
20
20
|
if (combined.includes("commandexecution") || combined.includes("command_execution")) {
|
|
21
21
|
return "running_command";
|
|
22
22
|
}
|
|
23
|
-
if (
|
|
23
|
+
if (method === "turn/diff/updated" ||
|
|
24
|
+
combined.includes("filechange") ||
|
|
25
|
+
combined.includes("file_change")) {
|
|
24
26
|
return "editing_files";
|
|
25
27
|
}
|
|
26
|
-
if (combined.includes("plan")) {
|
|
28
|
+
if (method === "turn/plan/updated" || combined.includes("plan")) {
|
|
27
29
|
return "planning";
|
|
28
30
|
}
|
|
29
31
|
if (combined.includes("mcptoolcall") ||
|
|
@@ -37,9 +39,6 @@ function actionFromNotification(notification) {
|
|
|
37
39
|
if (combined.includes("reasoning")) {
|
|
38
40
|
return "reading_context";
|
|
39
41
|
}
|
|
40
|
-
if (method === "item/agentMessage/delta" || method === "item/completed") {
|
|
41
|
-
return "finalizing";
|
|
42
|
-
}
|
|
43
42
|
return undefined;
|
|
44
43
|
}
|
|
45
44
|
function runtimeTokenUsage(usage) {
|
|
@@ -56,13 +56,13 @@ export declare function resolveCodexAppServerSkillInputs(options: {
|
|
|
56
56
|
selectionName?: CodexAppServerSkillSelectionName;
|
|
57
57
|
selection?: CodexAppServerSkillSelection;
|
|
58
58
|
builtInSkillsRoot?: string;
|
|
59
|
-
|
|
59
|
+
userSkillsRoot?: string;
|
|
60
60
|
}): CodexAppServerSkillInput[];
|
|
61
61
|
export declare function resolveCodexAppServerSkillsListWarmup(options: {
|
|
62
62
|
cwd: string;
|
|
63
63
|
selectionName?: CodexAppServerSkillSelectionName;
|
|
64
64
|
selection?: CodexAppServerSkillSelection;
|
|
65
|
-
|
|
65
|
+
userSkillsRoot?: string;
|
|
66
66
|
}): CodexAppServerSkillsListWarmup | undefined;
|
|
67
67
|
export declare function buildCodexAppServerTurnInput(options: {
|
|
68
68
|
prompt: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, statSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import {
|
|
4
|
+
import { listUserSkills } from "../../../skills/index.js";
|
|
5
5
|
export class CodexAppServerSkillSelectionError extends Error {
|
|
6
6
|
code;
|
|
7
7
|
constructor(code, message) {
|
|
@@ -117,7 +117,7 @@ function resolveBuiltInSkill(options) {
|
|
|
117
117
|
function resolveUserSkill(options) {
|
|
118
118
|
return {
|
|
119
119
|
name: options.name,
|
|
120
|
-
path: join(
|
|
120
|
+
path: join(options.userSkillsRoot, options.name),
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
123
|
export function resolveCodexAppServerSkillSelection(selectionName) {
|
|
@@ -134,8 +134,9 @@ export function resolveCodexAppServerSkillInputs(options) {
|
|
|
134
134
|
: resolveCodexAppServerSkillSelection(options.selectionName));
|
|
135
135
|
const builtInSkillsRoot = options.builtInSkillsRoot ?? DEFAULT_BUILT_IN_SKILLS_ROOT;
|
|
136
136
|
const builtInSkills = selection.builtInSkillNames.map((name) => resolveBuiltInSkill({ builtInSkillsRoot, name }));
|
|
137
|
-
const
|
|
138
|
-
|
|
137
|
+
const userSkillsRoot = options.userSkillsRoot;
|
|
138
|
+
const userSkills = selection.userSkillMode === "all_enabled" && userSkillsRoot !== undefined
|
|
139
|
+
? listUserSkills(userSkillsRoot).map((skill) => resolveUserSkill({ userSkillsRoot, name: skill.name }))
|
|
139
140
|
: [];
|
|
140
141
|
return [...builtInSkills, ...userSkills];
|
|
141
142
|
}
|
|
@@ -148,10 +149,10 @@ export function resolveCodexAppServerSkillsListWarmup(options) {
|
|
|
148
149
|
contextApiScopes: [],
|
|
149
150
|
}
|
|
150
151
|
: resolveCodexAppServerSkillSelection(options.selectionName));
|
|
151
|
-
if (selection.userSkillMode !== "all_enabled" || options.
|
|
152
|
+
if (selection.userSkillMode !== "all_enabled" || options.userSkillsRoot === undefined) {
|
|
152
153
|
return undefined;
|
|
153
154
|
}
|
|
154
|
-
if (listUserSkills(options.
|
|
155
|
+
if (listUserSkills(options.userSkillsRoot).length === 0) {
|
|
155
156
|
return undefined;
|
|
156
157
|
}
|
|
157
158
|
return {
|
|
@@ -160,7 +161,7 @@ export function resolveCodexAppServerSkillsListWarmup(options) {
|
|
|
160
161
|
perCwdExtraUserRoots: [
|
|
161
162
|
{
|
|
162
163
|
cwd: options.cwd,
|
|
163
|
-
extraUserRoots: [
|
|
164
|
+
extraUserRoots: [options.userSkillsRoot],
|
|
164
165
|
},
|
|
165
166
|
],
|
|
166
167
|
};
|
|
@@ -40,6 +40,7 @@ export type CodexAppServerWorkspaceWriteRunInput<TOutput> = {
|
|
|
40
40
|
approvalsReviewer?: CodexAppServerApprovalsReviewer;
|
|
41
41
|
skillSelectionName?: CodexAppServerSkillSelectionName;
|
|
42
42
|
tuttiHome?: string;
|
|
43
|
+
userSkillsRoot?: string;
|
|
43
44
|
builtInSkillsRoot?: string;
|
|
44
45
|
agentContext?: CodexAppServerAgentContextRuntime;
|
|
45
46
|
approvalHandler?: CodexAppServerApprovalHandler;
|
|
@@ -153,7 +153,7 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
153
153
|
try {
|
|
154
154
|
skillInputs = resolveCodexAppServerSkillInputs({
|
|
155
155
|
...(options.skillSelectionName === undefined ? {} : { selectionName: options.skillSelectionName }),
|
|
156
|
-
...(options.
|
|
156
|
+
...(options.userSkillsRoot === undefined ? {} : { userSkillsRoot: options.userSkillsRoot }),
|
|
157
157
|
...(options.builtInSkillsRoot === undefined
|
|
158
158
|
? {}
|
|
159
159
|
: { builtInSkillsRoot: options.builtInSkillsRoot }),
|
|
@@ -161,7 +161,7 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
161
161
|
skillsListWarmup = resolveCodexAppServerSkillsListWarmup({
|
|
162
162
|
cwd: options.workspaceRoot,
|
|
163
163
|
...(options.skillSelectionName === undefined ? {} : { selectionName: options.skillSelectionName }),
|
|
164
|
-
...(options.
|
|
164
|
+
...(options.userSkillsRoot === undefined ? {} : { userSkillsRoot: options.userSkillsRoot }),
|
|
165
165
|
});
|
|
166
166
|
contextRuntimeHint = resolveCodexAppServerContextRuntimeHint({
|
|
167
167
|
...(options.skillSelectionName === undefined ? {} : { selectionName: options.skillSelectionName }),
|
|
@@ -176,6 +176,7 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
176
176
|
options.apiKey,
|
|
177
177
|
options.workspaceRoot,
|
|
178
178
|
options.tuttiHome ?? "",
|
|
179
|
+
options.userSkillsRoot ?? "",
|
|
179
180
|
options.builtInSkillsRoot ?? "",
|
|
180
181
|
]));
|
|
181
182
|
}
|
|
@@ -219,6 +220,7 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
219
220
|
codexHome,
|
|
220
221
|
options.workspaceRoot,
|
|
221
222
|
options.tuttiHome ?? "",
|
|
223
|
+
options.userSkillsRoot ?? "",
|
|
222
224
|
options.builtInSkillsRoot ?? "",
|
|
223
225
|
...(contextRuntimeHint?.sensitiveValues ?? []),
|
|
224
226
|
...skillInputs.map((skill) => skill.path),
|
|
@@ -2,6 +2,7 @@ import { CHAT_ASSISTANT_OUTPUT_SCHEMA, isChatAssistantOutput, } from "../../chat
|
|
|
2
2
|
import { readOpenAiApiKeyCredential } from "./credential-store.js";
|
|
3
3
|
import { resolveOpenAiProviderConfig, } from "./provider-config.js";
|
|
4
4
|
import { runCodexAppServerReadOnlyProcedure } from "./app-server/read-only-procedure.js";
|
|
5
|
+
import { getProjectUserSkillsRoot } from "../../skills/index.js";
|
|
5
6
|
export function createOpenAiReadOnlyChatAssistantModel(options) {
|
|
6
7
|
return {
|
|
7
8
|
async answer(input) {
|
|
@@ -19,6 +20,7 @@ export function createOpenAiReadOnlyChatAssistantModel(options) {
|
|
|
19
20
|
webSearchMode: "live",
|
|
20
21
|
skillSelectionName: "chat_assistant",
|
|
21
22
|
...(options.tuttiHome === undefined ? {} : { tuttiHome: options.tuttiHome }),
|
|
23
|
+
...(options.userSkillsRoot === undefined ? {} : { userSkillsRoot: options.userSkillsRoot }),
|
|
22
24
|
...(options.builtInSkillsRoot === undefined
|
|
23
25
|
? {}
|
|
24
26
|
: { builtInSkillsRoot: options.builtInSkillsRoot }),
|
|
@@ -60,6 +62,7 @@ export function resolveProjectOpenAiReadOnlyChatAssistantModel(options) {
|
|
|
60
62
|
apiKey: credential.secret,
|
|
61
63
|
workspaceRoot: options.workspaceRoot,
|
|
62
64
|
tuttiHome: options.tuttiHome,
|
|
65
|
+
userSkillsRoot: getProjectUserSkillsRoot(options.tuttiHome, options.projectId),
|
|
63
66
|
...(options.agentContext === undefined ? {} : { agentContext: options.agentContext }),
|
|
64
67
|
...(options.recordUsage === undefined ? {} : { recordUsage: options.recordUsage }),
|
|
65
68
|
}),
|
|
@@ -13,6 +13,7 @@ export type OpenAiRunPipelineRunnerOptions = {
|
|
|
13
13
|
mergeWorkspaceRoot?: string;
|
|
14
14
|
promptsRoot?: string;
|
|
15
15
|
tuttiHome?: string;
|
|
16
|
+
userSkillsRoot?: string;
|
|
16
17
|
builtInSkillsRoot?: string;
|
|
17
18
|
agentContext?: CodexAppServerAgentContextRuntime;
|
|
18
19
|
approvalManager?: ApprovalRequestManager;
|
|
@@ -7,6 +7,7 @@ import { runWorkspaceWriteTask } from "./task-run-invocation.js";
|
|
|
7
7
|
import { readOpenAiApiKeyCredential } from "../providers/openai/credential-store.js";
|
|
8
8
|
import { resolveOpenAiProviderConfig, } from "../providers/openai/provider-config.js";
|
|
9
9
|
import { CodexAppServerWorkspaceWriteRunError } from "../providers/openai/app-server/workspace-write-run.js";
|
|
10
|
+
import { getProjectUserSkillsRoot } from "../skills/index.js";
|
|
10
11
|
import { cleanupRunWorkspace, collectRunDiff, createResultCommit, prepareRunWorkspace, promoteRunResult, WorkspaceOpsError, } from "../workspace-ops/index.js";
|
|
11
12
|
export { TASK_RUN_OUTPUT_SCHEMA } from "./task-run-output.js";
|
|
12
13
|
function isRecord(value) {
|
|
@@ -535,6 +536,7 @@ export function resolveProjectOpenAiRunPipelineRunner(options) {
|
|
|
535
536
|
runWorkspaceRoot: join(options.runWorkspaceRoot, "run-workspaces"),
|
|
536
537
|
mergeWorkspaceRoot: join(options.mergeWorkspaceRoot ?? options.runWorkspaceRoot, "merge-workspaces"),
|
|
537
538
|
tuttiHome: options.tuttiHome,
|
|
539
|
+
userSkillsRoot: getProjectUserSkillsRoot(options.tuttiHome, options.projectId),
|
|
538
540
|
...(options.agentContext === undefined ? {} : { agentContext: options.agentContext }),
|
|
539
541
|
...(options.approvalManager === undefined
|
|
540
542
|
? {}
|
|
@@ -99,6 +99,7 @@ export async function runWorkspaceWriteTask(options, input, handle) {
|
|
|
99
99
|
? {}
|
|
100
100
|
: { apiBaseUrl: options.config.api_base_url }),
|
|
101
101
|
...(options.tuttiHome === undefined ? {} : { tuttiHome: options.tuttiHome }),
|
|
102
|
+
...(options.userSkillsRoot === undefined ? {} : { userSkillsRoot: options.userSkillsRoot }),
|
|
102
103
|
...(options.builtInSkillsRoot === undefined
|
|
103
104
|
? {}
|
|
104
105
|
: { builtInSkillsRoot: options.builtInSkillsRoot }),
|
|
@@ -21,7 +21,7 @@ import { createTrustedRelaySessionMetadataStore, } from "../session/relay-sessio
|
|
|
21
21
|
import { LaunchError } from "./errors.js";
|
|
22
22
|
import { relayStateFromLaunchStatus } from "./host-relay-status.js";
|
|
23
23
|
import { appendHostLogLine, readHostRegistrationSecret, createMachineRuntimeEndpointToken, deleteMachineRuntimeEndpoint, ensureHostLogFile, getHostLogFilePath, writeMachineRuntimeEndpoint, } from "./machine-local.js";
|
|
24
|
-
import { readProjectDisplayName, writeProjectDisplayName } from "./project-identity.js";
|
|
24
|
+
import { readProjectDescription, readProjectDisplayName, writeProjectDescription, writeProjectDisplayName, } from "./project-identity.js";
|
|
25
25
|
export const HOST_SERVER_VERSION = "0.0.0";
|
|
26
26
|
function createHostRuntimeLogger(options) {
|
|
27
27
|
return {
|
|
@@ -163,6 +163,7 @@ export async function startForegroundHostServer(options) {
|
|
|
163
163
|
};
|
|
164
164
|
let projectDisplayName = readProjectDisplayName(options.preparation.workspace_root) ??
|
|
165
165
|
(basename(options.preparation.workspace_root) || options.preparation.project_id);
|
|
166
|
+
let projectDescription = readProjectDescription(options.preparation.workspace_root) ?? "";
|
|
166
167
|
const projectContext = {
|
|
167
168
|
workspaceRoot: options.preparation.workspace_root,
|
|
168
169
|
projectName: projectDisplayName,
|
|
@@ -174,6 +175,7 @@ export async function startForegroundHostServer(options) {
|
|
|
174
175
|
const projectApiProject = {
|
|
175
176
|
project_id: options.preparation.project_id,
|
|
176
177
|
display_name: projectDisplayName,
|
|
178
|
+
...(projectDescription.length === 0 ? {} : { description: projectDescription }),
|
|
177
179
|
identity_source: "git_config",
|
|
178
180
|
};
|
|
179
181
|
const updateRuntimeProjectDisplayName = (displayName) => {
|
|
@@ -183,6 +185,16 @@ export async function startForegroundHostServer(options) {
|
|
|
183
185
|
chatAssistantProject.display_name = displayName;
|
|
184
186
|
projectApiProject.display_name = displayName;
|
|
185
187
|
};
|
|
188
|
+
const updateRuntimeProjectDescription = (description) => {
|
|
189
|
+
writeProjectDescription(options.preparation.workspace_root, description);
|
|
190
|
+
projectDescription = description;
|
|
191
|
+
if (description.length === 0) {
|
|
192
|
+
delete projectApiProject.description;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
projectApiProject.description = description;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
186
198
|
const controlPlaneLogger = createHostRuntimeLogger({
|
|
187
199
|
component: "control-plane",
|
|
188
200
|
logFilePath,
|
|
@@ -353,6 +365,9 @@ export async function startForegroundHostServer(options) {
|
|
|
353
365
|
updateProjectDisplayName: (displayName) => {
|
|
354
366
|
updateRuntimeProjectDisplayName(displayName);
|
|
355
367
|
},
|
|
368
|
+
updateProjectDescription: (description) => {
|
|
369
|
+
updateRuntimeProjectDescription(description);
|
|
370
|
+
},
|
|
356
371
|
...(resolveStagedUpload === undefined ? {} : { resolveStagedUpload }),
|
|
357
372
|
capabilities: {
|
|
358
373
|
clarification: true,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ProjectId } from "@tutti/shared/ids";
|
|
2
2
|
export declare const PROJECT_ID_GIT_CONFIG_KEY = "tutti.project-id";
|
|
3
3
|
export declare const PROJECT_DISPLAY_NAME_GIT_CONFIG_KEY = "tutti.project-display-name";
|
|
4
|
+
export declare const PROJECT_DESCRIPTION_GIT_CONFIG_KEY = "tutti.project-description";
|
|
4
5
|
export type ProjectIdentityReadResult = {
|
|
5
6
|
kind: "missing";
|
|
6
7
|
} | {
|
|
@@ -12,6 +13,8 @@ export declare function readProjectIdentity(workspaceRoot: string): ProjectIdent
|
|
|
12
13
|
export declare function writeProjectIdentity(workspaceRoot: string, projectId: ProjectId): void;
|
|
13
14
|
export declare function readProjectDisplayName(workspaceRoot: string): string | null;
|
|
14
15
|
export declare function writeProjectDisplayName(workspaceRoot: string, displayName: string): void;
|
|
16
|
+
export declare function readProjectDescription(workspaceRoot: string): string | null;
|
|
17
|
+
export declare function writeProjectDescription(workspaceRoot: string, description: string): void;
|
|
15
18
|
export declare function ensureProjectIdentity(workspaceRoot: string, projectId?: ProjectId): {
|
|
16
19
|
project_id: ProjectId;
|
|
17
20
|
created: boolean;
|
|
@@ -5,6 +5,7 @@ import { createProjectId, ID_PREFIXES, isPrefixedId } from "@tutti/shared/ids";
|
|
|
5
5
|
import { LaunchError } from "./errors.js";
|
|
6
6
|
export const PROJECT_ID_GIT_CONFIG_KEY = "tutti.project-id";
|
|
7
7
|
export const PROJECT_DISPLAY_NAME_GIT_CONFIG_KEY = "tutti.project-display-name";
|
|
8
|
+
export const PROJECT_DESCRIPTION_GIT_CONFIG_KEY = "tutti.project-description";
|
|
8
9
|
function runGitRaw(args, cwd) {
|
|
9
10
|
const result = spawnSync("git", [...args], {
|
|
10
11
|
cwd,
|
|
@@ -76,6 +77,29 @@ export function readProjectDisplayName(workspaceRoot) {
|
|
|
76
77
|
export function writeProjectDisplayName(workspaceRoot, displayName) {
|
|
77
78
|
runGit(["config", "--local", PROJECT_DISPLAY_NAME_GIT_CONFIG_KEY, displayName], resolve(workspaceRoot));
|
|
78
79
|
}
|
|
80
|
+
export function readProjectDescription(workspaceRoot) {
|
|
81
|
+
const result = runGitRaw(["config", "--local", "--get", PROJECT_DESCRIPTION_GIT_CONFIG_KEY], resolve(workspaceRoot));
|
|
82
|
+
if (result.status !== 0) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const description = result.stdout.trim();
|
|
86
|
+
return description.length === 0 ? null : description;
|
|
87
|
+
}
|
|
88
|
+
export function writeProjectDescription(workspaceRoot, description) {
|
|
89
|
+
const workspace = resolve(workspaceRoot);
|
|
90
|
+
const trimmedDescription = description.trim();
|
|
91
|
+
if (trimmedDescription.length === 0) {
|
|
92
|
+
const result = runGitRaw(["config", "--local", "--unset", PROJECT_DESCRIPTION_GIT_CONFIG_KEY], workspace);
|
|
93
|
+
if (result.status === 0 || result.status === 5) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const stderr = result.stderr.trim();
|
|
97
|
+
throw new LaunchError("git_bootstrap_failed", stderr.length > 0
|
|
98
|
+
? stderr
|
|
99
|
+
: `git config --local --unset ${PROJECT_DESCRIPTION_GIT_CONFIG_KEY} failed`, "Resolve the Git error and run `tutti launch` again.");
|
|
100
|
+
}
|
|
101
|
+
runGit(["config", "--local", PROJECT_DESCRIPTION_GIT_CONFIG_KEY, trimmedDescription], workspace);
|
|
102
|
+
}
|
|
79
103
|
export function ensureProjectIdentity(workspaceRoot, projectId = createProjectId()) {
|
|
80
104
|
const existing = readProjectIdentity(workspaceRoot);
|
|
81
105
|
if (existing.kind === "present") {
|
|
@@ -31,4 +31,5 @@ export type AgentContextRouteOptions = Pick<HostProjectApiRouteOptions, "project
|
|
|
31
31
|
export declare function requireProjectStore(options: AgentContextRouteOptions): HostProjectStore;
|
|
32
32
|
export declare function requireWorkspaceRoot(options: AgentContextRouteOptions): string;
|
|
33
33
|
export declare function requireTuttiHome(options: AgentContextRouteOptions): string;
|
|
34
|
+
export declare function requireProjectUserSkillsRoot(options: AgentContextRouteOptions): string;
|
|
34
35
|
//# sourceMappingURL=agent-context-shared.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getProjectUserSkillsRoot } from "../../../skills/index.js";
|
|
1
2
|
import { AgentContextBadRequestError } from "./agent-context-errors.js";
|
|
2
3
|
export const AGENT_CONTEXT_BASE_PATH = "/internal/agent-context";
|
|
3
4
|
export const MESSAGE_LIMIT_DEFAULT = 50;
|
|
@@ -41,4 +42,7 @@ export function requireTuttiHome(options) {
|
|
|
41
42
|
}
|
|
42
43
|
return options.tuttiHome;
|
|
43
44
|
}
|
|
45
|
+
export function requireProjectUserSkillsRoot(options) {
|
|
46
|
+
return getProjectUserSkillsRoot(requireTuttiHome(options), options.project.project_id);
|
|
47
|
+
}
|
|
44
48
|
//# sourceMappingURL=agent-context-shared.js.map
|
|
@@ -3,7 +3,7 @@ import { listUserSkills, readUserSkill, SkillServiceError, } from "../../../skil
|
|
|
3
3
|
import { authorizeAgentContextRequest } from "./agent-context-auth.js";
|
|
4
4
|
import { AgentContextBadRequestError } from "./agent-context-errors.js";
|
|
5
5
|
import { boundedLimit, pageByOffset, queryString, truncateText } from "./agent-context-query.js";
|
|
6
|
-
import { AGENT_CONTEXT_BASE_PATH, USER_SKILLS_LIMIT_DEFAULT, USER_SKILLS_LIMIT_MAX, USER_SKILL_MD_DEFAULT_MAX_CHARS, USER_SKILL_MD_MAX_CHARS,
|
|
6
|
+
import { AGENT_CONTEXT_BASE_PATH, USER_SKILLS_LIMIT_DEFAULT, USER_SKILLS_LIMIT_MAX, USER_SKILL_MD_DEFAULT_MAX_CHARS, USER_SKILL_MD_MAX_CHARS, requireProjectUserSkillsRoot, } from "./agent-context-shared.js";
|
|
7
7
|
function skillUnavailable(input) {
|
|
8
8
|
return {
|
|
9
9
|
kind: "unavailable",
|
|
@@ -37,7 +37,7 @@ export function registerAgentContextSkillRoutes(app, options) {
|
|
|
37
37
|
max: USER_SKILLS_LIMIT_MAX,
|
|
38
38
|
});
|
|
39
39
|
const cursor = queryString(request.query.cursor);
|
|
40
|
-
const page = pageByOffset(listUserSkills(
|
|
40
|
+
const page = pageByOffset(listUserSkills(requireProjectUserSkillsRoot(options)), {
|
|
41
41
|
endpoint: "skills",
|
|
42
42
|
...(cursor === undefined ? {} : { cursor }),
|
|
43
43
|
limit,
|
|
@@ -59,7 +59,7 @@ export function registerAgentContextSkillRoutes(app, options) {
|
|
|
59
59
|
});
|
|
60
60
|
const skillName = request.params.skillName;
|
|
61
61
|
try {
|
|
62
|
-
const skill = readUserSkill(
|
|
62
|
+
const skill = readUserSkill(requireProjectUserSkillsRoot(options), skillName);
|
|
63
63
|
const skillMd = truncateText(redactText(skill.skill_md), maxChars);
|
|
64
64
|
return {
|
|
65
65
|
kind: "skill",
|
|
@@ -6,5 +6,6 @@ export declare function schedulerRunNowInvalidates(disposition: RunSchedulerNowD
|
|
|
6
6
|
export declare function clarificationRoundInvalidates(roundId: ClarificationRoundRef): QueryInvalidationHint[];
|
|
7
7
|
export declare function approvalInvalidates(): QueryInvalidationHint[];
|
|
8
8
|
export declare function readStateInvalidates(): QueryInvalidationHint[];
|
|
9
|
+
export declare function projectMetadataInvalidates(): QueryInvalidationHint[];
|
|
9
10
|
export declare function projectDisplayNameInvalidates(): QueryInvalidationHint[];
|
|
10
11
|
//# sourceMappingURL=invalidations.d.ts.map
|
|
@@ -51,7 +51,10 @@ export function approvalInvalidates() {
|
|
|
51
51
|
export function readStateInvalidates() {
|
|
52
52
|
return [{ kind: "read_state" }, { kind: "bootstrap" }];
|
|
53
53
|
}
|
|
54
|
-
export function
|
|
54
|
+
export function projectMetadataInvalidates() {
|
|
55
55
|
return [{ kind: "workspace" }, { kind: "bootstrap" }];
|
|
56
56
|
}
|
|
57
|
+
export function projectDisplayNameInvalidates() {
|
|
58
|
+
return projectMetadataInvalidates();
|
|
59
|
+
}
|
|
57
60
|
//# sourceMappingURL=invalidations.js.map
|
|
@@ -435,6 +435,10 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
|
|
|
435
435
|
readonly type: "string";
|
|
436
436
|
readonly minLength: 1;
|
|
437
437
|
};
|
|
438
|
+
readonly description: {
|
|
439
|
+
readonly type: "string";
|
|
440
|
+
readonly maxLength: 160;
|
|
441
|
+
};
|
|
438
442
|
readonly identity_source: {
|
|
439
443
|
readonly type: "string";
|
|
440
444
|
readonly enum: readonly ["git_config"];
|
|
@@ -631,6 +635,10 @@ export declare const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES: ({
|
|
|
631
635
|
readonly type: "string";
|
|
632
636
|
readonly minLength: 1;
|
|
633
637
|
};
|
|
638
|
+
readonly description: {
|
|
639
|
+
readonly type: "string";
|
|
640
|
+
readonly maxLength: 160;
|
|
641
|
+
};
|
|
634
642
|
readonly identity_source: {
|
|
635
643
|
readonly type: "string";
|
|
636
644
|
readonly enum: readonly ["git_config"];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MarkReadBodySchema, MarkReadResponseSchema, ReadStateSummaryProjectionSchema, UpdateProjectDisplayNameBodySchema, UpdateProjectDisplayNameResponseSchema, } from "@tutti/shared/schemas/api";
|
|
1
|
+
import { MarkReadBodySchema, MarkReadResponseSchema, ReadStateSummaryProjectionSchema, UpdateProjectDescriptionBodySchema, UpdateProjectDescriptionResponseSchema, UpdateProjectDisplayNameBodySchema, UpdateProjectDisplayNameResponseSchema, } from "@tutti/shared/schemas/api";
|
|
2
2
|
import { HOST_PROJECT_API_BASE_PATH } from "./constants.js";
|
|
3
3
|
import { BootstrapResponseSchema, ProviderConfigProjectionSchema, ProviderUsageProjectionSchema, SessionResponseSchema, WorkspaceResponseSchema, } from "./schemas.js";
|
|
4
4
|
export const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES = [
|
|
@@ -57,6 +57,19 @@ export const HOST_PROJECT_WORKSPACE_OPENAPI_ROUTES = [
|
|
|
57
57
|
},
|
|
58
58
|
},
|
|
59
59
|
},
|
|
60
|
+
{
|
|
61
|
+
method: "post",
|
|
62
|
+
path: `${HOST_PROJECT_API_BASE_PATH}/workspace/project-description`,
|
|
63
|
+
summary: "Update the current project description.",
|
|
64
|
+
tags: ["workspace"],
|
|
65
|
+
requestBody: UpdateProjectDescriptionBodySchema,
|
|
66
|
+
responses: {
|
|
67
|
+
200: {
|
|
68
|
+
description: "Project description update command response.",
|
|
69
|
+
schema: UpdateProjectDescriptionResponseSchema,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
60
73
|
{
|
|
61
74
|
method: "get",
|
|
62
75
|
path: `${HOST_PROJECT_API_BASE_PATH}/bootstrap`,
|
|
@@ -1600,6 +1600,10 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
|
|
|
1600
1600
|
readonly type: "string";
|
|
1601
1601
|
readonly minLength: 1;
|
|
1602
1602
|
};
|
|
1603
|
+
readonly description: {
|
|
1604
|
+
readonly type: "string";
|
|
1605
|
+
readonly maxLength: 160;
|
|
1606
|
+
};
|
|
1603
1607
|
readonly identity_source: {
|
|
1604
1608
|
readonly type: "string";
|
|
1605
1609
|
readonly enum: readonly ["git_config"];
|
|
@@ -1784,6 +1788,10 @@ export declare const HOST_PROJECT_OPENAPI_ROUTES: ({
|
|
|
1784
1788
|
readonly type: "string";
|
|
1785
1789
|
readonly minLength: 1;
|
|
1786
1790
|
};
|
|
1791
|
+
readonly description: {
|
|
1792
|
+
readonly type: "string";
|
|
1793
|
+
readonly maxLength: 160;
|
|
1794
|
+
};
|
|
1787
1795
|
readonly identity_source: {
|
|
1788
1796
|
readonly type: "string";
|
|
1789
1797
|
readonly enum: readonly ["git_config"];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { GetMessagesRequest, SendClarificationRoundMessagePayload, SendMainChatMessagePayload, UpdateProjectDisplayNamePayload } from "@tutti/shared/schemas/api";
|
|
1
|
+
import type { GetMessagesRequest, SendClarificationRoundMessagePayload, SendMainChatMessagePayload, UpdateProjectDescriptionPayload, UpdateProjectDisplayNamePayload } from "@tutti/shared/schemas/api";
|
|
2
2
|
export declare function requireValidMessageWindowRequest(query: GetMessagesRequest): GetMessagesRequest;
|
|
3
3
|
export declare function requireValidSendMainChatPayload(payload: SendMainChatMessagePayload): SendMainChatMessagePayload;
|
|
4
4
|
export declare function requireValidRoundMessagePayload(payload: SendClarificationRoundMessagePayload): SendClarificationRoundMessagePayload;
|
|
5
5
|
export declare function requireValidProjectDisplayNamePayload(payload: UpdateProjectDisplayNamePayload): UpdateProjectDisplayNamePayload;
|
|
6
|
+
export declare function requireValidProjectDescriptionPayload(payload: UpdateProjectDescriptionPayload): UpdateProjectDescriptionPayload;
|
|
6
7
|
//# sourceMappingURL=payload-validation.d.ts.map
|
|
@@ -33,4 +33,11 @@ export function requireValidProjectDisplayNamePayload(payload) {
|
|
|
33
33
|
}
|
|
34
34
|
return { display_name: displayName };
|
|
35
35
|
}
|
|
36
|
+
export function requireValidProjectDescriptionPayload(payload) {
|
|
37
|
+
const description = payload.description.trim();
|
|
38
|
+
if (description.length > 160) {
|
|
39
|
+
throw new HostProjectValidationError("Project description cannot exceed 160 characters");
|
|
40
|
+
}
|
|
41
|
+
return { description };
|
|
42
|
+
}
|
|
36
43
|
//# sourceMappingURL=payload-validation.js.map
|
|
@@ -440,6 +440,10 @@ export declare const WorkspaceResponseSchema: {
|
|
|
440
440
|
readonly type: "string";
|
|
441
441
|
readonly minLength: 1;
|
|
442
442
|
};
|
|
443
|
+
readonly description: {
|
|
444
|
+
readonly type: "string";
|
|
445
|
+
readonly maxLength: 160;
|
|
446
|
+
};
|
|
443
447
|
readonly identity_source: {
|
|
444
448
|
readonly type: "string";
|
|
445
449
|
readonly enum: readonly ["git_config"];
|
|
@@ -613,6 +617,10 @@ export declare const BootstrapResponseSchema: {
|
|
|
613
617
|
readonly type: "string";
|
|
614
618
|
readonly minLength: 1;
|
|
615
619
|
};
|
|
620
|
+
readonly description: {
|
|
621
|
+
readonly type: "string";
|
|
622
|
+
readonly maxLength: 160;
|
|
623
|
+
};
|
|
616
624
|
readonly identity_source: {
|
|
617
625
|
readonly type: "string";
|
|
618
626
|
readonly enum: readonly ["git_config"];
|
|
@@ -231,6 +231,7 @@ export const WorkspaceResponseSchema = {
|
|
|
231
231
|
properties: {
|
|
232
232
|
project_id: ProjectIdSchema,
|
|
233
233
|
display_name: { type: "string", minLength: 1 },
|
|
234
|
+
description: { type: "string", maxLength: 160 },
|
|
234
235
|
identity_source: { type: "string", enum: ["git_config"] },
|
|
235
236
|
},
|
|
236
237
|
},
|
|
@@ -2,6 +2,7 @@ import type { QueryInvalidationHint } from "@tutti/shared/schemas/api";
|
|
|
2
2
|
import type { HostProjectApiRouteOptions } from "./types.js";
|
|
3
3
|
export declare function skillsChangedInvalidates(): QueryInvalidationHint[];
|
|
4
4
|
export declare function requireTuttiHome(options: HostProjectApiRouteOptions): string;
|
|
5
|
+
export declare function requireProjectUserSkillsRoot(options: HostProjectApiRouteOptions): string;
|
|
5
6
|
export declare function withAsyncSkillServiceErrorMapping<T>(fn: () => Promise<T>): Promise<T>;
|
|
6
7
|
export declare function withSkillServiceErrorMapping<T>(fn: () => T): T;
|
|
7
8
|
//# sourceMappingURL=skills-helpers.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SkillServiceError } from "../../../../skills/index.js";
|
|
1
|
+
import { getProjectUserSkillsRoot, SkillServiceError } from "../../../../skills/index.js";
|
|
2
2
|
import { HostProjectBadRequestError, HostProjectNotFoundError, HostProjectStoreUnavailableError, HostProjectValidationError, } from "./errors.js";
|
|
3
3
|
export function skillsChangedInvalidates() {
|
|
4
4
|
return [{ kind: "skills" }, { kind: "read_state" }, { kind: "bootstrap" }];
|
|
@@ -9,6 +9,9 @@ export function requireTuttiHome(options) {
|
|
|
9
9
|
}
|
|
10
10
|
return options.tuttiHome;
|
|
11
11
|
}
|
|
12
|
+
export function requireProjectUserSkillsRoot(options) {
|
|
13
|
+
return getProjectUserSkillsRoot(requireTuttiHome(options), options.project.project_id);
|
|
14
|
+
}
|
|
12
15
|
function toHostProjectSkillError(error) {
|
|
13
16
|
switch (error.code) {
|
|
14
17
|
case "invalid_skill_name":
|