@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.
- package/.eslintrc.cjs +29 -0
- package/README.md +401 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +131 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +131 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/cli.ts.html +298 -0
- package/coverage/lcov-report/src/commands/createIdea.ts.html +193 -0
- package/coverage/lcov-report/src/commands/createTask.ts.html +235 -0
- package/coverage/lcov-report/src/commands/index.html +176 -0
- package/coverage/lcov-report/src/commands/listProjects.ts.html +160 -0
- package/coverage/lcov-report/src/commands/listTasks.ts.html +226 -0
- package/coverage/lcov-report/src/commands/updateTaskStatus.ts.html +205 -0
- package/coverage/lcov-report/src/index.html +146 -0
- package/coverage/lcov-report/src/index.ts.html +172 -0
- package/coverage/lcov-report/src/models.ts.html +364 -0
- package/coverage/lcov.info +240 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/cli.ts.html +298 -0
- package/coverage/src/commands/createIdea.ts.html +193 -0
- package/coverage/src/commands/createTask.ts.html +235 -0
- package/coverage/src/commands/index.html +176 -0
- package/coverage/src/commands/listProjects.ts.html +160 -0
- package/coverage/src/commands/listTasks.ts.html +226 -0
- package/coverage/src/commands/updateTaskStatus.ts.html +205 -0
- package/coverage/src/index.html +146 -0
- package/coverage/src/index.ts.html +172 -0
- package/coverage/src/models.ts.html +364 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +53 -0
- package/dist/commands/createIdea.d.ts +5 -0
- package/dist/commands/createIdea.js +29 -0
- package/dist/commands/createTask.d.ts +11 -0
- package/dist/commands/createTask.js +34 -0
- package/dist/commands/listProjects.d.ts +5 -0
- package/dist/commands/listProjects.js +24 -0
- package/dist/commands/listTasks.d.ts +10 -0
- package/dist/commands/listTasks.js +35 -0
- package/dist/commands/updateTaskStatus.d.ts +10 -0
- package/dist/commands/updateTaskStatus.js +27 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +28 -0
- package/dist/models.d.ts +89 -0
- package/dist/models.js +74 -0
- package/jest.config.cjs +22 -0
- package/package.json +46 -0
- package/src/__tests__/execa-mock-validation.test.ts +34 -0
- package/src/cli.test.ts +86 -0
- package/src/cli.ts +71 -0
- package/src/commands/createIdea.test.ts +77 -0
- package/src/commands/createIdea.ts +36 -0
- package/src/commands/createTask.test.ts +100 -0
- package/src/commands/createTask.ts +50 -0
- package/src/commands/listProjects.test.ts +72 -0
- package/src/commands/listProjects.ts +25 -0
- package/src/commands/listTasks.test.ts +183 -0
- package/src/commands/listTasks.ts +47 -0
- package/src/commands/updateTaskStatus.test.ts +96 -0
- package/src/commands/updateTaskStatus.ts +40 -0
- package/src/index.ts +29 -0
- package/src/models.test.ts +197 -0
- package/src/models.ts +93 -0
- package/tsconfig.json +18 -0
package/.eslintrc.cjs
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
|
+
module.exports = {
|
|
10
|
+
parser: '@typescript-eslint/parser',
|
|
11
|
+
extends: [
|
|
12
|
+
'eslint:recommended',
|
|
13
|
+
'plugin:@typescript-eslint/recommended',
|
|
14
|
+
],
|
|
15
|
+
parserOptions: {
|
|
16
|
+
ecmaVersion: 2020,
|
|
17
|
+
sourceType: 'module',
|
|
18
|
+
},
|
|
19
|
+
rules: {
|
|
20
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
21
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
22
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
|
23
|
+
},
|
|
24
|
+
env: {
|
|
25
|
+
node: true,
|
|
26
|
+
jest: true,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
# @bernierllc/braingrid-cli-wrapper
|
|
2
|
+
|
|
3
|
+
Type-safe wrapper for the BrainGrid CLI that provides a clean, programmatic interface for interacting with BrainGrid projects, requirements, and tasks.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides atomic utilities for interacting with the BrainGrid CLI in a type-safe manner. It wraps BrainGrid CLI commands with Zod schema validation, ensuring type safety and proper error handling.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Type-safe API**: Full TypeScript support with Zod schema validation
|
|
12
|
+
- **Error Handling**: Custom error types with detailed error information
|
|
13
|
+
- **CLI Integration**: Seamless integration with BrainGrid CLI commands
|
|
14
|
+
- **Schema Validation**: Automatic validation of CLI responses using Zod schemas
|
|
15
|
+
- **Minimal Dependencies**: Only depends on `execa` and `zod`
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @bernierllc/braingrid-cli-wrapper
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createIdea, listProjects, createTask } from '@bernierllc/braingrid-cli-wrapper';
|
|
27
|
+
|
|
28
|
+
// Create a new requirement (IDEA)
|
|
29
|
+
const requirement = await createIdea('Add OAuth2 authentication', 'proj-123');
|
|
30
|
+
console.log(`Created requirement ${requirement.id} with status ${requirement.status}`);
|
|
31
|
+
|
|
32
|
+
// List all projects
|
|
33
|
+
const projects = await listProjects();
|
|
34
|
+
console.log(`Found ${projects.length} projects`);
|
|
35
|
+
|
|
36
|
+
// Create a task under a requirement
|
|
37
|
+
const task = await createTask('req-456', {
|
|
38
|
+
title: 'Build login UI',
|
|
39
|
+
description: 'Create login form component',
|
|
40
|
+
tags: ['DEV', 'frontend'],
|
|
41
|
+
dependencies: ['task-100']
|
|
42
|
+
});
|
|
43
|
+
console.log(`Created task ${task.id}`);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API Reference
|
|
47
|
+
|
|
48
|
+
### Commands
|
|
49
|
+
|
|
50
|
+
#### `createIdea(prompt: string, projectId?: string): Promise<BrainGridRequirement>`
|
|
51
|
+
|
|
52
|
+
Creates a new requirement (IDEA) in BrainGrid.
|
|
53
|
+
|
|
54
|
+
**Input:**
|
|
55
|
+
- `prompt` (string, required): Description of the requirement/idea
|
|
56
|
+
- `projectId` (string, optional): Project ID to associate with the requirement
|
|
57
|
+
|
|
58
|
+
**Output:**
|
|
59
|
+
- Returns a `BrainGridRequirement` object with:
|
|
60
|
+
- `id`: Requirement ID
|
|
61
|
+
- `projectId`: Associated project ID
|
|
62
|
+
- `title`: Requirement title
|
|
63
|
+
- `status`: Requirement status (IDEA, PLANNED, IN_PROGRESS, COMPLETED, CANCELLED, PAUSED)
|
|
64
|
+
- `description`: Optional description
|
|
65
|
+
- `createdAt`: Optional creation timestamp
|
|
66
|
+
- `updatedAt`: Optional update timestamp
|
|
67
|
+
|
|
68
|
+
**Example:**
|
|
69
|
+
```typescript
|
|
70
|
+
const req = await createIdea('Add user authentication system');
|
|
71
|
+
// { id: 'req-123', projectId: 'proj-456', title: 'Add user authentication system', status: 'IDEA' }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### `listProjects(): Promise<BrainGridProject[]>`
|
|
75
|
+
|
|
76
|
+
Lists all projects in BrainGrid.
|
|
77
|
+
|
|
78
|
+
**Input:** None
|
|
79
|
+
|
|
80
|
+
**Output:**
|
|
81
|
+
- Returns an array of `BrainGridProject` objects with:
|
|
82
|
+
- `id`: Project ID
|
|
83
|
+
- `name`: Project name
|
|
84
|
+
- `description`: Optional project description
|
|
85
|
+
|
|
86
|
+
**Example:**
|
|
87
|
+
```typescript
|
|
88
|
+
const projects = await listProjects();
|
|
89
|
+
// [{ id: 'proj-1', name: 'My Project', description: 'Project description' }]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### `createTask(reqId: string, options: CreateTaskOptions): Promise<BrainGridTask>`
|
|
93
|
+
|
|
94
|
+
Creates a task under a requirement.
|
|
95
|
+
|
|
96
|
+
**Input:**
|
|
97
|
+
- `reqId` (string, required): Requirement ID
|
|
98
|
+
- `options` (CreateTaskOptions, required):
|
|
99
|
+
- `title` (string, required): Task title
|
|
100
|
+
- `description` (string, optional): Task description
|
|
101
|
+
- `tags` (string[], optional): Task tags
|
|
102
|
+
- `dependencies` (string[], optional): Task dependency IDs
|
|
103
|
+
|
|
104
|
+
**Output:**
|
|
105
|
+
- Returns a `BrainGridTask` object with:
|
|
106
|
+
- `id`: Task ID
|
|
107
|
+
- `reqId`: Parent requirement ID
|
|
108
|
+
- `title`: Task title
|
|
109
|
+
- `status`: Task status (TODO, READY, BLOCKED, IN_PROGRESS, COMPLETED, FAILED, PAUSED)
|
|
110
|
+
- `description`: Optional description
|
|
111
|
+
- `tags`: Optional array of tags
|
|
112
|
+
- `dependencies`: Optional array of dependency IDs
|
|
113
|
+
- `assignedTo`: Optional assignee ID
|
|
114
|
+
- `createdAt`: Optional creation timestamp
|
|
115
|
+
- `updatedAt`: Optional update timestamp
|
|
116
|
+
- `metadata`: Optional metadata object
|
|
117
|
+
|
|
118
|
+
**Example:**
|
|
119
|
+
```typescript
|
|
120
|
+
const task = await createTask('req-123', {
|
|
121
|
+
title: 'Build login UI',
|
|
122
|
+
description: 'Create login form component',
|
|
123
|
+
tags: ['DEV', 'frontend'],
|
|
124
|
+
dependencies: ['task-100']
|
|
125
|
+
});
|
|
126
|
+
// { id: 'task-456', reqId: 'req-123', title: 'Build login UI', status: 'TODO', ... }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### `listTasks(options?: ListTasksOptions): Promise<BrainGridTask[]>`
|
|
130
|
+
|
|
131
|
+
Lists tasks with optional filters.
|
|
132
|
+
|
|
133
|
+
**Input:**
|
|
134
|
+
- `options` (ListTasksOptions, optional):
|
|
135
|
+
- `reqId` (string, optional): Filter by requirement ID
|
|
136
|
+
- `status` (TaskStatus[], optional): Filter by status array
|
|
137
|
+
- `tags` (string[], optional): Filter by tags array
|
|
138
|
+
|
|
139
|
+
**Output:**
|
|
140
|
+
- Returns an array of `BrainGridTask` objects
|
|
141
|
+
|
|
142
|
+
**Example:**
|
|
143
|
+
```typescript
|
|
144
|
+
// List all tasks
|
|
145
|
+
const allTasks = await listTasks();
|
|
146
|
+
|
|
147
|
+
// List tasks for a specific requirement
|
|
148
|
+
const reqTasks = await listTasks({ reqId: 'req-123' });
|
|
149
|
+
|
|
150
|
+
// List tasks by status
|
|
151
|
+
const inProgressTasks = await listTasks({ status: ['IN_PROGRESS'] });
|
|
152
|
+
|
|
153
|
+
// Combine filters
|
|
154
|
+
const filteredTasks = await listTasks({
|
|
155
|
+
reqId: 'req-123',
|
|
156
|
+
status: ['TODO', 'READY'],
|
|
157
|
+
tags: ['DEV']
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### `updateTaskStatus(taskId: string, options: UpdateTaskOptions): Promise<void>`
|
|
162
|
+
|
|
163
|
+
Updates task status and metadata.
|
|
164
|
+
|
|
165
|
+
**Input:**
|
|
166
|
+
- `taskId` (string, required): Task ID to update
|
|
167
|
+
- `options` (UpdateTaskOptions, optional):
|
|
168
|
+
- `status` (TaskStatus, optional): New task status
|
|
169
|
+
- `assignedTo` (string, optional): Assignee ID
|
|
170
|
+
- `metadata` (Record<string, unknown>, optional): Metadata object
|
|
171
|
+
|
|
172
|
+
**Output:** Promise that resolves when update is complete
|
|
173
|
+
|
|
174
|
+
**Example:**
|
|
175
|
+
```typescript
|
|
176
|
+
// Update task status
|
|
177
|
+
await updateTaskStatus('task-123', { status: 'IN_PROGRESS' });
|
|
178
|
+
|
|
179
|
+
// Update with assignee
|
|
180
|
+
await updateTaskStatus('task-123', {
|
|
181
|
+
status: 'IN_PROGRESS',
|
|
182
|
+
assignedTo: 'user-456'
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Update with metadata
|
|
186
|
+
await updateTaskStatus('task-123', {
|
|
187
|
+
status: 'IN_PROGRESS',
|
|
188
|
+
metadata: { progress: 50, notes: 'Half done' }
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Types
|
|
193
|
+
|
|
194
|
+
#### `BrainGridProject`
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
interface BrainGridProject {
|
|
198
|
+
id: string;
|
|
199
|
+
name: string;
|
|
200
|
+
description?: string;
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### `BrainGridRequirement`
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
interface BrainGridRequirement {
|
|
208
|
+
id: string;
|
|
209
|
+
projectId: string;
|
|
210
|
+
title: string;
|
|
211
|
+
status: RequirementStatus;
|
|
212
|
+
description?: string;
|
|
213
|
+
createdAt?: string;
|
|
214
|
+
updatedAt?: string;
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### `BrainGridTask`
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
interface BrainGridTask {
|
|
222
|
+
id: string;
|
|
223
|
+
reqId: string;
|
|
224
|
+
title: string;
|
|
225
|
+
status: TaskStatus;
|
|
226
|
+
description?: string;
|
|
227
|
+
tags?: string[];
|
|
228
|
+
dependencies?: string[];
|
|
229
|
+
assignedTo?: string;
|
|
230
|
+
createdAt?: string;
|
|
231
|
+
updatedAt?: string;
|
|
232
|
+
metadata?: Record<string, unknown>;
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
#### `RequirementStatus`
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
type RequirementStatus = 'IDEA' | 'PLANNED' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED' | 'PAUSED';
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### `TaskStatus`
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
type TaskStatus = 'TODO' | 'READY' | 'BLOCKED' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'PAUSED';
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Error Handling
|
|
249
|
+
|
|
250
|
+
The package throws `BrainGridCliError` when CLI commands fail:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
class BrainGridCliError extends Error {
|
|
254
|
+
command: string;
|
|
255
|
+
exitCode: number;
|
|
256
|
+
stderr: string;
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Example:**
|
|
261
|
+
```typescript
|
|
262
|
+
import { createIdea, BrainGridCliError } from '@bernierllc/braingrid-cli-wrapper';
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const req = await createIdea('Test requirement');
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (error instanceof BrainGridCliError) {
|
|
268
|
+
console.error(`CLI command failed: ${error.command}`);
|
|
269
|
+
console.error(`Exit code: ${error.exitCode}`);
|
|
270
|
+
console.error(`Error output: ${error.stderr}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Configuration
|
|
276
|
+
|
|
277
|
+
### Environment Variables
|
|
278
|
+
|
|
279
|
+
- `BRAINGRID_CLI_PATH`: Custom path to the BrainGrid CLI executable (defaults to `'braingrid'`)
|
|
280
|
+
|
|
281
|
+
**Example:**
|
|
282
|
+
```bash
|
|
283
|
+
export BRAINGRID_CLI_PATH=/custom/path/braingrid
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Usage Examples
|
|
287
|
+
|
|
288
|
+
### Complete Workflow
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import {
|
|
292
|
+
listProjects,
|
|
293
|
+
createIdea,
|
|
294
|
+
createTask,
|
|
295
|
+
listTasks,
|
|
296
|
+
updateTaskStatus
|
|
297
|
+
} from '@bernierllc/braingrid-cli-wrapper';
|
|
298
|
+
|
|
299
|
+
async function workflow() {
|
|
300
|
+
// 1. List projects
|
|
301
|
+
const projects = await listProjects();
|
|
302
|
+
const project = projects[0];
|
|
303
|
+
|
|
304
|
+
// 2. Create a requirement
|
|
305
|
+
const requirement = await createIdea(
|
|
306
|
+
'Build user authentication system',
|
|
307
|
+
project.id
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
// 3. Create tasks
|
|
311
|
+
const task1 = await createTask(requirement.id, {
|
|
312
|
+
title: 'Design authentication flow',
|
|
313
|
+
tags: ['DESIGN']
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const task2 = await createTask(requirement.id, {
|
|
317
|
+
title: 'Implement login endpoint',
|
|
318
|
+
tags: ['DEV', 'backend'],
|
|
319
|
+
dependencies: [task1.id]
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// 4. List tasks
|
|
323
|
+
const tasks = await listTasks({ reqId: requirement.id });
|
|
324
|
+
console.log(`Created ${tasks.length} tasks`);
|
|
325
|
+
|
|
326
|
+
// 5. Update task status
|
|
327
|
+
await updateTaskStatus(task1.id, { status: 'COMPLETED' });
|
|
328
|
+
await updateTaskStatus(task2.id, {
|
|
329
|
+
status: 'IN_PROGRESS',
|
|
330
|
+
assignedTo: 'user-123'
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Error Handling Example
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
import { createIdea, BrainGridCliError } from '@bernierllc/braingrid-cli-wrapper';
|
|
339
|
+
|
|
340
|
+
async function createRequirementSafely(prompt: string) {
|
|
341
|
+
try {
|
|
342
|
+
const req = await createIdea(prompt);
|
|
343
|
+
return req;
|
|
344
|
+
} catch (error) {
|
|
345
|
+
if (error instanceof BrainGridCliError) {
|
|
346
|
+
console.error(`BrainGrid CLI error: ${error.message}`);
|
|
347
|
+
console.error(`Command: ${error.command}`);
|
|
348
|
+
console.error(`Exit code: ${error.exitCode}`);
|
|
349
|
+
console.error(`Stderr: ${error.stderr}`);
|
|
350
|
+
throw new Error('Failed to create requirement');
|
|
351
|
+
}
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Testing
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# Run tests
|
|
361
|
+
npm test
|
|
362
|
+
|
|
363
|
+
# Run tests with coverage
|
|
364
|
+
npm run test:coverage
|
|
365
|
+
|
|
366
|
+
# Run tests in watch mode
|
|
367
|
+
npm run test:watch
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Integration Status
|
|
371
|
+
|
|
372
|
+
### Logger Integration
|
|
373
|
+
**Status**: not-applicable
|
|
374
|
+
|
|
375
|
+
This is a pure utility core package with no dependencies. Logging is handled by consuming packages. Does not require @bernierllc/logger integration.
|
|
376
|
+
|
|
377
|
+
### Docs-Suite Integration
|
|
378
|
+
**Status**: ready
|
|
379
|
+
|
|
380
|
+
Complete API documentation with TypeScript types and examples available for documentation suite integration.
|
|
381
|
+
|
|
382
|
+
### NeverHub Integration
|
|
383
|
+
**Status**: not-applicable
|
|
384
|
+
|
|
385
|
+
Pure utility package with no runtime dependencies. NeverHub integration is handled at the service-level packages that consume this utility. Does not require @bernierllc/neverhub-adapter integration.
|
|
386
|
+
|
|
387
|
+
## Core Package Compliance
|
|
388
|
+
|
|
389
|
+
This package follows the core package rules:
|
|
390
|
+
|
|
391
|
+
- ✅ **Atomic functionality**: Single responsibility - wraps BrainGrid CLI
|
|
392
|
+
- ✅ **No internal dependencies**: Only depends on external packages (`execa`, `zod`)
|
|
393
|
+
- ✅ **Pure functions**: Explicit inputs/outputs with type safety
|
|
394
|
+
- ✅ **Full test coverage**: Comprehensive test suite for all commands
|
|
395
|
+
- ✅ **Single entrypoint**: All exports via `index.ts`
|
|
396
|
+
- ✅ **Strict typing**: TypeScript strict mode enabled, no implicit `any`
|
|
397
|
+
- ✅ **Documentation**: Complete README with purpose, usage, and examples
|
|
398
|
+
|
|
399
|
+
## License
|
|
400
|
+
|
|
401
|
+
MIT License - see LICENSE file for details.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
body, html {
|
|
2
|
+
margin:0; padding: 0;
|
|
3
|
+
height: 100%;
|
|
4
|
+
}
|
|
5
|
+
body {
|
|
6
|
+
font-family: Helvetica Neue, Helvetica, Arial;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
color:#333;
|
|
9
|
+
}
|
|
10
|
+
.small { font-size: 12px; }
|
|
11
|
+
*, *:after, *:before {
|
|
12
|
+
-webkit-box-sizing:border-box;
|
|
13
|
+
-moz-box-sizing:border-box;
|
|
14
|
+
box-sizing:border-box;
|
|
15
|
+
}
|
|
16
|
+
h1 { font-size: 20px; margin: 0;}
|
|
17
|
+
h2 { font-size: 14px; }
|
|
18
|
+
pre {
|
|
19
|
+
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
-moz-tab-size: 2;
|
|
23
|
+
-o-tab-size: 2;
|
|
24
|
+
tab-size: 2;
|
|
25
|
+
}
|
|
26
|
+
a { color:#0074D9; text-decoration:none; }
|
|
27
|
+
a:hover { text-decoration:underline; }
|
|
28
|
+
.strong { font-weight: bold; }
|
|
29
|
+
.space-top1 { padding: 10px 0 0 0; }
|
|
30
|
+
.pad2y { padding: 20px 0; }
|
|
31
|
+
.pad1y { padding: 10px 0; }
|
|
32
|
+
.pad2x { padding: 0 20px; }
|
|
33
|
+
.pad2 { padding: 20px; }
|
|
34
|
+
.pad1 { padding: 10px; }
|
|
35
|
+
.space-left2 { padding-left:55px; }
|
|
36
|
+
.space-right2 { padding-right:20px; }
|
|
37
|
+
.center { text-align:center; }
|
|
38
|
+
.clearfix { display:block; }
|
|
39
|
+
.clearfix:after {
|
|
40
|
+
content:'';
|
|
41
|
+
display:block;
|
|
42
|
+
height:0;
|
|
43
|
+
clear:both;
|
|
44
|
+
visibility:hidden;
|
|
45
|
+
}
|
|
46
|
+
.fl { float: left; }
|
|
47
|
+
@media only screen and (max-width:640px) {
|
|
48
|
+
.col3 { width:100%; max-width:100%; }
|
|
49
|
+
.hide-mobile { display:none!important; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.quiet {
|
|
53
|
+
color: #7f7f7f;
|
|
54
|
+
color: rgba(0,0,0,0.5);
|
|
55
|
+
}
|
|
56
|
+
.quiet a { opacity: 0.7; }
|
|
57
|
+
|
|
58
|
+
.fraction {
|
|
59
|
+
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
60
|
+
font-size: 10px;
|
|
61
|
+
color: #555;
|
|
62
|
+
background: #E8E8E8;
|
|
63
|
+
padding: 4px 5px;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
vertical-align: middle;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
div.path a:link, div.path a:visited { color: #333; }
|
|
69
|
+
table.coverage {
|
|
70
|
+
border-collapse: collapse;
|
|
71
|
+
margin: 10px 0 0 0;
|
|
72
|
+
padding: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
table.coverage td {
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
vertical-align: top;
|
|
79
|
+
}
|
|
80
|
+
table.coverage td.line-count {
|
|
81
|
+
text-align: right;
|
|
82
|
+
padding: 0 5px 0 20px;
|
|
83
|
+
}
|
|
84
|
+
table.coverage td.line-coverage {
|
|
85
|
+
text-align: right;
|
|
86
|
+
padding-right: 10px;
|
|
87
|
+
min-width:20px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
table.coverage td span.cline-any {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
padding: 0 5px;
|
|
93
|
+
width: 100%;
|
|
94
|
+
}
|
|
95
|
+
.missing-if-branch {
|
|
96
|
+
display: inline-block;
|
|
97
|
+
margin-right: 5px;
|
|
98
|
+
border-radius: 3px;
|
|
99
|
+
position: relative;
|
|
100
|
+
padding: 0 4px;
|
|
101
|
+
background: #333;
|
|
102
|
+
color: yellow;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.skip-if-branch {
|
|
106
|
+
display: none;
|
|
107
|
+
margin-right: 10px;
|
|
108
|
+
position: relative;
|
|
109
|
+
padding: 0 4px;
|
|
110
|
+
background: #ccc;
|
|
111
|
+
color: white;
|
|
112
|
+
}
|
|
113
|
+
.missing-if-branch .typ, .skip-if-branch .typ {
|
|
114
|
+
color: inherit !important;
|
|
115
|
+
}
|
|
116
|
+
.coverage-summary {
|
|
117
|
+
border-collapse: collapse;
|
|
118
|
+
width: 100%;
|
|
119
|
+
}
|
|
120
|
+
.coverage-summary tr { border-bottom: 1px solid #bbb; }
|
|
121
|
+
.keyline-all { border: 1px solid #ddd; }
|
|
122
|
+
.coverage-summary td, .coverage-summary th { padding: 10px; }
|
|
123
|
+
.coverage-summary tbody { border: 1px solid #bbb; }
|
|
124
|
+
.coverage-summary td { border-right: 1px solid #bbb; }
|
|
125
|
+
.coverage-summary td:last-child { border-right: none; }
|
|
126
|
+
.coverage-summary th {
|
|
127
|
+
text-align: left;
|
|
128
|
+
font-weight: normal;
|
|
129
|
+
white-space: nowrap;
|
|
130
|
+
}
|
|
131
|
+
.coverage-summary th.file { border-right: none !important; }
|
|
132
|
+
.coverage-summary th.pct { }
|
|
133
|
+
.coverage-summary th.pic,
|
|
134
|
+
.coverage-summary th.abs,
|
|
135
|
+
.coverage-summary td.pct,
|
|
136
|
+
.coverage-summary td.abs { text-align: right; }
|
|
137
|
+
.coverage-summary td.file { white-space: nowrap; }
|
|
138
|
+
.coverage-summary td.pic { min-width: 120px !important; }
|
|
139
|
+
.coverage-summary tfoot td { }
|
|
140
|
+
|
|
141
|
+
.coverage-summary .sorter {
|
|
142
|
+
height: 10px;
|
|
143
|
+
width: 7px;
|
|
144
|
+
display: inline-block;
|
|
145
|
+
margin-left: 0.5em;
|
|
146
|
+
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
|
147
|
+
}
|
|
148
|
+
.coverage-summary .sorted .sorter {
|
|
149
|
+
background-position: 0 -20px;
|
|
150
|
+
}
|
|
151
|
+
.coverage-summary .sorted-desc .sorter {
|
|
152
|
+
background-position: 0 -10px;
|
|
153
|
+
}
|
|
154
|
+
.status-line { height: 10px; }
|
|
155
|
+
/* yellow */
|
|
156
|
+
.cbranch-no { background: yellow !important; color: #111; }
|
|
157
|
+
/* dark red */
|
|
158
|
+
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
|
|
159
|
+
.low .chart { border:1px solid #C21F39 }
|
|
160
|
+
.highlighted,
|
|
161
|
+
.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
|
|
162
|
+
background: #C21F39 !important;
|
|
163
|
+
}
|
|
164
|
+
/* medium red */
|
|
165
|
+
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
|
|
166
|
+
/* light red */
|
|
167
|
+
.low, .cline-no { background:#FCE1E5 }
|
|
168
|
+
/* light green */
|
|
169
|
+
.high, .cline-yes { background:rgb(230,245,208) }
|
|
170
|
+
/* medium green */
|
|
171
|
+
.cstat-yes { background:rgb(161,215,106) }
|
|
172
|
+
/* dark green */
|
|
173
|
+
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
|
|
174
|
+
.high .chart { border:1px solid rgb(77,146,33) }
|
|
175
|
+
/* dark yellow (gold) */
|
|
176
|
+
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
|
|
177
|
+
.medium .chart { border:1px solid #f9cd0b; }
|
|
178
|
+
/* light yellow */
|
|
179
|
+
.medium { background: #fff4c2; }
|
|
180
|
+
|
|
181
|
+
.cstat-skip { background: #ddd; color: #111; }
|
|
182
|
+
.fstat-skip { background: #ddd; color: #111 !important; }
|
|
183
|
+
.cbranch-skip { background: #ddd !important; color: #111; }
|
|
184
|
+
|
|
185
|
+
span.cline-neutral { background: #eaeaea; }
|
|
186
|
+
|
|
187
|
+
.coverage-summary td.empty {
|
|
188
|
+
opacity: .5;
|
|
189
|
+
padding-top: 4px;
|
|
190
|
+
padding-bottom: 4px;
|
|
191
|
+
line-height: 1;
|
|
192
|
+
color: #888;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.cover-fill, .cover-empty {
|
|
196
|
+
display:inline-block;
|
|
197
|
+
height: 12px;
|
|
198
|
+
}
|
|
199
|
+
.chart {
|
|
200
|
+
line-height: 0;
|
|
201
|
+
}
|
|
202
|
+
.cover-empty {
|
|
203
|
+
background: white;
|
|
204
|
+
}
|
|
205
|
+
.cover-full {
|
|
206
|
+
border-right: none !important;
|
|
207
|
+
}
|
|
208
|
+
pre.prettyprint {
|
|
209
|
+
border: none !important;
|
|
210
|
+
padding: 0 !important;
|
|
211
|
+
margin: 0 !important;
|
|
212
|
+
}
|
|
213
|
+
.com { color: #999 !important; }
|
|
214
|
+
.ignore-none { color: #999; font-weight: normal; }
|
|
215
|
+
|
|
216
|
+
.wrapper {
|
|
217
|
+
min-height: 100%;
|
|
218
|
+
height: auto !important;
|
|
219
|
+
height: 100%;
|
|
220
|
+
margin: 0 auto -48px;
|
|
221
|
+
}
|
|
222
|
+
.footer, .push {
|
|
223
|
+
height: 48px;
|
|
224
|
+
}
|