@vibedx/vibekit 0.4.0 → 0.5.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 CHANGED
@@ -84,11 +84,13 @@ vibe get-started
84
84
  ```bash
85
85
  # Create a new ticket
86
86
  vibe new "Fix login bug"
87
- vibe new "Add dark mode" --priority high --status open
87
+ vibe new "Add dark mode" --priority high --assignee opusaku
88
+ vibe new "Quick task" --assignee mani-yadv -n # -n skips AI prompt
88
89
 
89
90
  # List all tickets (with optional filtering)
90
91
  vibe list
91
92
  vibe list --status=open
93
+ vibe list --assignee=opusaku
92
94
 
93
95
  # Close/complete a ticket
94
96
  vibe close TKT-001
@@ -98,6 +100,22 @@ vibe start TKT-001
98
100
  vibe start TKT-001 --base main --update-status
99
101
  ```
100
102
 
103
+ ### šŸ‘„ Team Management
104
+ ```bash
105
+ # List team members
106
+ vibe team
107
+
108
+ # Add a member (stored in .vibe/team.yml)
109
+ vibe team add mani-yadv --name "Mani" --github mani-yadv --slack U0ABC123 --x vernon1943 --role Founder
110
+ vibe team add opusaku --name "Opus" --github opusaku --slack U0DEF456 --role "Senior Engineer"
111
+
112
+ # Show a member's details
113
+ vibe team show mani-yadv
114
+
115
+ # Remove a member
116
+ vibe team remove old-member
117
+ ```
118
+
101
119
  ### šŸ¤– AI Integration
102
120
  ```bash
103
121
  # Connect Claude Code for ticket enhancement
@@ -281,6 +299,7 @@ VibeKit creates a `.vibe` directory in your project root:
281
299
  ```
282
300
  šŸ“ .vibe/
283
301
  ā”œā”€ā”€ šŸ“‹ config.yml # Main configuration
302
+ ā”œā”€ā”€ šŸ‘„ team.yml # Team members (GitHub, Slack, X handles)
284
303
  ā”œā”€ā”€ šŸ“ .templates/ # Ticket templates
285
304
  │ └── šŸ“„ default.md # Default ticket template
286
305
  ā”œā”€ā”€ šŸ“ tickets/ # Your ticket files
@@ -316,10 +335,13 @@ tickets:
316
335
  - high
317
336
  - critical
318
337
 
338
+ # Team (stored in separate file for large teams)
339
+ team:
340
+ path: .vibe/team.yml
341
+
319
342
  # AI integration
320
343
  ai:
321
344
  enabled: true
322
- provider: claude-code
323
345
 
324
346
  # Git integration
325
347
  git:
package/assets/config.yml CHANGED
@@ -21,9 +21,11 @@ tickets:
21
21
  - high
22
22
  - critical
23
23
 
24
+ team:
25
+ path: .vibe/team.yml
26
+
24
27
  ai:
25
28
  enabled: false
26
- provider: "none"
27
29
 
28
30
  hooks:
29
31
  pre_commit: false
@@ -0,0 +1,22 @@
1
+ # VibeKit Team Configuration
2
+ # Add team members here. Use their ID as the assignee value in tickets.
3
+ #
4
+ # Usage:
5
+ # vibe team - List all members
6
+ # vibe team add <id> --name "Name" ... - Add a member
7
+ # vibe team remove <id> - Remove a member
8
+ # vibe new "task" --assignee <id> - Assign ticket to member
9
+
10
+ members: {}
11
+ # Example:
12
+ # mani-yadv:
13
+ # name: Mani
14
+ # github: mani-yadv
15
+ # slack: U0XXXXXXXX
16
+ # x: vernon1943
17
+ # role: Founder
18
+ # opusaku:
19
+ # name: Opus
20
+ # github: opusaku
21
+ # slack: U0XXXXXXXX
22
+ # role: Senior Engineer
package/index.js CHANGED
@@ -22,8 +22,8 @@ const __dirname = dirname(__filename);
22
22
 
