@bernierllc/braingrid-cli-wrapper 0.3.2 → 0.6.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/dist/errors.d.ts +11 -0
- package/dist/errors.js +24 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -1
- package/dist/models.d.ts +9 -1
- package/dist/models.js +9 -3
- package/package.json +5 -1
- package/.eslintrc.cjs +0 -29
- package/CHANGELOG.md +0 -51
- package/jest.config.cjs +0 -21
- package/src/__tests__/execa-mock-validation.test.ts +0 -34
- package/src/__tests__/index.test.ts +0 -77
- package/src/cli.test.ts +0 -86
- package/src/cli.ts +0 -71
- package/src/commands/createIdea.test.ts +0 -77
- package/src/commands/createIdea.ts +0 -36
- package/src/commands/createProject.test.ts +0 -75
- package/src/commands/createProject.ts +0 -37
- package/src/commands/createTask.test.ts +0 -100
- package/src/commands/createTask.ts +0 -50
- package/src/commands/listProjects.test.ts +0 -72
- package/src/commands/listProjects.ts +0 -25
- package/src/commands/listRequirements.test.ts +0 -89
- package/src/commands/listRequirements.ts +0 -37
- package/src/commands/listTasks.test.ts +0 -183
- package/src/commands/listTasks.ts +0 -47
- package/src/commands/updateRequirementStatus.test.ts +0 -85
- package/src/commands/updateRequirementStatus.ts +0 -33
- package/src/commands/updateTaskStatus.test.ts +0 -96
- package/src/commands/updateTaskStatus.ts +0 -40
- package/src/index.ts +0 -32
- package/src/models.test.ts +0 -197
- package/src/models.ts +0 -93
- package/tsconfig.json +0 -18
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type BraingridCliWrapperErrorCode = 'BRAINGRID_CLI_WRAPPER_ERROR' | 'INVALID_INPUT' | 'OPERATION_FAILED';
|
|
2
|
+
export interface BraingridCliWrapperErrorOptions {
|
|
3
|
+
cause?: Error;
|
|
4
|
+
code?: BraingridCliWrapperErrorCode;
|
|
5
|
+
context?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export declare class BraingridCliWrapperError extends Error {
|
|
8
|
+
readonly code: BraingridCliWrapperErrorCode;
|
|
9
|
+
readonly context?: Record<string, unknown>;
|
|
10
|
+
constructor(message: string, options?: BraingridCliWrapperErrorOptions);
|
|
11
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code only within the scope of the project it was delivered for.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.BraingridCliWrapperError = void 0;
|
|
11
|
+
class BraingridCliWrapperError extends Error {
|
|
12
|
+
code;
|
|
13
|
+
context;
|
|
14
|
+
constructor(message, options) {
|
|
15
|
+
super(message, options?.cause ? { cause: options.cause } : undefined);
|
|
16
|
+
this.name = 'BraingridCliWrapperError';
|
|
17
|
+
this.code = options?.code ?? 'BRAINGRID_CLI_WRAPPER_ERROR';
|
|
18
|
+
if (options?.context !== undefined) {
|
|
19
|
+
this.context = options.context;
|
|
20
|
+
}
|
|
21
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.BraingridCliWrapperError = BraingridCliWrapperError;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { BrainGridProject, BrainGridRequirement, BrainGridTask, RequirementStatus, TaskStatus, BrainGridProjectSchema, BrainGridRequirementSchema, BrainGridTaskSchema, BrainGridCliError } from './models';
|
|
2
|
+
export type { BrainGridCliErrorCode, BrainGridCliErrorOptions } from './models';
|
|
2
3
|
export { createIdea } from './commands/createIdea';
|
|
3
4
|
export { listProjects } from './commands/listProjects';
|
|
4
5
|
export { createProject } from './commands/createProject';
|
|
@@ -7,3 +8,4 @@ export { updateRequirementStatus } from './commands/updateRequirementStatus';
|
|
|
7
8
|
export { createTask, CreateTaskOptions } from './commands/createTask';
|
|
8
9
|
export { updateTaskStatus, UpdateTaskOptions } from './commands/updateTaskStatus';
|
|
9
10
|
export { listTasks, ListTasksOptions } from './commands/listTasks';
|
|
11
|
+
export { BraingridCliWrapperError, type BraingridCliWrapperErrorCode, type BraingridCliWrapperErrorOptions } from './errors';
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ The client may use and modify this code *only within the scope of the project it
|
|
|
7
7
|
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.listTasks = exports.updateTaskStatus = exports.createTask = exports.updateRequirementStatus = exports.listRequirements = exports.createProject = exports.listProjects = exports.createIdea = exports.BrainGridCliError = exports.BrainGridTaskSchema = exports.BrainGridRequirementSchema = exports.BrainGridProjectSchema = void 0;
|
|
10
|
+
exports.BraingridCliWrapperError = exports.listTasks = exports.updateTaskStatus = exports.createTask = exports.updateRequirementStatus = exports.listRequirements = exports.createProject = exports.listProjects = exports.createIdea = exports.BrainGridCliError = exports.BrainGridTaskSchema = exports.BrainGridRequirementSchema = exports.BrainGridProjectSchema = void 0;
|
|
11
11
|
// BrainGrid CLI Wrapper - Type-safe wrapper for BrainGrid CLI
|
|
12
12
|
// Export types and schemas
|
|
13
13
|
var models_1 = require("./models");
|
|
@@ -32,3 +32,6 @@ var updateTaskStatus_1 = require("./commands/updateTaskStatus");
|
|
|
32
32
|
Object.defineProperty(exports, "updateTaskStatus", { enumerable: true, get: function () { return updateTaskStatus_1.updateTaskStatus; } });
|
|
33
33
|
var listTasks_1 = require("./commands/listTasks");
|
|
34
34
|
Object.defineProperty(exports, "listTasks", { enumerable: true, get: function () { return listTasks_1.listTasks; } });
|
|
35
|
+
// Error types
|
|
36
|
+
var errors_1 = require("./errors");
|
|
37
|
+
Object.defineProperty(exports, "BraingridCliWrapperError", { enumerable: true, get: function () { return errors_1.BraingridCliWrapperError; } });
|
package/dist/models.d.ts
CHANGED
|
@@ -81,9 +81,17 @@ export declare const BrainGridTaskSchema: z.ZodObject<{
|
|
|
81
81
|
metadata?: Record<string, unknown> | undefined;
|
|
82
82
|
}>;
|
|
83
83
|
export type BrainGridTask = z.infer<typeof BrainGridTaskSchema>;
|
|
84
|
+
export type BrainGridCliErrorCode = 'BRAINGRID_CLI_ERROR' | 'BRAINGRID_CLI_NOT_FOUND' | 'BRAINGRID_CLI_INVALID_OUTPUT' | 'BRAINGRID_CLI_NONZERO_EXIT';
|
|
85
|
+
export interface BrainGridCliErrorOptions {
|
|
86
|
+
cause?: Error;
|
|
87
|
+
code?: BrainGridCliErrorCode;
|
|
88
|
+
context?: Record<string, unknown>;
|
|
89
|
+
}
|
|
84
90
|
export declare class BrainGridCliError extends Error {
|
|
85
91
|
command: string;
|
|
86
92
|
exitCode: number;
|
|
87
93
|
stderr: string;
|
|
88
|
-
|
|
94
|
+
readonly code: BrainGridCliErrorCode;
|
|
95
|
+
readonly context?: Record<string, unknown>;
|
|
96
|
+
constructor(message: string, command: string, exitCode: number, stderr: string, options?: BrainGridCliErrorOptions);
|
|
89
97
|
}
|
package/dist/models.js
CHANGED
|
@@ -58,17 +58,23 @@ exports.BrainGridTaskSchema = zod_1.z.object({
|
|
|
58
58
|
updatedAt: zod_1.z.string().optional(),
|
|
59
59
|
metadata: zod_1.z.record(zod_1.z.unknown()).optional()
|
|
60
60
|
});
|
|
61
|
-
// CLI Error
|
|
62
61
|
class BrainGridCliError extends Error {
|
|
63
62
|
command;
|
|
64
63
|
exitCode;
|
|
65
64
|
stderr;
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
code;
|
|
66
|
+
context;
|
|
67
|
+
constructor(message, command, exitCode, stderr, options) {
|
|
68
|
+
super(message, options?.cause ? { cause: options.cause } : undefined);
|
|
68
69
|
this.name = 'BrainGridCliError';
|
|
69
70
|
this.command = command;
|
|
70
71
|
this.exitCode = exitCode;
|
|
71
72
|
this.stderr = stderr;
|
|
73
|
+
this.code = options?.code ?? 'BRAINGRID_CLI_ERROR';
|
|
74
|
+
if (options?.context !== undefined) {
|
|
75
|
+
this.context = options.context;
|
|
76
|
+
}
|
|
77
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
72
78
|
}
|
|
73
79
|
}
|
|
74
80
|
exports.BrainGridCliError = BrainGridCliError;
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bernierllc/braingrid-cli-wrapper",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Type-safe wrapper for BrainGrid CLI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/**/*",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
7
11
|
"keywords": [
|
|
8
12
|
"braingrid",
|
|
9
13
|
"cli",
|
package/.eslintrc.cjs
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
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/CHANGELOG.md
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
-
|
|
6
|
-
## [0.3.2](https://github.com/bernier-llc/tools/compare/@bernierllc/braingrid-cli-wrapper@0.3.1...@bernierllc/braingrid-cli-wrapper@0.3.2) (2026-03-09)
|
|
7
|
-
|
|
8
|
-
**Note:** Version bump only for package @bernierllc/braingrid-cli-wrapper
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## [0.3.1](https://github.com/bernier-llc/tools/compare/@bernierllc/braingrid-cli-wrapper@0.3.0...@bernierllc/braingrid-cli-wrapper@0.3.1) (2026-03-03)
|
|
15
|
-
|
|
16
|
-
**Note:** Version bump only for package @bernierllc/braingrid-cli-wrapper
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# 0.3.0 (2025-12-25)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
### Bug Fixes
|
|
26
|
-
|
|
27
|
-
* **ci:** add lerna version step before publish ([3d20300](https://github.com/bernier-llc/tools/commit/3d203002143bf353fffafe4f8a78a99009567347))
|
|
28
|
-
* **jest:** move global options to root config and fix typos ([c14710c](https://github.com/bernier-llc/tools/commit/c14710c11e8fc34dd7f773edf01328151564323a))
|
|
29
|
-
* update neverhub-adapter deps to workspace:* and publish 0.1.2 ([f0e3d04](https://github.com/bernier-llc/tools/commit/f0e3d04d8d4f094e3bb899ddf81e93243d16e2c2))
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
### Features
|
|
33
|
-
|
|
34
|
-
* add 4 more core/integration packages ([dd05b81](https://github.com/bernier-llc/tools/commit/dd05b816c94adcbd99556afbd9e316146654f44c))
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# 0.2.0 (2025-12-25)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
### Bug Fixes
|
|
44
|
-
|
|
45
|
-
* **jest:** move global options to root config and fix typos ([c14710c](https://github.com/bernier-llc/tools/commit/c14710c11e8fc34dd7f773edf01328151564323a))
|
|
46
|
-
* update neverhub-adapter deps to workspace:* and publish 0.1.2 ([f0e3d04](https://github.com/bernier-llc/tools/commit/f0e3d04d8d4f094e3bb899ddf81e93243d16e2c2))
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
### Features
|
|
50
|
-
|
|
51
|
-
* add 4 more core/integration packages ([dd05b81](https://github.com/bernier-llc/tools/commit/dd05b816c94adcbd99556afbd9e316146654f44c))
|
package/jest.config.cjs
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
preset: 'ts-jest',
|
|
3
|
-
// Use fixed environment to handle Node.js v25+ localStorage issue
|
|
4
|
-
testEnvironment: '<rootDir>/../../../jest-environment-node-fixed.cjs',
|
|
5
|
-
roots: ['<rootDir>/src'],
|
|
6
|
-
testMatch: [
|
|
7
|
-
'**/__tests__/**/*.ts',
|
|
8
|
-
'**/?(*.)+(spec|test).ts'
|
|
9
|
-
],
|
|
10
|
-
transform: {
|
|
11
|
-
'^.+\\.ts$': 'ts-jest',
|
|
12
|
-
},
|
|
13
|
-
collectCoverageFrom: [
|
|
14
|
-
'src/**/*.ts',
|
|
15
|
-
'!src/**/*.d.ts',
|
|
16
|
-
],
|
|
17
|
-
coverageDirectory: 'coverage',
|
|
18
|
-
moduleFileExtensions: ['ts', 'js', 'json'],
|
|
19
|
-
setupFilesAfterEnv: [],
|
|
20
|
-
};
|
|
21
|
-
|
|
@@ -1,34 +0,0 @@
|
|
|
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
|
-
/**
|
|
10
|
-
* Mock Validation Tests
|
|
11
|
-
*
|
|
12
|
-
* Per CLAUDE.md requirement: "mocks used in tests must always be validated!"
|
|
13
|
-
* These tests verify our execa mock matches the real execa library behavior.
|
|
14
|
-
*
|
|
15
|
-
* NOTE: This test is skipped because execa is an ESM module and Jest requires
|
|
16
|
-
* additional configuration to handle ESM imports. The mock structure is validated
|
|
17
|
-
* through integration with the actual CLI wrapper functions in other test files.
|
|
18
|
-
*/
|
|
19
|
-
describe.skip('Execa Mock Validation', () => {
|
|
20
|
-
it('should match real execa return structure for successful commands', async () => {
|
|
21
|
-
// Skipped - execa is ESM and requires additional Jest configuration
|
|
22
|
-
// Mock structure is validated through CLI wrapper function tests
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should match real execa error structure for failed commands', async () => {
|
|
26
|
-
// Skipped - execa is ESM and requires additional Jest configuration
|
|
27
|
-
// Error handling is validated through CLI wrapper function tests
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should handle JSON output correctly', async () => {
|
|
31
|
-
// Skipped - execa is ESM and requires additional Jest configuration
|
|
32
|
-
// JSON parsing is validated through CLI wrapper function tests
|
|
33
|
-
});
|
|
34
|
-
});
|
|
@@ -1,77 +0,0 @@
|
|
|
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
|
-
// Mock CLI module before importing index
|
|
10
|
-
jest.mock('../cli', () => ({
|
|
11
|
-
runBrainGridCommand: jest.fn()
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
// Mock all command modules to avoid loading real execa
|
|
15
|
-
jest.mock('../commands/createIdea', () => ({
|
|
16
|
-
createIdea: jest.fn()
|
|
17
|
-
}));
|
|
18
|
-
jest.mock('../commands/listProjects', () => ({
|
|
19
|
-
listProjects: jest.fn()
|
|
20
|
-
}));
|
|
21
|
-
jest.mock('../commands/createProject', () => ({
|
|
22
|
-
createProject: jest.fn()
|
|
23
|
-
}));
|
|
24
|
-
jest.mock('../commands/listRequirements', () => ({
|
|
25
|
-
listRequirements: jest.fn()
|
|
26
|
-
}));
|
|
27
|
-
jest.mock('../commands/updateRequirementStatus', () => ({
|
|
28
|
-
updateRequirementStatus: jest.fn()
|
|
29
|
-
}));
|
|
30
|
-
jest.mock('../commands/createTask', () => ({
|
|
31
|
-
createTask: jest.fn()
|
|
32
|
-
}));
|
|
33
|
-
jest.mock('../commands/updateTaskStatus', () => ({
|
|
34
|
-
updateTaskStatus: jest.fn()
|
|
35
|
-
}));
|
|
36
|
-
jest.mock('../commands/listTasks', () => ({
|
|
37
|
-
listTasks: jest.fn()
|
|
38
|
-
}));
|
|
39
|
-
|
|
40
|
-
import * as BrainGridWrapper from '../index';
|
|
41
|
-
|
|
42
|
-
describe('BrainGrid CLI Wrapper - Index Exports', () => {
|
|
43
|
-
it('should export all type definitions', () => {
|
|
44
|
-
expect(BrainGridWrapper.BrainGridProjectSchema).toBeDefined();
|
|
45
|
-
expect(BrainGridWrapper.BrainGridRequirementSchema).toBeDefined();
|
|
46
|
-
expect(BrainGridWrapper.BrainGridTaskSchema).toBeDefined();
|
|
47
|
-
expect(BrainGridWrapper.BrainGridCliError).toBeDefined();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should export all command functions', () => {
|
|
51
|
-
expect(typeof BrainGridWrapper.createIdea).toBe('function');
|
|
52
|
-
expect(typeof BrainGridWrapper.listProjects).toBe('function');
|
|
53
|
-
expect(typeof BrainGridWrapper.createProject).toBe('function');
|
|
54
|
-
expect(typeof BrainGridWrapper.listRequirements).toBe('function');
|
|
55
|
-
expect(typeof BrainGridWrapper.updateRequirementStatus).toBe('function');
|
|
56
|
-
expect(typeof BrainGridWrapper.createTask).toBe('function');
|
|
57
|
-
expect(typeof BrainGridWrapper.updateTaskStatus).toBe('function');
|
|
58
|
-
expect(typeof BrainGridWrapper.listTasks).toBe('function');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should export BrainGridCliError as a class', () => {
|
|
62
|
-
const error = new BrainGridWrapper.BrainGridCliError(
|
|
63
|
-
'Test error',
|
|
64
|
-
'braingrid test',
|
|
65
|
-
1,
|
|
66
|
-
'test stderr'
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
expect(error).toBeInstanceOf(Error);
|
|
70
|
-
expect(error).toBeInstanceOf(BrainGridWrapper.BrainGridCliError);
|
|
71
|
-
expect(error.name).toBe('BrainGridCliError');
|
|
72
|
-
expect(error.message).toBe('Test error');
|
|
73
|
-
expect(error.command).toBe('braingrid test');
|
|
74
|
-
expect(error.exitCode).toBe(1);
|
|
75
|
-
expect(error.stderr).toBe('test stderr');
|
|
76
|
-
});
|
|
77
|
-
});
|
package/src/cli.test.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
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 { BrainGridCliError } from './models';
|
|
11
|
-
|
|
12
|
-
// Mock execa
|
|
13
|
-
jest.mock('execa', () => ({
|
|
14
|
-
execa: jest.fn()
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
import { execa } from 'execa';
|
|
18
|
-
|
|
19
|
-
describe('CLI Helper', () => {
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
jest.clearAllMocks();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should run command successfully', async () => {
|
|
25
|
-
const mockOutput = { id: 'proj-123', name: 'Test' };
|
|
26
|
-
(execa as jest.MockedFunction<typeof execa>).mockResolvedValue({
|
|
27
|
-
stdout: JSON.stringify(mockOutput),
|
|
28
|
-
stderr: '',
|
|
29
|
-
exitCode: 0
|
|
30
|
-
} as any);
|
|
31
|
-
|
|
32
|
-
const result = await runBrainGridCommand(['projects', 'list', '--format', 'json']);
|
|
33
|
-
|
|
34
|
-
expect(result).toEqual(mockOutput);
|
|
35
|
-
expect(execa).toHaveBeenCalledWith(
|
|
36
|
-
'braingrid',
|
|
37
|
-
['projects', 'list', '--format', 'json'],
|
|
38
|
-
expect.any(Object)
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should handle command with no JSON output', async () => {
|
|
43
|
-
(execa as jest.MockedFunction<typeof execa>).mockResolvedValue({
|
|
44
|
-
stdout: 'Success',
|
|
45
|
-
stderr: '',
|
|
46
|
-
exitCode: 0
|
|
47
|
-
} as any);
|
|
48
|
-
|
|
49
|
-
const result = await runBrainGridCommand(['task', 'update', 'task-123']);
|
|
50
|
-
|
|
51
|
-
expect(result).toBeNull();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should throw BrainGridCliError on failure', async () => {
|
|
55
|
-
(execa as jest.MockedFunction<typeof execa>).mockRejectedValue({
|
|
56
|
-
exitCode: 1,
|
|
57
|
-
stderr: 'Invalid command',
|
|
58
|
-
stdout: ''
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
await expect(
|
|
62
|
-
runBrainGridCommand(['invalid'])
|
|
63
|
-
).rejects.toThrow(BrainGridCliError);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should use custom CLI path from env', async () => {
|
|
67
|
-
const originalEnv = process.env.BRAINGRID_CLI_PATH;
|
|
68
|
-
process.env.BRAINGRID_CLI_PATH = '/custom/path/braingrid';
|
|
69
|
-
|
|
70
|
-
(execa as jest.MockedFunction<typeof execa>).mockResolvedValue({
|
|
71
|
-
stdout: '{}',
|
|
72
|
-
stderr: '',
|
|
73
|
-
exitCode: 0
|
|
74
|
-
} as any);
|
|
75
|
-
|
|
76
|
-
await runBrainGridCommand(['projects', 'list']);
|
|
77
|
-
|
|
78
|
-
expect(execa).toHaveBeenCalledWith(
|
|
79
|
-
'/custom/path/braingrid',
|
|
80
|
-
expect.any(Array),
|
|
81
|
-
expect.any(Object)
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
process.env.BRAINGRID_CLI_PATH = originalEnv;
|
|
85
|
-
});
|
|
86
|
-
});
|
package/src/cli.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
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 { execa } from 'execa';
|
|
10
|
-
import { BrainGridCliError } from './models';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Run a BrainGrid CLI command and return parsed JSON output
|
|
14
|
-
*/
|
|
15
|
-
export async function runBrainGridCommand(
|
|
16
|
-
args: string[],
|
|
17
|
-
options?: {
|
|
18
|
-
cwd?: string;
|
|
19
|
-
env?: Record<string, string>;
|
|
20
|
-
}
|
|
21
|
-
): Promise<unknown> {
|
|
22
|
-
const cliPath = process.env.BRAINGRID_CLI_PATH || 'braingrid';
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const result = await execa(cliPath, args, {
|
|
26
|
-
cwd: options?.cwd,
|
|
27
|
-
env: {
|
|
28
|
-
...process.env,
|
|
29
|
-
...options?.env
|
|
30
|
-
},
|
|
31
|
-
timeout: 30000, // 30 second timeout
|
|
32
|
-
reject: false // Don't throw on non-zero exit
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Check for errors
|
|
36
|
-
if (result.exitCode !== 0) {
|
|
37
|
-
throw new BrainGridCliError(
|
|
38
|
-
`BrainGrid CLI command failed: ${args.join(' ')}`,
|
|
39
|
-
cliPath,
|
|
40
|
-
result.exitCode,
|
|
41
|
-
result.stderr
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Try to parse JSON output
|
|
46
|
-
const stdout = result.stdout.trim();
|
|
47
|
-
if (!stdout) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
return JSON.parse(stdout);
|
|
53
|
-
} catch (e) {
|
|
54
|
-
// Not JSON output, return as-is
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
} catch (error) {
|
|
58
|
-
if (error instanceof BrainGridCliError) {
|
|
59
|
-
throw error;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Handle execa errors
|
|
63
|
-
const execaError = error as Error & { exitCode?: number; stderr?: string };
|
|
64
|
-
throw new BrainGridCliError(
|
|
65
|
-
`Failed to execute BrainGrid CLI: ${execaError.message}`,
|
|
66
|
-
cliPath,
|
|
67
|
-
execaError.exitCode || -1,
|
|
68
|
-
execaError.stderr || ''
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
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 { createIdea } from './createIdea';
|
|
10
|
-
|
|
11
|
-
jest.mock('../cli', () => ({
|
|
12
|
-
runBrainGridCommand: jest.fn()
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
import { runBrainGridCommand } from '../cli';
|
|
16
|
-
|
|
17
|
-
describe('createIdea', () => {
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
jest.clearAllMocks();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should create idea with prompt only', async () => {
|
|
23
|
-
const mockReq = {
|
|
24
|
-
id: 'req-123',
|
|
25
|
-
projectId: 'proj-456',
|
|
26
|
-
title: 'Add OAuth2',
|
|
27
|
-
status: 'IDEA'
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
(runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(mockReq);
|
|
31
|
-
|
|
32
|
-
const result = await createIdea('Add OAuth2 authentication');
|
|
33
|
-
|
|
34
|
-
expect(runBrainGridCommand).toHaveBeenCalledWith([
|
|
35
|
-
'specify',
|
|
36
|
-
'Add OAuth2 authentication',
|
|
37
|
-
'--format',
|
|
38
|
-
'json'
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
expect(result.id).toBe('req-123');
|
|
42
|
-
expect(result.status).toBe('IDEA');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should create idea with project ID', async () => {
|
|
46
|
-
const mockReq = {
|
|
47
|
-
id: 'req-123',
|
|
48
|
-
projectId: 'proj-456',
|
|
49
|
-
title: 'Add OAuth2',
|
|
50
|
-
status: 'IDEA'
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
(runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(mockReq);
|
|
54
|
-
|
|
55
|
-
await createIdea('Add OAuth2 authentication', 'proj-456');
|
|
56
|
-
|
|
57
|
-
expect(runBrainGridCommand).toHaveBeenCalledWith([
|
|
58
|
-
'specify',
|
|
59
|
-
'Add OAuth2 authentication',
|
|
60
|
-
'--project',
|
|
61
|
-
'proj-456',
|
|
62
|
-
'--format',
|
|
63
|
-
'json'
|
|
64
|
-
]);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should validate response schema', async () => {
|
|
68
|
-
const invalidReq = {
|
|
69
|
-
id: 123, // Should be string
|
|
70
|
-
title: 'Test'
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
(runBrainGridCommand as jest.MockedFunction<typeof runBrainGridCommand>).mockResolvedValue(invalidReq);
|
|
74
|
-
|
|
75
|
-
await expect(createIdea('Test')).rejects.toThrow();
|
|
76
|
-
});
|
|
77
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
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 { BrainGridRequirement, BrainGridRequirementSchema } from '../models';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Create a new requirement (IDEA) in BrainGrid
|
|
14
|
-
*/
|
|
15
|
-
export async function createIdea(
|
|
16
|
-
prompt: string,
|
|
17
|
-
projectId?: string
|
|
18
|
-
): Promise<BrainGridRequirement> {
|
|
19
|
-
const args = ['specify', prompt];
|
|
20
|
-
|
|
21
|
-
if (projectId) {
|
|
22
|
-
args.push('--project', projectId);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
args.push('--format', 'json');
|
|
26
|
-
|
|
27
|
-
const result = await runBrainGridCommand(args);
|
|
28
|
-
|
|
29
|
-
// Validate response
|
|
30
|
-
const parsed = BrainGridRequirementSchema.safeParse(result);
|
|
31
|
-
if (!parsed.success) {
|
|
32
|
-
throw new Error(`Invalid BrainGrid response: ${parsed.error.message}`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return parsed.data;
|
|
36
|
-
}
|