Files
WeHub Mirror 6bf8bebf51
CI / Test and Build (push) Failing after 1s
CI / Migrate Dev DB (push) Has been skipped
CI / Migrate DB (push) Has been skipped
CodeQL / Analyze actions (push) Has been cancelled
CodeQL / Analyze javascript-typescript (push) Has been cancelled
CI / Detect Version (push) Has been cancelled
CI / Detect Desktop Changes (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/cron.Dockerfile, ubuntu-latest, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build AMD64 (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/cron.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/db.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/pii.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/realtime.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-8vcpu-ubuntu-2404-arm, ./docker/app.Dockerfile, linux-arm64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
Helm Chart / Lint, test, and validate chart (push) Has been cancelled
Helm Chart / Chart version bumped (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Build Dev ECR (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core) (push) Has been cancelled
CI / Promote Images (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Check Desktop Signing Secrets (push) Has been cancelled
CI / Desktop Release (push) Has been cancelled
CI / Create Desktop Prerelease (push) Has been cancelled
CI / Desktop Prerelease Build (push) Has been cancelled
CI / Publish Desktop Prerelease (push) Has been cancelled
CI / Prune Desktop Prereleases (push) Has been cancelled
Helm Chart / Install on kind and run helm test (push) Has been cancelled
WeHub snapshot of cb28d14c6f2c081de7a0d8729a8c816c9adef67a
2026-08-10 11:17:50 +08:00

367 lines
13 KiB
TypeScript

import {
mapProject,
PROJECT_OUTPUT_PROPERTIES,
ROCKETLANE_API_BASE,
type RocketlaneCreateProjectParams,
type RocketlaneProjectResponse,
rocketlaneError,
rocketlaneHeaders,
} from '@/tools/rocketlane/types'
import type { ToolConfig } from '@/tools/types'
export const rocketlaneCreateProjectTool: ToolConfig<
RocketlaneCreateProjectParams,
RocketlaneProjectResponse
> = {
id: 'rocketlane_create_project',
name: 'Rocketlane Create Project',
description:
'Create a new Rocketlane project with a customer, owner, dates, team members, templates, financials, and custom fields',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rocketlane API key',
},
projectName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the project',
},
customerCompanyName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Name of the customer company (case-sensitive exact match; cannot be changed after creation)',
},
ownerUserId: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description:
'User ID of the project owner (either ownerUserId or ownerEmailId must be provided)',
},
ownerEmailId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Email of the project owner (either ownerUserId or ownerEmailId must be provided)',
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Date on which the project begins (YYYY-MM-DD); required when sources are provided',
},
dueDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Date on which the project is planned to complete (YYYY-MM-DD, on or after startDate)',
},
visibility: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Who can see the project: EVERYONE or MEMBERS',
},
statusValue: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Value (identifier) of the project status',
},
memberUserIds: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description: 'User IDs of team members from your organization to add to the project',
items: { type: 'number', description: 'User ID of a team member' },
},
customerUserIds: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description: 'User IDs of customer stakeholders to add to the project',
items: { type: 'number', description: 'User ID of a customer' },
},
customerChampionUserId: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'User ID of the customer champion',
},
fields: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Custom field assignments, each with fieldId and fieldValue (string, number, or number array matching the field type)',
items: {
type: 'object',
description: 'Custom field assignment',
properties: {
fieldId: { type: 'number', description: 'Unique identifier of the field' },
fieldValue: {
type: 'string',
description: 'Value of the field (string, number, or number array)',
},
},
},
},
sources: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Project templates to import at creation, each with templateId, startDate (YYYY-MM-DD), and optional prefix',
items: {
type: 'object',
description: 'Template source',
properties: {
templateId: { type: 'number', description: 'Unique identifier of the template' },
startDate: { type: 'string', description: 'Date the template takes effect (YYYY-MM-DD)' },
prefix: { type: 'string', description: 'Prefix distinguishing this template' },
},
},
},
placeholders: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Placeholder-to-user mappings, each with placeholderId and user ({ userId } or { emailId }); ignored unless the project is built from sources',
items: {
type: 'object',
description: 'Placeholder mapping',
properties: {
placeholderId: { type: 'number', description: 'Unique identifier of the placeholder' },
user: { type: 'object', description: 'User to assign ({ userId } or { emailId })' },
},
},
},
assignProjectOwner: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description:
'Automatically assign unassigned tasks to the project owner (skipped when no sources are used)',
},
annualizedRecurringRevenue: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Recurring revenue of the customer subscriptions for a single calendar year',
},
projectFee: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Total fee charged for the project',
},
autoAllocation: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether auto allocation is enabled for the project',
},
autoCreateCompany: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Create the customer company if it does not already exist',
},
budgetedHours: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Total hours allocated for project execution (decimal, up to two places)',
},
contractType: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Contract type for the project financials: FIXED_FEE, TIME_AND_MATERIAL, NON_BILLABLE, or SUBSCRIPTION',
},
fixedFee: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Project fee for FIXED_FEE contract type projects',
},
projectBudget: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Project budget for TIME_AND_MATERIAL contract type projects',
},
rateCardId: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Rate card ID for TIME_AND_MATERIAL contract type projects',
},
subscriptionFrequency: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Subscription renewal interval for SUBSCRIPTION contracts: MONTHLY, QUARTERLY, HALF_YEARLY, or YEARLY',
},
subscriptionStartDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Date when the subscription interval begins (YYYY-MM-DD)',
},
periodMinutes: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Budgeted minutes for each subscription period',
},
periodBudget: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Fixed budget of every subscription period',
},
noOfPeriods: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of periods in the subscription',
},
currency: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Currency for the project financials (ISO code, e.g. USD); cannot be changed once set',
},
externalReferenceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Identifier linking the project to an external system',
},
includeFields: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated extra fields to return in the response (e.g. budgetedHours,progressPercentage)',
},
includeAllFields: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Return all fields in the response body',
},
},
request: {
url: (params) => {
const url = new URL(`${ROCKETLANE_API_BASE}/projects`)
if (params.includeFields) url.searchParams.set('includeFields', params.includeFields)
if (params.includeAllFields != null)
url.searchParams.set('includeAllFields', String(params.includeAllFields))
return url.toString()
},
method: 'POST',
headers: (params) => rocketlaneHeaders(params.apiKey),
body: (params) => {
const body: Record<string, unknown> = {
projectName: params.projectName,
customer: { companyName: params.customerCompanyName },
}
if (params.ownerUserId == null && !params.ownerEmailId) {
throw new Error('Either an owner user ID or an owner email is required to create a project')
}
const owner: Record<string, unknown> = {}
if (params.ownerUserId != null) owner.userId = params.ownerUserId
if (params.ownerEmailId) owner.emailId = params.ownerEmailId
body.owner = owner
if (params.startDate) body.startDate = params.startDate
if (params.dueDate) body.dueDate = params.dueDate
if (params.visibility) body.visibility = params.visibility
if (params.statusValue != null) body.status = { value: params.statusValue }
const teamMembers: Record<string, unknown> = {}
if (params.memberUserIds && params.memberUserIds.length > 0) {
teamMembers.members = params.memberUserIds.map((userId) => ({ userId }))
}
if (params.customerUserIds && params.customerUserIds.length > 0) {
teamMembers.customers = params.customerUserIds.map((userId) => ({ userId }))
}
if (params.customerChampionUserId != null) {
teamMembers.customerChampion = { userId: params.customerChampionUserId }
}
if (Object.keys(teamMembers).length > 0) body.teamMembers = teamMembers
if (params.fields && params.fields.length > 0) body.fields = params.fields
if (params.sources && params.sources.length > 0) body.sources = params.sources
if (params.placeholders && params.placeholders.length > 0)
body.placeholders = params.placeholders
if (params.assignProjectOwner != null) body.assignProjectOwner = params.assignProjectOwner
if (params.annualizedRecurringRevenue != null)
body.annualizedRecurringRevenue = params.annualizedRecurringRevenue
if (params.projectFee != null) body.projectFee = params.projectFee
if (params.autoAllocation != null) body.autoAllocation = params.autoAllocation
if (params.autoCreateCompany != null) body.autoCreateCompany = params.autoCreateCompany
if (params.budgetedHours != null) body.budgetedHours = params.budgetedHours
if (params.contractType) {
const financials: Record<string, unknown> = { contractType: params.contractType }
if (params.fixedFee != null) financials.fixedFeeContract = { fixedFee: params.fixedFee }
const timeAndMaterialContract: Record<string, unknown> = {}
if (params.rateCardId != null)
timeAndMaterialContract.rateCard = { rateCardId: params.rateCardId }
if (params.projectBudget != null)
timeAndMaterialContract.projectBudget = params.projectBudget
if (Object.keys(timeAndMaterialContract).length > 0)
financials.timeAndMaterialContract = timeAndMaterialContract
const subscriptionContract: Record<string, unknown> = {}
if (params.subscriptionFrequency)
subscriptionContract.subscriptionFrequency = params.subscriptionFrequency
if (params.subscriptionStartDate)
subscriptionContract.subscriptionStartDate = params.subscriptionStartDate
if (params.periodMinutes != null) subscriptionContract.periodMinutes = params.periodMinutes
if (params.periodBudget != null) subscriptionContract.periodBudget = params.periodBudget
if (params.noOfPeriods != null) subscriptionContract.noOfPeriods = params.noOfPeriods
if (Object.keys(subscriptionContract).length > 0)
financials.subscriptionContract = subscriptionContract
body.financials = financials
}
if (params.currency) body.currency = params.currency
if (params.externalReferenceId) body.externalReferenceId = params.externalReferenceId
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
throw new Error(await rocketlaneError(response))
}
const data = await response.json()
return {
success: true,
output: { project: mapProject(data) },
}
},
outputs: {
project: {
type: 'object',
description: 'The created project',
properties: PROJECT_OUTPUT_PROPERTIES,
},
},
}