@qelos/aidev 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +9 -0
- package/.cursor/rules/aidev.mdc +57 -0
- package/.env.aidev.example +17 -0
- package/CLAUDE.md +32 -0
- package/CONTRIBUTING.md +78 -0
- package/LICENSE +21 -0
- package/README.md +245 -0
- package/dist/ai/base.d.ts.map +1 -0
- package/dist/ai/base.js +3 -0
- package/dist/ai/claude.d.ts.map +1 -0
- package/dist/ai/claude.js +33 -0
- package/dist/ai/cursor.d.ts.map +1 -0
- package/dist/ai/cursor.js +33 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +74 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +48 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +255 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +257 -0
- package/dist/commands/schedule.d.ts.map +1 -0
- package/dist/commands/schedule.js +191 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +89 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +108 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +88 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +69 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +3 -0
- package/dist/providers/clickup.d.ts.map +1 -0
- package/dist/providers/clickup.js +67 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +19 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/package.json +28 -0
- package/src/ai/base.ts +11 -0
- package/src/ai/claude.ts +35 -0
- package/src/ai/cursor.ts +35 -0
- package/src/ai/index.ts +15 -0
- package/src/cli.ts +83 -0
- package/src/commands/help.ts +43 -0
- package/src/commands/init.ts +296 -0
- package/src/commands/run.ts +283 -0
- package/src/commands/schedule.ts +179 -0
- package/src/config.ts +59 -0
- package/src/git.ts +109 -0
- package/src/logger.ts +53 -0
- package/src/platform.ts +33 -0
- package/src/providers/base.ts +8 -0
- package/src/providers/clickup.ts +107 -0
- package/src/providers/index.ts +20 -0
- package/src/types.ts +33 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: aidev project rules
|
|
3
|
+
globs: ["**/*.ts", "**/*.js", "package.json", "tsconfig.json"]
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# aidev Project Rules
|
|
8
|
+
|
|
9
|
+
## Stack
|
|
10
|
+
- TypeScript 5, CommonJS (`"type": "commonjs"`), Node.js ≥ 18
|
|
11
|
+
- Dependencies: `chalk@4`, `commander@12`, `dotenv@16`
|
|
12
|
+
- No HTTP libraries — use native `fetch` (Node 18+) only
|
|
13
|
+
- chalk v4 specifically (v5 is ESM-only and incompatible)
|
|
14
|
+
|
|
15
|
+
## Code Conventions
|
|
16
|
+
- All native Node.js imports use the `node:` prefix:
|
|
17
|
+
`node:fs`, `node:path`, `node:child_process`, `node:os`, etc.
|
|
18
|
+
- All subprocess calls use `spawnSync(bin, [...args])` with array arguments — never string interpolation into shell commands
|
|
19
|
+
- Strict TypeScript: no `any`, explicit return types on exported functions
|
|
20
|
+
|
|
21
|
+
## Architecture
|
|
22
|
+
|
|
23
|
+
### Providers (`src/providers/`)
|
|
24
|
+
- `TaskProvider` interface: `fetchTasks()`, `postComment()`, `getComments()`, `updateStatus()`
|
|
25
|
+
- Only ClickUp is implemented; Jira/Notion/Trello stubs throw descriptive errors
|
|
26
|
+
- To add a provider: implement `TaskProvider`, register in `createProvider()` factory
|
|
27
|
+
|
|
28
|
+
### AI Runners (`src/ai/`)
|
|
29
|
+
- `AIRunner` interface: `name`, `isAvailable()`, `run(prompt, notes?)`
|
|
30
|
+
- Runners: `ClaudeRunner` (claude CLI), `CursorRunner` (cursor --agent)
|
|
31
|
+
- `auto` mode: no TTY → Claude first; TTY → Cursor first; fallback to next on failure
|
|
32
|
+
|
|
33
|
+
### Commands (`src/commands/`)
|
|
34
|
+
- `init` — writes `.env.aidev` from inline template; skips if file exists
|
|
35
|
+
- `run` — fetches tasks, applies filter (all/open/pending), implements each
|
|
36
|
+
- `schedule` — manages per-directory crontab entries using marker `# aidev-cwd:/path`
|
|
37
|
+
|
|
38
|
+
### CLI (`src/cli.ts`)
|
|
39
|
+
- `run [filter]` is registered with `{ isDefault: true }` — do not use `program.action()` as default, it causes double-execution
|
|
40
|
+
|
|
41
|
+
## Task Processing Flow
|
|
42
|
+
```
|
|
43
|
+
fetchTasks()
|
|
44
|
+
skip: closed/done/cancelled/complete statuses
|
|
45
|
+
skip: remote branch already exists (taskId prefix)
|
|
46
|
+
pending tasks: check for human reply before proceeding
|
|
47
|
+
open tasks: checkNeedsClarification() → postComment + set pending if unclear
|
|
48
|
+
implementTask():
|
|
49
|
+
updateStatus("in progress") → git branch → AI runner → commit → push
|
|
50
|
+
postComment(branch + PR link) → updateStatus(CLICKUP_IN_REVIEW_STATUS)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Build
|
|
54
|
+
```bash
|
|
55
|
+
npm run build # tsc + chmod +x dist/cli.js
|
|
56
|
+
npm run dev -- run --help
|
|
57
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
PROVIDER=clickup
|
|
2
|
+
CLICKUP_API_KEY=
|
|
3
|
+
CLICKUP_TEAM_ID=
|
|
4
|
+
CLICKUP_TAG=
|
|
5
|
+
CLICKUP_PENDING_STATUS=pending
|
|
6
|
+
CLICKUP_IN_REVIEW_STATUS=review
|
|
7
|
+
|
|
8
|
+
ASSIGNEE_TAG=
|
|
9
|
+
GIT_REMOTE=origin
|
|
10
|
+
GITHUB_BASE_BRANCH=main
|
|
11
|
+
GITHUB_REPO=
|
|
12
|
+
|
|
13
|
+
# Agents to use, in fallback order (comma-separated: claude, cursor)
|
|
14
|
+
AGENTS=claude,cursor
|
|
15
|
+
|
|
16
|
+
# DEV_NOTES_MODE: smart (only ask when unclear) | always (ask before every task)
|
|
17
|
+
DEV_NOTES_MODE=smart
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# aidev — Claude Project Rules
|
|
2
|
+
|
|
3
|
+
## Build & Run
|
|
4
|
+
```bash
|
|
5
|
+
npm run build # tsc + chmod +x dist/cli.js
|
|
6
|
+
npm run dev -- <cmd> # run via tsx without building
|
|
7
|
+
node dist/cli.js --help
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Project Layout
|
|
11
|
+
- `src/cli.ts` — Commander entry point; `run` is the default command (`isDefault: true`)
|
|
12
|
+
- `src/providers/` — `TaskProvider` interface + ClickUp implementation (native `fetch`)
|
|
13
|
+
- `src/ai/` — `AIRunner` interface + Claude/Cursor runners (`spawnSync`)
|
|
14
|
+
- `src/commands/` — `init`, `run`, `schedule`
|
|
15
|
+
- `src/git.ts` — all git ops via `spawnSync('git', [...args])`, never string concat
|
|
16
|
+
|
|
17
|
+
## Strict Rules
|
|
18
|
+
- **No shell injection**: always pass args as arrays to `spawnSync`, never interpolate into shell strings
|
|
19
|
+
- **No new HTTP dependencies**: use native `fetch` (Node 18+) only
|
|
20
|
+
- **CJS only**: `"type": "commonjs"` — do not use ESM syntax or ESM-only packages
|
|
21
|
+
- **chalk v4**: project uses chalk v4 (not v5, which is ESM-only)
|
|
22
|
+
- **`node:` prefix**: all built-in imports use `node:fs`, `node:path`, `node:child_process`, etc.
|
|
23
|
+
|
|
24
|
+
## Adding a Provider
|
|
25
|
+
1. Create `src/providers/<name>.ts` implementing `TaskProvider`
|
|
26
|
+
2. Register in `src/providers/index.ts` `createProvider()` switch
|
|
27
|
+
3. Add config fields to `src/types.ts` (`Config`) and `src/config.ts`
|
|
28
|
+
4. Document in `.env.aidev.example` and `README.md`
|
|
29
|
+
|
|
30
|
+
## Adding an AI Runner
|
|
31
|
+
1. Create `src/ai/<name>.ts` implementing `AIRunner`
|
|
32
|
+
2. Register in `src/ai/index.ts` `createRunners()` and update `AI_TOOL` logic
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Contributing to aidev
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing!
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository
|
|
8
|
+
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
9
|
+
3. Make your changes
|
|
10
|
+
4. Build and test: `npm install && npm run build`
|
|
11
|
+
5. Open a pull request
|
|
12
|
+
|
|
13
|
+
## Development Setup
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/your-org/aidev
|
|
17
|
+
cd aidev
|
|
18
|
+
npm install
|
|
19
|
+
npm run dev -- init # uses tsx, no build needed
|
|
20
|
+
npm run dev -- run --help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Adding a New Provider
|
|
24
|
+
|
|
25
|
+
1. Create `src/providers/<name>.ts` implementing the `TaskProvider` interface:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { TaskProvider } from './base';
|
|
29
|
+
import { Task, Comment, Config } from '../types';
|
|
30
|
+
|
|
31
|
+
export class MyProvider implements TaskProvider {
|
|
32
|
+
constructor(config: Config) { ... }
|
|
33
|
+
async fetchTasks(): Promise<Task[]> { ... }
|
|
34
|
+
async postComment(taskId: string, text: string): Promise<void> { ... }
|
|
35
|
+
async getComments(taskId: string): Promise<Comment[]> { ... }
|
|
36
|
+
async updateStatus(taskId: string, status: string): Promise<void> { ... }
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. Register it in `src/providers/index.ts`:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
case 'myprovider':
|
|
44
|
+
return new MyProvider(config);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
3. Add any new config keys to `src/types.ts` (`Config` interface) and `src/config.ts`.
|
|
48
|
+
|
|
49
|
+
4. Document the new env vars in `.env.aidev.example` and `README.md`.
|
|
50
|
+
|
|
51
|
+
## Adding a New AI Runner
|
|
52
|
+
|
|
53
|
+
1. Create `src/ai/<name>.ts` implementing the `AIRunner` interface:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { AIRunner, AIRunResult } from './base';
|
|
57
|
+
|
|
58
|
+
export class MyRunner implements AIRunner {
|
|
59
|
+
readonly name = 'myrunner';
|
|
60
|
+
isAvailable(): boolean { ... }
|
|
61
|
+
async run(prompt: string, notes?: string): Promise<AIRunResult> { ... }
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
2. Register it in `src/ai/index.ts` and update the `AI_TOOL` logic.
|
|
66
|
+
|
|
67
|
+
## Code Style
|
|
68
|
+
|
|
69
|
+
- TypeScript strict mode
|
|
70
|
+
- No shell string concatenation for subprocess calls — always use array args with `spawnSync`
|
|
71
|
+
- Native `fetch` only — no HTTP library dependencies
|
|
72
|
+
- Keep dependencies minimal
|
|
73
|
+
|
|
74
|
+
## Pull Request Guidelines
|
|
75
|
+
|
|
76
|
+
- One feature/fix per PR
|
|
77
|
+
- Update README.md if you add new config vars or commands
|
|
78
|
+
- Ensure `npm run build` passes before submitting
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 aidev contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# aidev
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/aidev)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
|
|
7
|
+
**aidev** turns your ClickUp tasks into merged code — automatically.
|
|
8
|
+
|
|
9
|
+
It polls your task manager, checks whether tasks are clear, runs Claude or Cursor to implement them, pushes a branch, and moves the task to review. All without touching your keyboard.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
ClickUp task → AI implements → git push → "in review"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Table of Contents
|
|
18
|
+
|
|
19
|
+
- [How it works](#how-it-works)
|
|
20
|
+
- [Quick start](#quick-start)
|
|
21
|
+
- [Commands](#commands)
|
|
22
|
+
- [Configuration](#configuration)
|
|
23
|
+
- [AI agents](#ai-agents)
|
|
24
|
+
- [Dev notes mode](#dev-notes-mode)
|
|
25
|
+
- [Scheduling](#scheduling)
|
|
26
|
+
- [Logging](#logging)
|
|
27
|
+
- [Providers](#providers)
|
|
28
|
+
- [Contributing](#contributing)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## How it works
|
|
33
|
+
|
|
34
|
+
1. **Fetch** — pulls all tasks tagged with your configured tag from ClickUp
|
|
35
|
+
2. **Filter** — skips done/cancelled tasks and tasks that already have a branch
|
|
36
|
+
3. **Clarify** — in `smart` mode, asks the AI if the task description is clear enough; if not, posts a question as a comment and marks the task `pending`
|
|
37
|
+
4. **Wait** — pending tasks are re-checked on the next run; if a human replied, implementation proceeds with the reply as extra context
|
|
38
|
+
5. **Implement** — checks out a fresh branch, runs your configured AI agent(s), falls back to the next agent if one fails
|
|
39
|
+
6. **Ship** — commits all changes, pushes the branch, posts a comment with the branch name and a PR link, moves the task to your "in review" status
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install -g aidev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Navigate to your project and run the interactive setup:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd my-project
|
|
53
|
+
aidev init
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The wizard will ask for your ClickUp credentials, git settings, and preferred AI agents. Sensitive values (API keys) can be left blank if they are already set as environment variables in your shell.
|
|
57
|
+
|
|
58
|
+
Once configured:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
aidev run
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Commands
|
|
67
|
+
|
|
68
|
+
| Command | Description |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `aidev init` | Interactive setup — creates `.env.aidev` |
|
|
71
|
+
| `aidev run` | Process all open + pending-with-replies tasks |
|
|
72
|
+
| `aidev run open` | Only open (non-pending) tasks |
|
|
73
|
+
| `aidev run pending` | Only pending tasks — check for human replies |
|
|
74
|
+
| `aidev schedule set` | Interactive cron picker for this directory |
|
|
75
|
+
| `aidev schedule set "<expr>"` | Set a specific cron expression |
|
|
76
|
+
| `aidev schedule get` | Show the current schedule for this directory |
|
|
77
|
+
| `aidev help` | Show command and config reference |
|
|
78
|
+
|
|
79
|
+
### Global flags
|
|
80
|
+
|
|
81
|
+
| Flag | Description |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `-e, --env <path>` | Load config from a custom env file instead of `.env.aidev` |
|
|
84
|
+
| `-V, --version` | Print version |
|
|
85
|
+
|
|
86
|
+
**Examples**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Use a shared env file for a staging environment
|
|
90
|
+
aidev --env /shared/.env.staging run
|
|
91
|
+
|
|
92
|
+
# Only process tasks that are waiting for a reply
|
|
93
|
+
aidev run pending
|
|
94
|
+
|
|
95
|
+
# Schedule to run every 30 minutes
|
|
96
|
+
aidev schedule set "*/30 * * * *"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
Run `aidev init` for an interactive setup, or create `.env.aidev` manually using `.env.aidev.example` as a template.
|
|
104
|
+
|
|
105
|
+
### ClickUp
|
|
106
|
+
|
|
107
|
+
| Variable | Default | Description |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `CLICKUP_API_KEY` | — | Personal API token — can be set as a shell env var |
|
|
110
|
+
| `CLICKUP_TEAM_ID` | — | Workspace / team ID — can be set as a shell env var |
|
|
111
|
+
| `CLICKUP_TAG` | — | Tasks with this tag will be picked up |
|
|
112
|
+
| `CLICKUP_PENDING_STATUS` | `pending` | Status name for "waiting for reply" |
|
|
113
|
+
| `CLICKUP_IN_REVIEW_STATUS` | `review` | Status set after implementation |
|
|
114
|
+
| `ASSIGNEE_TAG` | — | Only process tasks assigned to this user (optional) |
|
|
115
|
+
|
|
116
|
+
> **Tip:** `CLICKUP_API_KEY` and `CLICKUP_TEAM_ID` are intentionally omitted from `.env.aidev` if you leave them blank during `aidev init` — they will be read from your shell environment instead.
|
|
117
|
+
|
|
118
|
+
### Git & GitHub
|
|
119
|
+
|
|
120
|
+
| Variable | Default | Description |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `GIT_REMOTE` | auto-detected | Remote name — detected via `git remote get-url origin` if unset |
|
|
123
|
+
| `GITHUB_BASE_BRANCH` | `main` | Base branch; new task branches are cut from here |
|
|
124
|
+
| `GITHUB_REPO` | — | `owner/repo` — used to generate PR links in comments |
|
|
125
|
+
|
|
126
|
+
### AI agents
|
|
127
|
+
|
|
128
|
+
| Variable | Default | Description |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| `AGENTS` | `claude,cursor` | Comma-separated list of agents in priority order |
|
|
131
|
+
| `DEV_NOTES_MODE` | `smart` | When to ask for clarification (`smart` or `always`) |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## AI agents
|
|
136
|
+
|
|
137
|
+
aidev supports multiple AI agents with automatic fallback. The first available agent in the list is used; if it fails, the next one is tried with the previous agent's output as additional context.
|
|
138
|
+
|
|
139
|
+
**Supported agents**
|
|
140
|
+
|
|
141
|
+
| Agent | Requires |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `claude` | [Claude CLI](https://github.com/anthropics/claude-code) installed and authenticated |
|
|
144
|
+
| `cursor` | [Cursor](https://cursor.sh) installed with Agent mode |
|
|
145
|
+
|
|
146
|
+
**Configure agent order in `.env.aidev`:**
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Claude first, fall back to Cursor
|
|
150
|
+
AGENTS=claude,cursor
|
|
151
|
+
|
|
152
|
+
# Cursor only
|
|
153
|
+
AGENTS=cursor
|
|
154
|
+
|
|
155
|
+
# Cursor first (useful when working locally with a monitor)
|
|
156
|
+
AGENTS=cursor,claude
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Dev notes mode
|
|
162
|
+
|
|
163
|
+
Controls when aidev asks ClickUp for clarification before implementing.
|
|
164
|
+
|
|
165
|
+
| Mode | Behaviour |
|
|
166
|
+
|---|---|
|
|
167
|
+
| `smart` | Asks the AI whether the task description is clear enough. Only posts a clarification question if it's ambiguous. |
|
|
168
|
+
| `always` | Always posts "any dev notes?" before implementing every task. |
|
|
169
|
+
|
|
170
|
+
When a question is posted, the task is moved to `CLICKUP_PENDING_STATUS`. On the next run, aidev checks whether a human has replied and, if so, includes the reply as context for the AI.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Scheduling
|
|
175
|
+
|
|
176
|
+
aidev can run on a cron schedule, one entry per project directory.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Interactive picker
|
|
180
|
+
aidev schedule set
|
|
181
|
+
|
|
182
|
+
# Or pass an expression directly
|
|
183
|
+
aidev schedule set "*/15 * * * *"
|
|
184
|
+
|
|
185
|
+
# Check what's scheduled for the current directory
|
|
186
|
+
aidev schedule get
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Preset options (interactive picker)**
|
|
190
|
+
|
|
191
|
+
| Option | Expression |
|
|
192
|
+
|---|---|
|
|
193
|
+
| Every 15 minutes | `*/15 * * * *` |
|
|
194
|
+
| Every 30 minutes | `*/30 * * * *` |
|
|
195
|
+
| Every hour | `0 * * * *` |
|
|
196
|
+
| Every 5 hours | `0 */5 * * *` |
|
|
197
|
+
| Every day at 8am | `0 8 * * *` |
|
|
198
|
+
|
|
199
|
+
Each directory gets its own cron entry identified by a `# aidev-cwd:/path` marker — running `schedule set` again replaces the existing entry rather than adding a duplicate.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Logging
|
|
204
|
+
|
|
205
|
+
Every run appends to `aidev.log` in your project directory:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
────────────────────────────────────────────────────────────
|
|
209
|
+
2026-03-06T08:00:00.000Z [run] started
|
|
210
|
+
────────────────────────────────────────────────────────────
|
|
211
|
+
2026-03-06T08:00:00.120Z [info] Fetching tasks (filter: all)...
|
|
212
|
+
2026-03-06T08:00:01.340Z [task] [abc123] "Fix login flow" (status: open)
|
|
213
|
+
2026-03-06T08:00:12.780Z [info] Running claude...
|
|
214
|
+
2026-03-06T08:00:45.210Z [success] Task implemented: branch abc123/fix-login-flow pushed
|
|
215
|
+
2026-03-06T08:00:45.890Z [success] Done. Processed: 1, Skipped: 3
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
ANSI colour codes are stripped so the file stays readable in any editor or `tail -f`. `aidev.log` is added to `.gitignore` automatically by `aidev init`.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Providers
|
|
223
|
+
|
|
224
|
+
| Provider | Status |
|
|
225
|
+
|---|---|
|
|
226
|
+
| ClickUp | ✅ Implemented |
|
|
227
|
+
| Jira | 🔜 Stub — contributions welcome |
|
|
228
|
+
| Notion | 🔜 Stub — contributions welcome |
|
|
229
|
+
| Trello | 🔜 Stub — contributions welcome |
|
|
230
|
+
|
|
231
|
+
The `TaskProvider` interface makes it straightforward to add new providers. See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Contributing
|
|
236
|
+
|
|
237
|
+
Contributions are welcome — new providers, new AI runners, bug fixes, and docs improvements.
|
|
238
|
+
|
|
239
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full guide.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/ai/base.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,IAAI,OAAO,CAAC;IACvB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC3D"}
|
package/dist/ai/base.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/ai/claude.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAI/C,qBAAa,YAAa,YAAW,QAAQ;IAC3C,QAAQ,CAAC,IAAI,YAAY;IAEzB,WAAW,IAAI,OAAO;IAIhB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAsBhE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClaudeRunner = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const logger_1 = require("../logger");
|
|
6
|
+
const platform_1 = require("../platform");
|
|
7
|
+
class ClaudeRunner {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.name = 'claude';
|
|
10
|
+
}
|
|
11
|
+
isAvailable() {
|
|
12
|
+
return (0, platform_1.commandExists)('claude');
|
|
13
|
+
}
|
|
14
|
+
async run(prompt, notes) {
|
|
15
|
+
const fullPrompt = notes ? `${prompt}\n\nAdditional context:\n${notes}` : prompt;
|
|
16
|
+
logger_1.logger.info('Running Claude CLI...');
|
|
17
|
+
logger_1.logger.debug(`Prompt: ${fullPrompt.slice(0, 200)}...`);
|
|
18
|
+
const result = (0, node_child_process_1.spawnSync)('claude', ['-p', fullPrompt, '--dangerously-skip-permissions'], {
|
|
19
|
+
encoding: 'utf8',
|
|
20
|
+
timeout: 10 * 60 * 1000,
|
|
21
|
+
cwd: process.cwd(),
|
|
22
|
+
});
|
|
23
|
+
const success = result.status === 0;
|
|
24
|
+
const output = result.stdout || '';
|
|
25
|
+
const error = result.stderr || '';
|
|
26
|
+
if (!success) {
|
|
27
|
+
logger_1.logger.warn(`Claude exited with status ${result.status}`);
|
|
28
|
+
}
|
|
29
|
+
return { success, output, error };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.ClaudeRunner = ClaudeRunner;
|
|
33
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/ai/cursor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAI/C,qBAAa,YAAa,YAAW,QAAQ;IAC3C,QAAQ,CAAC,IAAI,YAAY;IAEzB,WAAW,IAAI,OAAO;IAIhB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAsBhE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CursorRunner = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const logger_1 = require("../logger");
|
|
6
|
+
const platform_1 = require("../platform");
|
|
7
|
+
class CursorRunner {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.name = 'cursor';
|
|
10
|
+
}
|
|
11
|
+
isAvailable() {
|
|
12
|
+
return (0, platform_1.commandExists)('cursor');
|
|
13
|
+
}
|
|
14
|
+
async run(prompt, notes) {
|
|
15
|
+
const fullPrompt = notes ? `${prompt}\n\nAdditional context:\n${notes}` : prompt;
|
|
16
|
+
logger_1.logger.info('Running Cursor Agent...');
|
|
17
|
+
logger_1.logger.debug(`Prompt: ${fullPrompt.slice(0, 200)}...`);
|
|
18
|
+
const result = (0, node_child_process_1.spawnSync)('cursor', ['--agent', fullPrompt], {
|
|
19
|
+
encoding: 'utf8',
|
|
20
|
+
timeout: 10 * 60 * 1000,
|
|
21
|
+
cwd: process.cwd(),
|
|
22
|
+
});
|
|
23
|
+
const success = result.status === 0;
|
|
24
|
+
const output = result.stdout || '';
|
|
25
|
+
const error = result.stderr || '';
|
|
26
|
+
if (!success) {
|
|
27
|
+
logger_1.logger.warn(`Cursor exited with status ${result.status}`);
|
|
28
|
+
}
|
|
29
|
+
return { success, output, error };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.CursorRunner = CursorRunner;
|
|
33
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AASlC,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAExD;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/ai/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRunners = createRunners;
|
|
4
|
+
const claude_1 = require("./claude");
|
|
5
|
+
const cursor_1 = require("./cursor");
|
|
6
|
+
const registry = {
|
|
7
|
+
claude: new claude_1.ClaudeRunner(),
|
|
8
|
+
cursor: new cursor_1.CursorRunner(),
|
|
9
|
+
};
|
|
10
|
+
function createRunners(config) {
|
|
11
|
+
return config.agents.map((name) => registry[name]);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const init_1 = require("./commands/init");
|
|
6
|
+
const run_1 = require("./commands/run");
|
|
7
|
+
const schedule_1 = require("./commands/schedule");
|
|
8
|
+
const help_1 = require("./commands/help");
|
|
9
|
+
const config_1 = require("./config");
|
|
10
|
+
const providers_1 = require("./providers");
|
|
11
|
+
const ai_1 = require("./ai");
|
|
12
|
+
const logger_1 = require("./logger");
|
|
13
|
+
const program = new commander_1.Command();
|
|
14
|
+
program
|
|
15
|
+
.name('aidev')
|
|
16
|
+
.description('AI-powered task executor — implements ClickUp tasks with Claude or Cursor')
|
|
17
|
+
.version('0.1.0')
|
|
18
|
+
.option('-e, --env <path>', 'path to env file (default: .env.aidev)');
|
|
19
|
+
program
|
|
20
|
+
.command('init')
|
|
21
|
+
.description('Create .env.aidev from template in current directory')
|
|
22
|
+
.action(async () => {
|
|
23
|
+
await (0, init_1.initCommand)();
|
|
24
|
+
});
|
|
25
|
+
program
|
|
26
|
+
.command('help')
|
|
27
|
+
.description('Show help')
|
|
28
|
+
.action(() => {
|
|
29
|
+
(0, help_1.helpCommand)();
|
|
30
|
+
});
|
|
31
|
+
async function runWithFilter(filter) {
|
|
32
|
+
const validFilters = ['all', 'open', 'pending'];
|
|
33
|
+
const resolvedFilter = filter && validFilters.includes(filter)
|
|
34
|
+
? filter
|
|
35
|
+
: 'all';
|
|
36
|
+
if (filter && !validFilters.includes(filter)) {
|
|
37
|
+
logger_1.logger.error(`Unknown filter: ${filter}. Valid options: all, open, pending`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const { env } = program.opts();
|
|
42
|
+
const config = (0, config_1.loadConfig)(env);
|
|
43
|
+
const provider = (0, providers_1.createProvider)(config);
|
|
44
|
+
const runners = (0, ai_1.createRunners)(config);
|
|
45
|
+
await (0, run_1.runCommand)(resolvedFilter, config, provider, runners);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
logger_1.logger.error(String(err));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
program
|
|
53
|
+
.command('run [filter]', { isDefault: true })
|
|
54
|
+
.description('Process tasks: all (default), open, or pending')
|
|
55
|
+
.action(async (filter) => {
|
|
56
|
+
await runWithFilter(filter);
|
|
57
|
+
});
|
|
58
|
+
const scheduleCmd = program
|
|
59
|
+
.command('schedule')
|
|
60
|
+
.description('Manage cron schedule for aidev in current directory');
|
|
61
|
+
scheduleCmd
|
|
62
|
+
.command('set [cron]')
|
|
63
|
+
.description('Set cron schedule — interactive picker if no cron given')
|
|
64
|
+
.action(async (cron) => {
|
|
65
|
+
await (0, schedule_1.scheduleSetCommand)(cron);
|
|
66
|
+
});
|
|
67
|
+
scheduleCmd
|
|
68
|
+
.command('get')
|
|
69
|
+
.description('Show current cron schedule for this directory')
|
|
70
|
+
.action(async () => {
|
|
71
|
+
await (0, schedule_1.scheduleGetCommand)();
|
|
72
|
+
});
|
|
73
|
+
program.parse(process.argv);
|
|
74
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/commands/help.ts"],"names":[],"mappings":"AAOA,wBAAgB,WAAW,IAAI,IAAI,CAmClC"}
|