@bernierllc/braingrid-cli-wrapper 0.1.1

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 (74) hide show
  1. package/.eslintrc.cjs +29 -0
  2. package/README.md +401 -0
  3. package/coverage/base.css +224 -0
  4. package/coverage/block-navigation.js +87 -0
  5. package/coverage/favicon.png +0 -0
  6. package/coverage/index.html +131 -0
  7. package/coverage/lcov-report/base.css +224 -0
  8. package/coverage/lcov-report/block-navigation.js +87 -0
  9. package/coverage/lcov-report/favicon.png +0 -0
  10. package/coverage/lcov-report/index.html +131 -0
  11. package/coverage/lcov-report/prettify.css +1 -0
  12. package/coverage/lcov-report/prettify.js +2 -0
  13. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  14. package/coverage/lcov-report/sorter.js +210 -0
  15. package/coverage/lcov-report/src/cli.ts.html +298 -0
  16. package/coverage/lcov-report/src/commands/createIdea.ts.html +193 -0
  17. package/coverage/lcov-report/src/commands/createTask.ts.html +235 -0
  18. package/coverage/lcov-report/src/commands/index.html +176 -0
  19. package/coverage/lcov-report/src/commands/listProjects.ts.html +160 -0
  20. package/coverage/lcov-report/src/commands/listTasks.ts.html +226 -0
  21. package/coverage/lcov-report/src/commands/updateTaskStatus.ts.html +205 -0
  22. package/coverage/lcov-report/src/index.html +146 -0
  23. package/coverage/lcov-report/src/index.ts.html +172 -0
  24. package/coverage/lcov-report/src/models.ts.html +364 -0
  25. package/coverage/lcov.info +240 -0
  26. package/coverage/prettify.css +1 -0
  27. package/coverage/prettify.js +2 -0
  28. package/coverage/sort-arrow-sprite.png +0 -0
  29. package/coverage/sorter.js +210 -0
  30. package/coverage/src/cli.ts.html +298 -0
  31. package/coverage/src/commands/createIdea.ts.html +193 -0
  32. package/coverage/src/commands/createTask.ts.html +235 -0
  33. package/coverage/src/commands/index.html +176 -0
  34. package/coverage/src/commands/listProjects.ts.html +160 -0
  35. package/coverage/src/commands/listTasks.ts.html +226 -0
  36. package/coverage/src/commands/updateTaskStatus.ts.html +205 -0
  37. package/coverage/src/index.html +146 -0
  38. package/coverage/src/index.ts.html +172 -0
  39. package/coverage/src/models.ts.html +364 -0
  40. package/dist/cli.d.ts +7 -0
  41. package/dist/cli.js +53 -0
  42. package/dist/commands/createIdea.d.ts +5 -0
  43. package/dist/commands/createIdea.js +29 -0
  44. package/dist/commands/createTask.d.ts +11 -0
  45. package/dist/commands/createTask.js +34 -0
  46. package/dist/commands/listProjects.d.ts +5 -0
  47. package/dist/commands/listProjects.js +24 -0
  48. package/dist/commands/listTasks.d.ts +10 -0
  49. package/dist/commands/listTasks.js +35 -0
  50. package/dist/commands/updateTaskStatus.d.ts +10 -0
  51. package/dist/commands/updateTaskStatus.js +27 -0
  52. package/dist/index.d.ts +6 -0
  53. package/dist/index.js +28 -0
  54. package/dist/models.d.ts +89 -0
  55. package/dist/models.js +74 -0
  56. package/jest.config.cjs +22 -0
  57. package/package.json +46 -0
  58. package/src/__tests__/execa-mock-validation.test.ts +34 -0
  59. package/src/cli.test.ts +86 -0
  60. package/src/cli.ts +71 -0
  61. package/src/commands/createIdea.test.ts +77 -0
  62. package/src/commands/createIdea.ts +36 -0
  63. package/src/commands/createTask.test.ts +100 -0
  64. package/src/commands/createTask.ts +50 -0
  65. package/src/commands/listProjects.test.ts +72 -0
  66. package/src/commands/listProjects.ts +25 -0
  67. package/src/commands/listTasks.test.ts +183 -0
  68. package/src/commands/listTasks.ts +47 -0
  69. package/src/commands/updateTaskStatus.test.ts +96 -0
  70. package/src/commands/updateTaskStatus.ts +40 -0
  71. package/src/index.ts +29 -0
  72. package/src/models.test.ts +197 -0
  73. package/src/models.ts +93 -0
  74. package/tsconfig.json +18 -0
