Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
5fa4861
fix(app): move 'Statement of Applicability' from Questionnaire to Doc…
chasprowebdev Apr 23, 2026
d8a9a8d
fix(app): update approval status after approving of 'Statement of App…
chasprowebdev Apr 23, 2026
4d6e854
fix(app): show approval status on Statement of Applicability card in …
chasprowebdev Apr 23, 2026
10c67f7
fix(api): include soa to documents score
chasprowebdev Apr 23, 2026
7364c58
fix(api): create endpoint to export soa into pdf
chasprowebdev Apr 23, 2026
e6731b2
fix(app): export Statement of Applicability as pdf
chasprowebdev Apr 23, 2026
1d3f903
fix(api): add metrics to SOA pdf document
chasprowebdev Apr 24, 2026
74fac2d
Merge branch 'main' of https://github.com/trycompai/comp into chas/mo…
chasprowebdev Apr 24, 2026
fd5ba8b
fix(app): add organizationId to frameworks SWR cache
chasprowebdev Apr 24, 2026
49c1673
fix(app): remove use of hasISO27001Framework on CompanyOverviewCards
chasprowebdev Apr 24, 2026
993e89b
fix(app): remove use of ai-vendor-questionnaire FF for SOA page
chasprowebdev Apr 24, 2026
589f285
fix(api): fix pagination overflow for long question blocks in soa pdf
chasprowebdev Apr 24, 2026
37e7d15
Merge branch 'main' into chas/move-statement-of-applicability
tofikwest Apr 24, 2026
ada6b5e
fix(api): correct SOA export classification for declined cases
chasprowebdev Apr 24, 2026
760c304
fix(app): use exact role checks instead of substring matching
chasprowebdev Apr 24, 2026
24f9791
fix(api): add coverage for SOA export endpoint
chasprowebdev Apr 24, 2026
3ab3698
Merge branch 'chas/move-statement-of-applicability' of https://github…
chasprowebdev Apr 24, 2026
94ad0ab
Merge branch 'main' of https://github.com/trycompai/comp into chas/mo…
chasprowebdev Apr 24, 2026
a5e8988
fix(framework-editor): add SOA document to ISO 27001 framework
chasprowebdev Apr 24, 2026
10fbfb1
Merge branch 'main' of https://github.com/trycompai/comp into chas/mo…
chasprowebdev Apr 24, 2026
56f5ae2
chore: merge release v3.33.1 back to main [skip ci]
github-actions[bot] Apr 24, 2026
2f12556
fix(app): handle serverApi.post errors to prevent infinite loading on…
chasprowebdev Apr 24, 2026
38642ba
fix(api): correct SOA completion logic based on approvedAt for SOA
chasprowebdev Apr 24, 2026
140db39
fix(app): avoid defaulting to 'Not approved' before SOA status loads
chasprowebdev Apr 24, 2026
fbd4b09
Merge branch 'main' of https://github.com/trycompai/comp into chas/mo…
chasprowebdev Apr 24, 2026
46b9575
feat: allow selecting which policies to download when clicking downlo…
github-actions[bot] Apr 24, 2026
1296eeb
fix(db): add declined fields to SOADocument
chasprowebdev Apr 24, 2026
83a5619
fix(db): remove declined from SOADocumentStatus
chasprowebdev Apr 24, 2026
dafde6f
fix(api): update declineAt during SOA Document status changes
chasprowebdev Apr 24, 2026
59567c4
fix(app): update approval status text on soa
chasprowebdev Apr 24, 2026
4813da6
fix(api): update approval status text on soa pdf
chasprowebdev Apr 24, 2026
af47b4e
fix(app): update SOA Document Info based on status changes
chasprowebdev Apr 24, 2026
4489630
Merge branch 'main' of https://github.com/trycompai/comp into chas/mo…
chasprowebdev Apr 24, 2026
08971f9
fix(app): correct approvalStatusText handling of declinedAt
chasprowebdev Apr 24, 2026
8c37800
chore(policies): add search + status grouping to download picker (#2676)
github-actions[bot] Apr 24, 2026
f817d44
fix(app): correct SOA document info during the status changes
chasprowebdev Apr 24, 2026
7705eca
fix(api): update the soa pdf content
chasprowebdev Apr 24, 2026
068a607
Merge branch 'main' of https://github.com/trycompai/comp into chas/mo…
chasprowebdev Apr 24, 2026
959d571
fix(app): handle /v1/frameworks fetch errors before showing not found…
chasprowebdev Apr 24, 2026
b9a580f
fix(app): guard answers sync effect from clearing answersMap on parti…
chasprowebdev Apr 24, 2026
32b210e
feat: add ability to set frequency on automations running
github-actions[bot] Apr 25, 2026
a27bc43
chore(db): publish flattened dist/schema.prisma for external consumer…
Marfuen Apr 25, 2026
a0a518b
[dev] [Marfuen] mariano/fix-db-dist-schema (#2678)
github-actions[bot] Apr 25, 2026
e8a751b
feat: add comprehensive project rules and guidelines documentation
carhartlewis Apr 27, 2026
2da22b6
chore(docs): update documentation for typecheck and testing commands
carhartlewis Apr 27, 2026
144876e
Merge pull request #2679 from trycompai/lewis/comp-skills-fix
carhartlewis Apr 27, 2026
65e60cc
fix(gws): coerce target_org_units to array in check-user-filter
tofikwest Apr 27, 2026
98290b6
Merge pull request #2680 from trycompai/fix/gws-target-org-units-arra…
tofikwest Apr 27, 2026
9cd78d1
chore: merge release v3.33.2 back to main [skip ci]
github-actions[bot] Apr 27, 2026
9463c5a
feat(integrations): split GitHub sanitized inputs check into two auto…
tofikwest Apr 27, 2026
07739f8
refactor(integrations): keep sanitized-inputs.ts in place, only add c…
tofikwest Apr 27, 2026
413088b
Merge pull request #2683 from trycompai/feat/split-sanitized-inputs-c…
tofikwest Apr 27, 2026
37fcd08
Merge branch 'main' into chas/move-statement-of-applicability
tofikwest Apr 27, 2026
bfd1f5f
fix(api): add non-empty validation for requirement fields in ExportSO…
chasprowebdev Apr 27, 2026
e56a698
Merge pull request #2648 from trycompai/chas/move-statement-of-applic…
tofikwest Apr 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .agents/skills/audit-design-system/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: audit-design-system
description: Audit & fix design system usage — migrate @trycompai/ui and lucide-react to @trycompai/design-system
---

Audit the specified files for design system compliance. **Fix every issue found immediately.**

## Rules

1. **`@trycompai/design-system`** is the primary component library. `@trycompai/ui` is legacy — only use as last resort when no DS equivalent exists.
2. **Always check DS exports first** before reaching for `@trycompai/ui`. Run `node -e "console.log(Object.keys(require('@trycompai/design-system')))"` to check.
3. **Icons**: Use `@trycompai/design-system/icons` (Carbon icons), NOT `lucide-react`. Check with `node -e "const i = require('@trycompai/design-system/icons'); console.log(Object.keys(i).filter(k => k.match(/YourSearch/i)))"`.
4. **DS components that do NOT accept `className`**: `Text`, `Stack`, `HStack`, `Badge`, `Button` — wrap in `<div>` for custom styling.
5. **Button**: Use DS `Button` with `loading`, `iconLeft`, `iconRight` props instead of manually rendering spinners/icons.
6. **Layout**: Use `PageLayout`, `PageHeader`, `Stack`, `HStack`, `Section`, `SettingGroup`.
7. **Patterns**: Sheet (`Sheet > SheetContent > SheetHeader + SheetBody`), Drawer, Collapsible.

## Process
1. Read files specified in `$ARGUMENTS`
2. Find `@trycompai/ui` imports — check if DS equivalent exists
3. Find `lucide-react` imports — find matching Carbon icons
4. Migrate components and icons
5. Run build to verify: `bunx turbo run typecheck --filter=@trycompai/app`
34 changes: 34 additions & 0 deletions .agents/skills/audit-hooks/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: audit-hooks
description: Audit & fix hooks and API usage patterns — eliminate server actions, raw fetch, and stale patterns
---

Audit the specified files for hook and API usage compliance. **Fix every issue found immediately.**

## Forbidden Patterns (fix immediately)

1. **`useAction` from `next-safe-action`** → replace with SWR hook or custom mutation hook
2. **Server actions mutating via `@db`** → delete and use API hook instead
3. **Direct `@db` in client components** → replace with `apiClient` via hook
4. **Direct `@db` in Next.js pages for mutations** → replace with `serverApi`
5. **Raw `fetch()` without `credentials: 'include'`** → use `apiClient`
6. **`window.location.reload()` after mutations** → use SWR `mutate()`
7. **`router.refresh()` after mutations** → use SWR `mutate()`
8. **`useEffect` + `apiClient.get` for data fetching** → replace with `useSWR`
9. **Callback props for data refresh** (`onXxxAdded`, `onSuccess`) → remove, rely on SWR cache sharing

## Required Patterns

- **Client data fetching**: `useSWR` with `apiClient` or custom hook
- **Client mutations**: custom hooks wrapping `apiClient` with `mutate()` for cache invalidation
- **Server components**: `serverApi` from `apps/app/src/lib/api-server.ts`
- **SWR**: `fallbackData` for SSR data, `revalidateOnMount: !initialData`
- **API response**: lists = `response.data.data`, single = `response.data`
- **`mutate()` safety**: guard against `undefined` in optimistic update functions
- **`Array.isArray()` checks**: when consuming SWR data that could be stale

## Process
1. Read files specified in `$ARGUMENTS`
2. Find forbidden patterns and fix them
3. Ensure all data fetching uses SWR hooks
4. Run typecheck to verify: `bunx turbo run typecheck --filter=@trycompai/app`
42 changes: 42 additions & 0 deletions .agents/skills/audit-rbac/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: audit-rbac
description: Audit & fix RBAC and audit log compliance in API endpoints and frontend components
---

Audit the specified files or directories for RBAC and audit log compliance. **Fix every issue found immediately.**

## Rules

### API Endpoints (NestJS — `apps/api/src/`)
1. **Every mutation endpoint** (POST, PATCH, PUT, DELETE) MUST have `@RequirePermission('resource', 'action')`. If missing, **add it**.
2. **Read endpoints** (GET) should have `@RequirePermission('resource', 'read')`. If missing, **add it**.
3. **Self-endpoints** (e.g., `/me/preferences`) may skip `@RequirePermission` — authentication via `HybridAuthGuard` is sufficient.
4. **Controller format**: Must use `@Controller({ path: 'name', version: '1' })`, NOT `@Controller('v1/name')`. If wrong, **fix it**.
5. **Guards**: Use `@UseGuards(HybridAuthGuard, PermissionGuard)` at controller or endpoint level. Never skip PermissionGuard.
6. **Webhooks**: External webhook endpoints use `@Public()` — no auth required.

### Frontend Components (`apps/app/src/`)
1. **Every mutation element** (button, form submit, toggle, switch, file upload) MUST be gated with `usePermissions` from `@/hooks/use-permissions`. If not:
- **Create/Add buttons**: Wrap with `{hasPermission('resource', 'create') && <Button>...`
- **Edit/Delete in dropdown menus**: Wrap the menu item
- **Inline form fields on detail pages**: Add `disabled={!canUpdate}`
- **Status/property selectors**: Add `disabled={!canUpdate}`
2. **Actions columns** in tables: hide entire column when user lacks write permission.
3. **No manual role string parsing** (`role.includes('admin')`) — use `hasPermission()`.
4. **Nav items**: gate with `canAccessRoute(permissions, 'routeSegment')`.
5. **Page-level**: call `requireRoutePermission('segment', orgId)` server-side.

### Permission Resources
`organization`, `member`, `control`, `evidence`, `policy`, `risk`, `vendor`, `task`, `framework`, `audit`, `finding`, `questionnaire`, `integration`, `apiKey`, `trust`, `pentest`, `app`, `compliance`

### Multi-Product RBAC
- Products (compliance, pen testing) are org-level feature flags — NOT RBAC
- `app:read` gates compliance dashboard; `pentest:read` gates security product
- Custom roles can grant access to any combination of resources
- Portal-only resources (`policy`, `compliance`) do NOT grant app access

## Process
1. Read files specified in `$ARGUMENTS` (or scan the directory)
2. Check each rule above
3. **Fix every violation immediately** — don't just report
4. Run typecheck to verify: `bunx turbo run typecheck --filter=@trycompai/api --filter=@trycompai/app`
30 changes: 30 additions & 0 deletions .agents/skills/audit-tests/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: audit-tests
description: Audit & fix unit tests for permission-gated components
---

Check that unit tests exist and pass for permission-gated components. **Write missing tests immediately.**

## Infrastructure
- **Framework**: Vitest with jsdom
- **Component testing**: `@testing-library/react` + `@testing-library/jest-dom`
- **Setup**: `apps/app/src/test-utils/setup.ts`
- **Permission mocks**: `apps/app/src/test-utils/mocks/permissions.ts`
- **Run**: `cd apps/app && bunx vitest run`

## Required Test Pattern

Every component importing `usePermissions` MUST have tests covering:

1. **Admin (write) user**: mutation elements visible/enabled
2. **Auditor (read-only)**: mutation elements hidden/disabled
3. **Data always visible**: read-only content renders regardless of permissions

Use `setMockPermissions`, `ADMIN_PERMISSIONS`, `AUDITOR_PERMISSIONS` from test utils.

## Process
1. Find components with `usePermissions` in `$ARGUMENTS`
2. Check for corresponding `.test.tsx` files
3. Write missing tests following the pattern above
4. Fix any failing tests
5. Run: `cd apps/app && bunx vitest run`
12 changes: 6 additions & 6 deletions .agents/skills/better-auth-best-practices/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ description: Configure Better Auth server and client, set up database adapters,

## Setup Workflow

1. Install: `npm install better-auth`
1. Install: `bun add better-auth`
2. Set env vars: `BETTER_AUTH_SECRET` and `BETTER_AUTH_URL`
3. Create `auth.ts` with database + config
4. Create route handler for your framework
5. Run `npx @better-auth/cli@latest migrate`
5. Run `bunx @better-auth/cli@latest migrate`
6. Verify: call `GET /api/auth/ok` — should return `{ status: "ok" }`

---
Expand All @@ -32,9 +32,9 @@ Only define `baseURL`/`secret` in config if env vars are NOT set.
CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or under `./src`. Use `--config` for custom path.

### CLI Commands
- `npx @better-auth/cli@latest migrate` - Apply schema (built-in adapter)
- `npx @better-auth/cli@latest generate` - Generate schema for Prisma/Drizzle
- `npx @better-auth/cli mcp --cursor` - Add MCP to AI tools
- `bunx @better-auth/cli@latest migrate` - Apply schema (built-in adapter)
- `bunx @better-auth/cli@latest generate` - Generate schema for Prisma/Drizzle
- `bunx @better-auth/cli@latest mcp --cursor` - Add MCP to AI tools

**Re-run after adding/changing plugins.**

Expand Down Expand Up @@ -172,4 +172,4 @@ For separate client/server projects: `createAuthClient<typeof auth>()`.
- [Options Reference](https://better-auth.com/docs/reference/options)
- [LLMs.txt](https://better-auth.com/llms.txt)
- [GitHub](https://github.com/better-auth/better-auth)
- [Init Options Source](https://github.com/better-auth/better-auth/blob/main/packages/core/src/types/init-options.ts)
- [Init Options Source](https://github.com/better-auth/better-auth/blob/main/packages/core/src/types/init-options.ts)
185 changes: 185 additions & 0 deletions .agents/skills/code/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
---
name: code
description: "Use when writing TypeScript/React code - covers type safety, component patterns, and file organization"
---

Source Cursor rule: `.cursor/rules/code.mdc`.
Original Cursor alwaysApply: `false`.

# Code Standards

## TypeScript

### No `any`, No Unsafe Casts

```tsx
// ✅ Validate with zod
const TaskSchema = z.object({ id: z.string(), title: z.string() });
const task = TaskSchema.parse(response.data);

// ✅ Use unknown and narrow
const parseResponse = (data: unknown): Task => {
if (!isTask(data)) throw new Error('Invalid');
return data;
};

// ❌ Never
const data: any = fetchData();
const task = response as Task;
const name = user!.name;
// @ts-ignore
```

### Generics Over Any

```tsx
// ✅ Generic
const first = <T>(items: T[]): T | undefined => items[0];

// ❌ Any
const first = (items: any[]): any => items[0];
```

## React Patterns

### Named Exports, PascalCase

```tsx
// ✅ Named export, PascalCase file
// TaskCard.tsx
export function TaskCard({ task }: TaskCardProps) { ... }

// ❌ Default export, lowercase
export default function taskCard() { ... }
```

### Derive State, Avoid useEffect

```tsx
// ✅ Derived
const completedCount = tasks.filter(t => t.completed).length;

// ❌ Synced state
const [count, setCount] = useState(0);
useEffect(() => {
setCount(tasks.filter(t => t.completed).length);
}, [tasks]);
```

### When useEffect IS Appropriate

```tsx
// External subscriptions
useEffect(() => {
const sub = eventSource.subscribe(handler);
return () => sub.unsubscribe();
}, []);

// DOM measurements
useEffect(() => {
setHeight(ref.current?.getBoundingClientRect().height);
}, []);
```

### Toasts with Sonner

```tsx
import { toast } from 'sonner';

toast.success('Task created');
toast.error('Failed to save');
toast.promise(saveTask(), {
loading: 'Saving...',
success: 'Saved!',
error: 'Failed',
});
```

## File Structure

### Colocate at Route Level

```
app/(app)/[orgId]/tasks/
├── page.tsx # Server component
├── components/
│ └── TaskList.tsx # Client component
├── hooks/
│ └── useTasks.ts # SWR hook
└── data/
└── queries.ts # Server queries
```

### Share Only When Reused 3+ Times

```
src/components/shared/ # Cross-page components
src/hooks/ # Shared hooks (useApiSWR, useDebounce)
```

## Code Quality

### File Size Limit: 300 Lines

Split large files into focused components.

### Named Parameters for 2+ Args

```tsx
// ✅ Named
const createTask = ({ title, assigneeId }: CreateTaskParams) => { ... };
createTask({ title: 'Review PR', assigneeId: user.id });

// ❌ Positional
const createTask = (title: string, assigneeId: string) => { ... };
createTask('Review PR', user.id); // What's the 2nd param?
```

### Early Returns

```tsx
// ✅ Early return
function processTask(task: Task | null) {
if (!task) return null;
if (task.deleted) return null;
return <TaskCard task={task} />;
}

// ❌ Nested
function processTask(task) {
if (task) {
if (!task.deleted) {
return <TaskCard task={task} />;
}
}
return null;
}
```

### Event Handler Naming

```tsx
// ✅ Prefix with "handle"
const handleClick = () => { ... };
const handleSubmit = (e: FormEvent) => { ... };
const handleTaskCreate = (task: Task) => { ... };
```

## Accessibility

```tsx
// Interactive elements need keyboard support
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
aria-label="Delete task"
>
<TrashIcon />
</div>

// Form inputs need labels
<label htmlFor="task-name">Task Name</label>
<input id="task-name" type="text" />
```
Loading
Loading