Skip to content
20 changes: 10 additions & 10 deletions .claude/skills/onboard-api/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,16 @@ Without a real response, you cannot reliably decide: which fields are optional,

## Step 4: Implement

Implementation order:
1. Create model files (`types.ts`, `constants.ts`, `models.ts`, optionally `internal-types.ts`) — follow type naming conventions, use "Options" never "Request". **Before creating any enum or interface, search `src/models/` for existing types to reuse.**
2. Define endpoint constants — `as const`, consistent param names, no redundancy
3. Define pagination constants (if paginated) — check BaseService vs FolderScopedService decision rule
4. Implement service class — apply only justified transform pipeline steps, use `@track()` on all public methods. **If Composite:** The public method orchestrates multiple internal API calls. Private helper methods (not decorated with `@track`) handle individual calls. Only the public composite method gets `@track`. Follow the composition pattern from Step 3 — see `references/composite-methods.md` § Implementation Patterns.
5. Wire up exports (area `index.ts`, `src/index.ts`, `package.json`, `rollup.config.js`)
6. Write unit tests — use shared mocks, test constants, success + error paths
7. Write integration tests — `throw` in test body guards (never `console.log` + `return`), `console.warn()` + skip for `beforeAll` setup preconditions, no try/catch around API calls. New services use v1 setup only.
8. Write JSDoc on `{Entity}ServiceModel` interface — `@example`, `{@link}`, camelCase in examples. Show the bare minimum call in the first `@example` (no optional params), then a second example with filtering. Never use `$` prefix on OData params in examples (`expand` not `$expand`). Use PascalCase for field names in `$filter` examples (e.g., `filter: "State eq 'Running'"`). Add JSDoc to non-obvious enum values.
9. Update docs (`oauth-scopes.md`, `pagination.md`, `mkdocs.yml`) — check NEVER Do § Docs
Implementation order (follow `conventions.md` for patterns, `rules.md` for quality rules and testing):
1. Create model files (`types.ts`, `constants.ts`, `models.ts`, optionally `internal-types.ts`) — see conventions.md § Type naming, § Service model + method attachment pattern, § Internal types. **Before creating any enum or interface, search `src/models/` for existing types to reuse.**
2. Define endpoint constants — see conventions.md § Endpoint constants
3. Define pagination constants (if paginated) — see conventions.md § Pagination
4. Implement service class — see conventions.md § Response transformation pipeline, § Constructor JSDoc, § Error types. **If Composite:** see `references/composite-methods.md` § Implementation Patterns. Only the public composite method gets `@track`.
5. Wire up exports (area `index.ts`, `src/index.ts`, `package.json`, `rollup.config.js`) — see conventions.md § Export naming
6. Write unit tests — see rules.md § Testing guidelines. If the service has a `{Entity}Methods` interface, also create `tests/unit/models/{domain}/{entity}.test.ts` (see `tests/unit/models/maestro/case-instances.test.ts` for the pattern).
7. Write integration tests — see rules.md § Integration tests
8. Write JSDoc on `{Entity}ServiceModel` interface — see rules.md § Documentation. Show bare minimum call first, then a second example with filtering. Use PascalCase for field names in `$filter` examples (e.g., `filter: "State eq 'Running'"`).
9. Update docs (`oauth-scopes.md`, `pagination.md`, `mkdocs.yml`) — see rules.md § NEVER Do Docs

---

Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/onboard-api/references/composite-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ private async downloadOutput(downloadUrl: string): Promise<unknown> {
}

