@brainfile/cli 0.12.3 → 0.12.5
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/CHANGELOG.md +24 -0
- package/dist/cli.js +32 -9
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.d.ts +12 -3
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +83 -81
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/archive.d.ts.map +1 -1
- package/dist/commands/archive.js +70 -47
- package/dist/commands/archive.js.map +1 -1
- package/dist/commands/contract.d.ts +20 -0
- package/dist/commands/contract.d.ts.map +1 -0
- package/dist/commands/contract.js +62 -0
- package/dist/commands/contract.js.map +1 -0
- package/dist/commands/hooks.d.ts +7 -6
- package/dist/commands/hooks.d.ts.map +1 -1
- package/dist/commands/hooks.js +130 -124
- package/dist/commands/hooks.js.map +1 -1
- package/dist/commands/lint.d.ts +9 -1
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +74 -77
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/list.d.ts +12 -3
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +59 -58
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +104 -17
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/move.d.ts +9 -1
- package/dist/commands/move.d.ts.map +1 -1
- package/dist/commands/move.js +78 -64
- package/dist/commands/move.js.map +1 -1
- package/dist/commands/restore.d.ts.map +1 -1
- package/dist/commands/restore.js +15 -13
- package/dist/commands/restore.js.map +1 -1
- package/dist/commands/template.d.ts +7 -1
- package/dist/commands/template.d.ts.map +1 -1
- package/dist/commands/template.js +105 -124
- package/dist/commands/template.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/contractRunner.d.ts +54 -0
- package/dist/lib/contractRunner.d.ts.map +1 -0
- package/dist/lib/contractRunner.js +273 -0
- package/dist/lib/contractRunner.js.map +1 -0
- package/dist/tui/BrainfileTUI.d.ts.map +1 -1
- package/dist/tui/BrainfileTUI.js +7 -1
- package/dist/tui/BrainfileTUI.js.map +1 -1
- package/dist/tui/actions.d.ts +5 -0
- package/dist/tui/actions.d.ts.map +1 -1
- package/dist/tui/actions.js +122 -0
- package/dist/tui/actions.js.map +1 -1
- package/dist/tui/components/StackedTaskList.d.ts.map +1 -1
- package/dist/tui/components/StackedTaskList.js +4 -4
- package/dist/tui/components/StackedTaskList.js.map +1 -1
- package/dist/tui/components/TaskCard.d.ts +3 -1
- package/dist/tui/components/TaskCard.d.ts.map +1 -1
- package/dist/tui/components/TaskCard.js +33 -9
- package/dist/tui/components/TaskCard.js.map +1 -1
- package/dist/tui/components/TaskCardMeasure.d.ts +1 -1
- package/dist/tui/components/TaskCardMeasure.d.ts.map +1 -1
- package/dist/tui/components/TaskCardMeasure.js +11 -1
- package/dist/tui/components/TaskCardMeasure.js.map +1 -1
- package/dist/tui/components/TaskDetail.d.ts +14 -0
- package/dist/tui/components/TaskDetail.d.ts.map +1 -0
- package/dist/tui/components/TaskDetail.js +41 -0
- package/dist/tui/components/TaskDetail.js.map +1 -0
- package/dist/tui/components/TaskList.d.ts.map +1 -1
- package/dist/tui/components/TaskList.js +5 -4
- package/dist/tui/components/TaskList.js.map +1 -1
- package/dist/tui/hooks/useKeyboardNavigation.d.ts.map +1 -1
- package/dist/tui/hooks/useKeyboardNavigation.js +15 -9
- package/dist/tui/hooks/useKeyboardNavigation.js.map +1 -1
- package/dist/utils/archive.d.ts +57 -0
- package/dist/utils/archive.d.ts.map +1 -0
- package/dist/utils/archive.js +304 -0
- package/dist/utils/archive.js.map +1 -0
- package/dist/utils/cli-error.d.ts +44 -0
- package/dist/utils/cli-error.d.ts.map +1 -0
- package/dist/utils/cli-error.js +85 -0
- package/dist/utils/cli-error.js.map +1 -0
- package/dist/utils/config.d.ts +30 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +80 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/errorHandler.d.ts +2 -2
- package/dist/utils/errorHandler.d.ts.map +1 -1
- package/dist/utils/errorHandler.js +8 -13
- package/dist/utils/errorHandler.js.map +1 -1
- package/dist/utils/git-helper.d.ts +8 -4
- package/dist/utils/git-helper.d.ts.map +1 -1
- package/dist/utils/git-helper.js +12 -9
- package/dist/utils/git-helper.js.map +1 -1
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +56 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +2 -2
- package/.aider/sessions/auto-save.json +0 -23
- package/.aider.chat.history.md +0 -81
- package/.aider.input.history +0 -12
- package/.aider.tags.cache.v8/cache.db +0 -0
- package/.aider.tags.cache.v8/cache.db-shm +0 -0
- package/.aider.tags.cache.v8/cache.db-wal +0 -0
- package/.claude/settings.json +0 -7
- package/brainfile.md +0 -102
- package/logo.png +0 -0
|
@@ -32,139 +32,120 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
36
|
exports.templateCommand = templateCommand;
|
|
40
37
|
const fs = __importStar(require("fs"));
|
|
41
38
|
const path = __importStar(require("path"));
|
|
42
39
|
const core_1 = require("@brainfile/core");
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
if (template.template.tags && template.template.tags.length > 0) {
|
|
57
|
-
console.log(chalk_1.default.gray(` Default Tags: ${template.template.tags.join(', ')}`));
|
|
58
|
-
}
|
|
59
|
-
if (template.template.subtasks && template.template.subtasks.length > 0) {
|
|
60
|
-
console.log(chalk_1.default.gray(` Subtasks: ${template.template.subtasks.length}`));
|
|
61
|
-
}
|
|
62
|
-
console.log('');
|
|
63
|
-
});
|
|
64
|
-
console.log(chalk_1.default.gray('Usage: brainfile template --use <template-id> --title "Task title"'));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
// Use a template
|
|
68
|
-
if (options.use) {
|
|
69
|
-
if (!options.title) {
|
|
70
|
-
console.error(chalk_1.default.red('Error: --title is required when using a template'));
|
|
71
|
-
console.log(chalk_1.default.gray('Usage: brainfile template --use <template-id> --title "Task title"'));
|
|
72
|
-
process.exit(1);
|
|
73
|
-
}
|
|
74
|
-
// Resolve file path
|
|
75
|
-
const filePath = path.resolve(options.file);
|
|
76
|
-
// Check if file exists
|
|
77
|
-
if (!fs.existsSync(filePath)) {
|
|
78
|
-
console.error(chalk_1.default.red(`Error: File not found: ${filePath}`));
|
|
79
|
-
console.log('');
|
|
80
|
-
console.log(chalk_1.default.gray('To create a new brainfile, run:'));
|
|
81
|
-
console.log(chalk_1.default.cyan(' brainfile init'));
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
// Read and parse the file
|
|
85
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
86
|
-
const result = core_1.Brainfile.parseWithErrors(content);
|
|
87
|
-
if (!result.board) {
|
|
88
|
-
console.error(chalk_1.default.red('Error: Failed to parse brainfile'));
|
|
89
|
-
if (result.error) {
|
|
90
|
-
console.error(chalk_1.default.red(result.error));
|
|
91
|
-
}
|
|
92
|
-
process.exit(1);
|
|
93
|
-
}
|
|
94
|
-
const board = result.board;
|
|
95
|
-
// Find the target column
|
|
96
|
-
const targetColumn = board.columns.find(col => col.id === options.column || col.title.toLowerCase() === options.column.toLowerCase());
|
|
97
|
-
if (!targetColumn) {
|
|
98
|
-
console.error(chalk_1.default.red(`Error: Column not found: ${options.column}`));
|
|
99
|
-
console.log(chalk_1.default.gray('Available columns:'));
|
|
100
|
-
board.columns.forEach(col => {
|
|
101
|
-
console.log(chalk_1.default.gray(` - ${col.id} (${col.title})`));
|
|
102
|
-
});
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
// Create task from template
|
|
106
|
-
const values = {
|
|
107
|
-
title: options.title,
|
|
108
|
-
};
|
|
109
|
-
if (options.description) {
|
|
110
|
-
values.description = options.description;
|
|
111
|
-
}
|
|
112
|
-
let partialTask;
|
|
113
|
-
try {
|
|
114
|
-
partialTask = core_1.Brainfile.createFromTemplate(options.use, values);
|
|
40
|
+
const logger_1 = require("../utils/logger");
|
|
41
|
+
const cli_error_1 = require("../utils/cli-error");
|
|
42
|
+
const errorHandler_1 = require("../utils/errorHandler");
|
|
43
|
+
function templateCommand(options, logger = logger_1.defaultLogger) {
|
|
44
|
+
// List templates
|
|
45
|
+
if (options.list) {
|
|
46
|
+
logger.log('\nAvailable Templates\n');
|
|
47
|
+
core_1.BUILT_IN_TEMPLATES.forEach(template => {
|
|
48
|
+
logger.log(template.id);
|
|
49
|
+
logger.log(` Name: ${template.name}`);
|
|
50
|
+
logger.log(` Description: ${template.description}`);
|
|
51
|
+
if (template.template.priority) {
|
|
52
|
+
logger.log(` Default Priority: ${template.template.priority}`);
|
|
115
53
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
console.log(chalk_1.default.gray('\nAvailable templates:'));
|
|
119
|
-
core_1.BUILT_IN_TEMPLATES.forEach(t => {
|
|
120
|
-
console.log(chalk_1.default.gray(` - ${t.id}: ${t.name}`));
|
|
121
|
-
});
|
|
122
|
-
process.exit(1);
|
|
54
|
+
if (template.template.tags && template.template.tags.length > 0) {
|
|
55
|
+
logger.log(` Default Tags: ${template.template.tags.join(', ')}`);
|
|
123
56
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
// Create complete task - ensure title is set
|
|
127
|
-
// Spread partialTask first, then override with explicit values
|
|
128
|
-
const newTask = {
|
|
129
|
-
...partialTask,
|
|
130
|
-
id: newTaskId,
|
|
131
|
-
title: options.title, // Always use the provided title
|
|
132
|
-
};
|
|
133
|
-
// Add task to column
|
|
134
|
-
targetColumn.tasks.push(newTask);
|
|
135
|
-
// Serialize and write back
|
|
136
|
-
const updatedContent = core_1.Brainfile.serialize(board);
|
|
137
|
-
fs.writeFileSync(filePath, updatedContent, 'utf-8');
|
|
138
|
-
// Success message
|
|
139
|
-
console.log(chalk_1.default.green('✓ Task created from template!'));
|
|
140
|
-
console.log('');
|
|
141
|
-
console.log(chalk_1.default.gray(` ID: ${newTaskId}`));
|
|
142
|
-
console.log(chalk_1.default.gray(` Title: ${newTask.title}`));
|
|
143
|
-
console.log(chalk_1.default.gray(` Template: ${options.use}`));
|
|
144
|
-
console.log(chalk_1.default.gray(` Column: ${targetColumn.title}`));
|
|
145
|
-
if (newTask.priority) {
|
|
146
|
-
console.log(chalk_1.default.gray(` Priority: ${newTask.priority}`));
|
|
57
|
+
if (template.template.subtasks && template.template.subtasks.length > 0) {
|
|
58
|
+
logger.log(` Subtasks: ${template.template.subtasks.length}`);
|
|
147
59
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
console.log(chalk_1.default.gray(` Subtasks: ${newTask.subtasks.length}`));
|
|
153
|
-
}
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
// No action specified
|
|
157
|
-
console.log(chalk_1.default.yellow('Please specify an action:'));
|
|
158
|
-
console.log(chalk_1.default.gray(' --list List all available templates'));
|
|
159
|
-
console.log(chalk_1.default.gray(' --use <id> Create task from template'));
|
|
160
|
-
console.log('');
|
|
161
|
-
console.log(chalk_1.default.gray('Examples:'));
|
|
162
|
-
console.log(chalk_1.default.gray(' brainfile template --list'));
|
|
163
|
-
console.log(chalk_1.default.gray(' brainfile template --use bug-report --title "Fix login issue"'));
|
|
60
|
+
logger.log('');
|
|
61
|
+
});
|
|
62
|
+
logger.log('Usage: brainfile template --use <template-id> --title "Task title"');
|
|
63
|
+
return { success: true };
|
|
164
64
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
65
|
+
// Use a template
|
|
66
|
+
if (options.use) {
|
|
67
|
+
if (!options.title) {
|
|
68
|
+
throw (0, cli_error_1.missingRequired)('--title', 'brainfile template --use <template-id> --title "Task title"');
|
|
69
|
+
}
|
|
70
|
+
// Resolve file path
|
|
71
|
+
const filePath = path.resolve(options.file);
|
|
72
|
+
// Check if file exists
|
|
73
|
+
if (!fs.existsSync(filePath)) {
|
|
74
|
+
throw (0, cli_error_1.fileNotFound)(filePath);
|
|
75
|
+
}
|
|
76
|
+
// Read and parse the file
|
|
77
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
78
|
+
const result = core_1.Brainfile.parseWithErrors(content);
|
|
79
|
+
if (!result.board) {
|
|
80
|
+
throw (0, cli_error_1.parseFailure)(result.error);
|
|
81
|
+
}
|
|
82
|
+
const board = result.board;
|
|
83
|
+
// Find the target column
|
|
84
|
+
const targetColumn = board.columns.find((col) => col.id === options.column || col.title.toLowerCase() === options.column.toLowerCase());
|
|
85
|
+
if (!targetColumn) {
|
|
86
|
+
const availableColumns = board.columns.map((c) => `${c.id} (${c.title})`);
|
|
87
|
+
throw (0, cli_error_1.columnNotFound)(options.column, availableColumns);
|
|
88
|
+
}
|
|
89
|
+
// Create task from template
|
|
90
|
+
const values = {
|
|
91
|
+
title: options.title,
|
|
92
|
+
};
|
|
93
|
+
if (options.description) {
|
|
94
|
+
values.description = options.description;
|
|
95
|
+
}
|
|
96
|
+
let partialTask;
|
|
97
|
+
try {
|
|
98
|
+
partialTask = core_1.Brainfile.createFromTemplate(options.use, values);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
// Create a nice error message listing available templates
|
|
102
|
+
const availableTemplates = core_1.BUILT_IN_TEMPLATES.map(t => ` - ${t.id}: ${t.name}`).join('\n');
|
|
103
|
+
throw new cli_error_1.CLIError(error instanceof Error ? error.message : String(error), errorHandler_1.ExitCode.USER_ERROR, `Available templates:\n${availableTemplates}`);
|
|
104
|
+
}
|
|
105
|
+
// Generate task ID
|
|
106
|
+
const newTaskId = (0, core_1.generateTaskId)();
|
|
107
|
+
// Create complete task - ensure title is set
|
|
108
|
+
// Spread partialTask first, then override with explicit values
|
|
109
|
+
const newTask = {
|
|
110
|
+
...partialTask,
|
|
111
|
+
id: newTaskId,
|
|
112
|
+
title: options.title, // Always use the provided title
|
|
113
|
+
};
|
|
114
|
+
// Add task to column
|
|
115
|
+
targetColumn.tasks.push(newTask);
|
|
116
|
+
// Serialize and write back
|
|
117
|
+
const updatedContent = core_1.Brainfile.serialize(board);
|
|
118
|
+
fs.writeFileSync(filePath, updatedContent, 'utf-8');
|
|
119
|
+
// Success message
|
|
120
|
+
logger.log('✓ Task created from template!');
|
|
121
|
+
logger.log('');
|
|
122
|
+
logger.log(` ID: ${newTaskId}`);
|
|
123
|
+
logger.log(` Title: ${newTask.title}`);
|
|
124
|
+
logger.log(` Template: ${options.use}`);
|
|
125
|
+
logger.log(` Column: ${targetColumn.title}`);
|
|
126
|
+
if (newTask.priority) {
|
|
127
|
+
logger.log(` Priority: ${newTask.priority}`);
|
|
128
|
+
}
|
|
129
|
+
if (newTask.tags && newTask.tags.length > 0) {
|
|
130
|
+
logger.log(` Tags: ${newTask.tags.join(', ')}`);
|
|
131
|
+
}
|
|
132
|
+
if (newTask.subtasks && newTask.subtasks.length > 0) {
|
|
133
|
+
logger.log(` Subtasks: ${newTask.subtasks.length}`);
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
success: true,
|
|
137
|
+
taskId: newTaskId,
|
|
138
|
+
templateName: options.use
|
|
139
|
+
};
|
|
168
140
|
}
|
|
141
|
+
// No action specified
|
|
142
|
+
logger.warn('Please specify an action:');
|
|
143
|
+
logger.log(' --list List all available templates');
|
|
144
|
+
logger.log(' --use <id> Create task from template');
|
|
145
|
+
logger.log('');
|
|
146
|
+
logger.log('Examples:');
|
|
147
|
+
logger.log(' brainfile template --list');
|
|
148
|
+
logger.log(' brainfile template --use bug-report --title "Fix login issue"');
|
|
149
|
+
return { success: false };
|
|
169
150
|
}
|
|
170
151
|
//# sourceMappingURL=template.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/commands/template.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/commands/template.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { addCommand } from './commands/add';
|
|
|
3
3
|
export { moveCommand } from './commands/move';
|
|
4
4
|
export { templateCommand } from './commands/template';
|
|
5
5
|
export { lintCommand } from './commands/lint';
|
|
6
|
+
export { contractPickupCommand, contractDeliverCommand, contractValidateCommand, } from './commands/contract';
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.lintCommand = exports.templateCommand = exports.moveCommand = exports.addCommand = exports.listCommand = void 0;
|
|
3
|
+
exports.contractValidateCommand = exports.contractDeliverCommand = exports.contractPickupCommand = exports.lintCommand = exports.templateCommand = exports.moveCommand = exports.addCommand = exports.listCommand = void 0;
|
|
4
4
|
// Export commands for programmatic use
|
|
5
5
|
var list_1 = require("./commands/list");
|
|
6
6
|
Object.defineProperty(exports, "listCommand", { enumerable: true, get: function () { return list_1.listCommand; } });
|
|
@@ -12,4 +12,8 @@ var template_1 = require("./commands/template");
|
|
|
12
12
|
Object.defineProperty(exports, "templateCommand", { enumerable: true, get: function () { return template_1.templateCommand; } });
|
|
13
13
|
var lint_1 = require("./commands/lint");
|
|
14
14
|
Object.defineProperty(exports, "lintCommand", { enumerable: true, get: function () { return lint_1.lintCommand; } });
|
|
15
|
+
var contract_1 = require("./commands/contract");
|
|
16
|
+
Object.defineProperty(exports, "contractPickupCommand", { enumerable: true, get: function () { return contract_1.contractPickupCommand; } });
|
|
17
|
+
Object.defineProperty(exports, "contractDeliverCommand", { enumerable: true, get: function () { return contract_1.contractDeliverCommand; } });
|
|
18
|
+
Object.defineProperty(exports, "contractValidateCommand", { enumerable: true, get: function () { return contract_1.contractValidateCommand; } });
|
|
15
19
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAAuC;AACvC,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,sCAA4C;AAAnC,iGAAA,UAAU,OAAA;AACnB,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,gDAAsD;AAA7C,2GAAA,eAAe,OAAA;AACxB,wCAA8C;AAArC,mGAAA,WAAW,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAAuC;AACvC,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,sCAA4C;AAAnC,iGAAA,UAAU,OAAA;AACnB,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,gDAAsD;AAA7C,2GAAA,eAAe,OAAA;AACxB,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,gDAI6B;AAH3B,iHAAA,qBAAqB,OAAA;AACrB,kHAAA,sBAAsB,OAAA;AACtB,mHAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type Board, type Contract, type Deliverable } from '@brainfile/core';
|
|
2
|
+
export type ContractAction = 'pickup' | 'deliver' | 'validate';
|
|
3
|
+
export interface ContractRunContext {
|
|
4
|
+
/** Path to brainfile.md */
|
|
5
|
+
filePath: string;
|
|
6
|
+
/** Task ID with a contract */
|
|
7
|
+
taskId: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ValidationCommandResult {
|
|
10
|
+
command: string;
|
|
11
|
+
exitCode: number;
|
|
12
|
+
stdout: string;
|
|
13
|
+
stderr: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ContractPickupResult {
|
|
16
|
+
action: 'pickup';
|
|
17
|
+
board: Board;
|
|
18
|
+
markdown: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ContractDeliverResult {
|
|
21
|
+
action: 'deliver';
|
|
22
|
+
board: Board;
|
|
23
|
+
}
|
|
24
|
+
export interface ContractValidateResult {
|
|
25
|
+
action: 'validate';
|
|
26
|
+
board: Board;
|
|
27
|
+
deliverableChecks: Array<{
|
|
28
|
+
deliverable: Deliverable;
|
|
29
|
+
ok: boolean;
|
|
30
|
+
resolvedPath?: string;
|
|
31
|
+
error?: string;
|
|
32
|
+
}>;
|
|
33
|
+
commandResults: ValidationCommandResult[];
|
|
34
|
+
ok: boolean;
|
|
35
|
+
}
|
|
36
|
+
export type ContractRunnerResult = ContractPickupResult | ContractDeliverResult | ContractValidateResult;
|
|
37
|
+
export declare function formatContractContextMarkdown(params: {
|
|
38
|
+
taskId: string;
|
|
39
|
+
taskTitle: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
columnTitle?: string;
|
|
42
|
+
contract: Contract;
|
|
43
|
+
relatedFiles?: string[];
|
|
44
|
+
}): string;
|
|
45
|
+
export declare function pickupContract(ctx: ContractRunContext): ContractPickupResult | {
|
|
46
|
+
error: string;
|
|
47
|
+
};
|
|
48
|
+
export declare function deliverContract(ctx: ContractRunContext): ContractDeliverResult | {
|
|
49
|
+
error: string;
|
|
50
|
+
};
|
|
51
|
+
export declare function validateContract(ctx: ContractRunContext): ContractValidateResult | {
|
|
52
|
+
error: string;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=contractRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contractRunner.d.ts","sourceRoot":"","sources":["../../src/lib/contractRunner.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IACjC,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,iBAAiB,EAAE,KAAK,CAAC;QACvB,WAAW,EAAE,WAAW,CAAC;QACzB,EAAE,EAAE,OAAO,CAAC;QACZ,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,cAAc,EAAE,uBAAuB,EAAE,CAAC;IAC1C,EAAE,EAAE,OAAO,CAAC;CACb;AAED,MAAM,MAAM,oBAAoB,GAC5B,oBAAoB,GACpB,qBAAqB,GACrB,sBAAsB,CAAC;AAiC3B,wBAAgB,6BAA6B,CAAC,MAAM,EAAE;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,GAAG,MAAM,CA2ET;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,kBAAkB,GAAG,oBAAoB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CA6BhG;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,kBAAkB,GAAG,qBAAqB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAiBlG;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,kBAAkB,GAAG,sBAAsB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CA4FpG"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.formatContractContextMarkdown = formatContractContextMarkdown;
|
|
37
|
+
exports.pickupContract = pickupContract;
|
|
38
|
+
exports.deliverContract = deliverContract;
|
|
39
|
+
exports.validateContract = validateContract;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const core_1 = require("@brainfile/core");
|
|
44
|
+
function readBoardFromFile(filePath) {
|
|
45
|
+
const resolvedPath = path.resolve(filePath);
|
|
46
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
47
|
+
return { error: `File not found: ${resolvedPath}` };
|
|
48
|
+
}
|
|
49
|
+
const content = fs.readFileSync(resolvedPath, 'utf-8');
|
|
50
|
+
const parsed = core_1.Brainfile.parseWithErrors(content);
|
|
51
|
+
if (!parsed.board) {
|
|
52
|
+
return { error: parsed.error || 'Failed to parse brainfile' };
|
|
53
|
+
}
|
|
54
|
+
return { board: parsed.board, content };
|
|
55
|
+
}
|
|
56
|
+
function writeBoardToFile(filePath, board) {
|
|
57
|
+
const resolvedPath = path.resolve(filePath);
|
|
58
|
+
fs.writeFileSync(resolvedPath, core_1.Brainfile.serialize(board), 'utf-8');
|
|
59
|
+
}
|
|
60
|
+
function normalizeNonEmpty(input, errorMessage) {
|
|
61
|
+
const trimmed = input.trim();
|
|
62
|
+
if (!trimmed)
|
|
63
|
+
return { ok: false, error: errorMessage };
|
|
64
|
+
return { ok: true, value: trimmed };
|
|
65
|
+
}
|
|
66
|
+
function getContractOrError(taskId, contract) {
|
|
67
|
+
if (!contract)
|
|
68
|
+
return { ok: false, error: `Task ${taskId} has no contract` };
|
|
69
|
+
return { ok: true, contract };
|
|
70
|
+
}
|
|
71
|
+
function formatContractContextMarkdown(params) {
|
|
72
|
+
const { taskId, taskTitle, description, columnTitle, contract, relatedFiles } = params;
|
|
73
|
+
const deliverables = contract.deliverables ?? [];
|
|
74
|
+
const constraints = contract.constraints ?? [];
|
|
75
|
+
const ctx = contract.context;
|
|
76
|
+
const lines = [];
|
|
77
|
+
lines.push(`# Contract pickup: ${taskId}`);
|
|
78
|
+
lines.push('');
|
|
79
|
+
lines.push(`## Task`);
|
|
80
|
+
lines.push(`- **ID**: ${taskId}`);
|
|
81
|
+
lines.push(`- **Title**: ${taskTitle}`);
|
|
82
|
+
if (columnTitle)
|
|
83
|
+
lines.push(`- **Column**: ${columnTitle}`);
|
|
84
|
+
lines.push(`- **Contract status**: ${contract.status}`);
|
|
85
|
+
lines.push('');
|
|
86
|
+
if (description && description.trim()) {
|
|
87
|
+
lines.push('## Description');
|
|
88
|
+
lines.push(description.trim());
|
|
89
|
+
lines.push('');
|
|
90
|
+
}
|
|
91
|
+
if (ctx?.background && ctx.background.trim()) {
|
|
92
|
+
lines.push('## Background');
|
|
93
|
+
lines.push(ctx.background.trim());
|
|
94
|
+
lines.push('');
|
|
95
|
+
}
|
|
96
|
+
lines.push('## Deliverables');
|
|
97
|
+
if (deliverables.length === 0) {
|
|
98
|
+
lines.push('- (none)');
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
for (const d of deliverables) {
|
|
102
|
+
const desc = d.description ? ` — ${d.description}` : '';
|
|
103
|
+
lines.push(`- \`${d.type}\` \`${d.path}\`${desc}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push('## Constraints');
|
|
108
|
+
if (constraints.length === 0) {
|
|
109
|
+
lines.push('- (none)');
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
for (const c of constraints)
|
|
113
|
+
lines.push(`- ${c}`);
|
|
114
|
+
}
|
|
115
|
+
lines.push('');
|
|
116
|
+
const rf = [
|
|
117
|
+
...(relatedFiles ?? []),
|
|
118
|
+
...(ctx?.relevantFiles ?? []),
|
|
119
|
+
];
|
|
120
|
+
lines.push('## Relevant files');
|
|
121
|
+
if (rf.length === 0) {
|
|
122
|
+
lines.push('- (none)');
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
for (const f of rf)
|
|
126
|
+
lines.push(`- \`${f}\``);
|
|
127
|
+
}
|
|
128
|
+
lines.push('');
|
|
129
|
+
if (ctx?.outOfScope && ctx.outOfScope.length > 0) {
|
|
130
|
+
lines.push('## Out of scope');
|
|
131
|
+
for (const item of ctx.outOfScope)
|
|
132
|
+
lines.push(`- ${item}`);
|
|
133
|
+
lines.push('');
|
|
134
|
+
}
|
|
135
|
+
const validationCommands = contract.validation?.commands ?? [];
|
|
136
|
+
lines.push('## Validation');
|
|
137
|
+
if (validationCommands.length === 0) {
|
|
138
|
+
lines.push('- (none)');
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
for (const cmd of validationCommands)
|
|
142
|
+
lines.push(`- \`${cmd}\``);
|
|
143
|
+
}
|
|
144
|
+
lines.push('');
|
|
145
|
+
return lines.join('\n');
|
|
146
|
+
}
|
|
147
|
+
function pickupContract(ctx) {
|
|
148
|
+
const read = readBoardFromFile(ctx.filePath);
|
|
149
|
+
if ('error' in read)
|
|
150
|
+
return { error: read.error };
|
|
151
|
+
const { board } = read;
|
|
152
|
+
const taskInfo = (0, core_1.findTaskById)(board, ctx.taskId);
|
|
153
|
+
if (!taskInfo)
|
|
154
|
+
return { error: `Task not found: ${ctx.taskId}` };
|
|
155
|
+
const contract = getContractOrError(ctx.taskId, taskInfo.task.contract);
|
|
156
|
+
if (!contract.ok)
|
|
157
|
+
return { error: contract.error };
|
|
158
|
+
const result = (0, core_1.setTaskContractStatus)(board, ctx.taskId, 'in_progress');
|
|
159
|
+
if (!result.success || !result.board)
|
|
160
|
+
return { error: result.error || 'Failed to update contract status' };
|
|
161
|
+
writeBoardToFile(ctx.filePath, result.board);
|
|
162
|
+
const updatedTaskInfo = (0, core_1.findTaskById)(result.board, ctx.taskId);
|
|
163
|
+
const updatedContract = updatedTaskInfo.task.contract;
|
|
164
|
+
const markdown = formatContractContextMarkdown({
|
|
165
|
+
taskId: updatedTaskInfo.task.id,
|
|
166
|
+
taskTitle: updatedTaskInfo.task.title,
|
|
167
|
+
description: updatedTaskInfo.task.description,
|
|
168
|
+
columnTitle: updatedTaskInfo.column.title,
|
|
169
|
+
contract: updatedContract,
|
|
170
|
+
relatedFiles: updatedTaskInfo.task.relatedFiles,
|
|
171
|
+
});
|
|
172
|
+
return { action: 'pickup', board: result.board, markdown };
|
|
173
|
+
}
|
|
174
|
+
function deliverContract(ctx) {
|
|
175
|
+
const read = readBoardFromFile(ctx.filePath);
|
|
176
|
+
if ('error' in read)
|
|
177
|
+
return { error: read.error };
|
|
178
|
+
const { board } = read;
|
|
179
|
+
const taskInfo = (0, core_1.findTaskById)(board, ctx.taskId);
|
|
180
|
+
if (!taskInfo)
|
|
181
|
+
return { error: `Task not found: ${ctx.taskId}` };
|
|
182
|
+
const contract = getContractOrError(ctx.taskId, taskInfo.task.contract);
|
|
183
|
+
if (!contract.ok)
|
|
184
|
+
return { error: contract.error };
|
|
185
|
+
const result = (0, core_1.setTaskContractStatus)(board, ctx.taskId, 'delivered');
|
|
186
|
+
if (!result.success || !result.board)
|
|
187
|
+
return { error: result.error || 'Failed to update contract status' };
|
|
188
|
+
writeBoardToFile(ctx.filePath, result.board);
|
|
189
|
+
return { action: 'deliver', board: result.board };
|
|
190
|
+
}
|
|
191
|
+
function validateContract(ctx) {
|
|
192
|
+
const read = readBoardFromFile(ctx.filePath);
|
|
193
|
+
if ('error' in read)
|
|
194
|
+
return { error: read.error };
|
|
195
|
+
const { board } = read;
|
|
196
|
+
const taskInfo = (0, core_1.findTaskById)(board, ctx.taskId);
|
|
197
|
+
if (!taskInfo)
|
|
198
|
+
return { error: `Task not found: ${ctx.taskId}` };
|
|
199
|
+
const contractInfo = getContractOrError(ctx.taskId, taskInfo.task.contract);
|
|
200
|
+
if (!contractInfo.ok)
|
|
201
|
+
return { error: contractInfo.error };
|
|
202
|
+
const contract = contractInfo.contract;
|
|
203
|
+
const brainfileAbs = path.resolve(ctx.filePath);
|
|
204
|
+
const baseDir = path.dirname(brainfileAbs);
|
|
205
|
+
const deliverables = contract.deliverables ?? [];
|
|
206
|
+
const deliverableChecks = [];
|
|
207
|
+
// Check file deliverables exist
|
|
208
|
+
for (const d of deliverables) {
|
|
209
|
+
if (d.type !== 'file') {
|
|
210
|
+
deliverableChecks.push({ deliverable: d, ok: true });
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const normalized = normalizeNonEmpty(d.path, 'Deliverable path is required');
|
|
214
|
+
if (!normalized.ok) {
|
|
215
|
+
deliverableChecks.push({ deliverable: d, ok: false, error: normalized.error });
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const resolved = path.isAbsolute(normalized.value)
|
|
219
|
+
? normalized.value
|
|
220
|
+
: path.join(baseDir, normalized.value);
|
|
221
|
+
if (!fs.existsSync(resolved)) {
|
|
222
|
+
deliverableChecks.push({ deliverable: d, ok: false, resolvedPath: resolved, error: 'File not found' });
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
deliverableChecks.push({ deliverable: d, ok: true, resolvedPath: resolved });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// If any deliverable failed, fail fast (and do not run commands)
|
|
229
|
+
const deliverablesOk = deliverableChecks.every((c) => c.ok);
|
|
230
|
+
const commandResults = [];
|
|
231
|
+
let ok = deliverablesOk;
|
|
232
|
+
if (ok) {
|
|
233
|
+
const commands = contract.validation?.commands ?? [];
|
|
234
|
+
for (const raw of commands) {
|
|
235
|
+
const normalized = normalizeNonEmpty(raw, 'Validation command is required');
|
|
236
|
+
if (!normalized.ok) {
|
|
237
|
+
commandResults.push({ command: raw, exitCode: 1, stdout: '', stderr: normalized.error });
|
|
238
|
+
ok = false;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
const res = (0, child_process_1.spawnSync)(normalized.value, {
|
|
242
|
+
shell: true,
|
|
243
|
+
cwd: baseDir,
|
|
244
|
+
encoding: 'utf-8',
|
|
245
|
+
});
|
|
246
|
+
const exitCode = typeof res.status === 'number' ? res.status : 1;
|
|
247
|
+
commandResults.push({
|
|
248
|
+
command: normalized.value,
|
|
249
|
+
exitCode,
|
|
250
|
+
stdout: res.stdout ?? '',
|
|
251
|
+
stderr: res.stderr ?? '',
|
|
252
|
+
});
|
|
253
|
+
if (exitCode !== 0) {
|
|
254
|
+
ok = false;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
const status = ok ? 'done' : 'failed';
|
|
260
|
+
const statusResult = (0, core_1.setTaskContractStatus)(board, ctx.taskId, status);
|
|
261
|
+
if (!statusResult.success || !statusResult.board) {
|
|
262
|
+
return { error: statusResult.error || 'Failed to update contract status' };
|
|
263
|
+
}
|
|
264
|
+
writeBoardToFile(ctx.filePath, statusResult.board);
|
|
265
|
+
return {
|
|
266
|
+
action: 'validate',
|
|
267
|
+
board: statusResult.board,
|
|
268
|
+
deliverableChecks,
|
|
269
|
+
commandResults,
|
|
270
|
+
ok,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=contractRunner.js.map
|