@vibedx/vibekit 0.3.0 → 0.4.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/assets/default.md CHANGED
@@ -4,6 +4,8 @@ title: {title}
4
4
  slug: {slug}
5
5
  status: open
6
6
  priority: medium
7
+ assignee: ""
8
+ author: ""
7
9
  created_at: {date}
8
10
  updated_at: {date}
9
11
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibedx/vibekit",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A powerful CLI tool for managing development tickets and project workflows",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -10,10 +10,13 @@ import { getTicketsDir } from '../../utils/index.js';
10
10
  function listCommand(args) {
11
11
  // Parse arguments for filtering
12
12
  let statusFilter = null;
13
-
13
+ let assigneeFilter = null;
14
+
14
15
  for (let i = 0; i < args.length; i++) {
15
16
  if (args[i].startsWith("--status=")) {
16
17
  statusFilter = args[i].split("=")[1];
18
+ } else if (args[i].startsWith("--assignee=") || args[i].startsWith("--owner=")) {
19
+ assigneeFilter = args[i].split("=")[1];
17
20
  }
18
21
  }
19
22
 
@@ -49,6 +52,8 @@ function listCommand(args) {
49
52
  title: frontmatter.title || "Untitled",
50
53
  status: frontmatter.status || "unknown",
51
54
  priority: frontmatter.priority || "medium",
55
+ assignee: frontmatter.assignee || frontmatter.owner || "",
56
+ author: frontmatter.author || "",
52
57
  file
53
58
  });
54
59
  }
@@ -57,10 +62,16 @@ function listCommand(args) {
57
62
  }
58
63
  }
59
64
 
60
- // Filter tickets if status filter is provided
61
- const filteredTickets = statusFilter
62
- ? tickets.filter(ticket => ticket.status === statusFilter)
63
- : tickets;
65
+ // Filter tickets
66
+ let filteredTickets = tickets;
67
+ if (statusFilter) {
68
+ filteredTickets = filteredTickets.filter(ticket => ticket.status === statusFilter);
69
+ }
70
+ if (assigneeFilter) {
71
+ filteredTickets = filteredTickets.filter(ticket =>
72
+ ticket.assignee.toLowerCase() === assigneeFilter.toLowerCase()
73
+ );
74
+ }
64
75
 
65
76
  // Sort tickets by ID
