docs: add Google Calendar section and new-tool checklist
Add GCal tools setup guide to README (prerequisites, config, fields). Add gmail-auth, gcal-auth, setup to the CLI commands table. Add "Adding a New Tool" checklist to CLAUDE.md covering the full wiring chain including the TUI registration gotcha. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -62,6 +62,70 @@ Registration chain: tool file → `src/tools/builtin/index.ts` → `src/tools/in
|
||||
- **Target**: ES2022, NodeNext modules, strict mode. Requires Node.js >=22.
|
||||
- **Error pattern**: `instanceof Error` checks, descriptive messages, try-catch in stream handlers
|
||||
|
||||
## Adding a New Tool
|
||||
|
||||
Checklist for adding a tool (or tool set) to Flynn. Every step is required unless noted.
|
||||
|
||||
### 1. Create the tool file — `src/tools/builtin/<name>.ts`
|
||||
|
||||
Pick the right pattern:
|
||||
- **Static** (`export const fooTool: Tool`) — no runtime deps (e.g. `system-info.ts`)
|
||||
- **Factory** (`export function createFooTool(dep): Tool`) — needs one dep (e.g. `memory-read.ts`)
|
||||
- **Multi-factory** (`export function createFooTools(dep): Tool[]`) — related tool set (e.g. `gmail.ts`, `gcal.ts`)
|
||||
|
||||
Each tool needs: `name` (dotted, e.g. `calendar.today`), `description`, `inputSchema` (JSON Schema object), `execute(args): Promise<ToolResult>`.
|
||||
|
||||
### 2. Create tests — `src/tools/builtin/<name>.test.ts`
|
||||
|
||||
Co-located next to the source file. Use the hoisted mock pattern for external deps:
|
||||
```typescript
|
||||
const { mockFn } = vi.hoisted(() => ({ mockFn: vi.fn() }));
|
||||
vi.mock('some-module', () => ({ thing: mockFn }));
|
||||
```
|
||||
|
||||
Cover: factory output (correct names/count), auth/config errors, happy paths, empty results, API errors.
|
||||
|
||||
### 3. Wire up the export chain
|
||||
|
||||
Three files, in order:
|
||||
|
||||
| File | Add |
|
||||
|------|-----|
|
||||
| `src/tools/builtin/index.ts` | `export { createFooTools } from './foo.js';` |
|
||||
| `src/tools/index.ts` | Add `createFooTools` to the barrel re-export from `./builtin/index.js` |
|
||||
| `src/daemon/index.ts` | Import + conditional registration (see existing `gmail`/`gcal` blocks) |
|
||||
|
||||
### 4. Register in TUI — `src/cli/tui.ts`
|
||||
|
||||
The TUI has its own tool registration (separate from the daemon). Add the import to the dynamic `import('../tools/index.js')` destructure and add a registration block matching the daemon pattern. **This is easy to forget.**
|
||||
|
||||
### 5. Config schema (if tool needs config)
|
||||
|
||||
In `src/config/schema.ts`:
|
||||
- Define a Zod schema (e.g. `const fooSchema = z.object({ ... }).optional()`)
|
||||
- Add the field to the parent schema (e.g. `automationSchema`)
|
||||
- Export the inferred type: `export type FooConfig = z.infer<typeof fooSchema>;`
|
||||
|
||||
### 6. Tool policy — `src/tools/policy.ts`
|
||||
|
||||
- Add tool names to the appropriate **profile sets** (`messaging`, `coding`, or both). The `full` profile matches everything automatically.
|
||||
- Add a **tool group** entry: `'group:foo': ['foo.bar', 'foo.baz']`
|
||||
|
||||
### 7. CLI auth command (if tool needs OAuth)
|
||||
|
||||
Mirror `src/cli/gmail-auth.ts` or `src/cli/gcal-auth.ts`:
|
||||
- Create `src/cli/<name>-auth.ts` with `registerFooAuthCommand(program)`
|
||||
- Register in `src/cli/index.ts`
|
||||
- Use the correct OAuth scope, token path, and config key
|
||||
|
||||
### Verification
|
||||
|
||||
```bash
|
||||
pnpm test:run src/tools/builtin/<name>.test.ts # new tests pass
|
||||
pnpm typecheck # no type errors
|
||||
pnpm test:run # full suite still passes
|
||||
```
|
||||
|
||||
## State Tracking
|
||||
|
||||
After implementing features, update `docs/plans/state.json` (test counts, progress, feature gap scorecard). Commit alongside the feature change.
|
||||
|
||||
Reference in New Issue
Block a user