ticketree 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.
Files changed (57) hide show
  1. package/dist/adapters/github.d.ts +21 -0
  2. package/dist/adapters/github.d.ts.map +1 -0
  3. package/dist/adapters/github.js +48 -0
  4. package/dist/adapters/github.js.map +1 -0
  5. package/dist/adapters/jira.d.ts +12 -0
  6. package/dist/adapters/jira.d.ts.map +1 -0
  7. package/dist/adapters/jira.js +71 -0
  8. package/dist/adapters/jira.js.map +1 -0
  9. package/dist/cli/commands/end.d.ts +9 -0
  10. package/dist/cli/commands/end.d.ts.map +1 -0
  11. package/dist/cli/commands/end.js +96 -0
  12. package/dist/cli/commands/end.js.map +1 -0
  13. package/dist/cli/commands/init.d.ts +2 -0
  14. package/dist/cli/commands/init.d.ts.map +1 -0
  15. package/dist/cli/commands/init.js +72 -0
  16. package/dist/cli/commands/init.js.map +1 -0
  17. package/dist/cli/commands/list.d.ts +2 -0
  18. package/dist/cli/commands/list.d.ts.map +1 -0
  19. package/dist/cli/commands/list.js +35 -0
  20. package/dist/cli/commands/list.js.map +1 -0
  21. package/dist/cli/commands/start.d.ts +2 -0
  22. package/dist/cli/commands/start.d.ts.map +1 -0
  23. package/dist/cli/commands/start.js +55 -0
  24. package/dist/cli/commands/start.js.map +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/index.js +27 -0
  28. package/dist/cli/index.js.map +1 -0
  29. package/dist/config/loader.d.ts +3 -0
  30. package/dist/config/loader.d.ts.map +1 -0
  31. package/dist/config/loader.js +12 -0
  32. package/dist/config/loader.js.map +1 -0
  33. package/dist/config/types.d.ts +57 -0
  34. package/dist/config/types.d.ts.map +1 -0
  35. package/dist/config/types.js +32 -0
  36. package/dist/config/types.js.map +1 -0
  37. package/dist/core/editor.d.ts +2 -0
  38. package/dist/core/editor.d.ts.map +1 -0
  39. package/dist/core/editor.js +8 -0
  40. package/dist/core/editor.js.map +1 -0
  41. package/dist/core/terminal.d.ts +10 -0
  42. package/dist/core/terminal.d.ts.map +1 -0
  43. package/dist/core/terminal.js +24 -0
  44. package/dist/core/terminal.js.map +1 -0
  45. package/dist/core/ticket-parser.d.ts +9 -0
  46. package/dist/core/ticket-parser.d.ts.map +1 -0
  47. package/dist/core/ticket-parser.js +58 -0
  48. package/dist/core/ticket-parser.js.map +1 -0
  49. package/dist/core/worktree.d.ts +26 -0
  50. package/dist/core/worktree.d.ts.map +1 -0
  51. package/dist/core/worktree.js +85 -0
  52. package/dist/core/worktree.js.map +1 -0
  53. package/dist/index.d.ts +3 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +3 -0
  56. package/dist/index.js.map +1 -0
  57. package/package.json +64 -0