// Public composite method — the only one decorated with @track
// Note: required params are always positional; Options objects are for optional params only
@track('Jobs.GetOutput')
async getOutput(jobId: string, options?: JobGetOutputOptions): Promise<JobOutputResponse> {
const headers = createHeaders({ [FOLDER_ID]: options?.folderId });
const job = await this.fetchJobDetails(jobId, headers);
async getOutput(jobKey: string): Promise<JobOutputResponse> {
const job = await this.fetchJobDetails(jobKey);

if (job.outputArguments && !isAttachmentReference(job.outputArguments)) {
return this.composeInlineOutput(job);
Expand Down
11 changes: 8 additions & 3 deletions .claude/skills/onboard-api/references/e2e-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,16 +337,21 @@ E2E failures mean the implementation has a bug that unit tests missed. Do NOT sk
5. Restart: `npm run dev`
6. Revalidate the specific check that failed

Do NOT clean up until ALL checks pass.
Do NOT clean up until ALL checks pass. The app must survive failures so the fix loop can iterate without re-scaffolding.

## Step 6: Clean Up

Delete everything:
**The calling skill controls when cleanup happens.** This section only describes what to delete — see the calling skill's own cleanup rules for when to run these commands. **NEVER clean up without checking the calling skill's cleanup policy first.**

- **`onboard-api`:** Clean up automatically after all checks pass. Do NOT clean up on failure.
- **`sdk-verify` (standalone):** Do NOT clean up automatically. Ask the user for explicit confirmation first — they may want to inspect the app in the browser.

Cleanup commands:

```bash
# From repo root
rm -rf samples/e2e-test
rm uipath-uipath-typescript-1.0.0-test.1.tgz
rm -f uipath-uipath-typescript-1.0.0-test.*.tgz

# Revert root package.json version
git checkout package.json
Expand Down
8 changes: 4 additions & 4 deletions .claude/skills/sdk-ship/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ Add the new endpoint pattern to the Cloudflare Workers proxy whitelist so browse

3. **Regenerate PR body** from the current state of the code:
- Read the service class, ServiceModel interface, endpoint constants, types, and test files to build all table sections
- **Method Added** — read ServiceModel interface for method signatures
- **Endpoint Called** — read endpoint constants + service methods for HTTP method, path, scope
- **Example Usage** — copy from JSDoc `@example` blocks on ServiceModel interface
- **API Response vs SDK Response** — read transform pipeline in service class + types for field mapping
- **Method Added** — only include methods that are **new on this branch**. Run `git diff main...HEAD -- <models file>` to identify which methods were added to the ServiceModel interface, not all methods on the interface.
- **Endpoint Called** — read endpoint constants + service methods for HTTP method, path, scope. Only include endpoints used by newly added methods.
- **Example Usage** — copy from JSDoc `@example` blocks on the newly added methods in the ServiceModel interface
- **API Response vs SDK Response** — read transform pipeline in service class + types for field mapping. Only include for newly added methods.
- **Files** — run `git diff main...HEAD --name-only` to get all files on the branch, group by area, count tests
- Use the exact same template structure as Create mode
4. **Update PR** using `gh pr edit <number> --body "<regenerated body>"`
Expand Down
7 changes: 6 additions & 1 deletion .claude/skills/sdk-verify/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ Quick summary:

### E2E Cleanup

**Always clean up**, even on failure:
Cleanup behavior depends on context:

- **Standalone (user-invoked):** After reporting the verification summary, **ask the user** whether to clean up the E2E app. The user may want to inspect the app, manually test in the browser, or iterate on fixes before cleanup. Only clean up after explicit confirmation.
- **Called from `onboard-api`:** Do **NOT** clean up on failure — the onboard skill owns the fix loop and needs the app alive to iterate (rebuild → bump version → reinstall → revalidate). Clean up only after all checks pass.

Cleanup commands (when confirmed):
```bash
# From repo root
rm -rf samples/e2e-test
Expand Down
29 changes: 27 additions & 2 deletions agent_docs/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- **Options types**: `{Entity}GetAllOptions`, `{Entity}GetByIdOptions`, `{Entity}{Operation}Options` (e.g., `TaskAssignmentOptions`, `ProcessInstanceOperationOptions`). Compose with `RequestOptions & PaginationOptions & { ... }` for list methods.
- **Common base types**: `BaseOptions` (expand, select), `RequestOptions` (extends BaseOptions with filter, orderby), `OperationResponse<TData>` (success + data) — all from `src/models/common/types.ts`.
- **Use "Options" not "Request"** for parameter types — never `{Entity}{Operation}Request`.
- **Required parameters are always positional; Options objects are reserved for optional parameters only.** Required values (IDs, keys, data) are positional arguments. Options objects are always the last parameter, always marked `?`, and contain only optional fields. E.g., `getOutput(jobKey: string)` not `getOutput(options: { jobKey: string })`, `close(instanceId, folderKey, options?)` not `close(options: { instanceId, folderKey })`.

Method names: **singular** for single-item ops (`insertRecordById`), **plural** for batch (`insertRecordsById`). Prefer plurals over `batch` prefix.

Expand All @@ -44,7 +45,7 @@ Each service has 3 files in `src/models/{domain}/`:

1. **`{domain}.types.ts`** — raw interfaces (`Raw{Entity}GetResponse`), options types, enums
2. **`{domain}.constants.ts`** — field mapping (`{Entity}Map`), status mapping (`{Entity}StatusMap`), expand defaults
3. **`{domain}.models.ts`** — the service model interface (`{Entity}ServiceModel`), methods interface (`{Entity}Methods`), the composed response type (`Raw{Entity}GetResponse & {Entity}Methods`), and `create{Entity}WithMethods()` factory
3. **`{domain}.models.ts`** — in this order: (a) composed response type (`type {Entity}GetResponse = Raw{Entity}GetResponse & {Entity}Methods`), (b) `{Entity}ServiceModel` interface, (c) `{Entity}Methods` interface (placed after ServiceModel, before factory functions), (d) `create{Entity}Methods()` private factory, (e) `create{Entity}WithMethods()` public factory

The method attachment pattern:
- `create{Entity}Methods(rawData, service)` — returns an object of bound async methods that delegate to the service
Expand Down Expand Up @@ -132,7 +133,7 @@ Naming: `{SERVICE}_PAGINATION` for response shape, `{SERVICE}_OFFSET_PARAMS` or

Types in `{domain}.types.ts` are public (re-exported through barrel). Types in `{domain}.internal-types.ts` are private (imported only by service implementations).

**Put in `internal-types.ts`:** Raw API response shapes before transformation, intermediate parsing types, service-internal operation types, internal enums.
**Put in `internal-types.ts`:** Raw API response shapes before transformation, intermediate parsing types, service-internal operation types, internal enums, return type interfaces for private service methods (e.g., `RawJobOutputFields` for `fetchJobByKey`).

**Put in `types.ts`:** All types in public method signatures, `Raw{Entity}GetResponse` types that users compose with `{Entity}Methods`.

Expand All @@ -151,6 +152,30 @@ OData APIs require `$` prefix on query params. The SDK accepts clean camelCase k
- **Orchestrator**: `createHeaders({ [FOLDER_ID]: folderId })` — numeric folder IDs
- **Maestro**: `createHeaders({ [FOLDER_KEY]: folderKey })` — string folder keys

## Constructor JSDoc

Service constructors that take dependency parameters (beyond the `UiPath` instance) must have JSDoc comments. Pattern (from `case-instances.ts`):

```typescript
/**
* Creates an instance of the {Entity} service.
*
* @param instance - UiPath SDK instance providing authentication and configuration
*/
constructor(instance: IUiPath) {
super(instance);
this.dependencyService = new DependencyService(instance);
}
```

If the constructor only calls `super()` with no additional setup, omit it entirely (redundant constructor rule).

## Error types

- **`ValidationError`** — for **user input validation only**: missing required params, invalid option values, malformed user-provided data. Example: `if (!jobKey) throw new ValidationError(...)`.
- **`ServerError`** — for server-side issues: failed JSON parsing of API responses, unexpected response formats, API returning unparseable data. Example: `catch { throw new ServerError({ message: 'Failed to parse output as JSON' }) }`.
- **`ErrorFactory.createFromHttpStatus()`** — for HTTP error responses from external calls (blob downloads, etc.). Maps status codes to typed errors automatically.

## BaseService

**`BaseService`** (`src/services/base.ts`): Authenticated HTTP methods, `createPaginationServiceAccess()`. All services extend this.
Expand Down
Loading
Loading