ticket-to-pr 1.2.1 → 1.3.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/README.md +35 -2
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +83 -2
- package/dist/config.js +1 -1
- package/dist/index.js +8 -3
- package/package.json +17 -1
package/README.md
CHANGED
|
@@ -212,6 +212,8 @@ ticket-to-pr --dry-run --once
|
|
|
212
212
|
|----------------|----------|
|
|
213
213
|
| `init` | Guided setup — validates Notion credentials live, auto-detects build commands, generates starter `CLAUDE.md`, configures projects, writes `.env.local` and `projects.json`. Detects existing config on re-run. |
|
|
214
214
|
| `doctor` | Diagnostic check — verifies environment, Notion connectivity, database schema, tools, and projects |
|
|
215
|
+
| `model` | View current models and available options |
|
|
216
|
+
| `model <review\|execute\|both> <model>` | Set the Claude model for an agent. Accepts aliases (`opus`, `sonnet`, `haiku`) or full model IDs. |
|
|
215
217
|
| *(none)* | Continuous polling every 30s |
|
|
216
218
|
| `--once` | Poll once, wait for agents to finish, exit |
|
|
217
219
|
| `--dry-run` | Poll and log what would happen, don't run agents |
|
|
@@ -289,7 +291,7 @@ Environment:
|
|
|
289
291
|
○ LICENSE_KEY Free tier
|
|
290
292
|
|
|
291
293
|
Models:
|
|
292
|
-
✓ Review model claude-sonnet-4-
|
|
294
|
+
✓ Review model claude-sonnet-4-6
|
|
293
295
|
✓ Execute model claude-opus-4-6
|
|
294
296
|
|
|
295
297
|
Notion:
|
|
@@ -320,6 +322,35 @@ Docs: https://www.tickettopr.com
|
|
|
320
322
|
- `gh` missing is a warning (PRs won't auto-create but everything else works), `claude` missing is a hard failure
|
|
321
323
|
- Exits with code 1 if any hard failures, 0 otherwise
|
|
322
324
|
|
|
325
|
+
### `model` — Change AI Models
|
|
326
|
+
|
|
327
|
+
View or change which Claude models the agents use:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
# Show current models and available options
|
|
331
|
+
ticket-to-pr model
|
|
332
|
+
|
|
333
|
+
# Set review model (used for scoring tickets)
|
|
334
|
+
ticket-to-pr model review sonnet
|
|
335
|
+
|
|
336
|
+
# Set execute model (used for writing code)
|
|
337
|
+
ticket-to-pr model execute opus
|
|
338
|
+
|
|
339
|
+
# Set both at once
|
|
340
|
+
ticket-to-pr model both haiku
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Available model aliases:
|
|
344
|
+
|
|
345
|
+
| Alias | Model ID | Best for |
|
|
346
|
+
|-------|----------|----------|
|
|
347
|
+
| `opus` | `claude-opus-4-6` | Best quality (recommended for execute) |
|
|
348
|
+
| `sonnet` | `claude-sonnet-4-6` | Fast and capable (recommended for review) |
|
|
349
|
+
| `sonnet45` | `claude-sonnet-4-5-20250929` | Previous generation Sonnet |
|
|
350
|
+
| `haiku` | `claude-haiku-4-5-20251001` | Fastest, lowest cost |
|
|
351
|
+
|
|
352
|
+
You can also pass a full model ID directly (e.g. `ticket-to-pr model review claude-sonnet-4-5-20250929`). Changes are saved to `.env.local` and take effect on the next poll cycle.
|
|
353
|
+
|
|
323
354
|
### Your First Ticket
|
|
324
355
|
|
|
325
356
|
1. Click **"+ New"** on your Notion board
|
|
@@ -481,6 +512,8 @@ All settings in `config.ts`:
|
|
|
481
512
|
|
|
482
513
|
| Setting | Default | Purpose |
|
|
483
514
|
|---------|---------|---------|
|
|
515
|
+
| `REVIEW_MODEL` | `claude-sonnet-4-6` | Review agent model (change with `ticket-to-pr model review <model>`) |
|
|
516
|
+
| `EXECUTE_MODEL` | `claude-opus-4-6` | Execute agent model (change with `ticket-to-pr model execute <model>`) |
|
|
484
517
|
| `POLL_INTERVAL_MS` | 30000 | How often to check Notion (ms) |
|
|
485
518
|
| `REVIEW_BUDGET_USD` | 2.00 | Max USD per review agent run |
|
|
486
519
|
| `EXECUTE_BUDGET_USD` | 15.00 | Max USD per execute agent run |
|
|
@@ -505,7 +538,7 @@ Project configuration in `projects.json`:
|
|
|
505
538
|
```
|
|
506
539
|
ticket-to-pr/
|
|
507
540
|
index.ts # Poll loop, agent runner, worktree git workflow, graceful shutdown
|
|
508
|
-
cli.ts # init
|
|
541
|
+
cli.ts # init, doctor, and model commands
|
|
509
542
|
config.ts # Budgets, column names, license check, TypeScript types
|
|
510
543
|
projects.json # Your project directories and build commands (git-ignored, copy from example)
|
|
511
544
|
projects.example.json # Template for projects.json
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createInterface } from 'node:readline';
|
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
import { readFileSync, existsSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import { mask, shellEscape, writeEnvFile, updateProjectsFile, getDefaultBranch } from './lib/utils.js';
|
|
5
|
+
import { mask, shellEscape, writeEnvFile, updateProjectsFile, getDefaultBranch, parseEnvFile } from './lib/utils.js';
|
|
6
6
|
import { getProjectNames, getProjectDir, getBaseBranch, getBlockedFiles, getSkipPR } from './lib/projects.js';
|
|
7
7
|
import { CONFIG_DIR } from './lib/paths.js';
|
|
8
8
|
// -- Colors --
|
|
@@ -624,7 +624,7 @@ export async function runInit() {
|
|
|
624
624
|
console.log(` ${DIM}Choose which Claude model each agent uses.${RESET}`);
|
|
625
625
|
console.log(` ${DIM}Sonnet = fast/cheap, Opus = best quality, Haiku = fastest/cheapest${RESET}\n`);
|
|
626
626
|
const modelChoices = [
|
|
627
|
-
{ label: 'sonnet', id: 'claude-sonnet-4-
|
|
627
|
+
{ label: 'sonnet', id: 'claude-sonnet-4-6' },
|
|
628
628
|
{ label: 'opus', id: 'claude-opus-4-6' },
|
|
629
629
|
{ label: 'haiku', id: 'claude-haiku-4-5-20251001' },
|
|
630
630
|
];
|
|
@@ -768,3 +768,84 @@ export async function runInit() {
|
|
|
768
768
|
rl.close();
|
|
769
769
|
}
|
|
770
770
|
}
|
|
771
|
+
// -- Model --
|
|
772
|
+
const KNOWN_MODELS = [
|
|
773
|
+
{ alias: 'opus', id: 'claude-opus-4-6', description: 'Best quality, highest cost' },
|
|
774
|
+
{ alias: 'sonnet', id: 'claude-sonnet-4-6', description: 'Fast and capable (recommended for review)' },
|
|
775
|
+
{ alias: 'sonnet45', id: 'claude-sonnet-4-5-20250929', description: 'Previous generation Sonnet' },
|
|
776
|
+
{ alias: 'haiku', id: 'claude-haiku-4-5-20251001', description: 'Fastest, lowest cost' },
|
|
777
|
+
];
|
|
778
|
+
function resolveModel(input) {
|
|
779
|
+
const lower = input.toLowerCase();
|
|
780
|
+
const byAlias = KNOWN_MODELS.find((m) => m.alias === lower);
|
|
781
|
+
if (byAlias)
|
|
782
|
+
return byAlias;
|
|
783
|
+
const byId = KNOWN_MODELS.find((m) => m.id === lower);
|
|
784
|
+
if (byId)
|
|
785
|
+
return byId;
|
|
786
|
+
// Accept any claude- prefixed model ID as a pass-through
|
|
787
|
+
if (input.startsWith('claude-'))
|
|
788
|
+
return { alias: input, id: input };
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
export async function runModel(args) {
|
|
792
|
+
const envPath = join(CONFIG_DIR, '.env.local');
|
|
793
|
+
const envVars = parseEnvFile(envPath);
|
|
794
|
+
const currentReview = envVars.REVIEW_MODEL || 'claude-sonnet-4-6';
|
|
795
|
+
const currentExecute = envVars.EXECUTE_MODEL || 'claude-opus-4-6';
|
|
796
|
+
// No args: show current models and available options
|
|
797
|
+
if (args.length === 0) {
|
|
798
|
+
console.log(`\n${BOLD}Current models:${RESET}`);
|
|
799
|
+
const reviewAlias = KNOWN_MODELS.find((m) => m.id === currentReview)?.alias;
|
|
800
|
+
const executeAlias = KNOWN_MODELS.find((m) => m.id === currentExecute)?.alias;
|
|
801
|
+
console.log(` Review: ${GREEN}${currentReview}${RESET}${reviewAlias ? ` (${reviewAlias})` : ''}`);
|
|
802
|
+
console.log(` Execute: ${GREEN}${currentExecute}${RESET}${executeAlias ? ` (${executeAlias})` : ''}`);
|
|
803
|
+
console.log(`\n${BOLD}Available models:${RESET}`);
|
|
804
|
+
for (const m of KNOWN_MODELS) {
|
|
805
|
+
console.log(` ${BOLD}${m.alias.padEnd(10)}${RESET} ${DIM}${m.id.padEnd(35)}${RESET} ${m.description}`);
|
|
806
|
+
}
|
|
807
|
+
console.log(`\n${BOLD}Usage:${RESET}`);
|
|
808
|
+
console.log(` ticket-to-pr model review sonnet ${DIM}# set review model${RESET}`);
|
|
809
|
+
console.log(` ticket-to-pr model execute opus ${DIM}# set execute model${RESET}`);
|
|
810
|
+
console.log(` ticket-to-pr model both haiku ${DIM}# set both at once${RESET}\n`);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
// Parse: model <agent> <model>
|
|
814
|
+
if (args.length < 2) {
|
|
815
|
+
console.log(`${RED}Usage: ticket-to-pr model <review|execute|both> <model>${RESET}`);
|
|
816
|
+
console.log(`${DIM}Run "ticket-to-pr model" to see available models.${RESET}`);
|
|
817
|
+
process.exitCode = 1;
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
const agent = args[0].toLowerCase();
|
|
821
|
+
const modelInput = args[1];
|
|
822
|
+
if (!['review', 'execute', 'both'].includes(agent)) {
|
|
823
|
+
console.log(`${RED}Unknown agent "${args[0]}". Use: review, execute, or both${RESET}`);
|
|
824
|
+
process.exitCode = 1;
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const resolved = resolveModel(modelInput);
|
|
828
|
+
if (!resolved) {
|
|
829
|
+
console.log(`${RED}Unknown model "${modelInput}".${RESET}`);
|
|
830
|
+
console.log(`\n${BOLD}Available models:${RESET}`);
|
|
831
|
+
for (const m of KNOWN_MODELS) {
|
|
832
|
+
console.log(` ${BOLD}${m.alias.padEnd(10)}${RESET} ${DIM}${m.id}${RESET}`);
|
|
833
|
+
}
|
|
834
|
+
console.log(`\n${DIM}You can also pass a full model ID like claude-sonnet-4-5-20250929${RESET}`);
|
|
835
|
+
process.exitCode = 1;
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
const updates = {};
|
|
839
|
+
if (agent === 'review' || agent === 'both')
|
|
840
|
+
updates.REVIEW_MODEL = resolved.id;
|
|
841
|
+
if (agent === 'execute' || agent === 'both')
|
|
842
|
+
updates.EXECUTE_MODEL = resolved.id;
|
|
843
|
+
writeEnvFile(envPath, updates);
|
|
844
|
+
if (updates.REVIEW_MODEL) {
|
|
845
|
+
printStatus(true, 'Review model', `${resolved.id}${resolved.alias !== resolved.id ? ` (${resolved.alias})` : ''}`);
|
|
846
|
+
}
|
|
847
|
+
if (updates.EXECUTE_MODEL) {
|
|
848
|
+
printStatus(true, 'Execute model', `${resolved.id}${resolved.alias !== resolved.id ? ` (${resolved.alias})` : ''}`);
|
|
849
|
+
}
|
|
850
|
+
console.log(`${DIM}Saved to .env.local. Takes effect on next poll cycle.${RESET}\n`);
|
|
851
|
+
}
|
package/dist/config.js
CHANGED
|
@@ -48,7 +48,7 @@ export const CONFIG = {
|
|
|
48
48
|
EXECUTE_BUDGET_USD: 15.00,
|
|
49
49
|
// Agent models (env override → default)
|
|
50
50
|
get REVIEW_MODEL() {
|
|
51
|
-
return process.env.REVIEW_MODEL || 'claude-sonnet-4-
|
|
51
|
+
return process.env.REVIEW_MODEL || 'claude-sonnet-4-6';
|
|
52
52
|
},
|
|
53
53
|
get EXECUTE_MODEL() {
|
|
54
54
|
return process.env.EXECUTE_MODEL || 'claude-opus-4-6';
|
package/dist/index.js
CHANGED
|
@@ -13,9 +13,14 @@ loadEnv(join(CONFIG_DIR, '.env.local'));
|
|
|
13
13
|
delete process.env.CLAUDECODE;
|
|
14
14
|
// -- Subcommand routing --
|
|
15
15
|
const subcommand = process.argv[2];
|
|
16
|
-
if (subcommand === 'init' || subcommand === 'doctor') {
|
|
17
|
-
const { runInit, runDoctor } = await import('./cli.js');
|
|
18
|
-
|
|
16
|
+
if (subcommand === 'init' || subcommand === 'doctor' || subcommand === 'model') {
|
|
17
|
+
const { runInit, runDoctor, runModel } = await import('./cli.js');
|
|
18
|
+
if (subcommand === 'model') {
|
|
19
|
+
await runModel(process.argv.slice(3));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
await (subcommand === 'init' ? runInit() : runDoctor());
|
|
23
|
+
}
|
|
19
24
|
process.exit(0);
|
|
20
25
|
}
|
|
21
26
|
// -- CLI flags --
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ticket-to-pr",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Drag a Notion ticket, get a pull request. AI-powered dev automation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,6 +13,22 @@
|
|
|
13
13
|
"projects.example.json",
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
16
|
+
"homepage": "https://www.tickettopr.com",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/JohnRiceML/ticket-to-pr.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/JohnRiceML/ticket-to-pr/issues"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"notion",
|
|
26
|
+
"claude",
|
|
27
|
+
"ai",
|
|
28
|
+
"pull-request",
|
|
29
|
+
"automation",
|
|
30
|
+
"developer-tools"
|
|
31
|
+
],
|
|
16
32
|
"engines": {
|
|
17
33
|
"node": ">=18.0.0"
|
|
18
34
|
},
|