@@ -0,0 +1,21 @@
1
+ export interface GitHubRepo {
2
+ owner: string;
3
+ repo: string;
4
+ }
5
+ export interface CreatePROptions {
6
+ owner: string;
7
+ repo: string;
8
+ head: string;
9
+ base: string;
10
+ title: string;
11
+ body: string;
12
+ draft: boolean;
13
+ }
14
+ export interface PRResult {
15
+ number: number;
16
+ url: string;
17
+ }
18
+ export declare const parseGitRemoteUrl: (remoteUrl: string) => GitHubRepo;
19
+ export declare const getRepoFromRemote: () => Promise<GitHubRepo>;
20
+ export declare const createPullRequest: (options: CreatePROptions) => Promise<PRResult>;
21
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/adapters/github.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAUD,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,KAAG,UAcrD,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,UAAU,CAS5D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,SAAS,eAAe,KAAG,OAAO,CAAC,QAAQ,CAiBlF,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { Octokit } from '@octokit/rest';
2
+ import { simpleGit } from 'simple-git';
3
+ const git = simpleGit();
4
+ const getGitHubToken = () => {
5
+ const token = process.env.GITHUB_TOKEN;
6
+ if (!token) {
7
+ throw new Error('GITHUB_TOKEN environment variable is not set');
8
+ }
9
+ return token;
10
+ };
11
+ export const parseGitRemoteUrl = (remoteUrl) => {
12
+ // HTTPS: https://github.com/owner/repo.git
13
+ const httpsMatch = /https:\/\/github\.com\/([^/]+)\/(.+?)(?:\.git)?$/.exec(remoteUrl);
14
+ if (httpsMatch?.[1] && httpsMatch[2]) {
15
+ return { owner: httpsMatch[1], repo: httpsMatch[2] };
16
+ }
17
+ // SSH variants: git@github.com:owner/repo.git, kurone-git:owner/repo.git, etc.
18
+ const sshMatch = /^[^:]+:([^/]+)\/(.+?)(?:\.git)?$/.exec(remoteUrl);
19
+ if (sshMatch?.[1] && sshMatch[2]) {
20
+ return { owner: sshMatch[1], repo: sshMatch[2] };
21
+ }
22
+ throw new Error(`Failed to parse GitHub remote URL: ${remoteUrl}`);
23
+ };
24
+ export const getRepoFromRemote = async () => {
25
+ const remotes = await git.getRemotes(true);
26
+ const origin = remotes.find((r) => r.name === 'origin');
27
+ if (!origin?.refs.fetch) {
28
+ throw new Error('No origin remote found');
29
+ }
30
+ return parseGitRemoteUrl(origin.refs.fetch);
31
+ };
32
+ export const createPullRequest = async (options) => {
33
+ const octokit = new Octokit({ auth: getGitHubToken() });
34
+ const response = await octokit.rest.pulls.create({
35
+ owner: options.owner,
36
+ repo: options.repo,
37
+ head: options.head,
38
+ base: options.base,
39
+ title: options.title,
40
+ body: options.body,
41
+ draft: options.draft,
42
+ });
43
+ return {
44
+ number: response.data.number,
45
+ url: response.data.html_url,
46
+ };
47
+ };
48
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/adapters/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAsBxB,MAAM,cAAc,GAAG,GAAW,EAAE;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAc,EAAE;IACjE,2CAA2C;IAC3C,MAAM,UAAU,GAAG,kDAAkD,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtF,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,CAAC;IAED,+EAA+E;IAC/E,MAAM,QAAQ,GAAG,kCAAkC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpE,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,sCAAsC,SAAS,EAAE,CAAC,CAAC;AACrE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,IAAyB,EAAE;IAC/D,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAExD,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC9C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,OAAwB,EAAqB,EAAE;IACrF,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;IAExD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAC/C,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM;QAC5B,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ;KAC5B,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { JiraCredentials } from '../config/types.js';
2
+ export declare const testJiraConnection: (credentials?: JiraCredentials) => Promise<void>;
3
+ export interface JiraIssue {
4
+ key: string;
5
+ summary: string;
6
+ status: string;
7
+ type: string;
8
+ }
9
+ export declare const fetchIssues: (jql: string, credentials?: JiraCredentials) => Promise<JiraIssue[]>;
10
+ export declare const fetchIssue: (issueKey: string, credentials?: JiraCredentials) => Promise<JiraIssue>;
11
+ export declare const transitionIssue: (issueKey: string, transitionName: string, credentials?: JiraCredentials) => Promise<void>;
12
+ //# sourceMappingURL=jira.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../../src/adapters/jira.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AA8B1D,eAAO,MAAM,kBAAkB,GAAU,cAAc,eAAe,KAAG,OAAO,CAAC,IAAI,CAGpF,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,WAAW,GAAU,KAAK,MAAM,EAAE,cAAc,eAAe,KAAG,OAAO,CAAC,SAAS,EAAE,CAcjG,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,UAAU,MAAM,EAAE,cAAc,eAAe,KAAG,OAAO,CAAC,SAAS,CAanG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,UAAU,MAAM,EAAE,gBAAgB,MAAM,EAAE,cAAc,eAAe,KAAG,OAAO,CAAC,IAAI,CAiB3H,CAAC"}
@@ -0,0 +1,71 @@
1
+ import { Version3Client } from 'jira.js';
2
+ const getCredentialsFromEnv = () => {
3
+ const baseUrl = process.env.JIRA_BASE_URL;
4
+ const email = process.env.JIRA_EMAIL;
5
+ const apiToken = process.env.JIRA_API_TOKEN;
6
+ if (!baseUrl) {
7
+ throw new Error('JIRA_BASE_URL environment variable is not set');
8
+ }
9
+ if (!email) {
10
+ throw new Error('JIRA_EMAIL environment variable is not set');
11
+ }
12
+ if (!apiToken) {
13
+ throw new Error('JIRA_API_TOKEN environment variable is not set');
14
+ }
15
+ return { baseUrl, email, apiToken };
16
+ };
17
+ const createClient = (credentials) => new Version3Client({
18
+ host: credentials.baseUrl,
19
+ authentication: {
20
+ basic: {
21
+ email: credentials.email,
22
+ apiToken: credentials.apiToken,
23
+ },
24
+ },
25
+ });
26
+ export const testJiraConnection = async (credentials) => {
27
+ const client = createClient(credentials ?? getCredentialsFromEnv());
28
+ await client.myself.getCurrentUser();
29
+ };
30
+ export const fetchIssues = async (jql, credentials) => {
31
+ const client = createClient(credentials ?? getCredentialsFromEnv());
32
+ const response = await client.issueSearch.searchForIssuesUsingJqlEnhancedSearch({
33
+ jql,
34
+ fields: ['summary', 'status', 'issuetype'],
35
+ maxResults: 50,
36
+ });
37
+ return (response.issues ?? []).map((issue) => ({
38
+ key: issue.key,
39
+ summary: issue.fields.summary,
40
+ status: issue.fields.status.name ?? '',
41
+ type: issue.fields.issuetype?.name ?? '',
42
+ }));
43
+ };
44
+ export const fetchIssue = async (issueKey, credentials) => {
45
+ const client = createClient(credentials ?? getCredentialsFromEnv());
46
+ const issue = await client.issues.getIssue({
47
+ issueIdOrKey: issueKey,
48
+ fields: ['summary', 'status', 'issuetype'],
49
+ });
50
+ return {
51
+ key: issue.key,
52
+ summary: issue.fields.summary,
53
+ status: issue.fields.status.name ?? '',
54
+ type: issue.fields.issuetype?.name ?? '',
55
+ };
56
+ };
57
+ export const transitionIssue = async (issueKey, transitionName, credentials) => {
58
+ const client = createClient(credentials ?? getCredentialsFromEnv());
59
+ const transitions = await client.issues.getTransitions({
60
+ issueIdOrKey: issueKey,
61
+ });
62
+ const transition = transitions.transitions?.find((t) => t.name?.toLowerCase() === transitionName.toLowerCase());
63
+ if (!transition?.id) {
64
+ throw new Error(`Transition "${transitionName}" not found for issue ${issueKey}`);
65
+ }
66
+ await client.issues.doTransition({
67
+ issueIdOrKey: issueKey,
68
+ transition: { id: transition.id },
69
+ });
70
+ };
71
+ //# sourceMappingURL=jira.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.js","sourceRoot":"","sources":["../../src/adapters/jira.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ interface EndOptions {
2
+ pr?: boolean;
3
+ draft?: boolean;
4
+ base?: string;
5
+ keep?: boolean;
6
+ }
7
+ export declare const endCommand: (ticketInput: string | undefined, options: EndOptions) => Promise<void>;
8
+ export {};
9
+ //# sourceMappingURL=end.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"end.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/end.ts"],"names":[],"mappings":"AAgBA,UAAU,UAAU;IAClB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA4CD,eAAO,MAAM,UAAU,GAAU,aAAa,MAAM,GAAG,SAAS,EAAE,SAAS,UAAU,KAAG,OAAO,CAAC,IAAI,CAuEnG,CAAC"}
@@ -0,0 +1,96 @@
1
+ import chalk from 'chalk';
2
+ import { createPullRequest, getRepoFromRemote } from '../../adapters/github.js';
3
+ import { fetchIssue, transitionIssue } from '../../adapters/jira.js';
4
+ import { loadConfig } from '../../config/loader.js';
5
+ import { selectTicketInteractively } from '../../core/ticket-parser.js';
6
+ import { deleteBranch, deleteWorktree, getCurrentTicketKey, getWorktreeBranch, getWorktreePath, listWorktrees, pushBranch, worktreeExists, } from '../../core/worktree.js';
7
+ const DEFAULT_PR_BODY_TEMPLATE = '## Related Issue\n{issueLink}';
8
+ const buildPRBody = (template, issue, jiraBaseUrl) => {
9
+ const issueUrl = `${jiraBaseUrl}/browse/${issue.key}`;
10
+ const issueLink = `[${issue.key}](${issueUrl})`;
11
+ return template
12
+ .replace(/{issueKey}/g, issue.key)
13
+ .replace(/{issueLink}/g, issueLink)
14
+ .replace(/{issueSummary}/g, issue.summary)
15
+ .replace(/{issueUrl}/g, issueUrl);
16
+ };
17
+ const resolveTicketKey = async (ticketInput) => {
18
+ if (ticketInput) {
19
+ return ticketInput.toUpperCase();
20
+ }
21
+ const currentKey = getCurrentTicketKey();
22
+ if (currentKey) {
23
+ return currentKey;
24
+ }
25
+ const worktrees = await listWorktrees();
26
+ if (worktrees.length === 0) {
27
+ throw new Error('No worktrees found. Nothing to end.');
28
+ }
29
+ const issues = await Promise.all(worktrees.map(async (wt) => {
30
+ try {
31
+ return await fetchIssue(wt.ticketKey);
32
+ }
33
+ catch {
34
+ return { key: wt.ticketKey, summary: '(Failed to fetch)', status: '', type: '' };
35
+ }
36
+ }));
37
+ const selected = await selectTicketInteractively(issues);
38
+ return selected.key;
39
+ };
40
+ export const endCommand = async (ticketInput, options) => {
41
+ const config = await loadConfig();
42
+ const jiraConfig = config.issueTracker.jira;
43
+ if (!jiraConfig) {
44
+ throw new Error('Jira configuration is missing in .ticketreerc');
45
+ }
46
+ const ticketKey = await resolveTicketKey(ticketInput);
47
+ console.log(chalk.blue(`Ending work on ${ticketKey}...`));
48
+ if (!worktreeExists(ticketKey)) {
49
+ throw new Error(`Worktree for ${ticketKey} does not exist`);
50
+ }
51
+ const issue = await fetchIssue(ticketKey);
52
+ const branchName = await getWorktreeBranch(ticketKey);
53
+ if (!branchName) {
54
+ throw new Error(`Could not determine branch name for ${ticketKey}`);
55
+ }
56
+ console.log(chalk.blue(`Pushing branch ${branchName}...`));
57
+ await pushBranch(ticketKey);
58
+ console.log(chalk.green('Branch pushed successfully'));
59
+ if (options.pr) {
60
+ console.log(chalk.blue('Creating pull request...'));
61
+ const jiraBaseUrl = process.env.JIRA_BASE_URL;
62
+ if (!jiraBaseUrl) {
63
+ throw new Error('JIRA_BASE_URL environment variable is not set');
64
+ }
65
+ const prBodyTemplate = config.git.github?.prBodyTemplate ?? DEFAULT_PR_BODY_TEMPLATE;
66
+ const prBody = buildPRBody(prBodyTemplate, issue, jiraBaseUrl);
67
+ const { owner, repo } = await getRepoFromRemote();
68
+ const baseBranch = options.base ?? config.git.baseBranch;
69
+ const isDraft = options.draft !== false;
70
+ const pr = await createPullRequest({
71
+ owner,
72
+ repo,
73
+ head: branchName,
74
+ base: baseBranch,
75
+ title: `[${issue.key}] ${issue.summary}`,
76
+ body: prBody,
77
+ draft: isDraft,
78
+ });
79
+ console.log(chalk.green(`Pull request created: ${pr.url}`));
80
+ }
81
+ if (config.issueTransition.onEnd) {
82
+ console.log(chalk.blue(`Transitioning issue to "${config.issueTransition.onEnd}"...`));
83
+ await transitionIssue(ticketKey, config.issueTransition.onEnd);
84
+ console.log(chalk.green('Issue transitioned successfully'));
85
+ }
86
+ if (!options.keep) {
87
+ console.log(chalk.blue(`Removing worktree ${getWorktreePath(ticketKey)}...`));
88
+ await deleteWorktree(ticketKey);
89
+ console.log(chalk.green('Worktree removed'));
90
+ console.log(chalk.blue(`Deleting local branch ${branchName}...`));
91
+ await deleteBranch(branchName);
92
+ console.log(chalk.green('Branch deleted'));
93
+ }
94
+ console.log(chalk.green('\nDone! Ticket work ended successfully.'));
95
+ };
96
+ //# sourceMappingURL=end.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"end.js","sourceRoot":"","sources":["../../../src/cli/commands/end.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const initCommand: () => Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,IAAI,CAmEhD,CAAC"}
@@ -0,0 +1,72 @@
1
+ import { existsSync, mkdirSync, appendFileSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { stringify } from 'yaml';
5
+ import { DEFAULT_CONFIG } from '../../config/types.js';
6
+ import { testJiraConnection } from '../../adapters/jira.js';
7
+ const TICKETREE_DIR = '.ticketree';
8
+ const CONFIG_FILE = '.ticketreerc';
9
+ const GIT_EXCLUDE_FILE = '.git/info/exclude';
10
+ export const initCommand = async () => {
11
+ console.log(chalk.blue('Initializing Ticketree...'));
12
+ if (existsSync(CONFIG_FILE)) {
13
+ console.log(chalk.yellow(`${CONFIG_FILE} already exists. Skipping config creation.`));
14
+ }
15
+ else {
16
+ const configYaml = stringify(DEFAULT_CONFIG);
17
+ writeFileSync(CONFIG_FILE, configYaml, 'utf-8');
18
+ console.log(chalk.green(`Created ${CONFIG_FILE}`));
19
+ }
20
+ if (!existsSync(TICKETREE_DIR)) {
21
+ mkdirSync(TICKETREE_DIR, { recursive: true });
22
+ console.log(chalk.green(`Created ${TICKETREE_DIR}/ directory`));
23
+ }
24
+ else {
25
+ console.log(chalk.yellow(`${TICKETREE_DIR}/ already exists.`));
26
+ }
27
+ if (existsSync('.git')) {
28
+ const excludeDir = join('.git', 'info');
29
+ if (!existsSync(excludeDir)) {
30
+ mkdirSync(excludeDir, { recursive: true });
31
+ }
32
+ const excludeLine = `${TICKETREE_DIR}/`;
33
+ let excludeContent = '';
34
+ if (existsSync(GIT_EXCLUDE_FILE)) {
35
+ excludeContent = readFileSync(GIT_EXCLUDE_FILE, 'utf-8');
36
+ }
37
+ if (!excludeContent.includes(excludeLine)) {
38
+ appendFileSync(GIT_EXCLUDE_FILE, `\n# Added by ticketree\n${excludeLine}\n`);
39
+ console.log(chalk.green(`Added ${TICKETREE_DIR}/ to ${GIT_EXCLUDE_FILE}`));
40
+ }
41
+ else {
42
+ console.log(chalk.yellow(`${TICKETREE_DIR}/ already in ${GIT_EXCLUDE_FILE}`));
43
+ }
44
+ }
45
+ else {
46
+ console.log(chalk.yellow('Not a git repository. Skipping .git/info/exclude modification.'));
47
+ }
48
+ console.log(chalk.blue('\nTesting Jira connection...'));
49
+ try {
50
+ await testJiraConnection();
51
+ console.log(chalk.green('Jira connection successful!'));
52
+ }
53
+ catch (error) {
54
+ if (error instanceof Error) {
55
+ console.log(chalk.red(`Jira connection failed: ${error.message}`));
56
+ }
57
+ console.log(chalk.yellow('\nPlease set up your Jira credentials using direnv:'));
58
+ console.log(chalk.gray(`
59
+ # .envrc
60
+ export JIRA_BASE_URL="https://your-company.atlassian.net"
61
+ export JIRA_EMAIL="your-email@example.com"
62
+ export JIRA_API_TOKEN="your-api-token"
63
+
64
+ # For PR creation (optional)
65
+ export GITHUB_TOKEN="ghp_xxx"
66
+ `));
67
+ console.log(chalk.gray('Then run: direnv allow'));
68
+ process.exit(1);
69
+ }
70
+ console.log(chalk.green('\nTicketree initialized successfully!'));
71
+ };
72
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const listCommand: () => Promise<void>;
2
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,IAAI,CAoChD,CAAC"}
@@ -0,0 +1,35 @@
1
+ import chalk from 'chalk';
2
+ import { fetchIssues } from '../../adapters/jira.js';
3
+ import { listWorktrees } from '../../core/worktree.js';
4
+ export const listCommand = async () => {
5
+ const worktrees = await listWorktrees();
6
+ if (worktrees.length === 0) {
7
+ console.log(chalk.yellow('No worktrees found.'));
8
+ return;
9
+ }
10
+ const ticketKeys = worktrees.map((w) => w.ticketKey);
11
+ const jql = `key in (${ticketKeys.join(', ')})`;
12
+ let issueMap = new Map();
13
+ try {
14
+ const issues = await fetchIssues(jql);
15
+ issueMap = new Map(issues.map((issue) => [issue.key, issue]));
16
+ }
17
+ catch {
18
+ console.log(chalk.yellow('Warning: Failed to fetch Jira issues\n'));
19
+ }
20
+ console.log(chalk.blue('Worktrees:\n'));
21
+ for (const worktree of worktrees) {
22
+ const issue = issueMap.get(worktree.ticketKey);
23
+ if (issue) {
24
+ console.log(` ${chalk.cyan(`[${issue.key}]`)} ${issue.summary} ${chalk.gray(`(${issue.status})`)}`);
25
+ }
26
+ else {
27
+ console.log(` ${chalk.cyan(`[${worktree.ticketKey}]`)} ${chalk.red('(Failed to fetch)')}`);
28
+ }
29
+ console.log(chalk.gray(` Branch: ${worktree.branch}`));
30
+ console.log(chalk.gray(` Path: ${worktree.path}\n`));
31
+ }
32
+ const count = worktrees.length;
33
+ console.log(chalk.gray(`Total: ${String(count)} worktree${count > 1 ? 's' : ''}`));
34
+ };
35
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAkB,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,IAAmB,EAAE;IACnD,MAAM,SAAS,GAAG,MAAM,aAAa,EAAE,CAAC;IAExC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,WAAW,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAEhD,IAAI,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACtC,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAExC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAE/C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;QACvG,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,SAAS,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QAC9F,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,MAAM,CAAC,KAAK,CAAC,YAAY,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AACrF,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const startCommand: (ticketInput?: string) => Promise<void>;
2
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,YAAY,GAAU,cAAc,MAAM,KAAG,OAAO,CAAC,IAAI,CAsDrE,CAAC"}
@@ -0,0 +1,55 @@
1
+ import chalk from 'chalk';
2
+ import { fetchIssue, fetchIssues, transitionIssue } from '../../adapters/jira.js';
3
+ import { loadConfig } from '../../config/loader.js';
4
+ import { openEditor } from '../../core/editor.js';
5
+ import { openTerminal } from '../../core/terminal.js';
6
+ import { parseTicketInput, selectTicketInteractively } from '../../core/ticket-parser.js';
7
+ import { createWorktree, getWorktreePath, worktreeExists } from '../../core/worktree.js';
8
+ export const startCommand = async (ticketInput) => {
9
+ const config = await loadConfig();
10
+ const jiraConfig = config.issueTracker.jira;
11
+ if (!jiraConfig) {
12
+ throw new Error('Jira configuration is missing in .ticketreerc');
13
+ }
14
+ let ticket;
15
+ if (ticketInput) {
16
+ const parsed = parseTicketInput(ticketInput, jiraConfig.project);
17
+ console.log(chalk.blue(`Fetching ticket ${parsed.key}...`));
18
+ ticket = await fetchIssue(parsed.key);
19
+ }
20
+ else {
21
+ console.log(chalk.blue('Fetching issues...'));
22
+ const jql = `project = ${jiraConfig.project} AND (${jiraConfig.jql})`;
23
+ const issues = await fetchIssues(jql);
24
+ ticket = await selectTicketInteractively(issues);
25
+ }
26
+ const isExisting = worktreeExists(ticket.key);
27
+ if (isExisting) {
28
+ console.log(chalk.yellow(`Worktree already exists for ${ticket.key}`));
29
+ }
30
+ else {
31
+ console.log(chalk.blue(`Creating worktree for ${ticket.key}...`));
32
+ const result = await createWorktree({
33
+ ticketKey: ticket.key,
34
+ baseBranch: config.git.baseBranch,
35
+ branchPrefix: config.git.branchPrefix,
36
+ });
37
+ console.log(chalk.green(`Created worktree at ${result.path} (branch: ${result.branch})`));
38
+ if (config.issueTransition.onStart) {
39
+ console.log(chalk.blue(`Transitioning issue to "${config.issueTransition.onStart}"...`));
40
+ await transitionIssue(ticket.key, config.issueTransition.onStart);
41
+ console.log(chalk.green('Issue transitioned successfully'));
42
+ }
43
+ }
44
+ const worktreePath = getWorktreePath(ticket.key);
45
+ if (config.editor.enabled) {
46
+ console.log(chalk.blue(`Opening editor (${config.editor.command})...`));
47
+ openEditor(worktreePath, config.editor.command);
48
+ }
49
+ if (config.terminal.enabled) {
50
+ console.log(chalk.blue(`Opening terminal (${config.terminal.preset})...`));
51
+ openTerminal({ worktreePath, title: ticket.key, preset: config.terminal.preset });
52
+ }
53
+ console.log(chalk.green('\nDone! Happy coding 🚀'));
54
+ };
55
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { initCommand } from './commands/init.js';
4
+ import { startCommand } from './commands/start.js';
5
+ import { listCommand } from './commands/list.js';
6
+ import { endCommand } from './commands/end.js';
7
+ const program = new Command();
8
+ program
9
+ .name('ticketree')
10
+ .description('CLI tool that connects issue tracker tickets with Git Worktree')
11
+ .version('0.1.0');
12
+ program.command('init').description('Initialize Ticketree in current project').action(initCommand);
13
+ program
14
+ .command('start [ticket]')
15
+ .description('Start working on a ticket (create worktree, open editor/terminal)')
16
+ .action(startCommand);
17
+ program.command('list').description('List current worktrees with ticket information').action(listCommand);
18
+ program
19
+ .command('end [ticket]')
20
+ .description('End working on a ticket (push, delete worktree)')
21
+ .option('--pr', 'Create a pull request')
22
+ .option('--no-draft', 'Create PR as ready for review (not draft)')
23
+ .option('--base <branch>', 'Base branch for PR')
24
+ .option('--keep', 'Keep worktree and branch after ending')
25
+ .action(endCommand);
26
+ program.parse();
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,gEAAgE,CAAC;KAC7E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,yCAAyC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAEnG,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,mEAAmE,CAAC;KAChF,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,gDAAgD,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAE1G,OAAO;KACJ,OAAO,CAAC,cAAc,CAAC;KACvB,WAAW,CAAC,iDAAiD,CAAC;KAC9D,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC;KACvC,MAAM,CAAC,YAAY,EAAE,2CAA2C,CAAC;KACjE,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC;KAC/C,MAAM,CAAC,QAAQ,EAAE,uCAAuC,CAAC;KACzD,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { TicketreeConfig } from './types.js';
2
+ export declare const loadConfig: () => Promise<TicketreeConfig>;
3
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMlD,eAAO,MAAM,UAAU,QAAa,OAAO,CAAC,eAAe,CAQ1D,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { cosmiconfig } from 'cosmiconfig';
2
+ const explorer = cosmiconfig('ticketree', {
3
+ searchPlaces: ['.ticketreerc', '.ticketreerc.yaml', '.ticketreerc.yml', '.ticketreerc.json'],
4
+ });
5
+ export const loadConfig = async () => {
6
+ const result = await explorer.search();
7
+ if (!result || result.isEmpty) {
8
+ throw new Error('No .ticketreerc config file found. Run "ticketree init" first.');
9
+ }
10
+ return result.config;
11
+ };
12
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE;IACxC,YAAY,EAAE,CAAC,cAAc,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,mBAAmB,CAAC;CAC7F,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,IAA8B,EAAE;IAC7D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;IAEvC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,MAAM,CAAC,MAAyB,CAAC;AAC1C,CAAC,CAAC"}
@@ -0,0 +1,57 @@
1
+ export interface JiraConfig {
2
+ project: string;
3
+ jql: string;
4
+ }
5
+ export interface IssueTrackerConfig {
6
+ type: 'jira';
7
+ jira?: JiraConfig;
8
+ }
9
+ export interface GitHubConfig {
10
+ prBodyTemplate?: string;
11
+ }
12
+ export interface GitConfig {
13
+ baseBranch: string;
14
+ branchPrefix: string;
15
+ github?: GitHubConfig;
16
+ }
17
+ export interface SymlinkConfig {
18
+ source: string;
19
+ target: string;
20
+ }
21
+ export interface PostCreateConfig {
22
+ symlinks: SymlinkConfig[];
23
+ }
24
+ export interface EditorConfig {
25
+ enabled: boolean;
26
+ command: string;
27
+ }
28
+ export interface TerminalConfig {
29
+ enabled: boolean;
30
+ preset: 'ghostty' | 'iterm' | 'terminal' | 'warp' | 'kitty' | 'alacritty';
31
+ }
32
+ export interface IssueTransitionConfig {
33
+ onStart: string | null;
34
+ onEnd: string | null;
35
+ }
36
+ export interface TicketreeConfig {
37
+ issueTracker: IssueTrackerConfig;
38
+ git: GitConfig;
39
+ postCreate: PostCreateConfig;
40
+ editor: EditorConfig;
41
+ terminal: TerminalConfig;
42
+ issueTransition: IssueTransitionConfig;
43
+ }
44
+ export interface JiraCredentials {
45
+ baseUrl: string;
46
+ email: string;
47
+ apiToken: string;
48
+ }
49
+ export interface GitHubCredentials {
50
+ token: string;
51
+ }
52
+ export interface Credentials {
53
+ jira: JiraCredentials;
54
+ github?: GitHubCredentials;
55
+ }
56
+ export declare const DEFAULT_CONFIG: TicketreeConfig;
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,WAAW,CAAC;CAC3E;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,kBAAkB,CAAC;IACjC,GAAG,EAAE,SAAS,CAAC;IACf,UAAU,EAAE,gBAAgB,CAAC;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,cAAc,CAAC;IACzB,eAAe,EAAE,qBAAqB,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,eAAO,MAAM,cAAc,EAAE,eA8B5B,CAAC"}
@@ -0,0 +1,32 @@
1
+ export const DEFAULT_CONFIG = {
2
+ issueTracker: {
3
+ type: 'jira',
4
+ jira: {
5
+ project: 'PROJ',
6
+ jql: 'assignee = currentUser() AND resolution = Unresolved',
7
+ },
8
+ },
9
+ git: {
10
+ baseBranch: 'main',
11
+ branchPrefix: 'feature/',
12
+ github: {
13
+ prBodyTemplate: '## Related Issue\n{issueLink}',
14
+ },
15
+ },
16
+ postCreate: {
17
+ symlinks: [],
18
+ },
19
+ editor: {
20
+ enabled: true,
21
+ command: 'code',
22
+ },
23
+ terminal: {
24
+ enabled: true,
25
+ preset: 'ghostty',
26
+ },
27
+ issueTransition: {
28
+ onStart: null,
29
+ onEnd: null,
30
+ },
31
+ };
32
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAoEA,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC7C,YAAY,EAAE;QACZ,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE;YACJ,OAAO,EAAE,MAAM;YACf,GAAG,EAAE,sDAAsD;SAC5D;KACF;IACD,GAAG,EAAE;QACH,UAAU,EAAE,MAAM;QAClB,YAAY,EAAE,UAAU;QACxB,MAAM,EAAE;YACN,cAAc,EAAE,+BAA+B;SAChD;KACF;IACD,UAAU,EAAE;QACV,QAAQ,EAAE,EAAE;KACb;IACD,MAAM,EAAE;QACN,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,MAAM;KAChB;IACD,QAAQ,EAAE;QACR,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,SAAS;KAClB;IACD,eAAe,EAAE;QACf,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,IAAI;KACZ;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const openEditor: (worktreePath: string, command: string) => void;
2
+ //# sourceMappingURL=editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/core/editor.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,GAAI,cAAc,MAAM,EAAE,SAAS,MAAM,KAAG,IAKlE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { spawn } from 'node:child_process';
2
+ export const openEditor = (worktreePath, command) => {
3
+ spawn(command, [worktreePath], {
4
+ detached: true,
5
+ stdio: 'ignore',
6
+ }).unref();
7
+ };
8
+ //# sourceMappingURL=editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/core/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,YAAoB,EAAE,OAAe,EAAQ,EAAE;IACxE,KAAK,CAAC,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE;QAC7B,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAC,KAAK,EAAE,CAAC;AACb,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { TerminalConfig } from '../config/types.js';
2
+ type TerminalPreset = TerminalConfig['preset'];
3
+ export interface OpenTerminalOptions {
4
+ worktreePath: string;
5
+ title: string;
6
+ preset: TerminalPreset;
7
+ }
8
+ export declare const openTerminal: (options: OpenTerminalOptions) => void;
9
+ export {};
10
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/core/terminal.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,KAAK,cAAc,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;AAE/C,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,CAAC;CACxB;AASD,eAAO,MAAM,YAAY,GAAI,SAAS,mBAAmB,KAAG,IAe3D,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { resolve } from 'node:path';
3
+ const openGhostty = (absolutePath, title) => {
4
+ spawn('open', ['-na', 'ghostty', '--args', `--title=${title}`, `--working-directory=${absolutePath}`], {
5
+ detached: true,
6
+ stdio: 'ignore',
7
+ }).unref();
8
+ };
9
+ export const openTerminal = (options) => {
10
+ const { worktreePath, title, preset } = options;
11
+ const absolutePath = resolve(worktreePath);
12
+ switch (preset) {
13
+ case 'ghostty':
14
+ openGhostty(absolutePath, title);
15
+ break;
16
+ case 'iterm':
17
+ case 'terminal':
18
+ case 'warp':
19
+ case 'kitty':
20
+ case 'alacritty':
21
+ throw new Error(`Terminal preset "${preset}" is not implemented yet`);
22
+ }
23
+ };
24
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/core/terminal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,MAAM,WAAW,GAAG,CAAC,YAAoB,EAAE,KAAa,EAAQ,EAAE;IAChE,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,KAAK,EAAE,EAAE,uBAAuB,YAAY,EAAE,CAAC,EAAE;QACrG,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAC,KAAK,EAAE,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAA4B,EAAQ,EAAE;IACjE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAChD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAE3C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,SAAS;YACZ,WAAW,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YACjC,MAAM;QACR,KAAK,OAAO,CAAC;QACb,KAAK,UAAU,CAAC;QAChB,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,WAAW;YACd,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,0BAA0B,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { JiraIssue } from '../adapters/jira.js';
2
+ export interface ParsedTicket {
3
+ key: string;
4
+ projectKey: string;
5
+ issueNumber: string;
6
+ }
7
+ export declare const parseTicketInput: (input: string, defaultProject: string) => ParsedTicket;
8
+ export declare const selectTicketInteractively: (issues: JiraIssue[]) => Promise<JiraIssue>;
9
+ //# sourceMappingURL=ticket-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-parser.d.ts","sourceRoot":"","sources":["../../src/core/ticket-parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,EAAE,gBAAgB,MAAM,KAAG,YAgCxE,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAU,QAAQ,SAAS,EAAE,KAAG,OAAO,CAAC,SAAS,CAuBtF,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { search } from '@inquirer/prompts';
2
+ const JIRA_URL_REGEX = /\/browse\/([A-Z]+-\d+)/i;
3
+ const FULL_KEY_REGEX = /^([A-Z]+)-(\d+)$/i;
4
+ const NUMBER_ONLY_REGEX = /^\d+$/;
5
+ export const parseTicketInput = (input, defaultProject) => {
6
+ const urlMatch = JIRA_URL_REGEX.exec(input);
7
+ if (urlMatch?.[1]) {
8
+ const key = urlMatch[1].toUpperCase();
9
+ const keyMatch = FULL_KEY_REGEX.exec(key);
10
+ if (keyMatch?.[1] && keyMatch[2]) {
11
+ return {
12
+ key,
13
+ projectKey: keyMatch[1],
14
+ issueNumber: keyMatch[2],
15
+ };
16
+ }
17
+ }
18
+ const fullKeyMatch = FULL_KEY_REGEX.exec(input);
19
+ if (fullKeyMatch?.[1] && fullKeyMatch[2]) {
20
+ return {
21
+ key: input.toUpperCase(),
22
+ projectKey: fullKeyMatch[1].toUpperCase(),
23
+ issueNumber: fullKeyMatch[2],
24
+ };
25
+ }
26
+ if (NUMBER_ONLY_REGEX.test(input)) {
27
+ return {
28
+ key: `${defaultProject}-${input}`,
29
+ projectKey: defaultProject,
30
+ issueNumber: input,
31
+ };
32
+ }
33
+ throw new Error(`Invalid ticket format: "${input}". Expected: PROJ-123, 123, or Jira URL`);
34
+ };
35
+ export const selectTicketInteractively = async (issues) => {
36
+ if (issues.length === 0) {
37
+ throw new Error('No issues found matching the configured JQL query');
38
+ }
39
+ const selected = await search({
40
+ message: 'Select a ticket:',
41
+ source: (term) => {
42
+ const searchTerm = term?.toLowerCase() ?? '';
43
+ return issues
44
+ .filter((issue) => {
45
+ if (!searchTerm)
46
+ return true;
47
+ const searchTarget = `${issue.key} ${issue.summary} ${issue.status}`.toLowerCase();
48
+ return searchTarget.includes(searchTerm);
49
+ })
50
+ .map((issue) => ({
51
+ name: `[${issue.key}] ${issue.summary} (${issue.status})`,
52
+ value: issue,
53
+ }));
54
+ },
55
+ });
56
+ return selected;
57
+ };
58
+ //# sourceMappingURL=ticket-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticket-parser.js","sourceRoot":"","sources":["../../src/core/ticket-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAS3C,MAAM,cAAc,GAAG,yBAAyB,CAAC;AACjD,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAC3C,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAElC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,cAAsB,EAAgB,EAAE;IACtF,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YACjC,OAAO;gBACL,GAAG;gBACH,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;gBACvB,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;aACzB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,GAAG,EAAE,KAAK,CAAC,WAAW,EAAE;YACxB,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;YACzC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;SAC7B,CAAC;IACJ,CAAC;IAED,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO;YACL,GAAG,EAAE,GAAG,cAAc,IAAI,KAAK,EAAE;YACjC,UAAU,EAAE,cAAc;YAC1B,WAAW,EAAE,KAAK;SACnB,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,2BAA2B,KAAK,yCAAyC,CAAC,CAAC;AAC7F,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,EAAE,MAAmB,EAAsB,EAAE;IACzF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAY;QACvC,OAAO,EAAE,kBAAkB;QAC3B,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACf,MAAM,UAAU,GAAG,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;YAC7C,OAAO,MAAM;iBACV,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBAChB,IAAI,CAAC,UAAU;oBAAE,OAAO,IAAI,CAAC;gBAC7B,MAAM,YAAY,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;gBACnF,OAAO,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YAC3C,CAAC,CAAC;iBACD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACf,IAAI,EAAE,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,MAAM,GAAG;gBACzD,KAAK,EAAE,KAAK;aACb,CAAC,CAAC,CAAC;QACR,CAAC;KACF,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ export interface WorktreeResult {
2
+ path: string;
3
+ branch: string;
4
+ created: boolean;
5
+ }
6
+ export interface CreateWorktreeOptions {
7
+ ticketKey: string;
8
+ baseBranch: string;
9
+ branchPrefix: string;
10
+ }
11
+ export interface WorktreeInfo {
12
+ ticketKey: string;
13
+ path: string;
14
+ branch: string;
15
+ }
16
+ export declare const getWorktreePath: (ticketKey: string) => string;
17
+ export declare const worktreeExists: (ticketKey: string) => boolean;
18
+ export declare const pullBaseBranch: (baseBranch: string) => Promise<void>;
19
+ export declare const createWorktree: (options: CreateWorktreeOptions) => Promise<WorktreeResult>;
20
+ export declare const getCurrentTicketKey: () => string | null;
21
+ export declare const pushBranch: (ticketKey: string) => Promise<void>;
22
+ export declare const deleteWorktree: (ticketKey: string) => Promise<void>;
23
+ export declare const deleteBranch: (branchName: string) => Promise<void>;
24
+ export declare const getWorktreeBranch: (ticketKey: string) => Promise<string | null>;
25
+ export declare const listWorktrees: () => Promise<WorktreeInfo[]>;
26
+ //# sourceMappingURL=worktree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/core/worktree.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,eAAe,GAAI,WAAW,MAAM,KAAG,MAAyC,CAAC;AAE9F,eAAO,MAAM,cAAc,GAAI,WAAW,MAAM,KAAG,OAAiD,CAAC;AAErG,eAAO,MAAM,cAAc,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,IAAI,CAIrE,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,SAAS,qBAAqB,KAAG,OAAO,CAAC,cAAc,CAqB3F,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,MAAM,GAAG,IAW/C,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,IAAI,CAIhE,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,IAAI,CAGpE,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,IAAI,CAEnE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAKhF,CAAC;AAEF,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,YAAY,EAAE,CA6B5D,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { existsSync, readdirSync } from 'node:fs';
2
+ import { simpleGit } from 'simple-git';
3
+ const git = simpleGit();
4
+ const TICKETREE_DIR = '.ticketree';
5
+ export const getWorktreePath = (ticketKey) => `${TICKETREE_DIR}/${ticketKey}`;
6
+ export const worktreeExists = (ticketKey) => existsSync(getWorktreePath(ticketKey));
7
+ export const pullBaseBranch = async (baseBranch) => {
8
+ await git.fetch('origin', baseBranch);
9
+ await git.checkout(baseBranch);
10
+ await git.pull('origin', baseBranch);
11
+ };
12
+ export const createWorktree = async (options) => {
13
+ const { ticketKey, baseBranch, branchPrefix } = options;
14
+ const worktreePath = getWorktreePath(ticketKey);
15
+ const branchName = `${branchPrefix}${ticketKey}`;
16
+ if (worktreeExists(ticketKey)) {
17
+ return {
18
+ path: worktreePath,
19
+ branch: branchName,
20
+ created: false,
21
+ };
22
+ }
23
+ await pullBaseBranch(baseBranch);
24
+ await git.raw(['worktree', 'add', '-b', branchName, worktreePath, baseBranch]);
25
+ return {
26
+ path: worktreePath,
27
+ branch: branchName,
28
+ created: true,
29
+ };
30
+ };
31
+ export const getCurrentTicketKey = () => {
32
+ const cwd = process.cwd();
33
+ const ticketreeDir = '/.ticketree/';
34
+ const ticketreeIndex = cwd.indexOf(ticketreeDir);
35
+ if (ticketreeIndex === -1)
36
+ return null;
37
+ const afterTicketree = cwd.slice(ticketreeIndex + ticketreeDir.length);
38
+ const ticketKey = afterTicketree.split('/')[0];
39
+ return ticketKey ?? null;
40
+ };
41
+ export const pushBranch = async (ticketKey) => {
42
+ const worktreePath = getWorktreePath(ticketKey);
43
+ const worktreeGit = simpleGit(worktreePath);
44
+ await worktreeGit.push(['--set-upstream', 'origin', 'HEAD']);
45
+ };
46
+ export const deleteWorktree = async (ticketKey) => {
47
+ const worktreePath = getWorktreePath(ticketKey);
48
+ await git.raw(['worktree', 'remove', worktreePath]);
49
+ };
50
+ export const deleteBranch = async (branchName) => {
51
+ await git.branch(['-d', branchName]);
52
+ };
53
+ export const getWorktreeBranch = async (ticketKey) => {
54
+ const worktreePath = getWorktreePath(ticketKey);
55
+ const worktreeGit = simpleGit(worktreePath);
56
+ const branch = await worktreeGit.revparse(['--abbrev-ref', 'HEAD']);
57
+ return branch.trim() || null;
58
+ };
59
+ export const listWorktrees = async () => {
60
+ if (!existsSync(TICKETREE_DIR)) {
61
+ return [];
62
+ }
63
+ const worktreeList = await git.raw(['worktree', 'list', '--porcelain']);
64
+ const worktreeMap = new Map();
65
+ let currentPath = '';
66
+ for (const line of worktreeList.split('\n')) {
67
+ if (line.startsWith('worktree ')) {
68
+ currentPath = line.slice(9);
69
+ }
70
+ else if (line.startsWith('branch ')) {
71
+ const branch = line.slice(7).replace('refs/heads/', '');
72
+ worktreeMap.set(currentPath, branch);
73
+ }
74
+ }
75
+ const entries = readdirSync(TICKETREE_DIR, { withFileTypes: true });
76
+ const directories = entries.filter((entry) => entry.isDirectory());
77
+ return directories.map((dir) => {
78
+ const ticketKey = dir.name;
79
+ const path = getWorktreePath(ticketKey);
80
+ const absolutePath = process.cwd() + '/' + path;
81
+ const branch = worktreeMap.get(absolutePath) ?? '';
82
+ return { ticketKey, path, branch };
83
+ });
84
+ };
85
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/core/worktree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from './config/types.js';
2
+ export * from './adapters/jira.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './config/types.js';
2
+ export * from './adapters/jira.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "ticketree",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool that connects issue tracker tickets with Git Worktree for automated ticket-based development workflow",
5
+ "type": "module",
6
+ "bin": {
7
+ "ticketree": "./dist/cli/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "start": "node ./dist/cli/index.js",
18
+ "lint": "eslint src --ext .ts",
19
+ "lint:fix": "eslint src --ext .ts --fix",
20
+ "format": "prettier --write \"src/**/*.ts\"",
21
+ "format:check": "prettier --check \"src/**/*.ts\"",
22
+ "typecheck": "tsc --noEmit",
23
+ "prepublishOnly": "pnpm run build"
24
+ },
25
+ "keywords": [
26
+ "git",
27
+ "worktree",
28
+ "jira",
29
+ "issue-tracker",
30
+ "cli",
31
+ "workflow",
32
+ "automation"
33
+ ],
34
+ "author": "kurone-ab",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/kurone-ab/ticketree.git"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "packageManager": "pnpm@10.26.0",
44
+ "dependencies": {
45
+ "@inquirer/prompts": "^8.1.0",
46
+ "@octokit/rest": "^22.0.1",
47
+ "chalk": "^5.6.2",
48
+ "commander": "^14.0.2",
49
+ "cosmiconfig": "^9.0.0",
50
+ "jira.js": "^5.2.2",
51
+ "simple-git": "^3.30.0",
52
+ "yaml": "^2.8.2"
53
+ },
54
+ "devDependencies": {
55
+ "@eslint/js": "^9.39.2",
56
+ "@types/node": "^25.0.3",
57
+ "eslint": "^9.39.2",
58
+ "eslint-config-prettier": "^10.1.8",
59
+ "eslint-plugin-prefer-arrow-functions": "^3.9.1",
60
+ "prettier": "^3.7.4",
61
+ "typescript": "^5.9.3",
62
+ "typescript-eslint": "^8.52.0"
63
+ }
64
+ }