23
23
  // Available commands in VibeKit
24
24
  const AVAILABLE_COMMANDS = [
25
- 'init', 'new', 'close', 'list', 'get-started',
26
- 'start', 'link', 'unlink', 'refine', 'lint', 'review'
25
+ 'init', 'new', 'close', 'list', 'get-started',
26
+ 'start', 'link', 'unlink', 'refine', 'lint', 'review', 'team'
27
27
  ];
28
28
 
29
29
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibedx/vibekit",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "A powerful CLI tool for managing development tickets and project workflows",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -23,7 +23,8 @@ function initCommand(args) {
23
23
  // Use real files instead of hardcoded template strings
24
24
  const templateSrc = path.join(__dirname, "../../../assets", "default.md");
25
25
  const configSrc = path.join(__dirname, "../../../assets", "config.yml");
26
-
26
+ const teamSrc = path.join(__dirname, "../../../assets", "team.yml");
27
+
27
28
  fs.mkdirSync(targetFolder, { recursive: true });
28
29
  fs.mkdirSync(path.join(targetFolder, "tickets"), { recursive: true });
29
30
  fs.mkdirSync(path.join(targetFolder, ".templates"), { recursive: true });
@@ -31,6 +32,7 @@ function initCommand(args) {
31
32
  // Copy files from assets directory instead of using hardcoded templates
32
33
  fs.copyFileSync(configSrc, path.join(targetFolder, "config.yml"));
33
34
  fs.copyFileSync(templateSrc, path.join(targetFolder, ".templates", "default.md"));
35
+ fs.copyFileSync(teamSrc, path.join(targetFolder, "team.yml"));
34
36
 
35
37
  console.log(`āœ… '${targetFolder}' initialized with config, tickets/, and .templates/default.md`);
36
38
 
@@ -162,7 +162,6 @@ async function linkCommand() {
162
162
  config.ai = {
163
163
  ...config.ai,
164
164
  enabled: true,
165
- provider: 'claude-code',
166
165
  };
167
166
 
168
167
  if (!saveConfig(config)) {
@@ -16,7 +16,7 @@ const GIT_STATUS_CHECK_TIMEOUT = 5000;
16
16
  * @returns {boolean} True if AI is enabled
17
17
  */
18
18
  function checkAiEnabled(config) {
19
- return config && config.ai && config.ai.enabled && config.ai.provider !== 'none';
19
+ return config && config.ai && config.ai.enabled;
20
20
  }
21
21
 
22
22
  /**
@@ -39,7 +39,7 @@ function loadConfig() {
39
39
  function checkAiConfiguration() {
40
40
  const config = loadConfig();
41
41
 
42
- if (!config.ai?.enabled || config.ai?.provider === 'none') {
42
+ if (!config.ai?.enabled) {
43
43
  return {
44
44
  configured: false,
45
45
  reason: 'AI is not enabled. Run "vibe link" first.'
@@ -0,0 +1,196 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import yaml from 'js-yaml';
4
+ import { getConfig } from '../../utils/index.js';
5
+
6
+ /**
7
+ * Get path to team.yml (from config or default)
8
+ */
9
+ function getTeamPath() {
10
+ const config = getConfig();
11
+ const teamPath = config.team?.path || '.vibe/team.yml';
12
+ return path.resolve(process.cwd(), teamPath);
13
+ }
14
+
15
+ /**
16
+ * Load team data from team.yml
17
+ */
18
+ function loadTeam() {
19
+ const teamPath = getTeamPath();
20
+ try {
21
+ if (fs.existsSync(teamPath)) {
22
+ const content = fs.readFileSync(teamPath, 'utf-8');
23
+ const data = yaml.load(content) || {};
24
+ return data.members || {};
25
+ }
26
+ } catch (error) {
27
+ console.error(`āŒ Error reading team file: ${error.message}`);
28
+ }
29
+ return {};
30
+ }
31
+
32
+ /**
33
+ * Save team data to team.yml
34
+ */
35
+ function saveTeam(members) {
36
+ const teamPath = getTeamPath();
37
+ const dir = path.dirname(teamPath);
38
+ if (!fs.existsSync(dir)) {
39
+ fs.mkdirSync(dir, { recursive: true });
40
+ }
41
+ const content = yaml.dump({ members }, { lineWidth: -1 });
42
+ fs.writeFileSync(teamPath, content, 'utf-8');
43
+ }
44
+
45
+ /**
46
+ * Manage team members
47
+ * Usage:
48
+ * vibe team - List all team members
49
+ * vibe team add <id> --name "Name" --github <gh> --slack <slack>
50
+ * vibe team remove <id>
51
+ * vibe team show <id>
52
+ */
53
+ async function teamCommand(args) {
54
+ const subcommand = args[0];
55
+
56
+ if (!subcommand || subcommand === 'list') {
57
+ return listTeam();
58
+ }
59
+ if (subcommand === 'add') {
60
+ return addMember(args.slice(1));
61
+ }
62
+ if (subcommand === 'remove') {
63
+ return removeMember(args[1]);
64
+ }
65
+ if (subcommand === 'show') {
66
+ return showMember(args[1]);
67
+ }
68
+ return showMember(subcommand);
69
+ }
70
+
71
+ function listTeam() {
72
+ const team = loadTeam();
73
+ const members = Object.entries(team);
74
+
75
+ if (members.length === 0) {
76
+ console.log('\nNo team members configured.\n');
77
+ console.log('Add members with: vibe team add <id> --name "Name" --github <gh> --slack <slack-id>\n');
78
+ return;
79
+ }
80
+
81
+ console.log('\n✨ Team Members ✨\n');
82
+
83
+ const idWidth = 16;
84
+ const nameWidth = 16;
85
+ const githubWidth = 16;
86
+ const slackWidth = 14;
87
+
88
+ console.log(
89
+ `${'ID'.padEnd(idWidth)}| ${'NAME'.padEnd(nameWidth)}| ${'GITHUB'.padEnd(githubWidth)}| SLACK`
90
+ );
91
+ console.log(`${'-'.repeat(idWidth)}+${'-'.repeat(nameWidth + 1)}+${'-'.repeat(githubWidth + 1)}+${'-'.repeat(slackWidth)}`);
92
+
93
+ for (const [id, member] of members) {
94
+ if (typeof member !== 'object') continue;
95
+ console.log(
96
+ `${id.padEnd(idWidth)}| ${(member.name || '').padEnd(nameWidth)}| ${(member.github || '').padEnd(githubWidth)}| ${member.slack || ''}`
97
+ );
98
+ }
99
+
100
+ console.log(`\nFound ${members.length} member(s).\n`);
101
+ }
102
+
103
+ function addMember(args) {
104
+ if (!args[0]) {
105
+ console.error('āŒ Please provide a member ID. Usage: vibe team add <id> --name "Name" --github <gh> --slack <slack>');
106
+ process.exit(1);
107
+ }
108
+
109
+ const id = args[0];
110
+ const member = {};
111
+
112
+ for (let i = 1; i < args.length; i++) {
113
+ if (args[i] === '--name' && args[i + 1]) {
114
+ member.name = args[++i];
115
+ } else if (args[i] === '--github' && args[i + 1]) {
116
+ member.github = args[++i];
117
+ } else if (args[i] === '--slack' && args[i + 1]) {
118
+ member.slack = args[++i];
119
+ } else if (args[i] === '--x' && args[i + 1]) {
120
+ member.x = args[++i];
121
+ } else if (args[i] === '--role' && args[i + 1]) {
122
+ member.role = args[++i];
123
+ }
124
+ }
125
+
126
+ const team = loadTeam();
127
+ team[id] = { ...team[id], ...member };
128
+ saveTeam(team);
129
+
130
+ console.log(`āœ… Added team member: ${id}`);
131
+ if (member.name) console.log(` Name: ${member.name}`);
132
+ if (member.github) console.log(` GitHub: ${member.github}`);
133
+ if (member.slack) console.log(` Slack: ${member.slack}`);
134
+ if (member.x) console.log(` X: ${member.x}`);
135
+ if (member.role) console.log(` Role: ${member.role}`);
136
+ }
137
+
138
+ function removeMember(id) {
139
+ if (!id) {
140
+ console.error('āŒ Please provide a member ID. Usage: vibe team remove <id>');
141
+ process.exit(1);
142
+ }
143
+
144
+ const team = loadTeam();
145
+ if (!team[id]) {
146
+ console.error(`āŒ Member '${id}' not found.`);
147
+ process.exit(1);
148
+ }
149
+
150
+ delete team[id];
151
+ saveTeam(team);
152
+ console.log(`āœ… Removed team member: ${id}`);
153
+ }
154
+
155
+ function showMember(id) {
156
+ if (!id) return listTeam();
157
+
158
+ const team = loadTeam();
159
+ const member = team[id];
160
+
161
+ if (!member) {
162
+ console.error(`āŒ Member '${id}' not found.`);
163
+ process.exit(1);
164
+ }
165
+
166
+ console.log(`\nšŸ“‹ ${id}`);
167
+ if (member.name) console.log(` Name: ${member.name}`);
168
+ if (member.github) console.log(` GitHub: @${member.github}`);
169
+ if (member.slack) console.log(` Slack: <@${member.slack}>`);
170
+ if (member.x) console.log(` X: @${member.x}`);
171
+ if (member.role) console.log(` Role: ${member.role}`);
172
+ console.log();
173
+ }
174
+
175
+ /**
176
+ * Resolve an assignee ID to their team info.
177
+ * Exported for use by other commands and external tools.
178
+ */
179
+ export function resolveAssignee(assigneeId) {
180
+ const team = loadTeam();
181
+ return team[assigneeId] || null;
182
+ }
183
+
184
+ /**
185
+ * Get Slack mention string for an assignee.
186
+ * Returns <@SLACK_ID> if found, or the raw assignee string.
187
+ */
188
+ export function getSlackMention(assigneeId) {
189
+ const member = resolveAssignee(assigneeId);
190
+ if (member?.slack) {
191
+ return `<@${member.slack}>`;
192
+ }
193
+ return assigneeId;
194
+ }
195
+
196
+ export default teamCommand;
@@ -83,8 +83,6 @@ async function unlinkCommand() {
83
83
 
84
84
  // Show current configuration
85
85
  console.log('šŸ“ Current AI configuration:');
86
- console.log(` Provider: ${config.ai.provider === 'claude-code' ? 'Claude Code (Anthropic API)' : config.ai.provider}`);
87
- console.log(` Model: ${config.ai.model || 'Not specified'}`);
88
86
  console.log(` Status: ${config.ai.enabled ? 'Enabled' : 'Disabled'}`);
89
87
  console.log();
90
88
 
@@ -101,7 +99,6 @@ async function unlinkCommand() {
101
99
  config.ai = {
102
100
  ...config.ai,
103
101
  enabled: false,
104
- provider: 'none'
105
102
  };
106
103
 
107
104
  if (saveConfig(config)) {
@@ -111,7 +111,6 @@ export function createMockVibeProject(baseDir, options = {}) {
111
111
  },
112
112
  ai: {
113
113
  enabled: false,
114
- provider: 'none'
115
114
  }
116
115
  };
117
116
 
@@ -141,7 +140,6 @@ git:
141
140
 
142
141
  ai:
143
142
  enabled: false
144
- provider: none
145
143
  `;
146
144
 
147
145
  fs.writeFileSync(configPath, configContent, 'utf-8');
@@ -460,7 +458,6 @@ git:
460
458
 
461
459
  ai:
462
460
  enabled: false
463
- provider: none
464
461
  `;
465
462
 
466
463
  // Create mock default.md template