66
77
  filteredTickets.sort((a, b) => {
@@ -79,20 +90,27 @@ function listCommand(args) {
79
90
  // Display tickets in a formatted table
80
91
  console.log("\n✨ VibeKit Tickets ✨\n");
81
92
 
82
- // Calculate column widths based on content
83
- const idWidth = 10; // Fixed width for ID column
84
- const statusWidth = 15; // Fixed width for status column
85
- const titleWidth = 50; // Fixed width for title column
86
-
93
+ // Calculate column widths
94
+ const idWidth = 10;
95
+ const statusWidth = 15;
96
+ const assigneeWidth = 14;
97
+ const titleWidth = 40;
98
+
99
+ // Check if any tickets have assignees
100
+ const hasAssignees = filteredTickets.some(t => t.assignee);
101
+
87
102
  // Print header
88
- console.log(
89
- `${"ID".padEnd(idWidth)}${"|"} ${
90
- "STATUS".padEnd(statusWidth)
91
- }${"|"} ${
92
- "TITLE"
93
- }`
94
- );
95
- console.log(`${'-'.repeat(idWidth)}+${'-'.repeat(statusWidth + 2)}+${'-'.repeat(titleWidth)}`);
103
+ if (hasAssignees) {
104
+ console.log(
105
+ `${"ID".padEnd(idWidth)}${"|"} ${"STATUS".padEnd(statusWidth)}${"|"} ${"ASSIGNEE".padEnd(assigneeWidth)}${"|"} TITLE`
106
+ );
107
+ console.log(`${'-'.repeat(idWidth)}+${'-'.repeat(statusWidth + 2)}+${'-'.repeat(assigneeWidth + 2)}+${'-'.repeat(titleWidth)}`);
108
+ } else {
109
+ console.log(
110
+ `${"ID".padEnd(idWidth)}${"|"} ${"STATUS".padEnd(statusWidth)}${"|"} TITLE`
111
+ );
112
+ console.log(`${'-'.repeat(idWidth)}+${'-'.repeat(statusWidth + 2)}+${'-'.repeat(titleWidth)}`);
113
+ }
96
114
 
97
115
  for (const ticket of filteredTickets) {
98
116
  let statusColor = "";
@@ -112,20 +130,39 @@ function listCommand(args) {
112
130
  statusColor = "\x1b[0m"; // Default
113
131
  }
114
132
 
115
- // Format each row with proper padding
116
- console.log(
117
- `${ticket.id.padEnd(idWidth)}${"|"} ${
118
- statusColor + ticket.status.padEnd(statusWidth - 1) + "\x1b[0m"
119
- }${"|"} ${
120
- ticket.title.length > titleWidth - 3
121
- ? ticket.title.substring(0, titleWidth - 3) + "..."
122
- : ticket.title
123
- }`
124
- );
133
+ // Format each row
134
+ const truncatedTitle = ticket.title.length > titleWidth - 3
135
+ ? ticket.title.substring(0, titleWidth - 3) + "..."
136
+ : ticket.title;
137
+
138
+ if (hasAssignees) {
139
+ console.log(
140
+ `${ticket.id.padEnd(idWidth)}${"|"} ${
141
+ statusColor + ticket.status.padEnd(statusWidth - 1) + "\x1b[0m"
142
+ }${"|"} ${
143
+ (ticket.assignee || "").padEnd(assigneeWidth - 1)
144
+ }${"|"} ${truncatedTitle}`
145
+ );
146
+ } else {
147
+ console.log(
148
+ `${ticket.id.padEnd(idWidth)}${"|"} ${
149
+ statusColor + ticket.status.padEnd(statusWidth - 1) + "\x1b[0m"
150
+ }${"|"} ${truncatedTitle}`
151
+ );
152
+ }
125
153
  }
126
-
127
- console.log(`${'-'.repeat(idWidth)}+${'-'.repeat(statusWidth + 2)}+${'-'.repeat(titleWidth)}`);
128
- console.log(`Found ${filteredTickets.length} ticket(s)${statusFilter ? ` with status: ${statusFilter}` : ""}.\n`);
154
+
155
+ if (hasAssignees) {
156
+ console.log(`${'-'.repeat(idWidth)}+${'-'.repeat(statusWidth + 2)}+${'-'.repeat(assigneeWidth + 2)}+${'-'.repeat(titleWidth)}`);
157
+ } else {
158
+ console.log(`${'-'.repeat(idWidth)}+${'-'.repeat(statusWidth + 2)}+${'-'.repeat(titleWidth)}`);
159
+ }
160
+
161
+ const filters = [
162
+ statusFilter ? `status: ${statusFilter}` : '',
163
+ assigneeFilter ? `assignee: ${assigneeFilter}` : '',
164
+ ].filter(Boolean).join(', ');
165
+ console.log(`Found ${filteredTickets.length} ticket(s)${filters ? ` (${filters})` : ''}.\n`);
129
166
  }
130
167
 
131
168
  export default listCommand;
@@ -32,28 +32,39 @@ function parseArguments(args) {
32
32
  let titleParts = [];
33
33
  let priority = DEFAULT_PRIORITY;
34
34
  let status = DEFAULT_STATUS;
35
-
35
+ let assignee = '';
36
+ let author = '';
37
+ let noInteractive = false;
38
+
36
39
  for (let i = 0; i < args.length; i++) {
37
40
  const arg = args[i];
38
-
41
+
39
42
  if (arg === '--priority' && i + 1 < args.length) {
40
43
  priority = args[i + 1];
41
- i++; // Skip the next argument as it's the priority value
44
+ i++;
42
45
  } else if (arg === '--status' && i + 1 < args.length) {
43
46
  status = args[i + 1];
44
- i++; // Skip the next argument as it's the status value
47
+ i++;
48
+ } else if ((arg === '--assignee' || arg === '--owner') && i + 1 < args.length) {
49
+ assignee = args[i + 1];
50
+ i++;
51
+ } else if (arg === '--author' && i + 1 < args.length) {
52
+ author = args[i + 1];
53
+ i++;
54
+ } else if (arg === '--no-interactive' || arg === '-n') {
55
+ noInteractive = true;
45
56
  } else if (!arg.startsWith('--')) {
46
57
  titleParts.push(arg);
47
58
  }
48
59
  }
49
-
60
+
50
61
  const title = titleParts.join(' ').trim();
51
-
62
+
52
63
  if (!title) {
53
64
  throw new Error('Please provide a title for the new ticket.');
54
65
  }
55
-
56
- return { title, priority, status };
66
+
67
+ return { title, priority, status, assignee, author, noInteractive };
57
68
  }
58
69
 
59
70
  /**
@@ -93,16 +104,18 @@ function createTicketContent(template, ticketData) {
93
104
  throw new Error('Template must be a string');
94
105
  }
95
106
 
96
- const { ticketId, title, slug, priority, status, timestamp } = ticketData;
107
+ const { ticketId, title, slug, priority, status, assignee, author, timestamp } = ticketData;
97
108
  const paddedId = ticketId.replace('TKT-', '');
98
-
109
+
99
110
  return template
100
111
  .replace(/{id}/g, paddedId)
101
112
  .replace(/{title}/g, title)
102
113
  .replace(/{slug}/g, slug)
103
114
  .replace(/{date}/g, timestamp)
104
115
  .replace(/^priority: .*$/m, `priority: ${priority}`)
105
- .replace(/^status: .*$/m, `status: ${status}`);
116
+ .replace(/^status: .*$/m, `status: ${status}`)
117
+ .replace(/^assignee: .*$/m, `assignee: "${assignee || ''}"`)
118
+ .replace(/^author: .*$/m, `author: "${author || ''}"`);
106
119
  }
107
120
 
108
121
  /**
@@ -193,7 +206,7 @@ async function handleFileRename(originalPath, ticketDir) {
193
206
  async function newCommand(args) {
194
207
  try {
195
208
  // Parse and validate arguments
196
- const { title, priority, status } = parseArguments(args);
209
+ const { title, priority, status, assignee, author, noInteractive } = parseArguments(args);
197
210
 
198
211
  // Check required files and paths
199
212
  const configPath = path.join(process.cwd(), '.vibe', 'config.yml');
@@ -236,6 +249,8 @@ async function newCommand(args) {
236
249
  slug: ticketSlug,
237
250
  priority: validatedOptions.priority,
238
251
  status: validatedOptions.status,
252
+ assignee,
253
+ author,
239
254
  timestamp
240
255
  };
241
256
 
@@ -254,8 +269,8 @@ async function newCommand(args) {
254
269
 
255
270
  logger.success(`Created ticket: ${filename} (priority: ${ticketData.priority}, status: ${ticketData.status})`);
256
271
 
257
- // Offer AI enhancement if available
258
- if (checkAiEnabled(config)) {
272
+ // Offer AI enhancement if available (skip in non-interactive mode)
273
+ if (checkAiEnabled(config) && !noInteractive) {
259
274
  await offerAiEnhancement(ticketId, outputPath, ticketDir);
260
275
  }
261
276