@xfey/tutti 0.1.43 → 0.1.44

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.
@@ -11,6 +11,8 @@ export type LaunchPreparationOptions = {
11
11
  now?: () => Date;
12
12
  confirm?: LaunchConfirmationHandler;
13
13
  allowWorkspaceRootTakeover?: boolean;
14
+ projectDisplayName?: string;
15
+ projectDescription?: string;
14
16
  };
15
17
  export type LaunchProviderStatus = OpenAiProviderConfigProjection["status"];
16
18
  export type LaunchPreparationResult = {
@@ -4,7 +4,7 @@ import { readOpenAiProviderConfigProjection, resolveTuttiHome, } from "../../pro
4
4
  import { LaunchError } from "./errors.js";
5
5
  import { assertSafeProjectRoot, ensureGitBootstrap, } from "./git-bootstrap.js";
6
6
  import { ensureMachineProjectBinding } from "./machine-local.js";
7
- import { readProjectIdentity, readProjectDisplayName, writeProjectIdentity, } from "./project-identity.js";
7
+ import { readProjectIdentity, readProjectDisplayName, writeProjectDescription, writeProjectDisplayName, writeProjectIdentity, } from "./project-identity.js";
8
8
  const DEFAULT_RELAY_URL = "https://tutti.now";
9
9
  const DEFAULT_HOST_ENDPOINT_HOST = "127.0.0.1";
10
10
  const AUTO_HOST_ENDPOINT_PORT = 0;
@@ -64,6 +64,12 @@ export async function prepareLaunchProject(options) {
64
64
  gitOptions.confirm = options.confirm;
65
65
  }
66
66
  const git = await ensureGitBootstrap(gitOptions);
67
+ if (projectIdentityCreated && options.projectDisplayName !== undefined) {
68
+ writeProjectDisplayName(workspaceRoot, options.projectDisplayName);
69
+ }
70
+ if (projectIdentityCreated && options.projectDescription !== undefined) {
71
+ writeProjectDescription(workspaceRoot, options.projectDescription);
72
+ }
67
73
  const bindingOptions = {
68
74
  tuttiHome,
69
75
  projectId,
@@ -23,6 +23,10 @@ export type LocalConsoleProviderInput = {
23
23
  api_key: string;
24
24
  model: string;
25
25
  };
26
+ export type LocalConsoleProjectMetadataInput = {
27
+ display_name: string;
28
+ description?: string;
29
+ };
26
30
  export type LocalConsoleLaunchResult = {
27
31
  project: LocalConsoleProject;
28
32
  project_created: boolean;
@@ -59,6 +63,7 @@ export declare class LocalConsoleProjectService {
59
63
  }>;
60
64
  launchProject(input: {
61
65
  workspacePath: string;
66
+ project?: LocalConsoleProjectMetadataInput;
62
67
  provider?: LocalConsoleProviderInput;
63
68
  }, context: LocalConsoleInvocationContext): Promise<LocalConsoleLaunchResult>;
64
69
  openProject(projectId: string, context: LocalConsoleInvocationContext): Promise<LocalConsoleOpenResult>;
@@ -50,6 +50,20 @@ function validateProvider(input) {
50
50
  }
51
51
  return provider;
52
52
  }
53
+ function validateProjectMetadata(input) {
54
+ const displayName = input.display_name.trim();
55
+ const description = input.description?.trim();
56
+ if (displayName === "" || displayName.length > 80) {
57
+ throw new LocalConsoleProjectError("project_display_name_invalid", "Project name must be between 1 and 80 characters.");
58
+ }
59
+ if (description !== undefined && description.length > 160) {
60
+ throw new LocalConsoleProjectError("project_description_invalid", "Project description cannot exceed 160 characters.");
61
+ }
62
+ return {
63
+ display_name: displayName,
64
+ ...(description === undefined || description === "" ? {} : { description }),
65
+ };
66
+ }
53
67
  function projectFromRuntimeRow(row, providerStatus, providerModel, metadata) {
54
68
  const currentVersion = readCliVersion();
55
69
  const openUrl = projectOpenUrl(metadata.relayUrl, row.relay_project_ref);
@@ -220,6 +234,9 @@ export class LocalConsoleProjectService {
220
234
  }
221
235
  const launch = this.#runMutation(async () => await this.#launchProject({
222
236
  workspacePath,
237
+ ...(input.project === undefined
238
+ ? {}
239
+ : { project: validateProjectMetadata(input.project) }),
223
240
  ...(input.provider === undefined ? {} : { provider: validateProvider(input.provider) }),
224
241
  }, context)).finally(() => {
225
242
  this.#launches.delete(workspacePath);
@@ -234,6 +251,14 @@ export class LocalConsoleProjectService {
234
251
  preparation = await prepareLaunchProject({
235
252
  workspacePath: input.workspacePath,
236
253
  yes: true,
254
+ ...(input.project === undefined
255
+ ? {}
256
+ : {
257
+ projectDisplayName: input.project.display_name,
258
+ ...(input.project.description === undefined
259
+ ? {}
260
+ : { projectDescription: input.project.description }),
261
+ }),
237
262
  ...operation,
238
263
  });
239
264
  }
@@ -256,6 +256,15 @@ export function createLocalConsoleServer(options) {
256
256
  additionalProperties: false,
257
257
  properties: {
258
258
  workspace_path: { type: "string", minLength: 1, maxLength: 4096 },
259
+ project: {
260
+ type: "object",
261
+ required: ["display_name"],
262
+ additionalProperties: false,
263
+ properties: {
264
+ display_name: { type: "string", minLength: 1, maxLength: 80 },
265
+ description: { type: "string", maxLength: 160 },
266
+ },
267
+ },
259
268
  provider: {
260
269
  type: "object",
261
270
  required: ["base_url", "api_key", "model"],
@@ -273,6 +282,7 @@ export function createLocalConsoleServer(options) {
273
282
  const session = requireSession(request, true);
274
283
  return await projects.launchProject({
275
284
  workspacePath: request.body.workspace_path,
285
+ ...(request.body.project === undefined ? {} : { project: request.body.project }),
276
286
  ...(request.body.provider === undefined ? {} : { provider: request.body.provider }),
277
287
  }, session.context);
278
288
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfey/tutti",
3
- "version": "0.1.43",
3
+ "version": "0.1.44",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",