rename(phase 1): CapaKraken → Nexus across code, UI, docs, CI (#61)
CI / Architecture Guardrails (push) Successful in 2m38s
CI / Assistant Split Regression (push) Successful in 3m33s
CI / Typecheck (push) Successful in 3m51s
CI / Lint (push) Successful in 5m2s
CI / E2E Tests (push) Has been cancelled
CI / Fresh-Linux Docker Deploy (push) Has been cancelled
CI / Release Images (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled

rename(phase 1): CapaKraken → Nexus across code, UI, docs, CI (#61)

Co-authored-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com>
Co-committed-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com>
This commit was merged in pull request #61.
This commit is contained in:
2026-05-21 16:28:40 +02:00
committed by Hartmut
parent d9a7ec0338
commit b41c1d2501
943 changed files with 24548 additions and 16832 deletions
@@ -1,4 +1,4 @@
import { AllocationStatus, PermissionKey, SystemRole } from "@capakraken/shared";
import { AllocationStatus, PermissionKey, SystemRole } from "@nexus/shared";
import type { TRPCContext } from "../../trpc.js";
import { withToolAccess, type ToolContext, type ToolDef, type ToolExecutor } from "./shared.js";
@@ -112,144 +112,157 @@ type StaffingDemandDeps = {
parseIsoDate: (value: string, fieldName: string) => Date;
parseOptionalIsoDate: (value: string | undefined, fieldName: string) => Date | undefined;
fmtDate: (value: Date | null | undefined) => string | null;
toAssistantDemandCreationError: (
error: unknown,
) => AssistantToolErrorResult | null;
toAssistantDemandFillError: (
error: unknown,
) => AssistantToolErrorResult | null;
toAssistantDemandCreationError: (error: unknown) => AssistantToolErrorResult | null;
toAssistantDemandFillError: (error: unknown) => AssistantToolErrorResult | null;
};
export const staffingDemandReadToolDefinitions: ToolDef[] = withToolAccess([
{
type: "function",
function: {
name: "list_demands",
description: "List staffing demand requirements for projects. Shows open positions that need to be filled.",
parameters: {
type: "object",
properties: {
projectId: { type: "string", description: "Filter by project ID or short code" },
status: { type: "string", description: "Filter by status: OPEN, PARTIALLY_FILLED, FILLED, CANCELLED" },
limit: { type: "integer", description: "Max results. Default: 30" },
export const staffingDemandReadToolDefinitions: ToolDef[] = withToolAccess(
[
{
type: "function",
function: {
name: "list_demands",
description:
"List staffing demand requirements for projects. Shows open positions that need to be filled.",
parameters: {
type: "object",
properties: {
projectId: { type: "string", description: "Filter by project ID or short code" },
status: {
type: "string",
description: "Filter by status: OPEN, PARTIALLY_FILLED, FILLED, CANCELLED",
},
limit: { type: "integer", description: "Max results. Default: 30" },
},
},
},
},
},
{
type: "function",
function: {
name: "check_resource_availability",
description: "Check if a resource is available in a given date range (no conflicting allocations or vacations).",
parameters: {
type: "object",
properties: {
resourceId: { type: "string", description: "Resource ID, eid, or name" },
startDate: { type: "string", description: "Start date YYYY-MM-DD" },
endDate: { type: "string", description: "End date YYYY-MM-DD" },
{
type: "function",
function: {
name: "check_resource_availability",
description:
"Check if a resource is available in a given date range (no conflicting allocations or vacations).",
parameters: {
type: "object",
properties: {
resourceId: { type: "string", description: "Resource ID, eid, or name" },
startDate: { type: "string", description: "Start date YYYY-MM-DD" },
endDate: { type: "string", description: "End date YYYY-MM-DD" },
},
required: ["resourceId", "startDate", "endDate"],
},
required: ["resourceId", "startDate", "endDate"],
},
},
},
{
type: "function",
function: {
name: "get_staffing_suggestions",
description: "Get AI-powered staffing suggestions for a project based on required skills, availability, and cost.",
parameters: {
type: "object",
properties: {
projectId: { type: "string", description: "Project ID or short code" },
roleName: { type: "string", description: "Role to find candidates for" },
startDate: { type: "string", description: "Start date YYYY-MM-DD" },
endDate: { type: "string", description: "End date YYYY-MM-DD" },
limit: { type: "integer", description: "Max suggestions. Default: 5" },
{
type: "function",
function: {
name: "get_staffing_suggestions",
description:
"Get AI-powered staffing suggestions for a project based on required skills, availability, and cost.",
parameters: {
type: "object",
properties: {
projectId: { type: "string", description: "Project ID or short code" },
roleName: { type: "string", description: "Role to find candidates for" },
startDate: { type: "string", description: "Start date YYYY-MM-DD" },
endDate: { type: "string", description: "End date YYYY-MM-DD" },
limit: { type: "integer", description: "Max suggestions. Default: 5" },
},
required: ["projectId"],
},
required: ["projectId"],
},
},
},
{
type: "function",
function: {
name: "find_capacity",
description: "Find resources with available capacity in a date range.",
parameters: {
type: "object",
properties: {
startDate: { type: "string", description: "Start date YYYY-MM-DD" },
endDate: { type: "string", description: "End date YYYY-MM-DD" },
minHoursPerDay: { type: "number", description: "Minimum available hours/day. Default: 4" },
roleName: { type: "string", description: "Filter by role name" },
chapter: { type: "string", description: "Filter by chapter" },
limit: { type: "integer", description: "Max results. Default: 20" },
{
type: "function",
function: {
name: "find_capacity",
description: "Find resources with available capacity in a date range.",
parameters: {
type: "object",
properties: {
startDate: { type: "string", description: "Start date YYYY-MM-DD" },
endDate: { type: "string", description: "End date YYYY-MM-DD" },
minHoursPerDay: {
type: "number",
description: "Minimum available hours/day. Default: 4",
},
roleName: { type: "string", description: "Filter by role name" },
chapter: { type: "string", description: "Filter by chapter" },
limit: { type: "integer", description: "Max results. Default: 20" },
},
required: ["startDate", "endDate"],
},
required: ["startDate", "endDate"],
},
},
],
{
list_demands: {
requiresPlanningRead: true,
},
check_resource_availability: {
requiresPlanningRead: true,
},
get_staffing_suggestions: {
requiresPlanningRead: true,
requiresCostView: true,
},
find_capacity: {
requiresPlanningRead: true,
},
},
], {
list_demands: {
requiresPlanningRead: true,
},
check_resource_availability: {
requiresPlanningRead: true,
},
get_staffing_suggestions: {
requiresPlanningRead: true,
requiresCostView: true,
},
find_capacity: {
requiresPlanningRead: true,
},
});
);
export const staffingDemandMutationToolDefinitions: ToolDef[] = withToolAccess([
{
type: "function",
function: {
name: "create_demand",
description: "Create a staffing demand requirement on a project. Requires manageAllocations permission. Always confirm first.",
parameters: {
type: "object",
properties: {
projectId: { type: "string", description: "Project ID or short code" },
roleName: { type: "string", description: "Role name for the demand" },
headcount: { type: "integer", description: "Number of people needed. Default: 1" },
hoursPerDay: { type: "number", description: "Hours per day required" },
startDate: { type: "string", description: "Start date YYYY-MM-DD" },
endDate: { type: "string", description: "End date YYYY-MM-DD" },
export const staffingDemandMutationToolDefinitions: ToolDef[] = withToolAccess(
[
{
type: "function",
function: {
name: "create_demand",
description:
"Create a staffing demand requirement on a project. Requires manageAllocations permission. Always confirm first.",
parameters: {
type: "object",
properties: {
projectId: { type: "string", description: "Project ID or short code" },
roleName: { type: "string", description: "Role name for the demand" },
headcount: { type: "integer", description: "Number of people needed. Default: 1" },
hoursPerDay: { type: "number", description: "Hours per day required" },
startDate: { type: "string", description: "Start date YYYY-MM-DD" },
endDate: { type: "string", description: "End date YYYY-MM-DD" },
},
required: ["projectId", "roleName", "hoursPerDay", "startDate", "endDate"],
},
required: ["projectId", "roleName", "hoursPerDay", "startDate", "endDate"],
},
},
},
{
type: "function",
function: {
name: "fill_demand",
description: "Fill/assign a resource to an open demand requirement. Requires manageAllocations permission. Always confirm first.",
parameters: {
type: "object",
properties: {
demandId: { type: "string", description: "Demand requirement ID" },
resourceId: { type: "string", description: "Resource ID or name to assign" },
{
type: "function",
function: {
name: "fill_demand",
description:
"Fill/assign a resource to an open demand requirement. Requires manageAllocations permission. Always confirm first.",
parameters: {
type: "object",
properties: {
demandId: { type: "string", description: "Demand requirement ID" },
resourceId: { type: "string", description: "Resource ID or name to assign" },
},
required: ["demandId", "resourceId"],
},
required: ["demandId", "resourceId"],
},
},
],
{
create_demand: {
requiredPermissions: [PermissionKey.MANAGE_ALLOCATIONS],
allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
},
fill_demand: {
requiredPermissions: [PermissionKey.MANAGE_ALLOCATIONS],
allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
},
},
], {
create_demand: {
requiredPermissions: [PermissionKey.MANAGE_ALLOCATIONS],
allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
},
fill_demand: {
requiredPermissions: [PermissionKey.MANAGE_ALLOCATIONS],
allowedSystemRoles: [SystemRole.ADMIN, SystemRole.MANAGER],
},
});
);
export function createStaffingDemandExecutors(
deps: StaffingDemandDeps,
@@ -273,19 +286,21 @@ export function createStaffingDemandExecutors(
...(params.status ? { status: params.status as AllocationStatus } : {}),
});
return demands.map((demand) => ({
id: demand.id,
project: demand.project.name,
projectCode: demand.project.shortCode,
role: demand.roleEntity?.name ?? demand.role ?? "Unspecified",
status: demand.status,
headcount: demand.headcount,
filled: demand.assignments.length,
remaining: demand.headcount - demand.assignments.length,
hoursPerDay: demand.hoursPerDay,
start: deps.fmtDate(demand.startDate),
end: deps.fmtDate(demand.endDate),
})).slice(0, limit);
return demands
.map((demand) => ({
id: demand.id,
project: demand.project.name,
projectCode: demand.project.shortCode,
role: demand.roleEntity?.name ?? demand.role ?? "Unspecified",
status: demand.status,
headcount: demand.headcount,
filled: demand.assignments.length,
remaining: demand.headcount - demand.assignments.length,
hoursPerDay: demand.hoursPerDay,
start: deps.fmtDate(demand.startDate),
end: deps.fmtDate(demand.endDate),
}))
.slice(0, limit);
},
async create_demand(
@@ -346,10 +361,7 @@ export function createStaffingDemandExecutors(
};
},
async fill_demand(
params: { demandId: string; resourceId: string },
ctx: ToolContext,
) {
async fill_demand(params: { demandId: string; resourceId: string }, ctx: ToolContext) {
deps.assertPermission(ctx, PermissionKey.MANAGE_ALLOCATIONS);
const allocationCaller = deps.createAllocationCaller(deps.createScopedCallerContext(ctx));
const resource = await deps.resolveResourceIdentifier(ctx, params.resourceId);
@@ -371,9 +383,8 @@ export function createStaffingDemandExecutors(
throw error;
}
const roleName = result.demandRequirement.roleEntity?.name
?? result.demandRequirement.role
?? null;
const roleName =
result.demandRequirement.roleEntity?.name ?? result.demandRequirement.role ?? null;
return {
__action: "invalidate",