@@ -0,0 +1,50 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ import { runBrainGridCommand } from '../cli';
10
+ import { BrainGridTask, BrainGridTaskSchema } from '../models';
11
+
12
+ export interface CreateTaskOptions {
13
+ title: string;
14
+ description?: string;
15
+ tags?: string[];
16
+ dependencies?: string[];
17
+ }
18
+
19
+ /**
20
+ * Create a task in BrainGrid under a requirement
21
+ */
22
+ export async function createTask(
23
+ reqId: string,
24
+ options: CreateTaskOptions
25
+ ): Promise<BrainGridTask> {
26
+ const args = ['task', 'create', reqId, '--title', options.title];
27
+
28
+ if (options.description) {
29
+ args.push('--description', options.description);
30
+ }
31
+
32
+ if (options.tags && options.tags.length > 0) {
33
+ args.push('--tags', options.tags.join(','));
34
+ }
35
+
36
+ if (options.dependencies && options.dependencies.length > 0) {
37
+ args.push('--dependencies', options.dependencies.join(','));
38
+ }
39
+
40
+ args.push('--format', 'json');
41
+
42
+ const result = await runBrainGridCommand(args);
43
+
44
+ const parsed = BrainGridTaskSchema.safeParse(result);
45
+ if (!parsed.success) {
46
+ throw new Error(`Invalid BrainGrid response: ${parsed.error.message}`);
47
+ }
48
+
49
+ return parsed.data;
50
+ }
@@ -0,0 +1,72 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ import { listProjects } from './listProjects';
10
+
11
+ jest.mock('../cli', () => ({
12
+ runBrainGridCommand: jest.fn()
13
+ }));
14
+
15
+ import { runBrainGridCommand } from '../cli';
16
+
17
+ describe('listProjects', () => {
18
+ beforeEach(() => {
19
+ jest.clearAllMocks();
20
+ });
21
+
22
+ it('should list all projects', async () => {
23
+ const mockProjects = [
24
+ {
25
+ id: 'proj-1',
26
+ name: 'Project 1',
27
+ description: 'First project'
28
+ },
29
+ {
30
+ id: 'proj-2',
31
+ name: 'Project 2',
32
+ description: 'Second project'
33
+ }
34
+ ];
35
+
36
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(mockProjects);
37
+
38
+ const result = await listProjects();
39
+
40
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
41
+ 'projects',
42
+ 'list',
43
+ '--format',
44
+ 'json'
45
+ ]);
46
+
47
+ expect(result).toHaveLength(2);
48
+ expect(result[0].id).toBe('proj-1');
49
+ expect(result[1].id).toBe('proj-2');
50
+ });
51
+
52
+ it('should return empty array when no projects', async () => {
53
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue([]);
54
+
55
+ const result = await listProjects();
56
+
57
+ expect(result).toEqual([]);
58
+ });
59
+
60
+ it('should validate response schema', async () => {
61
+ const invalidProjects = [
62
+ {
63
+ id: 123, // Should be string
64
+ name: 'Test'
65
+ }
66
+ ];
67
+
68
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(invalidProjects);
69
+
70
+ await expect(listProjects()).rejects.toThrow();
71
+ });
72
+ });
@@ -0,0 +1,25 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ import { runBrainGridCommand } from '../cli';
10
+ import { BrainGridProject, BrainGridProjectSchema } from '../models';
11
+ import { z } from 'zod';
12
+
13
+ /**
14
+ * List all projects in BrainGrid
15
+ */
16
+ export async function listProjects(): Promise<BrainGridProject[]> {
17
+ const result = await runBrainGridCommand(['projects', 'list', '--format', 'json']);
18
+
19
+ const parsed = z.array(BrainGridProjectSchema).safeParse(result);
20
+ if (!parsed.success) {
21
+ throw new Error(`Invalid BrainGrid response: ${parsed.error.message}`);
22
+ }
23
+
24
+ return parsed.data;
25
+ }
@@ -0,0 +1,183 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ import { listTasks } from './listTasks';
10
+
11
+ jest.mock('../cli', () => ({
12
+ runBrainGridCommand: jest.fn()
13
+ }));
14
+
15
+ import { runBrainGridCommand } from '../cli';
16
+
17
+ describe('listTasks', () => {
18
+ beforeEach(() => {
19
+ jest.clearAllMocks();
20
+ });
21
+
22
+ it('should list all tasks with no filters', async () => {
23
+ const mockTasks = [
24
+ {
25
+ id: 'task-1',
26
+ reqId: 'req-123',
27
+ title: 'Task 1',
28
+ status: 'TODO'
29
+ },
30
+ {
31
+ id: 'task-2',
32
+ reqId: 'req-123',
33
+ title: 'Task 2',
34
+ status: 'IN_PROGRESS'
35
+ }
36
+ ];
37
+
38
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(mockTasks);
39
+
40
+ const result = await listTasks();
41
+
42
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
43
+ 'task',
44
+ 'list',
45
+ '--format',
46
+ 'json'
47
+ ]);
48
+
49
+ expect(result).toHaveLength(2);
50
+ expect(result[0].id).toBe('task-1');
51
+ });
52
+
53
+ it('should filter tasks by requirement ID', async () => {
54
+ const mockTasks = [
55
+ {
56
+ id: 'task-1',
57
+ reqId: 'req-123',
58
+ title: 'Task 1',
59
+ status: 'TODO'
60
+ }
61
+ ];
62
+
63
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(mockTasks);
64
+
65
+ await listTasks({ reqId: 'req-123' });
66
+
67
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
68
+ 'task',
69
+ 'list',
70
+ '--req',
71
+ 'req-123',
72
+ '--format',
73
+ 'json'
74
+ ]);
75
+ });
76
+
77
+ it('should filter tasks by status', async () => {
78
+ const mockTasks = [
79
+ {
80
+ id: 'task-1',
81
+ reqId: 'req-123',
82
+ title: 'Task 1',
83
+ status: 'TODO'
84
+ }
85
+ ];
86
+
87
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(mockTasks);
88
+
89
+ await listTasks({
90
+ status: ['TODO', 'READY']
91
+ });
92
+
93
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
94
+ 'task',
95
+ 'list',
96
+ '--status',
97
+ 'TODO,READY',
98
+ '--format',
99
+ 'json'
100
+ ]);
101
+ });
102
+
103
+ it('should filter tasks by tags', async () => {
104
+ const mockTasks = [
105
+ {
106
+ id: 'task-1',
107
+ reqId: 'req-123',
108
+ title: 'Task 1',
109
+ status: 'TODO',
110
+ tags: ['DEV', 'frontend']
111
+ }
112
+ ];
113
+
114
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(mockTasks);
115
+
116
+ await listTasks({
117
+ tags: ['DEV', 'frontend']
118
+ });
119
+
120
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
121
+ 'task',
122
+ 'list',
123
+ '--tags',
124
+ 'DEV,frontend',
125
+ '--format',
126
+ 'json'
127
+ ]);
128
+ });
129
+
130
+ it('should combine all filters', async () => {
131
+ const mockTasks = [
132
+ {
133
+ id: 'task-1',
134
+ reqId: 'req-123',
135
+ title: 'Task 1',
136
+ status: 'TODO',
137
+ tags: ['DEV']
138
+ }
139
+ ];
140
+
141
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(mockTasks);
142
+
143
+ await listTasks({
144
+ reqId: 'req-123',
145
+ status: ['TODO'],
146
+ tags: ['DEV']
147
+ });
148
+
149
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
150
+ 'task',
151
+ 'list',
152
+ '--req',
153
+ 'req-123',
154
+ '--status',
155
+ 'TODO',
156
+ '--tags',
157
+ 'DEV',
158
+ '--format',
159
+ 'json'
160
+ ]);
161
+ });
162
+
163
+ it('should return empty array when no tasks', async () => {
164
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue([]);
165
+
166
+ const result = await listTasks();
167
+
168
+ expect(result).toEqual([]);
169
+ });
170
+
171
+ it('should validate response schema', async () => {
172
+ const invalidTasks = [
173
+ {
174
+ id: 123, // Should be string
175
+ title: 'Test'
176
+ }
177
+ ];
178
+
179
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(invalidTasks);
180
+
181
+ await expect(listTasks()).rejects.toThrow();
182
+ });
183
+ });
@@ -0,0 +1,47 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ import { runBrainGridCommand } from '../cli';
10
+ import { BrainGridTask, BrainGridTaskSchema, TaskStatus } from '../models';
11
+ import { z } from 'zod';
12
+
13
+ export interface ListTasksOptions {
14
+ reqId?: string;
15
+ status?: TaskStatus[];
16
+ tags?: string[];
17
+ }
18
+
19
+ /**
20
+ * List tasks in BrainGrid with optional filters
21
+ */
22
+ export async function listTasks(options: ListTasksOptions = {}): Promise<BrainGridTask[]> {
23
+ const args = ['task', 'list'];
24
+
25
+ if (options.reqId) {
26
+ args.push('--req', options.reqId);
27
+ }
28
+
29
+ if (options.status && options.status.length > 0) {
30
+ args.push('--status', options.status.join(','));
31
+ }
32
+
33
+ if (options.tags && options.tags.length > 0) {
34
+ args.push('--tags', options.tags.join(','));
35
+ }
36
+
37
+ args.push('--format', 'json');
38
+
39
+ const result = await runBrainGridCommand(args);
40
+
41
+ const parsed = z.array(BrainGridTaskSchema).safeParse(result);
42
+ if (!parsed.success) {
43
+ throw new Error(`Invalid BrainGrid response: ${parsed.error.message}`);
44
+ }
45
+
46
+ return parsed.data;
47
+ }
@@ -0,0 +1,96 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ import { updateTaskStatus } from './updateTaskStatus';
10
+
11
+ jest.mock('../cli', () => ({
12
+ runBrainGridCommand: jest.fn()
13
+ }));
14
+
15
+ import { runBrainGridCommand } from '../cli';
16
+
17
+ describe('updateTaskStatus', () => {
18
+ beforeEach(() => {
19
+ jest.clearAllMocks();
20
+ });
21
+
22
+ it('should update task status', async () => {
23
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(null);
24
+
25
+ await updateTaskStatus('task-123', {
26
+ status: 'IN_PROGRESS'
27
+ });
28
+
29
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
30
+ 'task',
31
+ 'update',
32
+ 'task-123',
33
+ '--status',
34
+ 'IN_PROGRESS'
35
+ ]);
36
+ });
37
+
38
+ it('should update task with assigned user', async () => {
39
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(null);
40
+
41
+ await updateTaskStatus('task-123', {
42
+ status: 'IN_PROGRESS',
43
+ assignedTo: 'user-456'
44
+ });
45
+
46
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
47
+ 'task',
48
+ 'update',
49
+ 'task-123',
50
+ '--status',
51
+ 'IN_PROGRESS',
52
+ '--assigned-to',
53
+ 'user-456'
54
+ ]);
55
+ });
56
+
57
+ it('should update task with metadata', async () => {
58
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(null);
59
+
60
+ const metadata = {
61
+ progress: 50,
62
+ notes: 'Half done'
63
+ };
64
+
65
+ await updateTaskStatus('task-123', {
66
+ status: 'IN_PROGRESS',
67
+ metadata
68
+ });
69
+
70
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
71
+ 'task',
72
+ 'update',
73
+ 'task-123',
74
+ '--status',
75
+ 'IN_PROGRESS',
76
+ '--metadata',
77
+ JSON.stringify(metadata)
78
+ ]);
79
+ });
80
+
81
+ it('should update without status (metadata only)', async () => {
82
+ (runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(null);
83
+
84
+ await updateTaskStatus('task-123', {
85
+ assignedTo: 'user-456'
86
+ });
87
+
88
+ expect(runBrainGridCommand).toHaveBeenCalledWith([
89
+ 'task',
90
+ 'update',
91
+ 'task-123',
92
+ '--assigned-to',
93
+ 'user-456'
94
+ ]);
95
+ });
96
+ });
@@ -0,0 +1,40 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ import { runBrainGridCommand } from '../cli';
10
+ import { TaskStatus } from '../models';
11
+
12
+ export interface UpdateTaskOptions {
13
+ status?: TaskStatus;
14
+ assignedTo?: string;
15
+ metadata?: Record<string, unknown>;
16
+ }
17
+
18
+ /**
19
+ * Update task status and metadata in BrainGrid
20
+ */
21
+ export async function updateTaskStatus(
22
+ taskId: string,
23
+ options: UpdateTaskOptions
24
+ ): Promise<void> {
25
+ const args = ['task', 'update', taskId];
26
+
27
+ if (options.status) {
28
+ args.push('--status', options.status);
29
+ }
30
+
31
+ if (options.assignedTo) {
32
+ args.push('--assigned-to', options.assignedTo);
33
+ }
34
+
35
+ if (options.metadata) {
36
+ args.push('--metadata', JSON.stringify(options.metadata));
37
+ }
38
+
39
+ await runBrainGridCommand(args);
40
+ }
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ // BrainGrid CLI Wrapper - Type-safe wrapper for BrainGrid CLI
10
+
11
+ // Export types and schemas
12
+ export {
13
+ BrainGridProject,
14
+ BrainGridRequirement,
15
+ BrainGridTask,
16
+ RequirementStatus,
17
+ TaskStatus,
18
+ BrainGridProjectSchema,
19
+ BrainGridRequirementSchema,
20
+ BrainGridTaskSchema,
21
+ BrainGridCliError
22
+ } from './models';
23
+
24
+ // Export commands
25
+ export { createIdea } from './commands/createIdea';
26
+ export { listProjects } from './commands/listProjects';
27
+ export { createTask, CreateTaskOptions } from './commands/createTask';
28
+ export { updateTaskStatus, UpdateTaskOptions } from './commands/updateTaskStatus';
29
+ export { listTasks, ListTasksOptions } from './commands/listTasks';