brainfile 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -24
- package/dist/__tests__/helpers/mcp-wire.d.ts +45 -0
- package/dist/__tests__/helpers/mcp-wire.d.ts.map +1 -0
- package/dist/__tests__/helpers/mcp-wire.js +133 -0
- package/dist/__tests__/helpers/mcp-wire.js.map +1 -0
- package/dist/{chunk-YTFLC673.mjs → chunk-FOLBAGJS.mjs} +2483 -1075
- package/dist/cli.mjs +2526 -1656
- package/dist/commands/adr.d.ts +1 -9
- package/dist/commands/adr.d.ts.map +1 -1
- package/dist/commands/adr.js +11 -88
- package/dist/commands/adr.js.map +1 -1
- package/dist/commands/archive.d.ts +2 -5
- package/dist/commands/archive.d.ts.map +1 -1
- package/dist/commands/archive.js +43 -11
- package/dist/commands/archive.js.map +1 -1
- package/dist/commands/brief.d.ts +32 -0
- package/dist/commands/brief.d.ts.map +1 -0
- package/dist/commands/brief.js +161 -0
- package/dist/commands/brief.js.map +1 -0
- package/dist/commands/complete.js +1 -1
- package/dist/commands/complete.js.map +1 -1
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +115 -15
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/log.js +31 -18
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/mcp.d.ts +9 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +72 -17
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/merge-driver.d.ts +26 -0
- package/dist/commands/merge-driver.d.ts.map +1 -0
- package/dist/commands/merge-driver.js +195 -0
- package/dist/commands/merge-driver.js.map +1 -0
- package/dist/commands/migrate-tracked.d.ts +8 -0
- package/dist/commands/migrate-tracked.d.ts.map +1 -0
- package/dist/commands/migrate-tracked.js +428 -0
- package/dist/commands/migrate-tracked.js.map +1 -0
- package/dist/commands/migrate.d.ts +6 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +19 -12
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/sync.d.ts +16 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +152 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/where.d.ts +21 -0
- package/dist/commands/where.d.ts.map +1 -0
- package/dist/commands/where.js +135 -0
- package/dist/commands/where.js.map +1 -0
- package/dist/mcp/helpers.d.ts +8 -0
- package/dist/mcp/helpers.d.ts.map +1 -1
- package/dist/mcp/helpers.js +44 -0
- package/dist/mcp/helpers.js.map +1 -1
- package/dist/mcp/schemas.d.ts +297 -0
- package/dist/mcp/schemas.d.ts.map +1 -0
- package/dist/mcp/schemas.js +328 -0
- package/dist/mcp/schemas.js.map +1 -0
- package/dist/mcp/tools/brief_tool.d.ts +14 -0
- package/dist/mcp/tools/brief_tool.d.ts.map +1 -0
- package/dist/mcp/tools/brief_tool.js +96 -0
- package/dist/mcp/tools/brief_tool.js.map +1 -0
- package/dist/mcp/tools/contract_tool.d.ts.map +1 -1
- package/dist/mcp/tools/contract_tool.js +43 -18
- package/dist/mcp/tools/contract_tool.js.map +1 -1
- package/dist/mcp/tools/get_task_tool.d.ts.map +1 -1
- package/dist/mcp/tools/get_task_tool.js +7 -2
- package/dist/mcp/tools/get_task_tool.js.map +1 -1
- package/dist/mcp/tools/list_tasks_tool.d.ts.map +1 -1
- package/dist/mcp/tools/list_tasks_tool.js +9 -3
- package/dist/mcp/tools/list_tasks_tool.js.map +1 -1
- package/dist/mcp/tools/search_tool.d.ts.map +1 -1
- package/dist/mcp/tools/search_tool.js +17 -4
- package/dist/mcp/tools/search_tool.js.map +1 -1
- package/dist/mcp/tools/subtask_tool.d.ts.map +1 -1
- package/dist/mcp/tools/subtask_tool.js +52 -17
- package/dist/mcp/tools/subtask_tool.js.map +1 -1
- package/dist/mcp/tools/task_add_tool.d.ts.map +1 -1
- package/dist/mcp/tools/task_add_tool.js +13 -7
- package/dist/mcp/tools/task_add_tool.js.map +1 -1
- package/dist/mcp/tools/task_complete_tool.d.ts.map +1 -1
- package/dist/mcp/tools/task_complete_tool.js +39 -10
- package/dist/mcp/tools/task_complete_tool.js.map +1 -1
- package/dist/mcp/tools/task_delete_tool.d.ts.map +1 -1
- package/dist/mcp/tools/task_delete_tool.js +12 -6
- package/dist/mcp/tools/task_delete_tool.js.map +1 -1
- package/dist/mcp/tools/task_move_tool.d.ts.map +1 -1
- package/dist/mcp/tools/task_move_tool.js +21 -11
- package/dist/mcp/tools/task_move_tool.js.map +1 -1
- package/dist/mcp/tools/task_patch_tool.d.ts.map +1 -1
- package/dist/mcp/tools/task_patch_tool.js +23 -10
- package/dist/mcp/tools/task_patch_tool.js.map +1 -1
- package/dist/schemas/board.json +1 -1
- package/dist/tui/theme.d.ts +98 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +141 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/{tui-P56H4X7N.mjs → tui-M2KWIG2E.mjs} +1707 -2006
- package/dist/utils/board-autosync.d.ts +22 -0
- package/dist/utils/board-autosync.d.ts.map +1 -0
- package/dist/utils/board-autosync.js +166 -0
- package/dist/utils/board-autosync.js.map +1 -0
- package/dist/utils/board-commit-hooks.d.ts +12 -0
- package/dist/utils/board-commit-hooks.d.ts.map +1 -0
- package/dist/utils/board-commit-hooks.js +51 -0
- package/dist/utils/board-commit-hooks.js.map +1 -0
- package/dist/utils/board-repo.d.ts +108 -0
- package/dist/utils/board-repo.d.ts.map +1 -0
- package/dist/utils/board-repo.js +501 -0
- package/dist/utils/board-repo.js.map +1 -0
- package/dist/utils/board-sync.d.ts +111 -0
- package/dist/utils/board-sync.d.ts.map +1 -0
- package/dist/utils/board-sync.js +469 -0
- package/dist/utils/board-sync.js.map +1 -0
- package/dist/utils/brainfile-path.d.ts +11 -1
- package/dist/utils/brainfile-path.d.ts.map +1 -1
- package/dist/utils/brainfile-path.js +39 -2
- package/dist/utils/brainfile-path.js.map +1 -1
- package/dist/utils/cli-error.d.ts +20 -0
- package/dist/utils/cli-error.d.ts.map +1 -1
- package/dist/utils/cli-error.js +36 -0
- package/dist/utils/cli-error.js.map +1 -1
- package/package.json +3 -3
- package/dist/commands/rules.d.ts +0 -68
- package/dist/commands/rules.d.ts.map +0 -1
- package/dist/commands/rules.js +0 -322
- package/dist/commands/rules.js.map +0 -1
|
@@ -880,15 +880,15 @@ var require_route = __commonJS({
|
|
|
880
880
|
};
|
|
881
881
|
}
|
|
882
882
|
function wrapConversion(toModel, graph) {
|
|
883
|
-
const
|
|
883
|
+
const path11 = [graph[toModel].parent, toModel];
|
|
884
884
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
885
885
|
let cur = graph[toModel].parent;
|
|
886
886
|
while (graph[cur].parent) {
|
|
887
|
-
|
|
887
|
+
path11.unshift(graph[cur].parent);
|
|
888
888
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
889
889
|
cur = graph[cur].parent;
|
|
890
890
|
}
|
|
891
|
-
fn.conversion =
|
|
891
|
+
fn.conversion = path11;
|
|
892
892
|
return fn;
|
|
893
893
|
}
|
|
894
894
|
module.exports = function(fromModel) {
|
|
@@ -1003,7 +1003,7 @@ var require_ansi_styles = __commonJS({
|
|
|
1003
1003
|
});
|
|
1004
1004
|
};
|
|
1005
1005
|
var colorConvert;
|
|
1006
|
-
var makeDynamicStyles = (wrap, targetSpace,
|
|
1006
|
+
var makeDynamicStyles = (wrap, targetSpace, identity2, isBackground) => {
|
|
1007
1007
|
if (colorConvert === void 0) {
|
|
1008
1008
|
colorConvert = require_color_convert();
|
|
1009
1009
|
}
|
|
@@ -1012,7 +1012,7 @@ var require_ansi_styles = __commonJS({
|
|
|
1012
1012
|
for (const [sourceSpace, suite] of Object.entries(colorConvert)) {
|
|
1013
1013
|
const name = sourceSpace === "ansi16" ? "ansi" : sourceSpace;
|
|
1014
1014
|
if (sourceSpace === targetSpace) {
|
|
1015
|
-
styles[name] = wrap(
|
|
1015
|
+
styles[name] = wrap(identity2, offset);
|
|
1016
1016
|
} else if (typeof suite === "object") {
|
|
1017
1017
|
styles[name] = wrap(suite[targetSpace], offset);
|
|
1018
1018
|
}
|
|
@@ -1128,7 +1128,7 @@ var require_has_flag = __commonJS({
|
|
|
1128
1128
|
var require_supports_color = __commonJS({
|
|
1129
1129
|
"../node_modules/supports-color/index.js"(exports, module) {
|
|
1130
1130
|
"use strict";
|
|
1131
|
-
var
|
|
1131
|
+
var os5 = __require("os");
|
|
1132
1132
|
var tty = __require("tty");
|
|
1133
1133
|
var hasFlag = require_has_flag();
|
|
1134
1134
|
var { env } = process;
|
|
@@ -1176,7 +1176,7 @@ var require_supports_color = __commonJS({
|
|
|
1176
1176
|
return min;
|
|
1177
1177
|
}
|
|
1178
1178
|
if (process.platform === "win32") {
|
|
1179
|
-
const osRelease =
|
|
1179
|
+
const osRelease = os5.release().split(".");
|
|
1180
1180
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
1181
1181
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
1182
1182
|
}
|
|
@@ -1327,14 +1327,14 @@ var require_templates = __commonJS({
|
|
|
1327
1327
|
}
|
|
1328
1328
|
return results;
|
|
1329
1329
|
}
|
|
1330
|
-
function buildStyle(
|
|
1330
|
+
function buildStyle(chalk5, styles) {
|
|
1331
1331
|
const enabled = {};
|
|
1332
1332
|
for (const layer of styles) {
|
|
1333
1333
|
for (const style of layer.styles) {
|
|
1334
1334
|
enabled[style[0]] = layer.inverse ? null : style.slice(1);
|
|
1335
1335
|
}
|
|
1336
1336
|
}
|
|
1337
|
-
let current =
|
|
1337
|
+
let current = chalk5;
|
|
1338
1338
|
for (const [styleName, styles2] of Object.entries(enabled)) {
|
|
1339
1339
|
if (!Array.isArray(styles2)) {
|
|
1340
1340
|
continue;
|
|
@@ -1346,7 +1346,7 @@ var require_templates = __commonJS({
|
|
|
1346
1346
|
}
|
|
1347
1347
|
return current;
|
|
1348
1348
|
}
|
|
1349
|
-
module.exports = (
|
|
1349
|
+
module.exports = (chalk5, temporary) => {
|
|
1350
1350
|
const styles = [];
|
|
1351
1351
|
const chunks = [];
|
|
1352
1352
|
let chunk = [];
|
|
@@ -1356,13 +1356,13 @@ var require_templates = __commonJS({
|
|
|
1356
1356
|
} else if (style) {
|
|
1357
1357
|
const string = chunk.join("");
|
|
1358
1358
|
chunk = [];
|
|
1359
|
-
chunks.push(styles.length === 0 ? string : buildStyle(
|
|
1359
|
+
chunks.push(styles.length === 0 ? string : buildStyle(chalk5, styles)(string));
|
|
1360
1360
|
styles.push({ inverse, styles: parseStyle(style) });
|
|
1361
1361
|
} else if (close) {
|
|
1362
1362
|
if (styles.length === 0) {
|
|
1363
1363
|
throw new Error("Found extraneous } in Chalk template literal");
|
|
1364
1364
|
}
|
|
1365
|
-
chunks.push(buildStyle(
|
|
1365
|
+
chunks.push(buildStyle(chalk5, styles)(chunk.join("")));
|
|
1366
1366
|
chunk = [];
|
|
1367
1367
|
styles.pop();
|
|
1368
1368
|
} else {
|
|
@@ -1410,16 +1410,16 @@ var require_source = __commonJS({
|
|
|
1410
1410
|
}
|
|
1411
1411
|
};
|
|
1412
1412
|
var chalkFactory = (options) => {
|
|
1413
|
-
const
|
|
1414
|
-
applyOptions(
|
|
1415
|
-
|
|
1416
|
-
Object.setPrototypeOf(
|
|
1417
|
-
Object.setPrototypeOf(
|
|
1418
|
-
|
|
1413
|
+
const chalk6 = {};
|
|
1414
|
+
applyOptions(chalk6, options);
|
|
1415
|
+
chalk6.template = (...arguments_) => chalkTag(chalk6.template, ...arguments_);
|
|
1416
|
+
Object.setPrototypeOf(chalk6, Chalk.prototype);
|
|
1417
|
+
Object.setPrototypeOf(chalk6.template, chalk6);
|
|
1418
|
+
chalk6.template.constructor = () => {
|
|
1419
1419
|
throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
|
|
1420
1420
|
};
|
|
1421
|
-
|
|
1422
|
-
return
|
|
1421
|
+
chalk6.template.Instance = ChalkClass;
|
|
1422
|
+
return chalk6.template;
|
|
1423
1423
|
};
|
|
1424
1424
|
function Chalk(options) {
|
|
1425
1425
|
return chalkFactory(options);
|
|
@@ -1530,7 +1530,7 @@ var require_source = __commonJS({
|
|
|
1530
1530
|
return openAll + string + closeAll;
|
|
1531
1531
|
};
|
|
1532
1532
|
var template;
|
|
1533
|
-
var chalkTag = (
|
|
1533
|
+
var chalkTag = (chalk6, ...strings) => {
|
|
1534
1534
|
const [firstString] = strings;
|
|
1535
1535
|
if (!isArray(firstString) || !isArray(firstString.raw)) {
|
|
1536
1536
|
return strings.join(" ");
|
|
@@ -1546,14 +1546,14 @@ var require_source = __commonJS({
|
|
|
1546
1546
|
if (template === void 0) {
|
|
1547
1547
|
template = require_templates();
|
|
1548
1548
|
}
|
|
1549
|
-
return template(
|
|
1549
|
+
return template(chalk6, parts.join(""));
|
|
1550
1550
|
};
|
|
1551
1551
|
Object.defineProperties(Chalk.prototype, styles);
|
|
1552
|
-
var
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
module.exports =
|
|
1552
|
+
var chalk5 = Chalk();
|
|
1553
|
+
chalk5.supportsColor = stdoutColor;
|
|
1554
|
+
chalk5.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
1555
|
+
chalk5.stderr.supportsColor = stderrColor;
|
|
1556
|
+
module.exports = chalk5;
|
|
1557
1557
|
}
|
|
1558
1558
|
});
|
|
1559
1559
|
|
|
@@ -2086,12 +2086,12 @@ var require_contractSpec = __commonJS({
|
|
|
2086
2086
|
const type = raw.slice(0, firstColon).trim();
|
|
2087
2087
|
const rest = raw.slice(firstColon + 1);
|
|
2088
2088
|
const secondColon = rest.indexOf(":");
|
|
2089
|
-
const
|
|
2089
|
+
const path11 = (secondColon === -1 ? rest : rest.slice(0, secondColon)).trim();
|
|
2090
2090
|
const description = (secondColon === -1 ? "" : rest.slice(secondColon + 1)).trim();
|
|
2091
2091
|
if (!type) {
|
|
2092
2092
|
throw new Error(`Invalid deliverable format: "${spec}". Expected "type:path:description" with non-empty type.`);
|
|
2093
2093
|
}
|
|
2094
|
-
if (!
|
|
2094
|
+
if (!path11) {
|
|
2095
2095
|
throw new Error(`Invalid deliverable format: "${spec}". Expected "type:path:description" with non-empty path.`);
|
|
2096
2096
|
}
|
|
2097
2097
|
const typeLower = type.toLowerCase();
|
|
@@ -2100,7 +2100,7 @@ var require_contractSpec = __commonJS({
|
|
|
2100
2100
|
}
|
|
2101
2101
|
const deliverable = {
|
|
2102
2102
|
type: typeLower,
|
|
2103
|
-
path:
|
|
2103
|
+
path: path11,
|
|
2104
2104
|
...description ? { description } : {}
|
|
2105
2105
|
};
|
|
2106
2106
|
return deliverable;
|
|
@@ -5421,61 +5421,6 @@ var require_parser = __commonJS({
|
|
|
5421
5421
|
}
|
|
5422
5422
|
return null;
|
|
5423
5423
|
}
|
|
5424
|
-
/**
|
|
5425
|
-
* Find the line number of a rule in the YAML frontmatter
|
|
5426
|
-
* @param content - The markdown content
|
|
5427
|
-
* @param ruleId - The rule ID to find
|
|
5428
|
-
* @param ruleType - The type of rule (always, never, prefer, context)
|
|
5429
|
-
* @returns Line and column location or null if not found
|
|
5430
|
-
*/
|
|
5431
|
-
static findRuleLocation(content, ruleId, ruleType) {
|
|
5432
|
-
const lines = content.split("\n");
|
|
5433
|
-
let inFrontmatter = false;
|
|
5434
|
-
let inRulesSection = false;
|
|
5435
|
-
let inRuleTypeSection = false;
|
|
5436
|
-
for (let i = 0; i < lines.length; i++) {
|
|
5437
|
-
const line = lines[i];
|
|
5438
|
-
const trimmedLine = line.trim();
|
|
5439
|
-
if (trimmedLine === "---") {
|
|
5440
|
-
if (!inFrontmatter) {
|
|
5441
|
-
inFrontmatter = true;
|
|
5442
|
-
continue;
|
|
5443
|
-
} else {
|
|
5444
|
-
break;
|
|
5445
|
-
}
|
|
5446
|
-
}
|
|
5447
|
-
if (!inFrontmatter)
|
|
5448
|
-
continue;
|
|
5449
|
-
if (trimmedLine === "rules:") {
|
|
5450
|
-
inRulesSection = true;
|
|
5451
|
-
continue;
|
|
5452
|
-
}
|
|
5453
|
-
if (inRulesSection && trimmedLine === `${ruleType}:`) {
|
|
5454
|
-
inRuleTypeSection = true;
|
|
5455
|
-
continue;
|
|
5456
|
-
}
|
|
5457
|
-
if (inRulesSection && line.match(/^[a-z]+:/) && !line.match(/^\s/)) {
|
|
5458
|
-
inRulesSection = false;
|
|
5459
|
-
inRuleTypeSection = false;
|
|
5460
|
-
}
|
|
5461
|
-
if (inRuleTypeSection) {
|
|
5462
|
-
if (line.match(/^\s{2}[a-z]+:/) && !line.includes(`${ruleType}:`)) {
|
|
5463
|
-
inRuleTypeSection = false;
|
|
5464
|
-
continue;
|
|
5465
|
-
}
|
|
5466
|
-
if (line.includes(`id: ${ruleId}`)) {
|
|
5467
|
-
if (line.match(/^\s*-\s+id:\s+/)) {
|
|
5468
|
-
return { line: i + 1, column: 0 };
|
|
5469
|
-
}
|
|
5470
|
-
if (i > 0 && lines[i - 1].match(/^\s*-\s*$/)) {
|
|
5471
|
-
return { line: i, column: 0 };
|
|
5472
|
-
}
|
|
5473
|
-
return { line: i + 1, column: 0 };
|
|
5474
|
-
}
|
|
5475
|
-
}
|
|
5476
|
-
}
|
|
5477
|
-
return null;
|
|
5478
|
-
}
|
|
5479
5424
|
};
|
|
5480
5425
|
exports.BrainfileParser = BrainfileParser;
|
|
5481
5426
|
}
|
|
@@ -5625,6 +5570,104 @@ ${yamlContent}---
|
|
|
5625
5570
|
}
|
|
5626
5571
|
});
|
|
5627
5572
|
|
|
5573
|
+
// ../core/dist/frontmatter.js
|
|
5574
|
+
var require_frontmatter = __commonJS({
|
|
5575
|
+
"../core/dist/frontmatter.js"(exports) {
|
|
5576
|
+
"use strict";
|
|
5577
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
5578
|
+
if (k2 === void 0) k2 = k;
|
|
5579
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5580
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
5581
|
+
desc = { enumerable: true, get: function() {
|
|
5582
|
+
return m[k];
|
|
5583
|
+
} };
|
|
5584
|
+
}
|
|
5585
|
+
Object.defineProperty(o, k2, desc);
|
|
5586
|
+
}) : (function(o, m, k, k2) {
|
|
5587
|
+
if (k2 === void 0) k2 = k;
|
|
5588
|
+
o[k2] = m[k];
|
|
5589
|
+
}));
|
|
5590
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
5591
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
5592
|
+
}) : function(o, v) {
|
|
5593
|
+
o["default"] = v;
|
|
5594
|
+
});
|
|
5595
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
5596
|
+
var ownKeys = function(o) {
|
|
5597
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
5598
|
+
var ar = [];
|
|
5599
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
5600
|
+
return ar;
|
|
5601
|
+
};
|
|
5602
|
+
return ownKeys(o);
|
|
5603
|
+
};
|
|
5604
|
+
return function(mod) {
|
|
5605
|
+
if (mod && mod.__esModule) return mod;
|
|
5606
|
+
var result = {};
|
|
5607
|
+
if (mod != null) {
|
|
5608
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
5609
|
+
}
|
|
5610
|
+
__setModuleDefault(result, mod);
|
|
5611
|
+
return result;
|
|
5612
|
+
};
|
|
5613
|
+
})();
|
|
5614
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5615
|
+
exports.parseFrontmatter = parseFrontmatter2;
|
|
5616
|
+
exports.serializeFrontmatter = serializeFrontmatter2;
|
|
5617
|
+
var yaml = __importStar(require_js_yaml());
|
|
5618
|
+
function parseFrontmatter2(content) {
|
|
5619
|
+
const lines = content.split("\n");
|
|
5620
|
+
if (!lines[0] || lines[0].trim() !== "---") {
|
|
5621
|
+
return null;
|
|
5622
|
+
}
|
|
5623
|
+
let endIndex = -1;
|
|
5624
|
+
for (let i = 1; i < lines.length; i++) {
|
|
5625
|
+
if (lines[i].trim() === "---") {
|
|
5626
|
+
endIndex = i;
|
|
5627
|
+
break;
|
|
5628
|
+
}
|
|
5629
|
+
}
|
|
5630
|
+
if (endIndex === -1) {
|
|
5631
|
+
return null;
|
|
5632
|
+
}
|
|
5633
|
+
const yamlContent = lines.slice(1, endIndex).join("\n");
|
|
5634
|
+
const bodyContent = lines.slice(endIndex + 1).join("\n");
|
|
5635
|
+
let parsed;
|
|
5636
|
+
try {
|
|
5637
|
+
parsed = yaml.load(yamlContent);
|
|
5638
|
+
} catch {
|
|
5639
|
+
return null;
|
|
5640
|
+
}
|
|
5641
|
+
if (!parsed || typeof parsed !== "object") {
|
|
5642
|
+
return null;
|
|
5643
|
+
}
|
|
5644
|
+
return {
|
|
5645
|
+
data: parsed,
|
|
5646
|
+
body: bodyContent.replace(/^\n/, "")
|
|
5647
|
+
};
|
|
5648
|
+
}
|
|
5649
|
+
function serializeFrontmatter2(data, body = "") {
|
|
5650
|
+
const yamlContent = yaml.dump(data, {
|
|
5651
|
+
indent: 2,
|
|
5652
|
+
lineWidth: -1,
|
|
5653
|
+
noRefs: true,
|
|
5654
|
+
sortKeys: false,
|
|
5655
|
+
quotingType: '"',
|
|
5656
|
+
forceQuotes: false
|
|
5657
|
+
});
|
|
5658
|
+
const parts = ["---\n", yamlContent, "---\n"];
|
|
5659
|
+
if (body.length > 0) {
|
|
5660
|
+
parts.push("\n");
|
|
5661
|
+
parts.push(body);
|
|
5662
|
+
if (!body.endsWith("\n")) {
|
|
5663
|
+
parts.push("\n");
|
|
5664
|
+
}
|
|
5665
|
+
}
|
|
5666
|
+
return parts.join("");
|
|
5667
|
+
}
|
|
5668
|
+
}
|
|
5669
|
+
});
|
|
5670
|
+
|
|
5628
5671
|
// ../core/dist/validator.js
|
|
5629
5672
|
var require_validator = __commonJS({
|
|
5630
5673
|
"../core/dist/validator.js"(exports) {
|
|
@@ -5656,10 +5699,6 @@ var require_validator = __commonJS({
|
|
|
5656
5699
|
errors.push(...columnErrors);
|
|
5657
5700
|
});
|
|
5658
5701
|
}
|
|
5659
|
-
if (board.rules !== void 0) {
|
|
5660
|
-
const rulesErrors = this.validateRules(board.rules, "rules");
|
|
5661
|
-
errors.push(...rulesErrors);
|
|
5662
|
-
}
|
|
5663
5702
|
if (board.archive !== void 0) {
|
|
5664
5703
|
if (!Array.isArray(board.archive)) {
|
|
5665
5704
|
errors.push({ path: "archive", message: "Archive must be an array" });
|
|
@@ -5689,23 +5728,23 @@ var require_validator = __commonJS({
|
|
|
5689
5728
|
* @param path - The path for error reporting
|
|
5690
5729
|
* @returns Array of validation errors
|
|
5691
5730
|
*/
|
|
5692
|
-
static validateColumn(column,
|
|
5731
|
+
static validateColumn(column, path11) {
|
|
5693
5732
|
const errors = [];
|
|
5694
5733
|
if (!column) {
|
|
5695
|
-
errors.push({ path:
|
|
5734
|
+
errors.push({ path: path11, message: "Column is null or undefined" });
|
|
5696
5735
|
return errors;
|
|
5697
5736
|
}
|
|
5698
5737
|
if (typeof column.id !== "string" || column.id.trim() === "") {
|
|
5699
|
-
errors.push({ path: `${
|
|
5738
|
+
errors.push({ path: `${path11}.id`, message: "Column id must be a non-empty string" });
|
|
5700
5739
|
}
|
|
5701
5740
|
if (typeof column.title !== "string" || column.title.trim() === "") {
|
|
5702
|
-
errors.push({ path: `${
|
|
5741
|
+
errors.push({ path: `${path11}.title`, message: "Column title must be a non-empty string" });
|
|
5703
5742
|
}
|
|
5704
5743
|
if (column.tasks !== void 0 && !Array.isArray(column.tasks)) {
|
|
5705
|
-
errors.push({ path: `${
|
|
5744
|
+
errors.push({ path: `${path11}.tasks`, message: "Column tasks must be an array" });
|
|
5706
5745
|
} else if (Array.isArray(column.tasks)) {
|
|
5707
5746
|
column.tasks.forEach((task, index) => {
|
|
5708
|
-
const taskErrors = this.validateTask(task, `${
|
|
5747
|
+
const taskErrors = this.validateTask(task, `${path11}.tasks[${index}]`);
|
|
5709
5748
|
errors.push(...taskErrors);
|
|
5710
5749
|
});
|
|
5711
5750
|
}
|
|
@@ -5717,23 +5756,23 @@ var require_validator = __commonJS({
|
|
|
5717
5756
|
* @param path - The path for error reporting
|
|
5718
5757
|
* @returns Array of validation errors
|
|
5719
5758
|
*/
|
|
5720
|
-
static validateTask(task,
|
|
5759
|
+
static validateTask(task, path11) {
|
|
5721
5760
|
const errors = [];
|
|
5722
5761
|
if (!task) {
|
|
5723
|
-
errors.push({ path:
|
|
5762
|
+
errors.push({ path: path11, message: "Task is null or undefined" });
|
|
5724
5763
|
return errors;
|
|
5725
5764
|
}
|
|
5726
5765
|
if (typeof task.id !== "string" || task.id.trim() === "") {
|
|
5727
|
-
errors.push({ path: `${
|
|
5766
|
+
errors.push({ path: `${path11}.id`, message: "Task id must be a non-empty string" });
|
|
5728
5767
|
}
|
|
5729
5768
|
if (typeof task.title !== "string" || task.title.trim() === "") {
|
|
5730
|
-
errors.push({ path: `${
|
|
5769
|
+
errors.push({ path: `${path11}.title`, message: "Task title must be a non-empty string" });
|
|
5731
5770
|
}
|
|
5732
5771
|
if (task.priority !== void 0) {
|
|
5733
5772
|
const validPriorities = ["low", "medium", "high", "critical"];
|
|
5734
5773
|
if (!validPriorities.includes(task.priority)) {
|
|
5735
5774
|
errors.push({
|
|
5736
|
-
path: `${
|
|
5775
|
+
path: `${path11}.priority`,
|
|
5737
5776
|
message: `Task priority must be one of: ${validPriorities.join(", ")}`
|
|
5738
5777
|
});
|
|
5739
5778
|
}
|
|
@@ -5742,23 +5781,23 @@ var require_validator = __commonJS({
|
|
|
5742
5781
|
const validTemplates = ["bug", "feature", "refactor"];
|
|
5743
5782
|
if (!validTemplates.includes(task.template)) {
|
|
5744
5783
|
errors.push({
|
|
5745
|
-
path: `${
|
|
5784
|
+
path: `${path11}.template`,
|
|
5746
5785
|
message: `Task template must be one of: ${validTemplates.join(", ")}`
|
|
5747
5786
|
});
|
|
5748
5787
|
}
|
|
5749
5788
|
}
|
|
5750
5789
|
if (task.tags !== void 0 && !Array.isArray(task.tags)) {
|
|
5751
|
-
errors.push({ path: `${
|
|
5790
|
+
errors.push({ path: `${path11}.tags`, message: "Task tags must be an array" });
|
|
5752
5791
|
}
|
|
5753
5792
|
if (task.relatedFiles !== void 0 && !Array.isArray(task.relatedFiles)) {
|
|
5754
|
-
errors.push({ path: `${
|
|
5793
|
+
errors.push({ path: `${path11}.relatedFiles`, message: "Task relatedFiles must be an array" });
|
|
5755
5794
|
}
|
|
5756
5795
|
if (task.subtasks !== void 0) {
|
|
5757
5796
|
if (!Array.isArray(task.subtasks)) {
|
|
5758
|
-
errors.push({ path: `${
|
|
5797
|
+
errors.push({ path: `${path11}.subtasks`, message: "Task subtasks must be an array" });
|
|
5759
5798
|
} else {
|
|
5760
5799
|
task.subtasks.forEach((subtask, index) => {
|
|
5761
|
-
const subtaskErrors = this.validateSubtask(subtask, `${
|
|
5800
|
+
const subtaskErrors = this.validateSubtask(subtask, `${path11}.subtasks[${index}]`);
|
|
5762
5801
|
errors.push(...subtaskErrors);
|
|
5763
5802
|
});
|
|
5764
5803
|
}
|
|
@@ -5771,67 +5810,20 @@ var require_validator = __commonJS({
|
|
|
5771
5810
|
* @param path - The path for error reporting
|
|
5772
5811
|
* @returns Array of validation errors
|
|
5773
5812
|
*/
|
|
5774
|
-
static validateSubtask(subtask,
|
|
5813
|
+
static validateSubtask(subtask, path11) {
|
|
5775
5814
|
const errors = [];
|
|
5776
5815
|
if (!subtask) {
|
|
5777
|
-
errors.push({ path:
|
|
5816
|
+
errors.push({ path: path11, message: "Subtask is null or undefined" });
|
|
5778
5817
|
return errors;
|
|
5779
5818
|
}
|
|
5780
5819
|
if (typeof subtask.id !== "string" || subtask.id.trim() === "") {
|
|
5781
|
-
errors.push({ path: `${
|
|
5820
|
+
errors.push({ path: `${path11}.id`, message: "Subtask id must be a non-empty string" });
|
|
5782
5821
|
}
|
|
5783
5822
|
if (typeof subtask.title !== "string" || subtask.title.trim() === "") {
|
|
5784
|
-
errors.push({ path: `${
|
|
5823
|
+
errors.push({ path: `${path11}.title`, message: "Subtask title must be a non-empty string" });
|
|
5785
5824
|
}
|
|
5786
5825
|
if (typeof subtask.completed !== "boolean") {
|
|
5787
|
-
errors.push({ path: `${
|
|
5788
|
-
}
|
|
5789
|
-
return errors;
|
|
5790
|
-
}
|
|
5791
|
-
/**
|
|
5792
|
-
* Validate Rules object
|
|
5793
|
-
* @param rules - The rules to validate
|
|
5794
|
-
* @param path - The path for error reporting
|
|
5795
|
-
* @returns Array of validation errors
|
|
5796
|
-
*/
|
|
5797
|
-
static validateRules(rules, path7) {
|
|
5798
|
-
const errors = [];
|
|
5799
|
-
if (!rules) {
|
|
5800
|
-
errors.push({ path: path7, message: "Rules is null or undefined" });
|
|
5801
|
-
return errors;
|
|
5802
|
-
}
|
|
5803
|
-
const ruleTypes = ["always", "never", "prefer", "context"];
|
|
5804
|
-
ruleTypes.forEach((ruleType) => {
|
|
5805
|
-
if (rules[ruleType] !== void 0) {
|
|
5806
|
-
if (!Array.isArray(rules[ruleType])) {
|
|
5807
|
-
errors.push({ path: `${path7}.${ruleType}`, message: `Rules ${ruleType} must be an array` });
|
|
5808
|
-
} else {
|
|
5809
|
-
rules[ruleType].forEach((rule, index) => {
|
|
5810
|
-
const ruleErrors = this.validateRule(rule, `${path7}.${ruleType}[${index}]`);
|
|
5811
|
-
errors.push(...ruleErrors);
|
|
5812
|
-
});
|
|
5813
|
-
}
|
|
5814
|
-
}
|
|
5815
|
-
});
|
|
5816
|
-
return errors;
|
|
5817
|
-
}
|
|
5818
|
-
/**
|
|
5819
|
-
* Validate a Rule object
|
|
5820
|
-
* @param rule - The rule to validate
|
|
5821
|
-
* @param path - The path for error reporting
|
|
5822
|
-
* @returns Array of validation errors
|
|
5823
|
-
*/
|
|
5824
|
-
static validateRule(rule, path7) {
|
|
5825
|
-
const errors = [];
|
|
5826
|
-
if (!rule) {
|
|
5827
|
-
errors.push({ path: path7, message: "Rule is null or undefined" });
|
|
5828
|
-
return errors;
|
|
5829
|
-
}
|
|
5830
|
-
if (typeof rule.id !== "number") {
|
|
5831
|
-
errors.push({ path: `${path7}.id`, message: "Rule id must be a number" });
|
|
5832
|
-
}
|
|
5833
|
-
if (typeof rule.rule !== "string" || rule.rule.trim() === "") {
|
|
5834
|
-
errors.push({ path: `${path7}.rule`, message: "Rule rule must be a non-empty string" });
|
|
5826
|
+
errors.push({ path: `${path11}.completed`, message: "Subtask completed must be a boolean" });
|
|
5835
5827
|
}
|
|
5836
5828
|
return errors;
|
|
5837
5829
|
}
|
|
@@ -5886,10 +5878,6 @@ var require_validator = __commonJS({
|
|
|
5886
5878
|
errors.push(...entryErrors);
|
|
5887
5879
|
});
|
|
5888
5880
|
}
|
|
5889
|
-
if (journal.rules !== void 0) {
|
|
5890
|
-
const rulesErrors = this.validateRules(journal.rules, "rules");
|
|
5891
|
-
errors.push(...rulesErrors);
|
|
5892
|
-
}
|
|
5893
5881
|
return { valid: errors.length === 0, errors };
|
|
5894
5882
|
}
|
|
5895
5883
|
/**
|
|
@@ -5898,32 +5886,32 @@ var require_validator = __commonJS({
|
|
|
5898
5886
|
* @param path - The path for error reporting
|
|
5899
5887
|
* @returns Array of validation errors
|
|
5900
5888
|
*/
|
|
5901
|
-
static validateJournalEntry(entry,
|
|
5889
|
+
static validateJournalEntry(entry, path11) {
|
|
5902
5890
|
const errors = [];
|
|
5903
5891
|
if (!entry) {
|
|
5904
|
-
errors.push({ path:
|
|
5892
|
+
errors.push({ path: path11, message: "Entry is null or undefined" });
|
|
5905
5893
|
return errors;
|
|
5906
5894
|
}
|
|
5907
5895
|
if (typeof entry.id !== "string" || entry.id.trim() === "") {
|
|
5908
|
-
errors.push({ path: `${
|
|
5896
|
+
errors.push({ path: `${path11}.id`, message: "Entry id must be a non-empty string" });
|
|
5909
5897
|
}
|
|
5910
5898
|
if (typeof entry.title !== "string" || entry.title.trim() === "") {
|
|
5911
|
-
errors.push({ path: `${
|
|
5899
|
+
errors.push({ path: `${path11}.title`, message: "Entry title must be a non-empty string" });
|
|
5912
5900
|
}
|
|
5913
5901
|
if (typeof entry.createdAt !== "string" || entry.createdAt.trim() === "") {
|
|
5914
|
-
errors.push({ path: `${
|
|
5902
|
+
errors.push({ path: `${path11}.createdAt`, message: "Entry createdAt must be an ISO 8601 timestamp string" });
|
|
5915
5903
|
}
|
|
5916
5904
|
if (entry.content !== void 0 && typeof entry.content !== "string") {
|
|
5917
|
-
errors.push({ path: `${
|
|
5905
|
+
errors.push({ path: `${path11}.content`, message: "Entry content must be a string" });
|
|
5918
5906
|
}
|
|
5919
5907
|
if (entry.summary !== void 0 && typeof entry.summary !== "string") {
|
|
5920
|
-
errors.push({ path: `${
|
|
5908
|
+
errors.push({ path: `${path11}.summary`, message: "Entry summary must be a string" });
|
|
5921
5909
|
}
|
|
5922
5910
|
if (entry.mood !== void 0 && typeof entry.mood !== "string") {
|
|
5923
|
-
errors.push({ path: `${
|
|
5911
|
+
errors.push({ path: `${path11}.mood`, message: "Entry mood must be a string" });
|
|
5924
5912
|
}
|
|
5925
5913
|
if (entry.tags !== void 0 && !Array.isArray(entry.tags)) {
|
|
5926
|
-
errors.push({ path: `${
|
|
5914
|
+
errors.push({ path: `${path11}.tags`, message: "Entry tags must be an array" });
|
|
5927
5915
|
}
|
|
5928
5916
|
return errors;
|
|
5929
5917
|
}
|
|
@@ -5974,10 +5962,13 @@ var require_linter = __commonJS({
|
|
|
5974
5962
|
};
|
|
5975
5963
|
})();
|
|
5976
5964
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5977
|
-
exports.BrainfileLinter = void 0;
|
|
5965
|
+
exports.BrainfileLinter = exports.LEGACY_RULES_MESSAGE = void 0;
|
|
5978
5966
|
var yaml = __importStar(require_js_yaml());
|
|
5979
5967
|
var parser_1 = require_parser();
|
|
5980
5968
|
var validator_1 = require_validator();
|
|
5969
|
+
var frontmatter_1 = require_frontmatter();
|
|
5970
|
+
exports.LEGACY_RULES_MESSAGE = "rules is removed (adr-2); fold into agent.instructions";
|
|
5971
|
+
var RULE_CATEGORY_ORDER = ["always", "never", "prefer", "context"];
|
|
5981
5972
|
var BrainfileLinter = class {
|
|
5982
5973
|
/**
|
|
5983
5974
|
* Lint a brainfile.md content string
|
|
@@ -6004,6 +5995,21 @@ var require_linter = __commonJS({
|
|
|
6004
5995
|
fixedContent = this.fixUnquotedStrings(content, quotableStrings);
|
|
6005
5996
|
}
|
|
6006
5997
|
}
|
|
5998
|
+
const legacyRules = this.findLegacyRules(fixedContent);
|
|
5999
|
+
if (legacyRules) {
|
|
6000
|
+
issues.push({
|
|
6001
|
+
type: "warning",
|
|
6002
|
+
message: exports.LEGACY_RULES_MESSAGE,
|
|
6003
|
+
line: legacyRules.line,
|
|
6004
|
+
fixable: true,
|
|
6005
|
+
code: "LEGACY_RULES"
|
|
6006
|
+
});
|
|
6007
|
+
if (options.autoFix) {
|
|
6008
|
+
const folded = this.foldLegacyRules(fixedContent);
|
|
6009
|
+
if (folded !== null)
|
|
6010
|
+
fixedContent = folded;
|
|
6011
|
+
}
|
|
6012
|
+
}
|
|
6007
6013
|
const contentToValidate = options.autoFix && fixedContent !== content ? fixedContent : content;
|
|
6008
6014
|
const yamlIssues = this.checkYAMLSyntax(contentToValidate);
|
|
6009
6015
|
if (options.autoFix && fixedContent !== content) {
|
|
@@ -6064,6 +6070,62 @@ var require_linter = __commonJS({
|
|
|
6064
6070
|
board: board || void 0
|
|
6065
6071
|
};
|
|
6066
6072
|
}
|
|
6073
|
+
/**
|
|
6074
|
+
* Locate a legacy top-level `rules:` block in the frontmatter.
|
|
6075
|
+
*
|
|
6076
|
+
* Deliberately textual rather than YAML-object based: this must report a
|
|
6077
|
+
* usable line number, and it must still fire on a file whose frontmatter
|
|
6078
|
+
* fails to `yaml.load` for some unrelated reason.
|
|
6079
|
+
*/
|
|
6080
|
+
static findLegacyRules(content) {
|
|
6081
|
+
const lines = content.split("\n");
|
|
6082
|
+
if (!lines[0] || lines[0].trim() !== "---")
|
|
6083
|
+
return null;
|
|
6084
|
+
for (let i = 1; i < lines.length; i++) {
|
|
6085
|
+
if (lines[i].trim() === "---")
|
|
6086
|
+
return null;
|
|
6087
|
+
if (/^rules:\s*$/.test(lines[i]) || /^rules:\s+\S/.test(lines[i])) {
|
|
6088
|
+
return { line: i + 1 };
|
|
6089
|
+
}
|
|
6090
|
+
}
|
|
6091
|
+
return null;
|
|
6092
|
+
}
|
|
6093
|
+
/**
|
|
6094
|
+
* Fold a legacy `rules:` block into `agent.instructions` and remove it.
|
|
6095
|
+
*
|
|
6096
|
+
* Each rule becomes `"<category>: <text>"` (adr-2's stated shape), appended
|
|
6097
|
+
* in category order after any instructions already present. Returns null if
|
|
6098
|
+
* the frontmatter cannot be round-tripped, in which case the caller keeps
|
|
6099
|
+
* the original content and the warning stands unfixed.
|
|
6100
|
+
*/
|
|
6101
|
+
static foldLegacyRules(content) {
|
|
6102
|
+
const doc = (0, frontmatter_1.parseFrontmatter)(content);
|
|
6103
|
+
if (!doc)
|
|
6104
|
+
return null;
|
|
6105
|
+
const data = doc.data;
|
|
6106
|
+
const rules = data.rules;
|
|
6107
|
+
if (!rules || typeof rules !== "object" || Array.isArray(rules))
|
|
6108
|
+
return null;
|
|
6109
|
+
const folded = [];
|
|
6110
|
+
for (const category of RULE_CATEGORY_ORDER) {
|
|
6111
|
+
const entries = rules[category];
|
|
6112
|
+
if (!Array.isArray(entries))
|
|
6113
|
+
continue;
|
|
6114
|
+
for (const entry of entries) {
|
|
6115
|
+
const text = typeof entry === "string" ? entry : typeof entry?.rule === "string" ? entry.rule : null;
|
|
6116
|
+
if (text && text.trim())
|
|
6117
|
+
folded.push(`${category}: ${text.trim()}`);
|
|
6118
|
+
}
|
|
6119
|
+
}
|
|
6120
|
+
delete data.rules;
|
|
6121
|
+
if (folded.length > 0) {
|
|
6122
|
+
const agent = data.agent && typeof data.agent === "object" && !Array.isArray(data.agent) ? data.agent : {};
|
|
6123
|
+
const existing = Array.isArray(agent.instructions) ? agent.instructions.filter((i) => typeof i === "string") : [];
|
|
6124
|
+
agent.instructions = [...existing, ...folded];
|
|
6125
|
+
data.agent = agent;
|
|
6126
|
+
}
|
|
6127
|
+
return (0, frontmatter_1.serializeFrontmatter)(data, doc.body);
|
|
6128
|
+
}
|
|
6067
6129
|
/**
|
|
6068
6130
|
* Check YAML syntax by attempting to parse
|
|
6069
6131
|
*/
|
|
@@ -6212,14 +6274,12 @@ var require_realtimeDiff = __commonJS({
|
|
|
6212
6274
|
protocolVersion: previous.protocolVersion,
|
|
6213
6275
|
schema: previous.schema,
|
|
6214
6276
|
agent: previous.agent,
|
|
6215
|
-
rules: previous.rules,
|
|
6216
6277
|
statsConfig: previous.statsConfig
|
|
6217
6278
|
}, {
|
|
6218
6279
|
title: next.title,
|
|
6219
6280
|
protocolVersion: next.protocolVersion,
|
|
6220
6281
|
schema: next.schema,
|
|
6221
6282
|
agent: next.agent,
|
|
6222
|
-
rules: next.rules,
|
|
6223
6283
|
statsConfig: next.statsConfig
|
|
6224
6284
|
});
|
|
6225
6285
|
const columnIdToPrev = indexColumns(previous.columns);
|
|
@@ -6678,8 +6738,6 @@ var require_operations = __commonJS({
|
|
|
6678
6738
|
exports.updateSubtask = updateSubtask;
|
|
6679
6739
|
exports.setSubtasksCompleted = setSubtasksCompleted;
|
|
6680
6740
|
exports.setAllSubtasksCompleted = setAllSubtasksCompleted;
|
|
6681
|
-
exports.addRule = addRule;
|
|
6682
|
-
exports.deleteRule = deleteRule;
|
|
6683
6741
|
exports.moveTasks = moveTasks;
|
|
6684
6742
|
exports.patchTasks = patchTasks;
|
|
6685
6743
|
exports.deleteTasks = deleteTasks;
|
|
@@ -7162,55 +7220,6 @@ var require_operations = __commonJS({
|
|
|
7162
7220
|
};
|
|
7163
7221
|
return { success: true, board: newBoard };
|
|
7164
7222
|
}
|
|
7165
|
-
function addRule(board, ruleType, ruleText) {
|
|
7166
|
-
if (!ruleText || ruleText.trim() === "") {
|
|
7167
|
-
return { success: false, error: "Rule text is required" };
|
|
7168
|
-
}
|
|
7169
|
-
const trimmedRule = ruleText.trim();
|
|
7170
|
-
const existingRules = board.rules?.[ruleType] ?? [];
|
|
7171
|
-
const nextId = existingRules.reduce((maxId, rule) => Math.max(maxId, rule.id), 0) + 1;
|
|
7172
|
-
const newRule = {
|
|
7173
|
-
id: nextId,
|
|
7174
|
-
rule: trimmedRule
|
|
7175
|
-
};
|
|
7176
|
-
const updatedRulesForType = [...existingRules, newRule];
|
|
7177
|
-
const updatedRules = {
|
|
7178
|
-
...board.rules ?? {},
|
|
7179
|
-
[ruleType]: updatedRulesForType
|
|
7180
|
-
};
|
|
7181
|
-
return {
|
|
7182
|
-
success: true,
|
|
7183
|
-
board: {
|
|
7184
|
-
...board,
|
|
7185
|
-
rules: updatedRules
|
|
7186
|
-
}
|
|
7187
|
-
};
|
|
7188
|
-
}
|
|
7189
|
-
function deleteRule(board, ruleType, ruleId) {
|
|
7190
|
-
const rulesForType = board.rules?.[ruleType];
|
|
7191
|
-
if (!rulesForType || rulesForType.length === 0) {
|
|
7192
|
-
return { success: false, error: `Rule type ${ruleType} has no entries` };
|
|
7193
|
-
}
|
|
7194
|
-
const exists = rulesForType.some((rule) => rule.id === ruleId);
|
|
7195
|
-
if (!exists) {
|
|
7196
|
-
return { success: false, error: `Rule ${ruleId} not found in ${ruleType}` };
|
|
7197
|
-
}
|
|
7198
|
-
const updatedRulesForType = rulesForType.filter((rule) => rule.id !== ruleId);
|
|
7199
|
-
const updatedRules = { ...board.rules ?? {} };
|
|
7200
|
-
if (updatedRulesForType.length > 0) {
|
|
7201
|
-
updatedRules[ruleType] = updatedRulesForType;
|
|
7202
|
-
} else {
|
|
7203
|
-
delete updatedRules[ruleType];
|
|
7204
|
-
}
|
|
7205
|
-
const hasAnyRules = Object.values(updatedRules).some((collection) => collection !== void 0 && collection.length > 0);
|
|
7206
|
-
return {
|
|
7207
|
-
success: true,
|
|
7208
|
-
board: {
|
|
7209
|
-
...board,
|
|
7210
|
-
rules: hasAnyRules ? updatedRules : void 0
|
|
7211
|
-
}
|
|
7212
|
-
};
|
|
7213
|
-
}
|
|
7214
7223
|
function moveTasks(board, taskIds, toColumnId) {
|
|
7215
7224
|
const results = [];
|
|
7216
7225
|
let currentBoard = board;
|
|
@@ -7434,8 +7443,8 @@ var require_discovery = __commonJS({
|
|
|
7434
7443
|
exports.findPrimaryBrainfile = findPrimaryBrainfile;
|
|
7435
7444
|
exports.findNearestBrainfile = findNearestBrainfile;
|
|
7436
7445
|
exports.watchBrainfiles = watchBrainfiles;
|
|
7437
|
-
var
|
|
7438
|
-
var
|
|
7446
|
+
var fs11 = __importStar(__require("fs"));
|
|
7447
|
+
var path11 = __importStar(__require("path"));
|
|
7439
7448
|
var parser_1 = require_parser();
|
|
7440
7449
|
var query_1 = require_query();
|
|
7441
7450
|
exports.BRAINFILE_PATTERNS = [
|
|
@@ -7471,7 +7480,7 @@ var require_discovery = __commonJS({
|
|
|
7471
7480
|
"vendor"
|
|
7472
7481
|
];
|
|
7473
7482
|
function isBrainfileName(filename) {
|
|
7474
|
-
const name =
|
|
7483
|
+
const name = path11.basename(filename).toLowerCase();
|
|
7475
7484
|
if (name === "brainfile.md" || name === ".brainfile.md" || name === ".bb.md") {
|
|
7476
7485
|
return true;
|
|
7477
7486
|
}
|
|
@@ -7481,11 +7490,11 @@ var require_discovery = __commonJS({
|
|
|
7481
7490
|
return false;
|
|
7482
7491
|
}
|
|
7483
7492
|
function shouldExclude(filePath, excludeDirs) {
|
|
7484
|
-
const parts = filePath.split(
|
|
7493
|
+
const parts = filePath.split(path11.sep);
|
|
7485
7494
|
return parts.some((part) => excludeDirs.includes(part));
|
|
7486
7495
|
}
|
|
7487
7496
|
function extractBrainfileSuffix(filename) {
|
|
7488
|
-
const name =
|
|
7497
|
+
const name = path11.basename(filename).toLowerCase();
|
|
7489
7498
|
if (name.startsWith("brainfile.") && name.endsWith(".md") && name !== "brainfile.md") {
|
|
7490
7499
|
const withoutPrefix = name.slice("brainfile.".length);
|
|
7491
7500
|
const suffix = withoutPrefix.slice(0, -".md".length);
|
|
@@ -7505,10 +7514,10 @@ var require_discovery = __commonJS({
|
|
|
7505
7514
|
}
|
|
7506
7515
|
function parseFileMetadata(absolutePath, relativePath) {
|
|
7507
7516
|
try {
|
|
7508
|
-
const content =
|
|
7517
|
+
const content = fs11.readFileSync(absolutePath, "utf-8");
|
|
7509
7518
|
const board = parser_1.BrainfileParser.parse(content);
|
|
7510
|
-
const stats =
|
|
7511
|
-
const filename =
|
|
7519
|
+
const stats = fs11.statSync(absolutePath);
|
|
7520
|
+
const filename = path11.basename(absolutePath);
|
|
7512
7521
|
const isHidden = filename.startsWith(".");
|
|
7513
7522
|
if (board) {
|
|
7514
7523
|
return {
|
|
@@ -7542,10 +7551,10 @@ var require_discovery = __commonJS({
|
|
|
7542
7551
|
return results;
|
|
7543
7552
|
}
|
|
7544
7553
|
try {
|
|
7545
|
-
const entries =
|
|
7554
|
+
const entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
7546
7555
|
for (const entry of entries) {
|
|
7547
|
-
const fullPath =
|
|
7548
|
-
const relativePath =
|
|
7556
|
+
const fullPath = path11.join(dir, entry.name);
|
|
7557
|
+
const relativePath = path11.relative(rootDir, fullPath);
|
|
7549
7558
|
if (entry.isDirectory()) {
|
|
7550
7559
|
if (shouldExclude(entry.name, options.excludeDirs)) {
|
|
7551
7560
|
continue;
|
|
@@ -7577,11 +7586,11 @@ var require_discovery = __commonJS({
|
|
|
7577
7586
|
maxDepth: options.maxDepth ?? 10,
|
|
7578
7587
|
excludeDirs: options.excludeDirs ?? [...exports.EXCLUDE_DIRS]
|
|
7579
7588
|
};
|
|
7580
|
-
const absoluteRoot =
|
|
7589
|
+
const absoluteRoot = path11.resolve(rootDir);
|
|
7581
7590
|
const files = findBrainfilesRecursive(absoluteRoot, absoluteRoot, opts);
|
|
7582
7591
|
files.sort((a, b) => {
|
|
7583
|
-
const aDepth = a.relativePath.split(
|
|
7584
|
-
const bDepth = b.relativePath.split(
|
|
7592
|
+
const aDepth = a.relativePath.split(path11.sep).length;
|
|
7593
|
+
const bDepth = b.relativePath.split(path11.sep).length;
|
|
7585
7594
|
if (aDepth !== bDepth) {
|
|
7586
7595
|
return aDepth - bDepth;
|
|
7587
7596
|
}
|
|
@@ -7595,17 +7604,17 @@ var require_discovery = __commonJS({
|
|
|
7595
7604
|
};
|
|
7596
7605
|
}
|
|
7597
7606
|
function findPrimaryBrainfile(rootDir) {
|
|
7598
|
-
const absoluteRoot =
|
|
7599
|
-
const preferred =
|
|
7600
|
-
if (
|
|
7601
|
-
const metadata = parseFileMetadata(preferred,
|
|
7607
|
+
const absoluteRoot = path11.resolve(rootDir);
|
|
7608
|
+
const preferred = path11.join(absoluteRoot, ".brainfile", "brainfile.md");
|
|
7609
|
+
if (fs11.existsSync(preferred)) {
|
|
7610
|
+
const metadata = parseFileMetadata(preferred, path11.join(".brainfile", "brainfile.md"));
|
|
7602
7611
|
if (metadata)
|
|
7603
7612
|
return metadata;
|
|
7604
7613
|
}
|
|
7605
7614
|
const priorityNames = ["brainfile.md", ".brainfile.md", ".bb.md"];
|
|
7606
7615
|
for (const name of priorityNames) {
|
|
7607
|
-
const fullPath =
|
|
7608
|
-
if (
|
|
7616
|
+
const fullPath = path11.join(absoluteRoot, name);
|
|
7617
|
+
if (fs11.existsSync(fullPath)) {
|
|
7609
7618
|
const metadata = parseFileMetadata(fullPath, name);
|
|
7610
7619
|
if (metadata) {
|
|
7611
7620
|
return metadata;
|
|
@@ -7613,11 +7622,11 @@ var require_discovery = __commonJS({
|
|
|
7613
7622
|
}
|
|
7614
7623
|
}
|
|
7615
7624
|
try {
|
|
7616
|
-
const entries =
|
|
7625
|
+
const entries = fs11.readdirSync(absoluteRoot);
|
|
7617
7626
|
for (const entry of entries) {
|
|
7618
7627
|
if (isBrainfileName(entry) && !priorityNames.includes(entry.toLowerCase())) {
|
|
7619
|
-
const fullPath =
|
|
7620
|
-
const stats =
|
|
7628
|
+
const fullPath = path11.join(absoluteRoot, entry);
|
|
7629
|
+
const stats = fs11.statSync(fullPath);
|
|
7621
7630
|
if (stats.isFile()) {
|
|
7622
7631
|
const metadata = parseFileMetadata(fullPath, entry);
|
|
7623
7632
|
if (metadata) {
|
|
@@ -7631,14 +7640,14 @@ var require_discovery = __commonJS({
|
|
|
7631
7640
|
return null;
|
|
7632
7641
|
}
|
|
7633
7642
|
function findNearestBrainfile(startDir) {
|
|
7634
|
-
let currentDir =
|
|
7635
|
-
const root =
|
|
7643
|
+
let currentDir = path11.resolve(startDir || process.cwd());
|
|
7644
|
+
const root = path11.parse(currentDir).root;
|
|
7636
7645
|
while (currentDir !== root) {
|
|
7637
7646
|
const found = findPrimaryBrainfile(currentDir);
|
|
7638
7647
|
if (found) {
|
|
7639
7648
|
return found;
|
|
7640
7649
|
}
|
|
7641
|
-
const parentDir =
|
|
7650
|
+
const parentDir = path11.dirname(currentDir);
|
|
7642
7651
|
if (parentDir === currentDir) {
|
|
7643
7652
|
break;
|
|
7644
7653
|
}
|
|
@@ -7651,11 +7660,11 @@ var require_discovery = __commonJS({
|
|
|
7651
7660
|
return null;
|
|
7652
7661
|
}
|
|
7653
7662
|
function watchBrainfiles(rootDir, callback, onError) {
|
|
7654
|
-
const absoluteRoot =
|
|
7663
|
+
const absoluteRoot = path11.resolve(rootDir);
|
|
7655
7664
|
let watcher = null;
|
|
7656
7665
|
let active = false;
|
|
7657
7666
|
try {
|
|
7658
|
-
const stats =
|
|
7667
|
+
const stats = fs11.statSync(absoluteRoot);
|
|
7659
7668
|
if (!stats.isDirectory()) {
|
|
7660
7669
|
return {
|
|
7661
7670
|
success: false,
|
|
@@ -7684,13 +7693,13 @@ var require_discovery = __commonJS({
|
|
|
7684
7693
|
};
|
|
7685
7694
|
}
|
|
7686
7695
|
try {
|
|
7687
|
-
watcher =
|
|
7696
|
+
watcher = fs11.watch(absoluteRoot, (eventType, filename) => {
|
|
7688
7697
|
if (!active || !filename || !isBrainfileName(filename))
|
|
7689
7698
|
return;
|
|
7690
|
-
const fullPath =
|
|
7699
|
+
const fullPath = path11.join(absoluteRoot, filename);
|
|
7691
7700
|
try {
|
|
7692
7701
|
if (eventType === "rename") {
|
|
7693
|
-
if (
|
|
7702
|
+
if (fs11.existsSync(fullPath)) {
|
|
7694
7703
|
const metadata = parseFileMetadata(fullPath, filename);
|
|
7695
7704
|
if (metadata) {
|
|
7696
7705
|
callback("add", metadata);
|
|
@@ -7797,7 +7806,7 @@ var require_files = __commonJS({
|
|
|
7797
7806
|
};
|
|
7798
7807
|
})();
|
|
7799
7808
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7800
|
-
exports.DOT_BRAINFILE_GITIGNORE_BASENAME = exports.BRAINFILE_STATE_BASENAME = exports.BRAINFILE_BASENAME = exports.DOT_BRAINFILE_DIRNAME = void 0;
|
|
7809
|
+
exports.DOT_BRAINFILE_STATE_IGNORE_ENTRY = exports.DOT_BRAINFILE_STATE_DIRNAME = exports.DOT_BRAINFILE_GITIGNORE_BASENAME = exports.BRAINFILE_STATE_BASENAME = exports.BRAINFILE_BASENAME = exports.DOT_BRAINFILE_DIRNAME = void 0;
|
|
7801
7810
|
exports.findBrainfile = findBrainfile2;
|
|
7802
7811
|
exports.resolveBrainfilePath = resolveBrainfilePath2;
|
|
7803
7812
|
exports.getBrainfileStateDir = getBrainfileStateDir;
|
|
@@ -7805,45 +7814,53 @@ var require_files = __commonJS({
|
|
|
7805
7814
|
exports.getDotBrainfileGitignorePath = getDotBrainfileGitignorePath;
|
|
7806
7815
|
exports.ensureDotBrainfileDir = ensureDotBrainfileDir;
|
|
7807
7816
|
exports.ensureDotBrainfileGitignore = ensureDotBrainfileGitignore;
|
|
7808
|
-
|
|
7809
|
-
var
|
|
7817
|
+
exports.atomicWriteFileSync = atomicWriteFileSync;
|
|
7818
|
+
var fs11 = __importStar(__require("fs"));
|
|
7819
|
+
var path11 = __importStar(__require("path"));
|
|
7810
7820
|
exports.DOT_BRAINFILE_DIRNAME = ".brainfile";
|
|
7811
7821
|
exports.BRAINFILE_BASENAME = "brainfile.md";
|
|
7812
7822
|
exports.BRAINFILE_STATE_BASENAME = "state.json";
|
|
7813
7823
|
exports.DOT_BRAINFILE_GITIGNORE_BASENAME = ".gitignore";
|
|
7824
|
+
exports.DOT_BRAINFILE_STATE_DIRNAME = "state";
|
|
7825
|
+
exports.DOT_BRAINFILE_STATE_IGNORE_ENTRY = "state/";
|
|
7814
7826
|
function toAbsolute(p) {
|
|
7815
|
-
return
|
|
7827
|
+
return path11.isAbsolute(p) ? p : path11.resolve(p);
|
|
7816
7828
|
}
|
|
7817
7829
|
function existsFile2(p) {
|
|
7818
7830
|
try {
|
|
7819
|
-
return
|
|
7831
|
+
return fs11.statSync(p).isFile();
|
|
7820
7832
|
} catch {
|
|
7821
7833
|
return false;
|
|
7822
7834
|
}
|
|
7823
7835
|
}
|
|
7824
|
-
function
|
|
7825
|
-
|
|
7826
|
-
|
|
7836
|
+
function isGitBoundary(dir) {
|
|
7837
|
+
return fs11.existsSync(path11.join(dir, ".git"));
|
|
7838
|
+
}
|
|
7839
|
+
function findBrainfile2(startDir = process.cwd(), options = {}) {
|
|
7840
|
+
let currentDir = path11.resolve(startDir);
|
|
7841
|
+
const root = path11.parse(currentDir).root;
|
|
7827
7842
|
while (true) {
|
|
7828
|
-
const preferred =
|
|
7843
|
+
const preferred = path11.join(currentDir, exports.DOT_BRAINFILE_DIRNAME, exports.BRAINFILE_BASENAME);
|
|
7829
7844
|
if (existsFile2(preferred)) {
|
|
7830
7845
|
return { absolutePath: preferred, projectRoot: currentDir, kind: "dotdir" };
|
|
7831
7846
|
}
|
|
7832
|
-
const legacy =
|
|
7847
|
+
const legacy = path11.join(currentDir, exports.BRAINFILE_BASENAME);
|
|
7833
7848
|
if (existsFile2(legacy)) {
|
|
7834
7849
|
return { absolutePath: legacy, projectRoot: currentDir, kind: "root" };
|
|
7835
7850
|
}
|
|
7836
|
-
const hiddenLegacy =
|
|
7851
|
+
const hiddenLegacy = path11.join(currentDir, ".brainfile.md");
|
|
7837
7852
|
if (existsFile2(hiddenLegacy)) {
|
|
7838
7853
|
return { absolutePath: hiddenLegacy, projectRoot: currentDir, kind: "hidden" };
|
|
7839
7854
|
}
|
|
7840
|
-
const bbLegacy =
|
|
7855
|
+
const bbLegacy = path11.join(currentDir, ".bb.md");
|
|
7841
7856
|
if (existsFile2(bbLegacy)) {
|
|
7842
7857
|
return { absolutePath: bbLegacy, projectRoot: currentDir, kind: "bb" };
|
|
7843
7858
|
}
|
|
7859
|
+
if (options.stopAtGitRoot && isGitBoundary(currentDir))
|
|
7860
|
+
break;
|
|
7844
7861
|
if (currentDir === root)
|
|
7845
7862
|
break;
|
|
7846
|
-
const parent =
|
|
7863
|
+
const parent = path11.dirname(currentDir);
|
|
7847
7864
|
if (parent === currentDir)
|
|
7848
7865
|
break;
|
|
7849
7866
|
currentDir = parent;
|
|
@@ -7851,192 +7868,99 @@ var require_files = __commonJS({
|
|
|
7851
7868
|
return null;
|
|
7852
7869
|
}
|
|
7853
7870
|
function resolveBrainfilePath2(options = {}) {
|
|
7854
|
-
const startDir = options.startDir ?
|
|
7871
|
+
const startDir = options.startDir ? path11.resolve(options.startDir) : process.cwd();
|
|
7855
7872
|
const filePath = options.filePath;
|
|
7856
7873
|
const isDefaultPlaceholder = filePath === void 0 || filePath === exports.BRAINFILE_BASENAME || filePath === `./${exports.BRAINFILE_BASENAME}`;
|
|
7857
7874
|
if (isDefaultPlaceholder) {
|
|
7858
|
-
const found = findBrainfile2(startDir);
|
|
7875
|
+
const found = findBrainfile2(startDir, { stopAtGitRoot: options.stopAtGitRoot });
|
|
7859
7876
|
if (found)
|
|
7860
7877
|
return found.absolutePath;
|
|
7861
7878
|
return toAbsolute(filePath ?? exports.BRAINFILE_BASENAME);
|
|
7862
7879
|
}
|
|
7863
|
-
return toAbsolute(
|
|
7880
|
+
return toAbsolute(path11.isAbsolute(filePath) ? filePath : path11.resolve(startDir, filePath));
|
|
7864
7881
|
}
|
|
7865
7882
|
function getBrainfileStateDir(brainfilePath) {
|
|
7866
7883
|
const abs = toAbsolute(brainfilePath);
|
|
7867
|
-
const dir =
|
|
7868
|
-
if (
|
|
7884
|
+
const dir = path11.dirname(abs);
|
|
7885
|
+
if (path11.basename(dir) === exports.DOT_BRAINFILE_DIRNAME)
|
|
7869
7886
|
return dir;
|
|
7870
|
-
return
|
|
7887
|
+
return path11.join(dir, exports.DOT_BRAINFILE_DIRNAME);
|
|
7871
7888
|
}
|
|
7872
7889
|
function getBrainfileStatePath(brainfilePath) {
|
|
7873
|
-
return
|
|
7890
|
+
return path11.join(getBrainfileStateDir(brainfilePath), exports.BRAINFILE_STATE_BASENAME);
|
|
7874
7891
|
}
|
|
7875
7892
|
function getDotBrainfileGitignorePath(brainfilePath) {
|
|
7876
|
-
return
|
|
7893
|
+
return path11.join(getBrainfileStateDir(brainfilePath), exports.DOT_BRAINFILE_GITIGNORE_BASENAME);
|
|
7877
7894
|
}
|
|
7878
7895
|
function ensureDotBrainfileDir(brainfilePath) {
|
|
7879
7896
|
const dir = getBrainfileStateDir(brainfilePath);
|
|
7880
|
-
|
|
7897
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
7881
7898
|
return dir;
|
|
7882
7899
|
}
|
|
7883
7900
|
function ensureDotBrainfileGitignore(brainfilePath) {
|
|
7884
7901
|
ensureDotBrainfileDir(brainfilePath);
|
|
7885
7902
|
const gitignorePath = getDotBrainfileGitignorePath(brainfilePath);
|
|
7886
|
-
const existing =
|
|
7887
|
-
const
|
|
7888
|
-
|
|
7903
|
+
const existing = fs11.existsSync(gitignorePath) ? fs11.readFileSync(gitignorePath, "utf-8") : "";
|
|
7904
|
+
const lines = existing.split(/\r?\n/).filter((line) => line.trim() !== exports.BRAINFILE_STATE_BASENAME);
|
|
7905
|
+
const hasStateDir = lines.some((line) => line.trim() === exports.DOT_BRAINFILE_STATE_IGNORE_ENTRY);
|
|
7906
|
+
if (!hasStateDir) {
|
|
7907
|
+
lines.push(exports.DOT_BRAINFILE_STATE_IGNORE_ENTRY);
|
|
7908
|
+
}
|
|
7909
|
+
const filtered = lines.join("\n").trim();
|
|
7910
|
+
fs11.writeFileSync(gitignorePath, filtered.length > 0 ? `${filtered}
|
|
7889
7911
|
` : "", "utf-8");
|
|
7890
7912
|
}
|
|
7913
|
+
function atomicWriteFileSync(filePath, content) {
|
|
7914
|
+
const abs = toAbsolute(filePath);
|
|
7915
|
+
const dir = path11.dirname(abs);
|
|
7916
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
7917
|
+
const tmp = path11.join(dir, `.${path11.basename(abs)}.tmp-${process.pid}-${Date.now()}`);
|
|
7918
|
+
try {
|
|
7919
|
+
fs11.writeFileSync(tmp, content, "utf-8");
|
|
7920
|
+
fs11.renameSync(tmp, abs);
|
|
7921
|
+
} catch (err) {
|
|
7922
|
+
try {
|
|
7923
|
+
if (fs11.existsSync(tmp))
|
|
7924
|
+
fs11.unlinkSync(tmp);
|
|
7925
|
+
} catch {
|
|
7926
|
+
}
|
|
7927
|
+
throw err;
|
|
7928
|
+
}
|
|
7929
|
+
}
|
|
7891
7930
|
}
|
|
7892
7931
|
});
|
|
7893
7932
|
|
|
7894
|
-
// ../core/dist/
|
|
7895
|
-
var
|
|
7896
|
-
"../core/dist/
|
|
7933
|
+
// ../core/dist/taskContent.js
|
|
7934
|
+
var require_taskContent = __commonJS({
|
|
7935
|
+
"../core/dist/taskContent.js"(exports) {
|
|
7897
7936
|
"use strict";
|
|
7898
7937
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7899
|
-
exports.
|
|
7900
|
-
exports.
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
const
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
sections.push(task.description);
|
|
7907
|
-
}
|
|
7908
|
-
if (includeSubtasks && task.subtasks && task.subtasks.length > 0) {
|
|
7909
|
-
sections.push(formatSubtasksMarkdown(task.subtasks));
|
|
7910
|
-
}
|
|
7911
|
-
if (includeMeta) {
|
|
7912
|
-
const meta = formatMetadataSection(task, { fromColumn, boardTitle });
|
|
7913
|
-
if (meta) {
|
|
7914
|
-
sections.push(meta);
|
|
7915
|
-
}
|
|
7916
|
-
}
|
|
7917
|
-
if (includeRelatedFiles && task.relatedFiles && task.relatedFiles.length > 0) {
|
|
7918
|
-
sections.push(formatRelatedFilesSection(task.relatedFiles));
|
|
7919
|
-
}
|
|
7920
|
-
if (resolvedBy || resolvedByPR) {
|
|
7921
|
-
sections.push(formatResolutionSection(resolvedBy, resolvedByPR));
|
|
7922
|
-
}
|
|
7923
|
-
sections.push("---\n*Archived from brainfile.md*");
|
|
7924
|
-
const labels = [...task.tags || [], ...extraLabels];
|
|
7925
|
-
if (task.priority) {
|
|
7926
|
-
labels.push(`priority:${task.priority}`);
|
|
7938
|
+
exports.parseTaskContent = parseTaskContent;
|
|
7939
|
+
exports.serializeTaskContent = serializeTaskContent;
|
|
7940
|
+
var frontmatter_1 = require_frontmatter();
|
|
7941
|
+
function parseTaskContent(content) {
|
|
7942
|
+
const parsed = (0, frontmatter_1.parseFrontmatter)(content);
|
|
7943
|
+
if (!parsed) {
|
|
7944
|
+
return null;
|
|
7927
7945
|
}
|
|
7928
|
-
|
|
7929
|
-
|
|
7946
|
+
const task = parsed.data;
|
|
7947
|
+
if (!task.id || !task.title) {
|
|
7948
|
+
return null;
|
|
7930
7949
|
}
|
|
7931
7950
|
return {
|
|
7932
|
-
|
|
7933
|
-
body:
|
|
7934
|
-
labels: labels.length > 0 ? labels : void 0,
|
|
7935
|
-
state: "closed"
|
|
7951
|
+
task,
|
|
7952
|
+
body: parsed.body
|
|
7936
7953
|
};
|
|
7937
7954
|
}
|
|
7938
|
-
function
|
|
7939
|
-
|
|
7940
|
-
case "critical":
|
|
7941
|
-
return 1;
|
|
7942
|
-
case "high":
|
|
7943
|
-
return 2;
|
|
7944
|
-
case "medium":
|
|
7945
|
-
return 3;
|
|
7946
|
-
case "low":
|
|
7947
|
-
return 4;
|
|
7948
|
-
default:
|
|
7949
|
-
return void 0;
|
|
7950
|
-
}
|
|
7951
|
-
}
|
|
7952
|
-
function formatTaskForLinear(task, options = {}) {
|
|
7953
|
-
const { includeMeta = true, includeSubtasks = true, includeRelatedFiles = true, resolvedBy, resolvedByPR, fromColumn, boardTitle, stateName = "Done", includeTaskId = false } = options;
|
|
7954
|
-
const title = includeTaskId ? `[${task.id}] ${task.title}` : task.title;
|
|
7955
|
-
const sections = [];
|
|
7956
|
-
if (task.description) {
|
|
7957
|
-
sections.push(task.description);
|
|
7958
|
-
}
|
|
7959
|
-
if (includeSubtasks && task.subtasks && task.subtasks.length > 0) {
|
|
7960
|
-
sections.push(formatSubtasksMarkdown(task.subtasks));
|
|
7961
|
-
}
|
|
7962
|
-
if (includeMeta) {
|
|
7963
|
-
const meta = formatMetadataSection(task, { fromColumn, boardTitle });
|
|
7964
|
-
if (meta) {
|
|
7965
|
-
sections.push(meta);
|
|
7966
|
-
}
|
|
7967
|
-
}
|
|
7968
|
-
if (includeRelatedFiles && task.relatedFiles && task.relatedFiles.length > 0) {
|
|
7969
|
-
sections.push(formatRelatedFilesSection(task.relatedFiles));
|
|
7970
|
-
}
|
|
7971
|
-
if (resolvedBy || resolvedByPR) {
|
|
7972
|
-
sections.push(formatResolutionSection(resolvedBy, resolvedByPR));
|
|
7973
|
-
}
|
|
7974
|
-
sections.push("---\n*Archived from brainfile.md*");
|
|
7975
|
-
return {
|
|
7976
|
-
title,
|
|
7977
|
-
description: sections.join("\n\n"),
|
|
7978
|
-
priority: mapPriorityToLinear(task.priority),
|
|
7979
|
-
labelNames: task.tags && task.tags.length > 0 ? task.tags : void 0,
|
|
7980
|
-
stateName
|
|
7981
|
-
};
|
|
7982
|
-
}
|
|
7983
|
-
function formatSubtasksMarkdown(subtasks) {
|
|
7984
|
-
const items = subtasks.map((st) => `- [${st.completed ? "x" : " "}] ${st.title}`);
|
|
7985
|
-
return `## Subtasks
|
|
7986
|
-
|
|
7987
|
-
${items.join("\n")}`;
|
|
7988
|
-
}
|
|
7989
|
-
function formatMetadataSection(task, context) {
|
|
7990
|
-
const lines = [];
|
|
7991
|
-
if (context.boardTitle) {
|
|
7992
|
-
lines.push(`**Board:** ${context.boardTitle}`);
|
|
7993
|
-
}
|
|
7994
|
-
if (context.fromColumn) {
|
|
7995
|
-
lines.push(`**Column:** ${context.fromColumn}`);
|
|
7996
|
-
}
|
|
7997
|
-
if (task.priority) {
|
|
7998
|
-
lines.push(`**Priority:** ${task.priority}`);
|
|
7999
|
-
}
|
|
8000
|
-
if (task.assignee) {
|
|
8001
|
-
lines.push(`**Assignee:** ${task.assignee}`);
|
|
8002
|
-
}
|
|
8003
|
-
if (task.dueDate) {
|
|
8004
|
-
lines.push(`**Due Date:** ${task.dueDate}`);
|
|
8005
|
-
}
|
|
8006
|
-
if (task.createdAt) {
|
|
8007
|
-
lines.push(`**Created:** ${task.createdAt}`);
|
|
8008
|
-
}
|
|
8009
|
-
if (lines.length === 0) {
|
|
8010
|
-
return null;
|
|
8011
|
-
}
|
|
8012
|
-
return `## Details
|
|
8013
|
-
|
|
8014
|
-
${lines.join("\n")}`;
|
|
8015
|
-
}
|
|
8016
|
-
function formatRelatedFilesSection(files) {
|
|
8017
|
-
const items = files.map((f) => `- \`${f}\``);
|
|
8018
|
-
return `## Related Files
|
|
8019
|
-
|
|
8020
|
-
${items.join("\n")}`;
|
|
8021
|
-
}
|
|
8022
|
-
function formatResolutionSection(resolvedBy, resolvedByPR) {
|
|
8023
|
-
const lines = ["## Resolution"];
|
|
8024
|
-
if (resolvedByPR) {
|
|
8025
|
-
lines.push(`
|
|
8026
|
-
**Pull Request:** ${resolvedByPR}`);
|
|
8027
|
-
}
|
|
8028
|
-
if (resolvedBy) {
|
|
8029
|
-
lines.push(`
|
|
8030
|
-
**Commit:** ${resolvedBy}`);
|
|
8031
|
-
}
|
|
8032
|
-
return lines.join("");
|
|
7955
|
+
function serializeTaskContent(task, body = "") {
|
|
7956
|
+
return (0, frontmatter_1.serializeFrontmatter)(task, body);
|
|
8033
7957
|
}
|
|
8034
7958
|
}
|
|
8035
7959
|
});
|
|
8036
7960
|
|
|
8037
|
-
// ../core/dist/
|
|
8038
|
-
var
|
|
8039
|
-
"../core/dist/
|
|
7961
|
+
// ../core/dist/taskFile.js
|
|
7962
|
+
var require_taskFile = __commonJS({
|
|
7963
|
+
"../core/dist/taskFile.js"(exports) {
|
|
8040
7964
|
"use strict";
|
|
8041
7965
|
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
8042
7966
|
if (k2 === void 0) k2 = k;
|
|
@@ -8076,89 +8000,89 @@ var require_frontmatter = __commonJS({
|
|
|
8076
8000
|
};
|
|
8077
8001
|
})();
|
|
8078
8002
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8079
|
-
exports.
|
|
8080
|
-
exports.
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8003
|
+
exports.serializeTaskContent = exports.parseTaskContent = void 0;
|
|
8004
|
+
exports.readTaskFile = readTaskFile;
|
|
8005
|
+
exports.writeTaskFile = writeTaskFile;
|
|
8006
|
+
exports.readTasksDir = readTasksDir;
|
|
8007
|
+
exports.taskFileName = taskFileName;
|
|
8008
|
+
var fs11 = __importStar(__require("fs"));
|
|
8009
|
+
var path11 = __importStar(__require("path"));
|
|
8010
|
+
var taskContent_1 = require_taskContent();
|
|
8011
|
+
var taskContent_2 = require_taskContent();
|
|
8012
|
+
Object.defineProperty(exports, "parseTaskContent", { enumerable: true, get: function() {
|
|
8013
|
+
return taskContent_2.parseTaskContent;
|
|
8014
|
+
} });
|
|
8015
|
+
Object.defineProperty(exports, "serializeTaskContent", { enumerable: true, get: function() {
|
|
8016
|
+
return taskContent_2.serializeTaskContent;
|
|
8017
|
+
} });
|
|
8018
|
+
function isUnsafeTaskId(taskId) {
|
|
8019
|
+
if (!taskId || taskId.trim() === "") {
|
|
8020
|
+
return true;
|
|
8086
8021
|
}
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
endIndex = i;
|
|
8091
|
-
break;
|
|
8092
|
-
}
|
|
8022
|
+
const trimmed = taskId.trim();
|
|
8023
|
+
if (trimmed.includes("/") || trimmed.includes("\\") || trimmed.includes("..")) {
|
|
8024
|
+
return true;
|
|
8093
8025
|
}
|
|
8094
|
-
if (
|
|
8095
|
-
return
|
|
8026
|
+
if (path11.isAbsolute(trimmed)) {
|
|
8027
|
+
return true;
|
|
8096
8028
|
}
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8029
|
+
return path11.basename(trimmed) !== trimmed;
|
|
8030
|
+
}
|
|
8031
|
+
function readTaskFile(filePath) {
|
|
8032
|
+
let content;
|
|
8100
8033
|
try {
|
|
8101
|
-
|
|
8034
|
+
content = fs11.readFileSync(filePath, "utf-8");
|
|
8102
8035
|
} catch {
|
|
8103
8036
|
return null;
|
|
8104
8037
|
}
|
|
8105
|
-
|
|
8038
|
+
const parsed = (0, taskContent_1.parseTaskContent)(content);
|
|
8039
|
+
if (!parsed) {
|
|
8106
8040
|
return null;
|
|
8107
8041
|
}
|
|
8108
8042
|
return {
|
|
8109
|
-
|
|
8110
|
-
body:
|
|
8043
|
+
task: parsed.task,
|
|
8044
|
+
body: parsed.body,
|
|
8045
|
+
filePath: path11.resolve(filePath)
|
|
8111
8046
|
};
|
|
8112
8047
|
}
|
|
8113
|
-
function
|
|
8114
|
-
const
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8048
|
+
function writeTaskFile(filePath, task, body = "") {
|
|
8049
|
+
const dir = path11.dirname(filePath);
|
|
8050
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
8051
|
+
const content = (0, taskContent_1.serializeTaskContent)(task, body);
|
|
8052
|
+
fs11.writeFileSync(filePath, content, "utf-8");
|
|
8053
|
+
}
|
|
8054
|
+
function readTasksDir(dirPath) {
|
|
8055
|
+
let entries;
|
|
8056
|
+
try {
|
|
8057
|
+
entries = fs11.readdirSync(dirPath, { withFileTypes: true });
|
|
8058
|
+
} catch {
|
|
8059
|
+
return [];
|
|
8060
|
+
}
|
|
8061
|
+
const docs = [];
|
|
8062
|
+
for (const entry of entries) {
|
|
8063
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) {
|
|
8064
|
+
continue;
|
|
8065
|
+
}
|
|
8066
|
+
const filePath = path11.join(dirPath, entry.name);
|
|
8067
|
+
const doc = readTaskFile(filePath);
|
|
8068
|
+
if (doc) {
|
|
8069
|
+
docs.push(doc);
|
|
8128
8070
|
}
|
|
8129
8071
|
}
|
|
8130
|
-
return
|
|
8072
|
+
return docs;
|
|
8131
8073
|
}
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
// ../core/dist/boardContent.js
|
|
8136
|
-
var require_boardContent = __commonJS({
|
|
8137
|
-
"../core/dist/boardContent.js"(exports) {
|
|
8138
|
-
"use strict";
|
|
8139
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8140
|
-
exports.parseBoardConfig = parseBoardConfig;
|
|
8141
|
-
exports.serializeBoardConfig = serializeBoardConfig;
|
|
8142
|
-
var frontmatter_1 = require_frontmatter();
|
|
8143
|
-
function parseBoardConfig(content) {
|
|
8144
|
-
const parsed = (0, frontmatter_1.parseFrontmatter)(content);
|
|
8145
|
-
if (!parsed) {
|
|
8146
|
-
return null;
|
|
8074
|
+
function taskFileName(taskId) {
|
|
8075
|
+
if (isUnsafeTaskId(taskId)) {
|
|
8076
|
+
throw new Error(`Invalid task ID: ${taskId}`);
|
|
8147
8077
|
}
|
|
8148
|
-
return {
|
|
8149
|
-
config: parsed.data,
|
|
8150
|
-
body: parsed.body
|
|
8151
|
-
};
|
|
8152
|
-
}
|
|
8153
|
-
function serializeBoardConfig(config, body = "") {
|
|
8154
|
-
return (0, frontmatter_1.serializeFrontmatter)(config, body);
|
|
8078
|
+
return `${taskId.trim()}.md`;
|
|
8155
8079
|
}
|
|
8156
8080
|
}
|
|
8157
8081
|
});
|
|
8158
8082
|
|
|
8159
|
-
// ../core/dist/
|
|
8160
|
-
var
|
|
8161
|
-
"../core/dist/
|
|
8083
|
+
// ../core/dist/ledger.js
|
|
8084
|
+
var require_ledger2 = __commonJS({
|
|
8085
|
+
"../core/dist/ledger.js"(exports) {
|
|
8162
8086
|
"use strict";
|
|
8163
8087
|
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
8164
8088
|
if (k2 === void 0) k2 = k;
|
|
@@ -8198,256 +8122,25 @@ var require_boardFile = __commonJS({
|
|
|
8198
8122
|
};
|
|
8199
8123
|
})();
|
|
8200
8124
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8201
|
-
exports.
|
|
8202
|
-
exports.
|
|
8203
|
-
exports.
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
content = fs7.readFileSync(filePath, "utf-8");
|
|
8218
|
-
} catch {
|
|
8219
|
-
return null;
|
|
8220
|
-
}
|
|
8221
|
-
const parsed = (0, boardContent_1.parseBoardConfig)(content);
|
|
8222
|
-
if (!parsed) {
|
|
8223
|
-
return null;
|
|
8224
|
-
}
|
|
8225
|
-
return {
|
|
8226
|
-
config: parsed.config,
|
|
8227
|
-
body: parsed.body,
|
|
8228
|
-
filePath: path7.resolve(filePath)
|
|
8229
|
-
};
|
|
8125
|
+
exports.normalizePathValue = normalizePathValue;
|
|
8126
|
+
exports.isLedgerContractStatus = isLedgerContractStatus;
|
|
8127
|
+
exports.buildLedgerRecord = buildLedgerRecord;
|
|
8128
|
+
exports.appendLedgerRecord = appendLedgerRecord;
|
|
8129
|
+
exports.readLedger = readLedger;
|
|
8130
|
+
exports.queryLedger = queryLedger;
|
|
8131
|
+
exports.getFileHistory = getFileHistory;
|
|
8132
|
+
exports.getTaskContext = getTaskContext;
|
|
8133
|
+
var fs11 = __importStar(__require("fs"));
|
|
8134
|
+
var path11 = __importStar(__require("path"));
|
|
8135
|
+
var taskFile_1 = require_taskFile();
|
|
8136
|
+
var ledger_1 = require_ledger();
|
|
8137
|
+
var LEDGER_FILE_NAME = "ledger.jsonl";
|
|
8138
|
+
var LEGACY_WARNING_TRACKER = /* @__PURE__ */ new Set();
|
|
8139
|
+
function getLedgerPath(logsDir) {
|
|
8140
|
+
return path11.join(logsDir, LEDGER_FILE_NAME);
|
|
8230
8141
|
}
|
|
8231
|
-
function
|
|
8232
|
-
|
|
8233
|
-
fs7.mkdirSync(dir, { recursive: true });
|
|
8234
|
-
const content = (0, boardContent_1.serializeBoardConfig)(config, body);
|
|
8235
|
-
fs7.writeFileSync(filePath, content, "utf-8");
|
|
8236
|
-
}
|
|
8237
|
-
}
|
|
8238
|
-
});
|
|
8239
|
-
|
|
8240
|
-
// ../core/dist/taskContent.js
|
|
8241
|
-
var require_taskContent = __commonJS({
|
|
8242
|
-
"../core/dist/taskContent.js"(exports) {
|
|
8243
|
-
"use strict";
|
|
8244
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8245
|
-
exports.parseTaskContent = parseTaskContent;
|
|
8246
|
-
exports.serializeTaskContent = serializeTaskContent;
|
|
8247
|
-
var frontmatter_1 = require_frontmatter();
|
|
8248
|
-
function parseTaskContent(content) {
|
|
8249
|
-
const parsed = (0, frontmatter_1.parseFrontmatter)(content);
|
|
8250
|
-
if (!parsed) {
|
|
8251
|
-
return null;
|
|
8252
|
-
}
|
|
8253
|
-
const task = parsed.data;
|
|
8254
|
-
if (!task.id || !task.title) {
|
|
8255
|
-
return null;
|
|
8256
|
-
}
|
|
8257
|
-
return {
|
|
8258
|
-
task,
|
|
8259
|
-
body: parsed.body
|
|
8260
|
-
};
|
|
8261
|
-
}
|
|
8262
|
-
function serializeTaskContent(task, body = "") {
|
|
8263
|
-
return (0, frontmatter_1.serializeFrontmatter)(task, body);
|
|
8264
|
-
}
|
|
8265
|
-
}
|
|
8266
|
-
});
|
|
8267
|
-
|
|
8268
|
-
// ../core/dist/taskFile.js
|
|
8269
|
-
var require_taskFile = __commonJS({
|
|
8270
|
-
"../core/dist/taskFile.js"(exports) {
|
|
8271
|
-
"use strict";
|
|
8272
|
-
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
8273
|
-
if (k2 === void 0) k2 = k;
|
|
8274
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8275
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8276
|
-
desc = { enumerable: true, get: function() {
|
|
8277
|
-
return m[k];
|
|
8278
|
-
} };
|
|
8279
|
-
}
|
|
8280
|
-
Object.defineProperty(o, k2, desc);
|
|
8281
|
-
}) : (function(o, m, k, k2) {
|
|
8282
|
-
if (k2 === void 0) k2 = k;
|
|
8283
|
-
o[k2] = m[k];
|
|
8284
|
-
}));
|
|
8285
|
-
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
8286
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
8287
|
-
}) : function(o, v) {
|
|
8288
|
-
o["default"] = v;
|
|
8289
|
-
});
|
|
8290
|
-
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
8291
|
-
var ownKeys = function(o) {
|
|
8292
|
-
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
8293
|
-
var ar = [];
|
|
8294
|
-
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
8295
|
-
return ar;
|
|
8296
|
-
};
|
|
8297
|
-
return ownKeys(o);
|
|
8298
|
-
};
|
|
8299
|
-
return function(mod) {
|
|
8300
|
-
if (mod && mod.__esModule) return mod;
|
|
8301
|
-
var result = {};
|
|
8302
|
-
if (mod != null) {
|
|
8303
|
-
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
8304
|
-
}
|
|
8305
|
-
__setModuleDefault(result, mod);
|
|
8306
|
-
return result;
|
|
8307
|
-
};
|
|
8308
|
-
})();
|
|
8309
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8310
|
-
exports.serializeTaskContent = exports.parseTaskContent = void 0;
|
|
8311
|
-
exports.readTaskFile = readTaskFile;
|
|
8312
|
-
exports.writeTaskFile = writeTaskFile;
|
|
8313
|
-
exports.readTasksDir = readTasksDir;
|
|
8314
|
-
exports.taskFileName = taskFileName;
|
|
8315
|
-
var fs7 = __importStar(__require("fs"));
|
|
8316
|
-
var path7 = __importStar(__require("path"));
|
|
8317
|
-
var taskContent_1 = require_taskContent();
|
|
8318
|
-
var taskContent_2 = require_taskContent();
|
|
8319
|
-
Object.defineProperty(exports, "parseTaskContent", { enumerable: true, get: function() {
|
|
8320
|
-
return taskContent_2.parseTaskContent;
|
|
8321
|
-
} });
|
|
8322
|
-
Object.defineProperty(exports, "serializeTaskContent", { enumerable: true, get: function() {
|
|
8323
|
-
return taskContent_2.serializeTaskContent;
|
|
8324
|
-
} });
|
|
8325
|
-
function isUnsafeTaskId(taskId) {
|
|
8326
|
-
if (!taskId || taskId.trim() === "") {
|
|
8327
|
-
return true;
|
|
8328
|
-
}
|
|
8329
|
-
const trimmed = taskId.trim();
|
|
8330
|
-
if (trimmed.includes("/") || trimmed.includes("\\") || trimmed.includes("..")) {
|
|
8331
|
-
return true;
|
|
8332
|
-
}
|
|
8333
|
-
if (path7.isAbsolute(trimmed)) {
|
|
8334
|
-
return true;
|
|
8335
|
-
}
|
|
8336
|
-
return path7.basename(trimmed) !== trimmed;
|
|
8337
|
-
}
|
|
8338
|
-
function readTaskFile(filePath) {
|
|
8339
|
-
let content;
|
|
8340
|
-
try {
|
|
8341
|
-
content = fs7.readFileSync(filePath, "utf-8");
|
|
8342
|
-
} catch {
|
|
8343
|
-
return null;
|
|
8344
|
-
}
|
|
8345
|
-
const parsed = (0, taskContent_1.parseTaskContent)(content);
|
|
8346
|
-
if (!parsed) {
|
|
8347
|
-
return null;
|
|
8348
|
-
}
|
|
8349
|
-
return {
|
|
8350
|
-
task: parsed.task,
|
|
8351
|
-
body: parsed.body,
|
|
8352
|
-
filePath: path7.resolve(filePath)
|
|
8353
|
-
};
|
|
8354
|
-
}
|
|
8355
|
-
function writeTaskFile(filePath, task, body = "") {
|
|
8356
|
-
const dir = path7.dirname(filePath);
|
|
8357
|
-
fs7.mkdirSync(dir, { recursive: true });
|
|
8358
|
-
const content = (0, taskContent_1.serializeTaskContent)(task, body);
|
|
8359
|
-
fs7.writeFileSync(filePath, content, "utf-8");
|
|
8360
|
-
}
|
|
8361
|
-
function readTasksDir(dirPath) {
|
|
8362
|
-
let entries;
|
|
8363
|
-
try {
|
|
8364
|
-
entries = fs7.readdirSync(dirPath, { withFileTypes: true });
|
|
8365
|
-
} catch {
|
|
8366
|
-
return [];
|
|
8367
|
-
}
|
|
8368
|
-
const docs = [];
|
|
8369
|
-
for (const entry of entries) {
|
|
8370
|
-
if (!entry.isFile() || !entry.name.endsWith(".md")) {
|
|
8371
|
-
continue;
|
|
8372
|
-
}
|
|
8373
|
-
const filePath = path7.join(dirPath, entry.name);
|
|
8374
|
-
const doc = readTaskFile(filePath);
|
|
8375
|
-
if (doc) {
|
|
8376
|
-
docs.push(doc);
|
|
8377
|
-
}
|
|
8378
|
-
}
|
|
8379
|
-
return docs;
|
|
8380
|
-
}
|
|
8381
|
-
function taskFileName(taskId) {
|
|
8382
|
-
if (isUnsafeTaskId(taskId)) {
|
|
8383
|
-
throw new Error(`Invalid task ID: ${taskId}`);
|
|
8384
|
-
}
|
|
8385
|
-
return `${taskId.trim()}.md`;
|
|
8386
|
-
}
|
|
8387
|
-
}
|
|
8388
|
-
});
|
|
8389
|
-
|
|
8390
|
-
// ../core/dist/ledger.js
|
|
8391
|
-
var require_ledger2 = __commonJS({
|
|
8392
|
-
"../core/dist/ledger.js"(exports) {
|
|
8393
|
-
"use strict";
|
|
8394
|
-
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
8395
|
-
if (k2 === void 0) k2 = k;
|
|
8396
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8397
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8398
|
-
desc = { enumerable: true, get: function() {
|
|
8399
|
-
return m[k];
|
|
8400
|
-
} };
|
|
8401
|
-
}
|
|
8402
|
-
Object.defineProperty(o, k2, desc);
|
|
8403
|
-
}) : (function(o, m, k, k2) {
|
|
8404
|
-
if (k2 === void 0) k2 = k;
|
|
8405
|
-
o[k2] = m[k];
|
|
8406
|
-
}));
|
|
8407
|
-
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
8408
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
8409
|
-
}) : function(o, v) {
|
|
8410
|
-
o["default"] = v;
|
|
8411
|
-
});
|
|
8412
|
-
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
8413
|
-
var ownKeys = function(o) {
|
|
8414
|
-
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
8415
|
-
var ar = [];
|
|
8416
|
-
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
8417
|
-
return ar;
|
|
8418
|
-
};
|
|
8419
|
-
return ownKeys(o);
|
|
8420
|
-
};
|
|
8421
|
-
return function(mod) {
|
|
8422
|
-
if (mod && mod.__esModule) return mod;
|
|
8423
|
-
var result = {};
|
|
8424
|
-
if (mod != null) {
|
|
8425
|
-
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
8426
|
-
}
|
|
8427
|
-
__setModuleDefault(result, mod);
|
|
8428
|
-
return result;
|
|
8429
|
-
};
|
|
8430
|
-
})();
|
|
8431
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8432
|
-
exports.normalizePathValue = normalizePathValue;
|
|
8433
|
-
exports.isLedgerContractStatus = isLedgerContractStatus;
|
|
8434
|
-
exports.buildLedgerRecord = buildLedgerRecord;
|
|
8435
|
-
exports.appendLedgerRecord = appendLedgerRecord;
|
|
8436
|
-
exports.readLedger = readLedger;
|
|
8437
|
-
exports.queryLedger = queryLedger;
|
|
8438
|
-
exports.getFileHistory = getFileHistory;
|
|
8439
|
-
exports.getTaskContext = getTaskContext;
|
|
8440
|
-
var fs7 = __importStar(__require("fs"));
|
|
8441
|
-
var path7 = __importStar(__require("path"));
|
|
8442
|
-
var taskFile_1 = require_taskFile();
|
|
8443
|
-
var ledger_1 = require_ledger();
|
|
8444
|
-
var LEDGER_FILE_NAME = "ledger.jsonl";
|
|
8445
|
-
var LEGACY_WARNING_TRACKER = /* @__PURE__ */ new Set();
|
|
8446
|
-
function getLedgerPath(logsDir) {
|
|
8447
|
-
return path7.join(logsDir, LEDGER_FILE_NAME);
|
|
8448
|
-
}
|
|
8449
|
-
function normalizePathValue(value) {
|
|
8450
|
-
return value.replace(/\\/g, "/").replace(/^\.\//, "").trim();
|
|
8142
|
+
function normalizePathValue(value) {
|
|
8143
|
+
return value.replace(/\\/g, "/").replace(/^\.\//, "").trim();
|
|
8451
8144
|
}
|
|
8452
8145
|
function toUniqueStrings(values) {
|
|
8453
8146
|
if (!values) {
|
|
@@ -8662,7 +8355,7 @@ var require_ledger2 = __commonJS({
|
|
|
8662
8355
|
return parsed;
|
|
8663
8356
|
}
|
|
8664
8357
|
function shouldWarnLegacyFallback(logsDir) {
|
|
8665
|
-
const key =
|
|
8358
|
+
const key = path11.resolve(logsDir);
|
|
8666
8359
|
if (LEGACY_WARNING_TRACKER.has(key)) {
|
|
8667
8360
|
return false;
|
|
8668
8361
|
}
|
|
@@ -8748,18 +8441,18 @@ var require_ledger2 = __commonJS({
|
|
|
8748
8441
|
return record;
|
|
8749
8442
|
}
|
|
8750
8443
|
function appendLedgerRecord(logsDir, record) {
|
|
8751
|
-
|
|
8444
|
+
fs11.mkdirSync(logsDir, { recursive: true });
|
|
8752
8445
|
const ledgerPath = getLedgerPath(logsDir);
|
|
8753
|
-
|
|
8446
|
+
fs11.appendFileSync(ledgerPath, `${JSON.stringify(record)}
|
|
8754
8447
|
`, "utf-8");
|
|
8755
8448
|
return ledgerPath;
|
|
8756
8449
|
}
|
|
8757
8450
|
function readLedger(logsDir) {
|
|
8758
8451
|
const ledgerPath = getLedgerPath(logsDir);
|
|
8759
|
-
if (!
|
|
8452
|
+
if (!fs11.existsSync(ledgerPath)) {
|
|
8760
8453
|
return readLegacyMarkdownLedger(logsDir);
|
|
8761
8454
|
}
|
|
8762
|
-
const content =
|
|
8455
|
+
const content = fs11.readFileSync(ledgerPath, "utf-8");
|
|
8763
8456
|
const lines = content.split("\n");
|
|
8764
8457
|
const records = [];
|
|
8765
8458
|
for (let index = 0; index < lines.length; index++) {
|
|
@@ -8808,29 +8501,903 @@ var require_ledger2 = __commonJS({
|
|
|
8808
8501
|
if (options.dateRange) {
|
|
8809
8502
|
records = records.filter((record) => matchesDateRange(record.completedAt, options.dateRange));
|
|
8810
8503
|
}
|
|
8811
|
-
records.sort((a, b) => timestampOr(b.completedAt, 0) - timestampOr(a.completedAt, 0));
|
|
8812
|
-
if (options.limit !== void 0 && options.limit > 0) {
|
|
8813
|
-
return records.slice(0, options.limit);
|
|
8504
|
+
records.sort((a, b) => timestampOr(b.completedAt, 0) - timestampOr(a.completedAt, 0));
|
|
8505
|
+
if (options.limit !== void 0 && options.limit > 0) {
|
|
8506
|
+
return records.slice(0, options.limit);
|
|
8507
|
+
}
|
|
8508
|
+
return records;
|
|
8509
|
+
}
|
|
8510
|
+
function getTaskContext(logsDir, relatedFiles, deliverables, options = {}) {
|
|
8511
|
+
const scopeFiles = toUniquePaths([
|
|
8512
|
+
...relatedFiles,
|
|
8513
|
+
...collectDeliverableInputPaths(deliverables)
|
|
8514
|
+
]);
|
|
8515
|
+
if (scopeFiles.length === 0) {
|
|
8516
|
+
return [];
|
|
8517
|
+
}
|
|
8518
|
+
let entries = readLedger(logsDir).filter((record) => matchesDateRange(record.completedAt, options.dateRange)).map((record) => {
|
|
8519
|
+
const matchedFiles = matchedFilesForScope(scopeFiles, collectRecordFiles(record));
|
|
8520
|
+
return { record, matchedFiles };
|
|
8521
|
+
}).filter((entry) => entry.matchedFiles.length > 0);
|
|
8522
|
+
entries.sort((a, b) => timestampOr(b.record.completedAt, 0) - timestampOr(a.record.completedAt, 0));
|
|
8523
|
+
if (options.limit !== void 0 && options.limit > 0) {
|
|
8524
|
+
entries = entries.slice(0, options.limit);
|
|
8525
|
+
}
|
|
8526
|
+
return entries;
|
|
8527
|
+
}
|
|
8528
|
+
}
|
|
8529
|
+
});
|
|
8530
|
+
|
|
8531
|
+
// ../core/dist/workspace.js
|
|
8532
|
+
var require_workspace = __commonJS({
|
|
8533
|
+
"../core/dist/workspace.js"(exports) {
|
|
8534
|
+
"use strict";
|
|
8535
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
8536
|
+
if (k2 === void 0) k2 = k;
|
|
8537
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8538
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8539
|
+
desc = { enumerable: true, get: function() {
|
|
8540
|
+
return m[k];
|
|
8541
|
+
} };
|
|
8542
|
+
}
|
|
8543
|
+
Object.defineProperty(o, k2, desc);
|
|
8544
|
+
}) : (function(o, m, k, k2) {
|
|
8545
|
+
if (k2 === void 0) k2 = k;
|
|
8546
|
+
o[k2] = m[k];
|
|
8547
|
+
}));
|
|
8548
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
8549
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
8550
|
+
}) : function(o, v) {
|
|
8551
|
+
o["default"] = v;
|
|
8552
|
+
});
|
|
8553
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
8554
|
+
var ownKeys = function(o) {
|
|
8555
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
8556
|
+
var ar = [];
|
|
8557
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
8558
|
+
return ar;
|
|
8559
|
+
};
|
|
8560
|
+
return ownKeys(o);
|
|
8561
|
+
};
|
|
8562
|
+
return function(mod) {
|
|
8563
|
+
if (mod && mod.__esModule) return mod;
|
|
8564
|
+
var result = {};
|
|
8565
|
+
if (mod != null) {
|
|
8566
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
8567
|
+
}
|
|
8568
|
+
__setModuleDefault(result, mod);
|
|
8569
|
+
return result;
|
|
8570
|
+
};
|
|
8571
|
+
})();
|
|
8572
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8573
|
+
exports.getV2Dirs = getV2Dirs2;
|
|
8574
|
+
exports.isV2 = isV25;
|
|
8575
|
+
exports.ensureV2Dirs = ensureV2Dirs2;
|
|
8576
|
+
exports.getTaskFilePath = getTaskFilePath2;
|
|
8577
|
+
exports.getLogFilePath = getLogFilePath2;
|
|
8578
|
+
exports.findV2Task = findV2Task2;
|
|
8579
|
+
exports.extractDescription = extractDescription2;
|
|
8580
|
+
exports.extractLog = extractLog2;
|
|
8581
|
+
exports.composeBody = composeBody2;
|
|
8582
|
+
exports.readV2BoardConfig = readV2BoardConfig2;
|
|
8583
|
+
exports.buildBoardFromV2 = buildBoardFromV22;
|
|
8584
|
+
var fs11 = __importStar(__require("fs"));
|
|
8585
|
+
var path11 = __importStar(__require("path"));
|
|
8586
|
+
var parser_1 = require_parser();
|
|
8587
|
+
var taskFile_1 = require_taskFile();
|
|
8588
|
+
function getV2Dirs2(brainfilePath) {
|
|
8589
|
+
const resolvedPath = path11.resolve(brainfilePath);
|
|
8590
|
+
const dotDir = path11.dirname(resolvedPath);
|
|
8591
|
+
return {
|
|
8592
|
+
dotDir,
|
|
8593
|
+
boardDir: path11.join(dotDir, "board"),
|
|
8594
|
+
logsDir: path11.join(dotDir, "logs"),
|
|
8595
|
+
brainfilePath: resolvedPath
|
|
8596
|
+
};
|
|
8597
|
+
}
|
|
8598
|
+
function isV25(brainfilePath) {
|
|
8599
|
+
const { boardDir } = getV2Dirs2(brainfilePath);
|
|
8600
|
+
return fs11.existsSync(boardDir);
|
|
8601
|
+
}
|
|
8602
|
+
function ensureV2Dirs2(brainfilePath) {
|
|
8603
|
+
const dirs = getV2Dirs2(brainfilePath);
|
|
8604
|
+
fs11.mkdirSync(dirs.boardDir, { recursive: true });
|
|
8605
|
+
fs11.mkdirSync(dirs.logsDir, { recursive: true });
|
|
8606
|
+
return dirs;
|
|
8607
|
+
}
|
|
8608
|
+
function getTaskFilePath2(boardDir, taskId) {
|
|
8609
|
+
return path11.join(boardDir, (0, taskFile_1.taskFileName)(taskId));
|
|
8610
|
+
}
|
|
8611
|
+
function getLogFilePath2(logsDir, taskId) {
|
|
8612
|
+
return path11.join(logsDir, (0, taskFile_1.taskFileName)(taskId));
|
|
8613
|
+
}
|
|
8614
|
+
function findV2Task2(dirs, taskId, searchLogs = false) {
|
|
8615
|
+
const taskPath = getTaskFilePath2(dirs.boardDir, taskId);
|
|
8616
|
+
const taskDoc = (0, taskFile_1.readTaskFile)(taskPath);
|
|
8617
|
+
if (taskDoc && taskDoc.task.id === taskId) {
|
|
8618
|
+
return { doc: taskDoc, filePath: taskPath, isLog: false };
|
|
8619
|
+
}
|
|
8620
|
+
if (searchLogs) {
|
|
8621
|
+
const logPath = getLogFilePath2(dirs.logsDir, taskId);
|
|
8622
|
+
const logDoc = (0, taskFile_1.readTaskFile)(logPath);
|
|
8623
|
+
if (logDoc && logDoc.task.id === taskId) {
|
|
8624
|
+
return { doc: logDoc, filePath: logPath, isLog: true };
|
|
8625
|
+
}
|
|
8626
|
+
}
|
|
8627
|
+
const boardDocs = (0, taskFile_1.readTasksDir)(dirs.boardDir);
|
|
8628
|
+
const boardMatch = boardDocs.find((d) => d.task.id === taskId);
|
|
8629
|
+
if (boardMatch) {
|
|
8630
|
+
return {
|
|
8631
|
+
doc: boardMatch,
|
|
8632
|
+
filePath: boardMatch.filePath || taskPath,
|
|
8633
|
+
isLog: false
|
|
8634
|
+
};
|
|
8635
|
+
}
|
|
8636
|
+
if (searchLogs) {
|
|
8637
|
+
const logDocs = (0, taskFile_1.readTasksDir)(dirs.logsDir);
|
|
8638
|
+
const logMatch = logDocs.find((d) => d.task.id === taskId);
|
|
8639
|
+
if (logMatch) {
|
|
8640
|
+
return {
|
|
8641
|
+
doc: logMatch,
|
|
8642
|
+
filePath: logMatch.filePath || getLogFilePath2(dirs.logsDir, taskId),
|
|
8643
|
+
isLog: true
|
|
8644
|
+
};
|
|
8645
|
+
}
|
|
8646
|
+
}
|
|
8647
|
+
return null;
|
|
8648
|
+
}
|
|
8649
|
+
function extractDescription2(body) {
|
|
8650
|
+
const match = body.match(/## Description\n([\s\S]*?)(?=\n## |\n*$)/);
|
|
8651
|
+
return match ? match[1].trim() || void 0 : void 0;
|
|
8652
|
+
}
|
|
8653
|
+
function extractLog2(body) {
|
|
8654
|
+
const match = body.match(/## Log\n([\s\S]*?)(?=\n## |\n*$)/);
|
|
8655
|
+
return match ? match[1].trim() || void 0 : void 0;
|
|
8656
|
+
}
|
|
8657
|
+
function composeBody2(description, log) {
|
|
8658
|
+
const sections = [];
|
|
8659
|
+
if (description && description.trim()) {
|
|
8660
|
+
sections.push(`## Description
|
|
8661
|
+
${description.trim()}`);
|
|
8662
|
+
}
|
|
8663
|
+
if (log && log.trim()) {
|
|
8664
|
+
sections.push(`## Log
|
|
8665
|
+
${log.trim()}`);
|
|
8666
|
+
}
|
|
8667
|
+
if (sections.length === 0)
|
|
8668
|
+
return "";
|
|
8669
|
+
return `${sections.join("\n\n")}
|
|
8670
|
+
`;
|
|
8671
|
+
}
|
|
8672
|
+
function readV2BoardConfig2(brainfilePath) {
|
|
8673
|
+
const content = fs11.readFileSync(brainfilePath, "utf-8");
|
|
8674
|
+
const result = parser_1.BrainfileParser.parseWithErrors(content);
|
|
8675
|
+
if (!result.board) {
|
|
8676
|
+
throw new Error(`Failed to parse brainfile: ${result.error}`);
|
|
8677
|
+
}
|
|
8678
|
+
const board = result.board;
|
|
8679
|
+
for (const col of board.columns) {
|
|
8680
|
+
if (!col.tasks)
|
|
8681
|
+
col.tasks = [];
|
|
8682
|
+
}
|
|
8683
|
+
return board;
|
|
8684
|
+
}
|
|
8685
|
+
function buildBoardFromV22(brainfilePath) {
|
|
8686
|
+
const dirs = getV2Dirs2(brainfilePath);
|
|
8687
|
+
const board = readV2BoardConfig2(brainfilePath);
|
|
8688
|
+
const taskDocs = (0, taskFile_1.readTasksDir)(dirs.boardDir);
|
|
8689
|
+
const tasksByColumn = /* @__PURE__ */ new Map();
|
|
8690
|
+
for (const doc of taskDocs) {
|
|
8691
|
+
const colId = doc.task.column || "todo";
|
|
8692
|
+
if (!tasksByColumn.has(colId)) {
|
|
8693
|
+
tasksByColumn.set(colId, []);
|
|
8694
|
+
}
|
|
8695
|
+
tasksByColumn.get(colId).push(doc);
|
|
8696
|
+
}
|
|
8697
|
+
for (const col of board.columns) {
|
|
8698
|
+
const colTasks = tasksByColumn.get(col.id) || [];
|
|
8699
|
+
colTasks.sort((a, b) => {
|
|
8700
|
+
const posA = a.task.position ?? Number.MAX_SAFE_INTEGER;
|
|
8701
|
+
const posB = b.task.position ?? Number.MAX_SAFE_INTEGER;
|
|
8702
|
+
if (posA !== posB)
|
|
8703
|
+
return posA - posB;
|
|
8704
|
+
return a.task.id.localeCompare(b.task.id);
|
|
8705
|
+
});
|
|
8706
|
+
col.tasks = colTasks.map((doc) => {
|
|
8707
|
+
const task = { ...doc.task };
|
|
8708
|
+
if (!task.description) {
|
|
8709
|
+
const description = extractDescription2(doc.body);
|
|
8710
|
+
if (description)
|
|
8711
|
+
task.description = description;
|
|
8712
|
+
}
|
|
8713
|
+
return task;
|
|
8714
|
+
});
|
|
8715
|
+
}
|
|
8716
|
+
return board;
|
|
8717
|
+
}
|
|
8718
|
+
}
|
|
8719
|
+
});
|
|
8720
|
+
|
|
8721
|
+
// ../core/dist/brief.js
|
|
8722
|
+
var require_brief = __commonJS({
|
|
8723
|
+
"../core/dist/brief.js"(exports) {
|
|
8724
|
+
"use strict";
|
|
8725
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
8726
|
+
if (k2 === void 0) k2 = k;
|
|
8727
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8728
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8729
|
+
desc = { enumerable: true, get: function() {
|
|
8730
|
+
return m[k];
|
|
8731
|
+
} };
|
|
8732
|
+
}
|
|
8733
|
+
Object.defineProperty(o, k2, desc);
|
|
8734
|
+
}) : (function(o, m, k, k2) {
|
|
8735
|
+
if (k2 === void 0) k2 = k;
|
|
8736
|
+
o[k2] = m[k];
|
|
8737
|
+
}));
|
|
8738
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
8739
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
8740
|
+
}) : function(o, v) {
|
|
8741
|
+
o["default"] = v;
|
|
8742
|
+
});
|
|
8743
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
8744
|
+
var ownKeys = function(o) {
|
|
8745
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
8746
|
+
var ar = [];
|
|
8747
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
8748
|
+
return ar;
|
|
8749
|
+
};
|
|
8750
|
+
return ownKeys(o);
|
|
8751
|
+
};
|
|
8752
|
+
return function(mod) {
|
|
8753
|
+
if (mod && mod.__esModule) return mod;
|
|
8754
|
+
var result = {};
|
|
8755
|
+
if (mod != null) {
|
|
8756
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
8757
|
+
}
|
|
8758
|
+
__setModuleDefault(result, mod);
|
|
8759
|
+
return result;
|
|
8760
|
+
};
|
|
8761
|
+
})();
|
|
8762
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8763
|
+
exports.parseNoteLine = parseNoteLine;
|
|
8764
|
+
exports.parseNotes = parseNotes;
|
|
8765
|
+
exports.relativeTime = relativeTime;
|
|
8766
|
+
exports.buildBrief = buildBrief;
|
|
8767
|
+
exports.isEmptyBrief = isEmptyBrief;
|
|
8768
|
+
var fs11 = __importStar(__require("fs"));
|
|
8769
|
+
var taskFile_1 = require_taskFile();
|
|
8770
|
+
var ledger_1 = require_ledger2();
|
|
8771
|
+
var workspace_1 = require_workspace();
|
|
8772
|
+
var FULL_MODE_COMPLETION_LIMIT = 10;
|
|
8773
|
+
var ISO_TIMESTAMP_SHAPE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/;
|
|
8774
|
+
function parseNoteLine(line) {
|
|
8775
|
+
const match = /^-\s+(\S+)/.exec(line);
|
|
8776
|
+
if (!match)
|
|
8777
|
+
return null;
|
|
8778
|
+
let token = match[1];
|
|
8779
|
+
if (token.endsWith(":"))
|
|
8780
|
+
token = token.slice(0, -1);
|
|
8781
|
+
if (!ISO_TIMESTAMP_SHAPE.test(token))
|
|
8782
|
+
return null;
|
|
8783
|
+
const parsed = Date.parse(token);
|
|
8784
|
+
if (Number.isNaN(parsed))
|
|
8785
|
+
return null;
|
|
8786
|
+
let rest = line.slice(match[0].length);
|
|
8787
|
+
let agent;
|
|
8788
|
+
const takeBracket = () => {
|
|
8789
|
+
const bracket = /^\s*\[([^\]]+)\]/.exec(rest);
|
|
8790
|
+
if (bracket) {
|
|
8791
|
+
agent = bracket[1].trim() || void 0;
|
|
8792
|
+
rest = rest.slice(bracket[0].length);
|
|
8793
|
+
}
|
|
8794
|
+
};
|
|
8795
|
+
takeBracket();
|
|
8796
|
+
rest = rest.replace(/^\s*:/, "");
|
|
8797
|
+
if (!agent)
|
|
8798
|
+
takeBracket();
|
|
8799
|
+
return {
|
|
8800
|
+
at: new Date(parsed).toISOString(),
|
|
8801
|
+
text: rest.trim(),
|
|
8802
|
+
agent
|
|
8803
|
+
};
|
|
8804
|
+
}
|
|
8805
|
+
function parseNotes(body) {
|
|
8806
|
+
const log = (0, workspace_1.extractLog)(body);
|
|
8807
|
+
if (!log)
|
|
8808
|
+
return [];
|
|
8809
|
+
const notes = [];
|
|
8810
|
+
for (const line of log.split("\n")) {
|
|
8811
|
+
const parsed = parseNoteLine(line);
|
|
8812
|
+
if (parsed)
|
|
8813
|
+
notes.push(parsed);
|
|
8814
|
+
}
|
|
8815
|
+
return notes.sort((a, b) => Date.parse(b.at) - Date.parse(a.at));
|
|
8816
|
+
}
|
|
8817
|
+
function lastRawLogLine(body) {
|
|
8818
|
+
const log = (0, workspace_1.extractLog)(body);
|
|
8819
|
+
if (!log)
|
|
8820
|
+
return null;
|
|
8821
|
+
const lines = log.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
8822
|
+
if (lines.length === 0)
|
|
8823
|
+
return null;
|
|
8824
|
+
return lines[lines.length - 1].replace(/^-\s+/, "");
|
|
8825
|
+
}
|
|
8826
|
+
function parseMs(value) {
|
|
8827
|
+
if (!value)
|
|
8828
|
+
return null;
|
|
8829
|
+
const ms = Date.parse(value);
|
|
8830
|
+
return Number.isNaN(ms) ? null : ms;
|
|
8831
|
+
}
|
|
8832
|
+
function isAssignedTo(assignee, agentName) {
|
|
8833
|
+
if (!assignee)
|
|
8834
|
+
return false;
|
|
8835
|
+
return assignee.trim().toLowerCase() === agentName.trim().toLowerCase();
|
|
8836
|
+
}
|
|
8837
|
+
function relativeTime(from, to) {
|
|
8838
|
+
const fromMs = parseMs(from);
|
|
8839
|
+
const toMs = parseMs(to);
|
|
8840
|
+
if (fromMs === null || toMs === null)
|
|
8841
|
+
return "unknown";
|
|
8842
|
+
const deltaSec = Math.max(0, Math.round((toMs - fromMs) / 1e3));
|
|
8843
|
+
if (deltaSec < 60)
|
|
8844
|
+
return "just now";
|
|
8845
|
+
const min = Math.floor(deltaSec / 60);
|
|
8846
|
+
if (min < 60)
|
|
8847
|
+
return `${min}m`;
|
|
8848
|
+
const hours = Math.floor(min / 60);
|
|
8849
|
+
if (hours < 24)
|
|
8850
|
+
return `${hours}h`;
|
|
8851
|
+
const days = Math.floor(hours / 24);
|
|
8852
|
+
return `${days}d`;
|
|
8853
|
+
}
|
|
8854
|
+
function agoPhrase(from, to) {
|
|
8855
|
+
const rel = relativeTime(from, to);
|
|
8856
|
+
return rel === "just now" || rel === "unknown" ? rel : `${rel} ago`;
|
|
8857
|
+
}
|
|
8858
|
+
function taskStateWhy(task) {
|
|
8859
|
+
const parts = [task.column || "unknown"];
|
|
8860
|
+
if (task.priority)
|
|
8861
|
+
parts.push(task.priority);
|
|
8862
|
+
if (task.contract?.status)
|
|
8863
|
+
parts.push(`contract:${task.contract.status}`);
|
|
8864
|
+
return parts.join(" \xB7 ");
|
|
8865
|
+
}
|
|
8866
|
+
function completionWhy(record) {
|
|
8867
|
+
const cycle = typeof record.cycleTimeHours === "number" ? `${record.cycleTimeHours}h cycle` : "cycle unknown";
|
|
8868
|
+
return `completed \xB7 ${cycle}`;
|
|
8869
|
+
}
|
|
8870
|
+
function boardMtimeMs(brainfilePath) {
|
|
8871
|
+
try {
|
|
8872
|
+
return fs11.statSync(brainfilePath).mtimeMs;
|
|
8873
|
+
} catch {
|
|
8874
|
+
return null;
|
|
8875
|
+
}
|
|
8876
|
+
}
|
|
8877
|
+
function completionsFor(dirs, agentName, lastBriefAtMs) {
|
|
8878
|
+
let records;
|
|
8879
|
+
try {
|
|
8880
|
+
records = (0, ledger_1.queryLedger)(dirs.logsDir, {});
|
|
8881
|
+
} catch {
|
|
8882
|
+
return [];
|
|
8883
|
+
}
|
|
8884
|
+
const matching = records.filter((record) => {
|
|
8885
|
+
if (!isAssignedTo(record.assignee, agentName))
|
|
8886
|
+
return false;
|
|
8887
|
+
if (lastBriefAtMs === null)
|
|
8888
|
+
return true;
|
|
8889
|
+
const completedMs = parseMs(record.completedAt);
|
|
8890
|
+
return completedMs !== null && completedMs > lastBriefAtMs;
|
|
8891
|
+
});
|
|
8892
|
+
return matching.sort((a, b) => (parseMs(b.completedAt) ?? 0) - (parseMs(a.completedAt) ?? 0));
|
|
8893
|
+
}
|
|
8894
|
+
function readBoardConfig(brainfilePath) {
|
|
8895
|
+
try {
|
|
8896
|
+
return (0, workspace_1.readV2BoardConfig)(brainfilePath);
|
|
8897
|
+
} catch {
|
|
8898
|
+
return null;
|
|
8899
|
+
}
|
|
8900
|
+
}
|
|
8901
|
+
function buildBrief(dirs, agentName, opts) {
|
|
8902
|
+
const generatedAt = opts.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
8903
|
+
const lastBriefAt = opts.lastBriefAt;
|
|
8904
|
+
const lastBriefAtMs = parseMs(lastBriefAt);
|
|
8905
|
+
const mode = lastBriefAtMs === null ? "full" : "delta";
|
|
8906
|
+
const assigned = (0, taskFile_1.readTasksDir)(dirs.boardDir).filter((doc) => isAssignedTo(doc.task.assignee, agentName));
|
|
8907
|
+
const lanes = mode === "full" ? fullLanes(dirs, agentName, assigned, generatedAt) : deltaLanes(dirs, agentName, assigned, generatedAt, lastBriefAtMs);
|
|
8908
|
+
return {
|
|
8909
|
+
agent: agentName,
|
|
8910
|
+
mode,
|
|
8911
|
+
generatedAt,
|
|
8912
|
+
// Normalize away an unparseable stored checkpoint rather than echoing it.
|
|
8913
|
+
lastBriefAt: lastBriefAtMs === null ? null : lastBriefAt,
|
|
8914
|
+
lanes
|
|
8915
|
+
};
|
|
8916
|
+
}
|
|
8917
|
+
function sortAssigned(docs) {
|
|
8918
|
+
return [...docs].sort((a, b) => {
|
|
8919
|
+
const aMs = parseMs(a.task.updatedAt) ?? parseMs(a.task.createdAt) ?? 0;
|
|
8920
|
+
const bMs = parseMs(b.task.updatedAt) ?? parseMs(b.task.createdAt) ?? 0;
|
|
8921
|
+
return bMs - aMs;
|
|
8922
|
+
});
|
|
8923
|
+
}
|
|
8924
|
+
function acceptedAdrs(dirs) {
|
|
8925
|
+
const ACCEPTED = /* @__PURE__ */ new Set(["accepted", "promoted"]);
|
|
8926
|
+
const docs = [];
|
|
8927
|
+
for (const dir of [dirs.boardDir, dirs.logsDir]) {
|
|
8928
|
+
let entries;
|
|
8929
|
+
try {
|
|
8930
|
+
entries = (0, taskFile_1.readTasksDir)(dir);
|
|
8931
|
+
} catch {
|
|
8932
|
+
continue;
|
|
8933
|
+
}
|
|
8934
|
+
for (const doc of entries) {
|
|
8935
|
+
const task = doc.task;
|
|
8936
|
+
if ((task.type || "").toLowerCase() !== "adr")
|
|
8937
|
+
continue;
|
|
8938
|
+
if (!ACCEPTED.has((task.status || "").toLowerCase()))
|
|
8939
|
+
continue;
|
|
8940
|
+
docs.push(doc);
|
|
8941
|
+
}
|
|
8942
|
+
}
|
|
8943
|
+
return docs.sort((a, b) => a.task.id.localeCompare(b.task.id, void 0, { numeric: true }));
|
|
8944
|
+
}
|
|
8945
|
+
function fullLanes(dirs, agentName, assigned, generatedAt) {
|
|
8946
|
+
const orientation = [];
|
|
8947
|
+
const board = readBoardConfig(dirs.brainfilePath);
|
|
8948
|
+
if (board?.title) {
|
|
8949
|
+
orientation.push({ text: board.title, why: "board" });
|
|
8950
|
+
}
|
|
8951
|
+
for (const instruction of board?.agent?.instructions ?? []) {
|
|
8952
|
+
orientation.push({ text: instruction, why: "agent instructions" });
|
|
8953
|
+
}
|
|
8954
|
+
for (const doc of acceptedAdrs(dirs)) {
|
|
8955
|
+
orientation.push({ taskId: doc.task.id, text: doc.task.title, why: "accepted adr" });
|
|
8956
|
+
}
|
|
8957
|
+
const assignedItems = sortAssigned(assigned).map((doc) => ({
|
|
8958
|
+
taskId: doc.task.id,
|
|
8959
|
+
text: doc.task.title,
|
|
8960
|
+
why: taskStateWhy(doc.task),
|
|
8961
|
+
...doc.task.updatedAt ? { at: doc.task.updatedAt } : {}
|
|
8962
|
+
}));
|
|
8963
|
+
const noteItems = [];
|
|
8964
|
+
for (const doc of assigned) {
|
|
8965
|
+
const notes = parseNotes(doc.body);
|
|
8966
|
+
if (notes.length > 0) {
|
|
8967
|
+
const latest = notes[0];
|
|
8968
|
+
noteItems.push({
|
|
8969
|
+
taskId: doc.task.id,
|
|
8970
|
+
text: latest.text,
|
|
8971
|
+
why: `logged ${agoPhrase(latest.at, generatedAt)}`,
|
|
8972
|
+
at: latest.at
|
|
8973
|
+
});
|
|
8974
|
+
continue;
|
|
8975
|
+
}
|
|
8976
|
+
const raw = lastRawLogLine(doc.body);
|
|
8977
|
+
if (raw) {
|
|
8978
|
+
noteItems.push({ taskId: doc.task.id, text: raw, why: "unstamped entry" });
|
|
8979
|
+
}
|
|
8980
|
+
}
|
|
8981
|
+
noteItems.sort((a, b) => (parseMs(b.at) ?? 0) - (parseMs(a.at) ?? 0));
|
|
8982
|
+
const completionItems = completionsFor(dirs, agentName, null).slice(0, FULL_MODE_COMPLETION_LIMIT).map((record) => ({
|
|
8983
|
+
taskId: record.id,
|
|
8984
|
+
text: record.title,
|
|
8985
|
+
why: completionWhy(record),
|
|
8986
|
+
at: record.completedAt
|
|
8987
|
+
}));
|
|
8988
|
+
return [
|
|
8989
|
+
{ id: "orientation", label: "Board & Decisions", items: orientation },
|
|
8990
|
+
{ id: "assigned", label: "Your Tasks", items: assignedItems },
|
|
8991
|
+
{ id: "notes", label: "Latest Notes", items: noteItems },
|
|
8992
|
+
{ id: "completions", label: "Recently Completed (yours)", items: completionItems }
|
|
8993
|
+
];
|
|
8994
|
+
}
|
|
8995
|
+
function deltaLanes(dirs, agentName, assigned, generatedAt, lastBriefAtMs) {
|
|
8996
|
+
const noteItems = [];
|
|
8997
|
+
for (const doc of assigned) {
|
|
8998
|
+
for (const note of parseNotes(doc.body)) {
|
|
8999
|
+
const noteMs = parseMs(note.at);
|
|
9000
|
+
if (noteMs === null || noteMs <= lastBriefAtMs)
|
|
9001
|
+
continue;
|
|
9002
|
+
noteItems.push({
|
|
9003
|
+
taskId: doc.task.id,
|
|
9004
|
+
text: note.agent ? `[${note.agent}] ${note.text}` : note.text,
|
|
9005
|
+
why: agoPhrase(note.at, generatedAt),
|
|
9006
|
+
at: note.at
|
|
9007
|
+
});
|
|
9008
|
+
}
|
|
9009
|
+
}
|
|
9010
|
+
noteItems.sort((a, b) => (parseMs(b.at) ?? 0) - (parseMs(a.at) ?? 0));
|
|
9011
|
+
const changeItems = [];
|
|
9012
|
+
for (const doc of sortAssigned(assigned)) {
|
|
9013
|
+
const createdMs = parseMs(doc.task.createdAt);
|
|
9014
|
+
const updatedMs = parseMs(doc.task.updatedAt);
|
|
9015
|
+
const isNew = createdMs !== null && createdMs > lastBriefAtMs;
|
|
9016
|
+
const isUpdated = updatedMs !== null && updatedMs > lastBriefAtMs;
|
|
9017
|
+
if (!isNew && !isUpdated)
|
|
9018
|
+
continue;
|
|
9019
|
+
const stamp2 = isNew ? doc.task.createdAt : doc.task.updatedAt;
|
|
9020
|
+
const verb = isNew ? "created" : "updated";
|
|
9021
|
+
changeItems.push({
|
|
9022
|
+
taskId: doc.task.id,
|
|
9023
|
+
text: doc.task.title,
|
|
9024
|
+
why: `${verb} ${agoPhrase(stamp2, generatedAt)} \xB7 ${taskStateWhy(doc.task)}`,
|
|
9025
|
+
...stamp2 ? { at: stamp2 } : {}
|
|
9026
|
+
});
|
|
9027
|
+
}
|
|
9028
|
+
const completionItems = completionsFor(dirs, agentName, lastBriefAtMs).map((record) => ({
|
|
9029
|
+
taskId: record.id,
|
|
9030
|
+
text: record.title,
|
|
9031
|
+
why: completionWhy(record),
|
|
9032
|
+
at: record.completedAt
|
|
9033
|
+
}));
|
|
9034
|
+
const configItems = [];
|
|
9035
|
+
const mtime = boardMtimeMs(dirs.brainfilePath);
|
|
9036
|
+
if (mtime !== null && mtime > lastBriefAtMs) {
|
|
9037
|
+
const at = new Date(mtime).toISOString();
|
|
9038
|
+
configItems.push({
|
|
9039
|
+
text: "Board config changed",
|
|
9040
|
+
why: "brainfile.md changed since last brief",
|
|
9041
|
+
at
|
|
9042
|
+
});
|
|
9043
|
+
}
|
|
9044
|
+
return [
|
|
9045
|
+
{ id: "notes", label: "New Notes", items: noteItems },
|
|
9046
|
+
{ id: "changes", label: "Task Changes", items: changeItems },
|
|
9047
|
+
{ id: "completions", label: "Completed Since Last Brief", items: completionItems },
|
|
9048
|
+
{ id: "config", label: "Board Config", items: configItems }
|
|
9049
|
+
];
|
|
9050
|
+
}
|
|
9051
|
+
function isEmptyBrief(result) {
|
|
9052
|
+
return result.lanes.every((lane) => lane.items.length === 0);
|
|
9053
|
+
}
|
|
9054
|
+
}
|
|
9055
|
+
});
|
|
9056
|
+
|
|
9057
|
+
// ../core/dist/briefState.js
|
|
9058
|
+
var require_briefState = __commonJS({
|
|
9059
|
+
"../core/dist/briefState.js"(exports) {
|
|
9060
|
+
"use strict";
|
|
9061
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
9062
|
+
if (k2 === void 0) k2 = k;
|
|
9063
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9064
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9065
|
+
desc = { enumerable: true, get: function() {
|
|
9066
|
+
return m[k];
|
|
9067
|
+
} };
|
|
9068
|
+
}
|
|
9069
|
+
Object.defineProperty(o, k2, desc);
|
|
9070
|
+
}) : (function(o, m, k, k2) {
|
|
9071
|
+
if (k2 === void 0) k2 = k;
|
|
9072
|
+
o[k2] = m[k];
|
|
9073
|
+
}));
|
|
9074
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
9075
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
9076
|
+
}) : function(o, v) {
|
|
9077
|
+
o["default"] = v;
|
|
9078
|
+
});
|
|
9079
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
9080
|
+
var ownKeys = function(o) {
|
|
9081
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
9082
|
+
var ar = [];
|
|
9083
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
9084
|
+
return ar;
|
|
9085
|
+
};
|
|
9086
|
+
return ownKeys(o);
|
|
9087
|
+
};
|
|
9088
|
+
return function(mod) {
|
|
9089
|
+
if (mod && mod.__esModule) return mod;
|
|
9090
|
+
var result = {};
|
|
9091
|
+
if (mod != null) {
|
|
9092
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
9093
|
+
}
|
|
9094
|
+
__setModuleDefault(result, mod);
|
|
9095
|
+
return result;
|
|
9096
|
+
};
|
|
9097
|
+
})();
|
|
9098
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9099
|
+
exports.BRIEF_STATE_VERSION = void 0;
|
|
9100
|
+
exports.sanitizeAgentFilename = sanitizeAgentFilename;
|
|
9101
|
+
exports.getBriefStateDir = getBriefStateDir;
|
|
9102
|
+
exports.getBriefStatePath = getBriefStatePath;
|
|
9103
|
+
exports.readBriefState = readBriefState;
|
|
9104
|
+
exports.writeBriefState = writeBriefState;
|
|
9105
|
+
var fs11 = __importStar(__require("fs"));
|
|
9106
|
+
var path11 = __importStar(__require("path"));
|
|
9107
|
+
var files_1 = require_files();
|
|
9108
|
+
exports.BRIEF_STATE_VERSION = 1;
|
|
9109
|
+
function sanitizeAgentFilename(agentName) {
|
|
9110
|
+
const trimmed = agentName.trim().toLowerCase();
|
|
9111
|
+
let cleaned = "";
|
|
9112
|
+
for (const ch of trimmed) {
|
|
9113
|
+
if (/[a-z0-9._-]/.test(ch)) {
|
|
9114
|
+
cleaned += ch;
|
|
9115
|
+
} else {
|
|
9116
|
+
cleaned += `_${ch.charCodeAt(0).toString(16).padStart(2, "0")}`;
|
|
9117
|
+
}
|
|
9118
|
+
}
|
|
9119
|
+
if (cleaned.length === 0 || cleaned === "." || cleaned === "..")
|
|
9120
|
+
return "_";
|
|
9121
|
+
return cleaned;
|
|
9122
|
+
}
|
|
9123
|
+
function getBriefStateDir(brainfilePath) {
|
|
9124
|
+
return path11.join((0, files_1.getBrainfileStateDir)(brainfilePath), files_1.DOT_BRAINFILE_STATE_DIRNAME);
|
|
9125
|
+
}
|
|
9126
|
+
function getBriefStatePath(brainfilePath, agentName) {
|
|
9127
|
+
return path11.join(getBriefStateDir(brainfilePath), `${sanitizeAgentFilename(agentName)}.json`);
|
|
9128
|
+
}
|
|
9129
|
+
function readBriefState(brainfilePath, agentName) {
|
|
9130
|
+
const statePath = getBriefStatePath(brainfilePath, agentName);
|
|
9131
|
+
const fallback = { version: exports.BRIEF_STATE_VERSION, agent: agentName, lastBriefAt: null };
|
|
9132
|
+
if (!fs11.existsSync(statePath))
|
|
9133
|
+
return fallback;
|
|
9134
|
+
try {
|
|
9135
|
+
const parsed = JSON.parse(fs11.readFileSync(statePath, "utf-8"));
|
|
9136
|
+
const lastBriefAt = typeof parsed.lastBriefAt === "string" ? parsed.lastBriefAt : null;
|
|
9137
|
+
return {
|
|
9138
|
+
version: typeof parsed.version === "number" ? parsed.version : exports.BRIEF_STATE_VERSION,
|
|
9139
|
+
agent: typeof parsed.agent === "string" ? parsed.agent : agentName,
|
|
9140
|
+
lastBriefAt
|
|
9141
|
+
};
|
|
9142
|
+
} catch {
|
|
9143
|
+
console.warn(`Warning: unreadable brief state at ${statePath}; treating as first brief`);
|
|
9144
|
+
return fallback;
|
|
9145
|
+
}
|
|
9146
|
+
}
|
|
9147
|
+
function writeBriefState(brainfilePath, agentName, lastBriefAt) {
|
|
9148
|
+
(0, files_1.ensureDotBrainfileGitignore)(brainfilePath);
|
|
9149
|
+
const state = { version: exports.BRIEF_STATE_VERSION, agent: agentName, lastBriefAt };
|
|
9150
|
+
(0, files_1.atomicWriteFileSync)(getBriefStatePath(brainfilePath, agentName), `${JSON.stringify(state, null, 2)}
|
|
9151
|
+
`);
|
|
9152
|
+
return state;
|
|
9153
|
+
}
|
|
9154
|
+
}
|
|
9155
|
+
});
|
|
9156
|
+
|
|
9157
|
+
// ../core/dist/formatters.js
|
|
9158
|
+
var require_formatters = __commonJS({
|
|
9159
|
+
"../core/dist/formatters.js"(exports) {
|
|
9160
|
+
"use strict";
|
|
9161
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9162
|
+
exports.formatTaskForGitHub = formatTaskForGitHub;
|
|
9163
|
+
exports.formatTaskForLinear = formatTaskForLinear;
|
|
9164
|
+
function formatTaskForGitHub(task, options = {}) {
|
|
9165
|
+
const { includeMeta = true, includeSubtasks = true, includeRelatedFiles = true, resolvedBy, resolvedByPR, fromColumn, boardTitle, extraLabels = [], includeTaskId = true } = options;
|
|
9166
|
+
const title = includeTaskId ? `[${task.id}] ${task.title}` : task.title;
|
|
9167
|
+
const sections = [];
|
|
9168
|
+
if (task.description) {
|
|
9169
|
+
sections.push(task.description);
|
|
9170
|
+
}
|
|
9171
|
+
if (includeSubtasks && task.subtasks && task.subtasks.length > 0) {
|
|
9172
|
+
sections.push(formatSubtasksMarkdown(task.subtasks));
|
|
9173
|
+
}
|
|
9174
|
+
if (includeMeta) {
|
|
9175
|
+
const meta = formatMetadataSection(task, { fromColumn, boardTitle });
|
|
9176
|
+
if (meta) {
|
|
9177
|
+
sections.push(meta);
|
|
9178
|
+
}
|
|
9179
|
+
}
|
|
9180
|
+
if (includeRelatedFiles && task.relatedFiles && task.relatedFiles.length > 0) {
|
|
9181
|
+
sections.push(formatRelatedFilesSection(task.relatedFiles));
|
|
9182
|
+
}
|
|
9183
|
+
if (resolvedBy || resolvedByPR) {
|
|
9184
|
+
sections.push(formatResolutionSection(resolvedBy, resolvedByPR));
|
|
9185
|
+
}
|
|
9186
|
+
sections.push("---\n*Archived from brainfile.md*");
|
|
9187
|
+
const labels = [...task.tags || [], ...extraLabels];
|
|
9188
|
+
if (task.priority) {
|
|
9189
|
+
labels.push(`priority:${task.priority}`);
|
|
9190
|
+
}
|
|
9191
|
+
if (task.template) {
|
|
9192
|
+
labels.push(task.template);
|
|
9193
|
+
}
|
|
9194
|
+
return {
|
|
9195
|
+
title,
|
|
9196
|
+
body: sections.join("\n\n"),
|
|
9197
|
+
labels: labels.length > 0 ? labels : void 0,
|
|
9198
|
+
state: "closed"
|
|
9199
|
+
};
|
|
9200
|
+
}
|
|
9201
|
+
function mapPriorityToLinear(priority) {
|
|
9202
|
+
switch (priority) {
|
|
9203
|
+
case "critical":
|
|
9204
|
+
return 1;
|
|
9205
|
+
case "high":
|
|
9206
|
+
return 2;
|
|
9207
|
+
case "medium":
|
|
9208
|
+
return 3;
|
|
9209
|
+
case "low":
|
|
9210
|
+
return 4;
|
|
9211
|
+
default:
|
|
9212
|
+
return void 0;
|
|
9213
|
+
}
|
|
9214
|
+
}
|
|
9215
|
+
function formatTaskForLinear(task, options = {}) {
|
|
9216
|
+
const { includeMeta = true, includeSubtasks = true, includeRelatedFiles = true, resolvedBy, resolvedByPR, fromColumn, boardTitle, stateName = "Done", includeTaskId = false } = options;
|
|
9217
|
+
const title = includeTaskId ? `[${task.id}] ${task.title}` : task.title;
|
|
9218
|
+
const sections = [];
|
|
9219
|
+
if (task.description) {
|
|
9220
|
+
sections.push(task.description);
|
|
9221
|
+
}
|
|
9222
|
+
if (includeSubtasks && task.subtasks && task.subtasks.length > 0) {
|
|
9223
|
+
sections.push(formatSubtasksMarkdown(task.subtasks));
|
|
9224
|
+
}
|
|
9225
|
+
if (includeMeta) {
|
|
9226
|
+
const meta = formatMetadataSection(task, { fromColumn, boardTitle });
|
|
9227
|
+
if (meta) {
|
|
9228
|
+
sections.push(meta);
|
|
9229
|
+
}
|
|
9230
|
+
}
|
|
9231
|
+
if (includeRelatedFiles && task.relatedFiles && task.relatedFiles.length > 0) {
|
|
9232
|
+
sections.push(formatRelatedFilesSection(task.relatedFiles));
|
|
9233
|
+
}
|
|
9234
|
+
if (resolvedBy || resolvedByPR) {
|
|
9235
|
+
sections.push(formatResolutionSection(resolvedBy, resolvedByPR));
|
|
9236
|
+
}
|
|
9237
|
+
sections.push("---\n*Archived from brainfile.md*");
|
|
9238
|
+
return {
|
|
9239
|
+
title,
|
|
9240
|
+
description: sections.join("\n\n"),
|
|
9241
|
+
priority: mapPriorityToLinear(task.priority),
|
|
9242
|
+
labelNames: task.tags && task.tags.length > 0 ? task.tags : void 0,
|
|
9243
|
+
stateName
|
|
9244
|
+
};
|
|
9245
|
+
}
|
|
9246
|
+
function formatSubtasksMarkdown(subtasks) {
|
|
9247
|
+
const items = subtasks.map((st) => `- [${st.completed ? "x" : " "}] ${st.title}`);
|
|
9248
|
+
return `## Subtasks
|
|
9249
|
+
|
|
9250
|
+
${items.join("\n")}`;
|
|
9251
|
+
}
|
|
9252
|
+
function formatMetadataSection(task, context) {
|
|
9253
|
+
const lines = [];
|
|
9254
|
+
if (context.boardTitle) {
|
|
9255
|
+
lines.push(`**Board:** ${context.boardTitle}`);
|
|
9256
|
+
}
|
|
9257
|
+
if (context.fromColumn) {
|
|
9258
|
+
lines.push(`**Column:** ${context.fromColumn}`);
|
|
9259
|
+
}
|
|
9260
|
+
if (task.priority) {
|
|
9261
|
+
lines.push(`**Priority:** ${task.priority}`);
|
|
9262
|
+
}
|
|
9263
|
+
if (task.assignee) {
|
|
9264
|
+
lines.push(`**Assignee:** ${task.assignee}`);
|
|
9265
|
+
}
|
|
9266
|
+
if (task.dueDate) {
|
|
9267
|
+
lines.push(`**Due Date:** ${task.dueDate}`);
|
|
9268
|
+
}
|
|
9269
|
+
if (task.createdAt) {
|
|
9270
|
+
lines.push(`**Created:** ${task.createdAt}`);
|
|
9271
|
+
}
|
|
9272
|
+
if (lines.length === 0) {
|
|
9273
|
+
return null;
|
|
9274
|
+
}
|
|
9275
|
+
return `## Details
|
|
9276
|
+
|
|
9277
|
+
${lines.join("\n")}`;
|
|
9278
|
+
}
|
|
9279
|
+
function formatRelatedFilesSection(files) {
|
|
9280
|
+
const items = files.map((f) => `- \`${f}\``);
|
|
9281
|
+
return `## Related Files
|
|
9282
|
+
|
|
9283
|
+
${items.join("\n")}`;
|
|
9284
|
+
}
|
|
9285
|
+
function formatResolutionSection(resolvedBy, resolvedByPR) {
|
|
9286
|
+
const lines = ["## Resolution"];
|
|
9287
|
+
if (resolvedByPR) {
|
|
9288
|
+
lines.push(`
|
|
9289
|
+
**Pull Request:** ${resolvedByPR}`);
|
|
9290
|
+
}
|
|
9291
|
+
if (resolvedBy) {
|
|
9292
|
+
lines.push(`
|
|
9293
|
+
**Commit:** ${resolvedBy}`);
|
|
9294
|
+
}
|
|
9295
|
+
return lines.join("");
|
|
9296
|
+
}
|
|
9297
|
+
}
|
|
9298
|
+
});
|
|
9299
|
+
|
|
9300
|
+
// ../core/dist/boardContent.js
|
|
9301
|
+
var require_boardContent = __commonJS({
|
|
9302
|
+
"../core/dist/boardContent.js"(exports) {
|
|
9303
|
+
"use strict";
|
|
9304
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9305
|
+
exports.parseBoardConfig = parseBoardConfig;
|
|
9306
|
+
exports.serializeBoardConfig = serializeBoardConfig;
|
|
9307
|
+
var frontmatter_1 = require_frontmatter();
|
|
9308
|
+
function parseBoardConfig(content) {
|
|
9309
|
+
const parsed = (0, frontmatter_1.parseFrontmatter)(content);
|
|
9310
|
+
if (!parsed) {
|
|
9311
|
+
return null;
|
|
9312
|
+
}
|
|
9313
|
+
return {
|
|
9314
|
+
config: parsed.data,
|
|
9315
|
+
body: parsed.body
|
|
9316
|
+
};
|
|
9317
|
+
}
|
|
9318
|
+
function serializeBoardConfig(config, body = "") {
|
|
9319
|
+
return (0, frontmatter_1.serializeFrontmatter)(config, body);
|
|
9320
|
+
}
|
|
9321
|
+
}
|
|
9322
|
+
});
|
|
9323
|
+
|
|
9324
|
+
// ../core/dist/boardFile.js
|
|
9325
|
+
var require_boardFile = __commonJS({
|
|
9326
|
+
"../core/dist/boardFile.js"(exports) {
|
|
9327
|
+
"use strict";
|
|
9328
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
9329
|
+
if (k2 === void 0) k2 = k;
|
|
9330
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9331
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9332
|
+
desc = { enumerable: true, get: function() {
|
|
9333
|
+
return m[k];
|
|
9334
|
+
} };
|
|
9335
|
+
}
|
|
9336
|
+
Object.defineProperty(o, k2, desc);
|
|
9337
|
+
}) : (function(o, m, k, k2) {
|
|
9338
|
+
if (k2 === void 0) k2 = k;
|
|
9339
|
+
o[k2] = m[k];
|
|
9340
|
+
}));
|
|
9341
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
9342
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
9343
|
+
}) : function(o, v) {
|
|
9344
|
+
o["default"] = v;
|
|
9345
|
+
});
|
|
9346
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
9347
|
+
var ownKeys = function(o) {
|
|
9348
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
9349
|
+
var ar = [];
|
|
9350
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
9351
|
+
return ar;
|
|
9352
|
+
};
|
|
9353
|
+
return ownKeys(o);
|
|
9354
|
+
};
|
|
9355
|
+
return function(mod) {
|
|
9356
|
+
if (mod && mod.__esModule) return mod;
|
|
9357
|
+
var result = {};
|
|
9358
|
+
if (mod != null) {
|
|
9359
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
9360
|
+
}
|
|
9361
|
+
__setModuleDefault(result, mod);
|
|
9362
|
+
return result;
|
|
9363
|
+
};
|
|
9364
|
+
})();
|
|
9365
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9366
|
+
exports.serializeBoardConfig = exports.parseBoardConfig = void 0;
|
|
9367
|
+
exports.readBoardConfig = readBoardConfig;
|
|
9368
|
+
exports.writeBoardConfig = writeBoardConfig;
|
|
9369
|
+
var fs11 = __importStar(__require("fs"));
|
|
9370
|
+
var path11 = __importStar(__require("path"));
|
|
9371
|
+
var boardContent_1 = require_boardContent();
|
|
9372
|
+
var boardContent_2 = require_boardContent();
|
|
9373
|
+
Object.defineProperty(exports, "parseBoardConfig", { enumerable: true, get: function() {
|
|
9374
|
+
return boardContent_2.parseBoardConfig;
|
|
9375
|
+
} });
|
|
9376
|
+
Object.defineProperty(exports, "serializeBoardConfig", { enumerable: true, get: function() {
|
|
9377
|
+
return boardContent_2.serializeBoardConfig;
|
|
9378
|
+
} });
|
|
9379
|
+
function readBoardConfig(filePath) {
|
|
9380
|
+
let content;
|
|
9381
|
+
try {
|
|
9382
|
+
content = fs11.readFileSync(filePath, "utf-8");
|
|
9383
|
+
} catch {
|
|
9384
|
+
return null;
|
|
9385
|
+
}
|
|
9386
|
+
const parsed = (0, boardContent_1.parseBoardConfig)(content);
|
|
9387
|
+
if (!parsed) {
|
|
9388
|
+
return null;
|
|
8814
9389
|
}
|
|
8815
|
-
return
|
|
9390
|
+
return {
|
|
9391
|
+
config: parsed.config,
|
|
9392
|
+
body: parsed.body,
|
|
9393
|
+
filePath: path11.resolve(filePath)
|
|
9394
|
+
};
|
|
8816
9395
|
}
|
|
8817
|
-
function
|
|
8818
|
-
const
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
if (scopeFiles.length === 0) {
|
|
8823
|
-
return [];
|
|
8824
|
-
}
|
|
8825
|
-
let entries = readLedger(logsDir).filter((record) => matchesDateRange(record.completedAt, options.dateRange)).map((record) => {
|
|
8826
|
-
const matchedFiles = matchedFilesForScope(scopeFiles, collectRecordFiles(record));
|
|
8827
|
-
return { record, matchedFiles };
|
|
8828
|
-
}).filter((entry) => entry.matchedFiles.length > 0);
|
|
8829
|
-
entries.sort((a, b) => timestampOr(b.record.completedAt, 0) - timestampOr(a.record.completedAt, 0));
|
|
8830
|
-
if (options.limit !== void 0 && options.limit > 0) {
|
|
8831
|
-
entries = entries.slice(0, options.limit);
|
|
8832
|
-
}
|
|
8833
|
-
return entries;
|
|
9396
|
+
function writeBoardConfig(filePath, config, body = "") {
|
|
9397
|
+
const dir = path11.dirname(filePath);
|
|
9398
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
9399
|
+
const content = (0, boardContent_1.serializeBoardConfig)(config, body);
|
|
9400
|
+
fs11.writeFileSync(filePath, content, "utf-8");
|
|
8834
9401
|
}
|
|
8835
9402
|
}
|
|
8836
9403
|
});
|
|
@@ -8902,8 +9469,8 @@ var require_taskOperations = __commonJS({
|
|
|
8902
9469
|
exports.activateTaskContract = activateTaskContract;
|
|
8903
9470
|
exports.activateTaskContractsByParent = activateTaskContractsByParent;
|
|
8904
9471
|
exports.getEffectiveState = getEffectiveState;
|
|
8905
|
-
var
|
|
8906
|
-
var
|
|
9472
|
+
var fs11 = __importStar(__require("fs"));
|
|
9473
|
+
var path11 = __importStar(__require("path"));
|
|
8907
9474
|
var boardValidation_1 = require_boardValidation();
|
|
8908
9475
|
var contractSpec_1 = require_contractSpec();
|
|
8909
9476
|
var idGen_1 = require_idGen();
|
|
@@ -9005,52 +9572,29 @@ ${section}
|
|
|
9005
9572
|
return lines.join("\n");
|
|
9006
9573
|
}
|
|
9007
9574
|
function writeTaskFileExclusive(filePath, task, body) {
|
|
9008
|
-
const dir =
|
|
9009
|
-
|
|
9575
|
+
const dir = path11.dirname(filePath);
|
|
9576
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
9010
9577
|
const content = (0, taskFile_1.serializeTaskContent)(task, body);
|
|
9011
|
-
|
|
9578
|
+
fs11.writeFileSync(filePath, content, { encoding: "utf-8", flag: "wx" });
|
|
9012
9579
|
}
|
|
9013
9580
|
function rollbackLedgerAppend(logsDir, appendedRecord) {
|
|
9014
|
-
const ledgerPath =
|
|
9581
|
+
const ledgerPath = path11.join(logsDir, "ledger.jsonl");
|
|
9015
9582
|
const appendedLine = `${JSON.stringify(appendedRecord)}
|
|
9016
9583
|
`;
|
|
9017
9584
|
const appendedBytes = Buffer.byteLength(appendedLine, "utf-8");
|
|
9018
9585
|
try {
|
|
9019
|
-
const stat =
|
|
9586
|
+
const stat = fs11.statSync(ledgerPath);
|
|
9020
9587
|
const newSize = stat.size - appendedBytes;
|
|
9021
9588
|
if (newSize >= 0) {
|
|
9022
|
-
|
|
9589
|
+
fs11.truncateSync(ledgerPath, newSize);
|
|
9023
9590
|
}
|
|
9024
9591
|
} catch {
|
|
9025
9592
|
}
|
|
9026
9593
|
}
|
|
9027
|
-
function
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
if (doc.task.type === "epic") {
|
|
9032
|
-
const childTasksSection = buildChildTasksSection(childStates ?? []);
|
|
9033
|
-
completedBody = appendBodySection(doc.body, childTasksSection);
|
|
9034
|
-
}
|
|
9035
|
-
if (fs7.existsSync(destPath)) {
|
|
9036
|
-
return { success: false, error: `Task already exists in logs: ${doc.task.id}` };
|
|
9037
|
-
}
|
|
9038
|
-
try {
|
|
9039
|
-
fs7.mkdirSync(logsDir, { recursive: true });
|
|
9040
|
-
writeTaskFileExclusive(destPath, completedTask, completedBody);
|
|
9041
|
-
} catch (err) {
|
|
9042
|
-
return { success: false, error: `Failed to complete task: ${err}` };
|
|
9043
|
-
}
|
|
9044
|
-
try {
|
|
9045
|
-
fs7.unlinkSync(taskPath);
|
|
9046
|
-
return { success: true, task: completedTask, filePath: destPath };
|
|
9047
|
-
} catch (err) {
|
|
9048
|
-
try {
|
|
9049
|
-
fs7.unlinkSync(destPath);
|
|
9050
|
-
} catch {
|
|
9051
|
-
}
|
|
9052
|
-
return { success: false, error: `Failed to finalize completion: ${err}` };
|
|
9053
|
-
}
|
|
9594
|
+
function archivedBody(doc, childStates) {
|
|
9595
|
+
if (doc.task.type !== "epic")
|
|
9596
|
+
return doc.body;
|
|
9597
|
+
return appendBodySection(doc.body, buildChildTasksSection(childStates ?? []));
|
|
9054
9598
|
}
|
|
9055
9599
|
function generateNextFileTaskId(boardDir, logsDir, typePrefix = "task") {
|
|
9056
9600
|
let maxNum = 0;
|
|
@@ -9124,7 +9668,7 @@ ${section}
|
|
|
9124
9668
|
};
|
|
9125
9669
|
let filePath;
|
|
9126
9670
|
try {
|
|
9127
|
-
filePath =
|
|
9671
|
+
filePath = path11.join(boardDir, (0, taskFile_1.taskFileName)(taskId));
|
|
9128
9672
|
} catch (err) {
|
|
9129
9673
|
return { success: false, error: err.message };
|
|
9130
9674
|
}
|
|
@@ -9178,7 +9722,7 @@ ${section}
|
|
|
9178
9722
|
if (!doc) {
|
|
9179
9723
|
return { success: false, error: `Task not found: ${taskId}` };
|
|
9180
9724
|
}
|
|
9181
|
-
let filePath = doc.filePath ??
|
|
9725
|
+
let filePath = doc.filePath ?? path11.join(dirs.boardDir, (0, taskFile_1.taskFileName)(taskId));
|
|
9182
9726
|
if (doc.task.column === resolvedColumn.id) {
|
|
9183
9727
|
return { success: true, task: doc.task, filePath, column: resolvedColumn, noop: true };
|
|
9184
9728
|
}
|
|
@@ -9198,7 +9742,7 @@ ${section}
|
|
|
9198
9742
|
if (!shouldAutoComplete) {
|
|
9199
9743
|
return { success: true, task, filePath, column: resolvedColumn };
|
|
9200
9744
|
}
|
|
9201
|
-
const completeResult = completeTaskFile(filePath, dirs.logsDir
|
|
9745
|
+
const completeResult = completeTaskFile(filePath, dirs.logsDir);
|
|
9202
9746
|
if (!completeResult.success || !completeResult.task) {
|
|
9203
9747
|
return {
|
|
9204
9748
|
success: false,
|
|
@@ -9394,7 +9938,7 @@ ${section}
|
|
|
9394
9938
|
let childStates;
|
|
9395
9939
|
let incompleteChildren;
|
|
9396
9940
|
if (doc.task.type === "epic") {
|
|
9397
|
-
const boardDir =
|
|
9941
|
+
const boardDir = path11.dirname(taskPath);
|
|
9398
9942
|
childStates = resolveEpicChildStates(doc.task, boardDir, logsDir);
|
|
9399
9943
|
const incomplete = childStates.filter((child) => child.status === "active").map((child) => ({ id: child.id, title: child.title }));
|
|
9400
9944
|
if (incomplete.length > 0) {
|
|
@@ -9415,32 +9959,43 @@ ${section}
|
|
|
9415
9959
|
completedAt: now,
|
|
9416
9960
|
updatedAt: now
|
|
9417
9961
|
};
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
return
|
|
9962
|
+
const destPath = path11.join(logsDir, path11.basename(taskPath));
|
|
9963
|
+
if (fs11.existsSync(destPath)) {
|
|
9964
|
+
return { success: false, error: `Task already exists in logs: ${doc.task.id}` };
|
|
9421
9965
|
}
|
|
9422
|
-
const
|
|
9966
|
+
const completedBody = archivedBody(doc, childStates);
|
|
9967
|
+
const record = (0, ledger_2.buildLedgerRecord)(completedTask, completedBody, {
|
|
9423
9968
|
summary: options.summary,
|
|
9424
9969
|
filesChanged: options.filesChanged,
|
|
9425
9970
|
completedAt: now,
|
|
9426
9971
|
columnHistory: options.columnHistory,
|
|
9427
9972
|
validationAttempts: options.validationAttempts
|
|
9428
9973
|
});
|
|
9429
|
-
let ledgerPath;
|
|
9430
9974
|
try {
|
|
9431
|
-
|
|
9975
|
+
(0, ledger_2.appendLedgerRecord)(logsDir, record);
|
|
9432
9976
|
} catch (err) {
|
|
9433
9977
|
return { success: false, error: `Failed to append ledger record: ${err}` };
|
|
9434
9978
|
}
|
|
9435
9979
|
try {
|
|
9436
|
-
|
|
9980
|
+
fs11.mkdirSync(logsDir, { recursive: true });
|
|
9981
|
+
writeTaskFileExclusive(destPath, completedTask, completedBody);
|
|
9982
|
+
} catch (err) {
|
|
9983
|
+
rollbackLedgerAppend(logsDir, record);
|
|
9984
|
+
return { success: false, error: `Failed to complete task: ${err}` };
|
|
9985
|
+
}
|
|
9986
|
+
try {
|
|
9987
|
+
fs11.unlinkSync(taskPath);
|
|
9437
9988
|
return {
|
|
9438
9989
|
success: true,
|
|
9439
9990
|
task: completedTask,
|
|
9440
|
-
filePath:
|
|
9991
|
+
filePath: destPath,
|
|
9441
9992
|
...incompleteChildren && { incompleteChildren }
|
|
9442
9993
|
};
|
|
9443
9994
|
} catch (err) {
|
|
9995
|
+
try {
|
|
9996
|
+
fs11.unlinkSync(destPath);
|
|
9997
|
+
} catch {
|
|
9998
|
+
}
|
|
9444
9999
|
rollbackLedgerAppend(logsDir, record);
|
|
9445
10000
|
return { success: false, error: `Failed to finalize completion: ${err}` };
|
|
9446
10001
|
}
|
|
@@ -9451,7 +10006,7 @@ ${section}
|
|
|
9451
10006
|
return { success: false, error: `Failed to read task file: ${taskPath}` };
|
|
9452
10007
|
}
|
|
9453
10008
|
try {
|
|
9454
|
-
|
|
10009
|
+
fs11.unlinkSync(taskPath);
|
|
9455
10010
|
return { success: true, task: doc.task };
|
|
9456
10011
|
} catch (err) {
|
|
9457
10012
|
return { success: false, error: `Failed to delete task file: ${err}` };
|
|
@@ -9526,7 +10081,7 @@ ${section}
|
|
|
9526
10081
|
}
|
|
9527
10082
|
function findTask(boardDir, taskId) {
|
|
9528
10083
|
try {
|
|
9529
|
-
const directPath =
|
|
10084
|
+
const directPath = path11.join(boardDir, (0, taskFile_1.taskFileName)(taskId));
|
|
9530
10085
|
const directDoc = (0, taskFile_1.readTaskFile)(directPath);
|
|
9531
10086
|
if (directDoc && directDoc.task.id === taskId) {
|
|
9532
10087
|
return directDoc;
|
|
@@ -9759,7 +10314,7 @@ ${section}
|
|
|
9759
10314
|
if (doc.task.contract?.status !== "draft")
|
|
9760
10315
|
continue;
|
|
9761
10316
|
const task = applyContractActivation(doc.task, (/* @__PURE__ */ new Date()).toISOString());
|
|
9762
|
-
const taskPath = doc.filePath ??
|
|
10317
|
+
const taskPath = doc.filePath ?? path11.join(boardDir, (0, taskFile_1.taskFileName)(task.id));
|
|
9763
10318
|
(0, taskFile_1.writeTaskFile)(taskPath, task, doc.body);
|
|
9764
10319
|
activated.push(task.id);
|
|
9765
10320
|
}
|
|
@@ -9775,196 +10330,6 @@ ${section}
|
|
|
9775
10330
|
}
|
|
9776
10331
|
});
|
|
9777
10332
|
|
|
9778
|
-
// ../core/dist/workspace.js
|
|
9779
|
-
var require_workspace = __commonJS({
|
|
9780
|
-
"../core/dist/workspace.js"(exports) {
|
|
9781
|
-
"use strict";
|
|
9782
|
-
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
9783
|
-
if (k2 === void 0) k2 = k;
|
|
9784
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9785
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9786
|
-
desc = { enumerable: true, get: function() {
|
|
9787
|
-
return m[k];
|
|
9788
|
-
} };
|
|
9789
|
-
}
|
|
9790
|
-
Object.defineProperty(o, k2, desc);
|
|
9791
|
-
}) : (function(o, m, k, k2) {
|
|
9792
|
-
if (k2 === void 0) k2 = k;
|
|
9793
|
-
o[k2] = m[k];
|
|
9794
|
-
}));
|
|
9795
|
-
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
9796
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
9797
|
-
}) : function(o, v) {
|
|
9798
|
-
o["default"] = v;
|
|
9799
|
-
});
|
|
9800
|
-
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
9801
|
-
var ownKeys = function(o) {
|
|
9802
|
-
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
9803
|
-
var ar = [];
|
|
9804
|
-
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
9805
|
-
return ar;
|
|
9806
|
-
};
|
|
9807
|
-
return ownKeys(o);
|
|
9808
|
-
};
|
|
9809
|
-
return function(mod) {
|
|
9810
|
-
if (mod && mod.__esModule) return mod;
|
|
9811
|
-
var result = {};
|
|
9812
|
-
if (mod != null) {
|
|
9813
|
-
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
9814
|
-
}
|
|
9815
|
-
__setModuleDefault(result, mod);
|
|
9816
|
-
return result;
|
|
9817
|
-
};
|
|
9818
|
-
})();
|
|
9819
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9820
|
-
exports.getV2Dirs = getV2Dirs2;
|
|
9821
|
-
exports.isV2 = isV25;
|
|
9822
|
-
exports.ensureV2Dirs = ensureV2Dirs2;
|
|
9823
|
-
exports.getTaskFilePath = getTaskFilePath2;
|
|
9824
|
-
exports.getLogFilePath = getLogFilePath2;
|
|
9825
|
-
exports.findV2Task = findV2Task2;
|
|
9826
|
-
exports.extractDescription = extractDescription2;
|
|
9827
|
-
exports.extractLog = extractLog2;
|
|
9828
|
-
exports.composeBody = composeBody2;
|
|
9829
|
-
exports.readV2BoardConfig = readV2BoardConfig2;
|
|
9830
|
-
exports.buildBoardFromV2 = buildBoardFromV22;
|
|
9831
|
-
var fs7 = __importStar(__require("fs"));
|
|
9832
|
-
var path7 = __importStar(__require("path"));
|
|
9833
|
-
var parser_1 = require_parser();
|
|
9834
|
-
var taskFile_1 = require_taskFile();
|
|
9835
|
-
function getV2Dirs2(brainfilePath) {
|
|
9836
|
-
const resolvedPath = path7.resolve(brainfilePath);
|
|
9837
|
-
const dotDir = path7.dirname(resolvedPath);
|
|
9838
|
-
return {
|
|
9839
|
-
dotDir,
|
|
9840
|
-
boardDir: path7.join(dotDir, "board"),
|
|
9841
|
-
logsDir: path7.join(dotDir, "logs"),
|
|
9842
|
-
brainfilePath: resolvedPath
|
|
9843
|
-
};
|
|
9844
|
-
}
|
|
9845
|
-
function isV25(brainfilePath) {
|
|
9846
|
-
const { boardDir } = getV2Dirs2(brainfilePath);
|
|
9847
|
-
return fs7.existsSync(boardDir);
|
|
9848
|
-
}
|
|
9849
|
-
function ensureV2Dirs2(brainfilePath) {
|
|
9850
|
-
const dirs = getV2Dirs2(brainfilePath);
|
|
9851
|
-
fs7.mkdirSync(dirs.boardDir, { recursive: true });
|
|
9852
|
-
fs7.mkdirSync(dirs.logsDir, { recursive: true });
|
|
9853
|
-
return dirs;
|
|
9854
|
-
}
|
|
9855
|
-
function getTaskFilePath2(boardDir, taskId) {
|
|
9856
|
-
return path7.join(boardDir, (0, taskFile_1.taskFileName)(taskId));
|
|
9857
|
-
}
|
|
9858
|
-
function getLogFilePath2(logsDir, taskId) {
|
|
9859
|
-
return path7.join(logsDir, (0, taskFile_1.taskFileName)(taskId));
|
|
9860
|
-
}
|
|
9861
|
-
function findV2Task2(dirs, taskId, searchLogs = false) {
|
|
9862
|
-
const taskPath = getTaskFilePath2(dirs.boardDir, taskId);
|
|
9863
|
-
const taskDoc = (0, taskFile_1.readTaskFile)(taskPath);
|
|
9864
|
-
if (taskDoc && taskDoc.task.id === taskId) {
|
|
9865
|
-
return { doc: taskDoc, filePath: taskPath, isLog: false };
|
|
9866
|
-
}
|
|
9867
|
-
if (searchLogs) {
|
|
9868
|
-
const logPath = getLogFilePath2(dirs.logsDir, taskId);
|
|
9869
|
-
const logDoc = (0, taskFile_1.readTaskFile)(logPath);
|
|
9870
|
-
if (logDoc && logDoc.task.id === taskId) {
|
|
9871
|
-
return { doc: logDoc, filePath: logPath, isLog: true };
|
|
9872
|
-
}
|
|
9873
|
-
}
|
|
9874
|
-
const boardDocs = (0, taskFile_1.readTasksDir)(dirs.boardDir);
|
|
9875
|
-
const boardMatch = boardDocs.find((d) => d.task.id === taskId);
|
|
9876
|
-
if (boardMatch) {
|
|
9877
|
-
return {
|
|
9878
|
-
doc: boardMatch,
|
|
9879
|
-
filePath: boardMatch.filePath || taskPath,
|
|
9880
|
-
isLog: false
|
|
9881
|
-
};
|
|
9882
|
-
}
|
|
9883
|
-
if (searchLogs) {
|
|
9884
|
-
const logDocs = (0, taskFile_1.readTasksDir)(dirs.logsDir);
|
|
9885
|
-
const logMatch = logDocs.find((d) => d.task.id === taskId);
|
|
9886
|
-
if (logMatch) {
|
|
9887
|
-
return {
|
|
9888
|
-
doc: logMatch,
|
|
9889
|
-
filePath: logMatch.filePath || getLogFilePath2(dirs.logsDir, taskId),
|
|
9890
|
-
isLog: true
|
|
9891
|
-
};
|
|
9892
|
-
}
|
|
9893
|
-
}
|
|
9894
|
-
return null;
|
|
9895
|
-
}
|
|
9896
|
-
function extractDescription2(body) {
|
|
9897
|
-
const match = body.match(/## Description\n([\s\S]*?)(?=\n## |\n*$)/);
|
|
9898
|
-
return match ? match[1].trim() || void 0 : void 0;
|
|
9899
|
-
}
|
|
9900
|
-
function extractLog2(body) {
|
|
9901
|
-
const match = body.match(/## Log\n([\s\S]*?)(?=\n## |\n*$)/);
|
|
9902
|
-
return match ? match[1].trim() || void 0 : void 0;
|
|
9903
|
-
}
|
|
9904
|
-
function composeBody2(description, log) {
|
|
9905
|
-
const sections = [];
|
|
9906
|
-
if (description && description.trim()) {
|
|
9907
|
-
sections.push(`## Description
|
|
9908
|
-
${description.trim()}`);
|
|
9909
|
-
}
|
|
9910
|
-
if (log && log.trim()) {
|
|
9911
|
-
sections.push(`## Log
|
|
9912
|
-
${log.trim()}`);
|
|
9913
|
-
}
|
|
9914
|
-
if (sections.length === 0)
|
|
9915
|
-
return "";
|
|
9916
|
-
return `${sections.join("\n\n")}
|
|
9917
|
-
`;
|
|
9918
|
-
}
|
|
9919
|
-
function readV2BoardConfig2(brainfilePath) {
|
|
9920
|
-
const content = fs7.readFileSync(brainfilePath, "utf-8");
|
|
9921
|
-
const result = parser_1.BrainfileParser.parseWithErrors(content);
|
|
9922
|
-
if (!result.board) {
|
|
9923
|
-
throw new Error(`Failed to parse brainfile: ${result.error}`);
|
|
9924
|
-
}
|
|
9925
|
-
const board = result.board;
|
|
9926
|
-
for (const col of board.columns) {
|
|
9927
|
-
if (!col.tasks)
|
|
9928
|
-
col.tasks = [];
|
|
9929
|
-
}
|
|
9930
|
-
return board;
|
|
9931
|
-
}
|
|
9932
|
-
function buildBoardFromV22(brainfilePath) {
|
|
9933
|
-
const dirs = getV2Dirs2(brainfilePath);
|
|
9934
|
-
const board = readV2BoardConfig2(brainfilePath);
|
|
9935
|
-
const taskDocs = (0, taskFile_1.readTasksDir)(dirs.boardDir);
|
|
9936
|
-
const tasksByColumn = /* @__PURE__ */ new Map();
|
|
9937
|
-
for (const doc of taskDocs) {
|
|
9938
|
-
const colId = doc.task.column || "todo";
|
|
9939
|
-
if (!tasksByColumn.has(colId)) {
|
|
9940
|
-
tasksByColumn.set(colId, []);
|
|
9941
|
-
}
|
|
9942
|
-
tasksByColumn.get(colId).push(doc);
|
|
9943
|
-
}
|
|
9944
|
-
for (const col of board.columns) {
|
|
9945
|
-
const colTasks = tasksByColumn.get(col.id) || [];
|
|
9946
|
-
colTasks.sort((a, b) => {
|
|
9947
|
-
const posA = a.task.position ?? Number.MAX_SAFE_INTEGER;
|
|
9948
|
-
const posB = b.task.position ?? Number.MAX_SAFE_INTEGER;
|
|
9949
|
-
if (posA !== posB)
|
|
9950
|
-
return posA - posB;
|
|
9951
|
-
return a.task.id.localeCompare(b.task.id);
|
|
9952
|
-
});
|
|
9953
|
-
col.tasks = colTasks.map((doc) => {
|
|
9954
|
-
const task = { ...doc.task };
|
|
9955
|
-
if (!task.description) {
|
|
9956
|
-
const description = extractDescription2(doc.body);
|
|
9957
|
-
if (description)
|
|
9958
|
-
task.description = description;
|
|
9959
|
-
}
|
|
9960
|
-
return task;
|
|
9961
|
-
});
|
|
9962
|
-
}
|
|
9963
|
-
return board;
|
|
9964
|
-
}
|
|
9965
|
-
}
|
|
9966
|
-
});
|
|
9967
|
-
|
|
9968
10333
|
// ../core/dist/search.js
|
|
9969
10334
|
var require_search = __commonJS({
|
|
9970
10335
|
"../core/dist/search.js"(exports) {
|
|
@@ -10309,10 +10674,10 @@ var require_dist = __commonJS({
|
|
|
10309
10674
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
|
|
10310
10675
|
};
|
|
10311
10676
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10312
|
-
exports.
|
|
10313
|
-
exports.
|
|
10314
|
-
exports.
|
|
10315
|
-
exports.Brainfile = exports.buildBoardFromV2 = exports.readV2BoardConfig = exports.composeBody = exports.extractLog = exports.extractDescription = exports.findV2Task = exports.getLogFilePath = exports.getTaskFilePath = exports.ensureV2Dirs = exports.isV2 = exports.getV2Dirs = exports.topologicalSort = exports.DependencyCycleError = exports.MissingDependencyError = exports.ledgerRecordToCompletedRef = exports.taskToCompletedRef = void 0;
|
|
10677
|
+
exports.patchTasks = exports.moveTasks = exports.setAllSubtasksCompleted = exports.setSubtasksCompleted = exports.updateSubtask = exports.deleteSubtask = exports.addSubtask = exports.patchTask = exports.restoreTask = exports.archiveTask = exports.updateStatsConfig = exports.updateBoardTitle = exports.toggleSubtask = exports.deleteTask = exports.updateTask = exports.addTask = exports.moveTask = exports.getAllTemplateIds = exports.getTemplateById = exports.processTemplate = exports.generateSubtaskId = exports.generateTaskId = exports.BUILT_IN_TEMPLATES = exports.hashBoardContent = exports.hashBoard = exports.diffBoards = exports.BrainfileLinter = exports.BrainfileValidator = exports.serializeFrontmatter = exports.parseFrontmatter = exports.BrainfileSerializer = exports.loadSchemaHints = exports.parseSchemaHints = exports.inferRenderer = exports.inferType = exports.BrainfileParser = exports.buildContract = exports.parseDeliverableSpec = exports.normalizeToArray = exports.ALLOWED_DELIVERABLE_TYPES = exports.removeTaskContractConstraint = exports.addTaskContractConstraint = exports.removeTaskContractValidationCommand = exports.addTaskContractValidationCommand = exports.removeTaskContractDeliverable = exports.addTaskContractDeliverable = exports.patchTaskContract = exports.setTaskContractStatus = exports.clearTaskContract = exports.setTaskContract = void 0;
|
|
10678
|
+
exports.BRAINFILE_BASENAME = exports.DOT_BRAINFILE_DIRNAME = exports.atomicWriteFileSync = exports.ensureDotBrainfileGitignore = exports.ensureDotBrainfileDir = exports.getDotBrainfileGitignorePath = exports.getBrainfileStatePath = exports.getBrainfileStateDir = exports.resolveBrainfilePath = exports.findBrainfile = exports.EXCLUDE_DIRS = exports.BRAINFILE_GLOBS = exports.BRAINFILE_PATTERNS = exports.extractBrainfileSuffix = exports.isBrainfileName = exports.watchBrainfiles = exports.findNearestBrainfile = exports.findPrimaryBrainfile = exports.discover = exports.getParentTaskId = exports.isValidSubtaskId = exports.isValidTaskId = exports.generateNextSubtaskId = exports.generateSubtaskIdFromIndex = exports.generateNextTaskId = exports.getMaxTaskIdNumber = exports.extractTaskIdNumber = exports.getOverdueTasks = exports.getIncompleteSubtasksSummary = exports.getTasksWithIncompleteSubtasks = exports.isCompletionColumn = exports.findCompletionColumn = exports.columnExists = exports.getTotalTaskCount = exports.getColumnTaskCount = exports.searchTasks = exports.getTasksByAssignee = exports.getTasksByPriority = exports.getTasksByTag = exports.getAllTasks = exports.taskIdExists = exports.findTaskById = exports.findColumnByName = exports.findColumnById = exports.validateColumn = exports.validateType = exports.isTypeCompletable = exports.getBoardTypes = exports.archiveTasks = exports.deleteTasks = void 0;
|
|
10679
|
+
exports.activateTaskContract = exports.attachTaskContract = exports.failTaskContract = exports.completeTaskContract = exports.deliverTaskContract = exports.pickupTaskContract = exports.updateSubtasksInFile = exports.toggleSubtasksInFile = exports.deleteSubtasksFromFile = exports.addSubtasksToFile = exports.searchLogs = exports.searchTaskFiles = exports.findTask = exports.listTasks = exports.appendLog = exports.deleteTaskFile = exports.completeTaskFile = exports.patchTaskFile = exports.moveTaskFileToColumn = exports.moveTaskFile = exports.addTaskFile = exports.generateNextFileTaskId = exports.DEFAULT_CONTRACT_COLUMN_MAP = exports.taskFileName = exports.readTasksDir = exports.writeTaskFile = exports.readTaskFile = exports.serializeTaskContent = exports.parseTaskContent = exports.writeBoardConfig = exports.readBoardConfig = exports.serializeBoardConfig = exports.parseBoardConfig = exports.formatTaskForLinear = exports.formatTaskForGitHub = exports.BRIEF_STATE_VERSION = exports.sanitizeAgentFilename = exports.getBriefStatePath = exports.getBriefStateDir = exports.writeBriefState = exports.readBriefState = exports.relativeTime = exports.parseNotes = exports.parseNoteLine = exports.isEmptyBrief = exports.buildBrief = exports.DOT_BRAINFILE_STATE_IGNORE_ENTRY = exports.DOT_BRAINFILE_STATE_DIRNAME = exports.DOT_BRAINFILE_GITIGNORE_BASENAME = exports.BRAINFILE_STATE_BASENAME = void 0;
|
|
10680
|
+
exports.Brainfile = exports.buildBoardFromV2 = exports.readV2BoardConfig = exports.composeBody = exports.extractLog = exports.extractDescription = exports.findV2Task = exports.getLogFilePath = exports.getTaskFilePath = exports.ensureV2Dirs = exports.isV2 = exports.getV2Dirs = exports.topologicalSort = exports.DependencyCycleError = exports.MissingDependencyError = exports.ledgerRecordToCompletedRef = exports.taskToCompletedRef = exports.isLedgerContractStatus = exports.normalizePathValue = exports.getTaskContext = exports.getFileHistory = exports.queryLedger = exports.readLedger = exports.appendLedgerRecord = exports.buildLedgerRecord = exports.searchTasksRanked = exports.scoreTaskDocument = exports.taskMatchesFilters = exports.parseSearchQuery = exports.getEffectiveState = exports.activateTaskContractsByParent = void 0;
|
|
10316
10681
|
__exportStar(require_types2(), exports);
|
|
10317
10682
|
__exportStar(require_contract(), exports);
|
|
10318
10683
|
var contract_1 = require_contract2();
|
|
@@ -10381,6 +10746,13 @@ var require_dist = __commonJS({
|
|
|
10381
10746
|
Object.defineProperty(exports, "BrainfileSerializer", { enumerable: true, get: function() {
|
|
10382
10747
|
return serializer_1.BrainfileSerializer;
|
|
10383
10748
|
} });
|
|
10749
|
+
var frontmatter_1 = require_frontmatter();
|
|
10750
|
+
Object.defineProperty(exports, "parseFrontmatter", { enumerable: true, get: function() {
|
|
10751
|
+
return frontmatter_1.parseFrontmatter;
|
|
10752
|
+
} });
|
|
10753
|
+
Object.defineProperty(exports, "serializeFrontmatter", { enumerable: true, get: function() {
|
|
10754
|
+
return frontmatter_1.serializeFrontmatter;
|
|
10755
|
+
} });
|
|
10384
10756
|
var validator_1 = require_validator();
|
|
10385
10757
|
Object.defineProperty(exports, "BrainfileValidator", { enumerable: true, get: function() {
|
|
10386
10758
|
return validator_1.BrainfileValidator;
|
|
@@ -10476,12 +10848,6 @@ var require_dist = __commonJS({
|
|
|
10476
10848
|
Object.defineProperty(exports, "archiveTasks", { enumerable: true, get: function() {
|
|
10477
10849
|
return operations_1.archiveTasks;
|
|
10478
10850
|
} });
|
|
10479
|
-
Object.defineProperty(exports, "addRule", { enumerable: true, get: function() {
|
|
10480
|
-
return operations_1.addRule;
|
|
10481
|
-
} });
|
|
10482
|
-
Object.defineProperty(exports, "deleteRule", { enumerable: true, get: function() {
|
|
10483
|
-
return operations_1.deleteRule;
|
|
10484
|
-
} });
|
|
10485
10851
|
var boardValidation_1 = require_boardValidation();
|
|
10486
10852
|
Object.defineProperty(exports, "getBoardTypes", { enumerable: true, get: function() {
|
|
10487
10853
|
return boardValidation_1.getBoardTypes;
|
|
@@ -10622,6 +10988,9 @@ var require_dist = __commonJS({
|
|
|
10622
10988
|
Object.defineProperty(exports, "ensureDotBrainfileGitignore", { enumerable: true, get: function() {
|
|
10623
10989
|
return files_1.ensureDotBrainfileGitignore;
|
|
10624
10990
|
} });
|
|
10991
|
+
Object.defineProperty(exports, "atomicWriteFileSync", { enumerable: true, get: function() {
|
|
10992
|
+
return files_1.atomicWriteFileSync;
|
|
10993
|
+
} });
|
|
10625
10994
|
Object.defineProperty(exports, "DOT_BRAINFILE_DIRNAME", { enumerable: true, get: function() {
|
|
10626
10995
|
return files_1.DOT_BRAINFILE_DIRNAME;
|
|
10627
10996
|
} });
|
|
@@ -10634,6 +11003,47 @@ var require_dist = __commonJS({
|
|
|
10634
11003
|
Object.defineProperty(exports, "DOT_BRAINFILE_GITIGNORE_BASENAME", { enumerable: true, get: function() {
|
|
10635
11004
|
return files_1.DOT_BRAINFILE_GITIGNORE_BASENAME;
|
|
10636
11005
|
} });
|
|
11006
|
+
Object.defineProperty(exports, "DOT_BRAINFILE_STATE_DIRNAME", { enumerable: true, get: function() {
|
|
11007
|
+
return files_1.DOT_BRAINFILE_STATE_DIRNAME;
|
|
11008
|
+
} });
|
|
11009
|
+
Object.defineProperty(exports, "DOT_BRAINFILE_STATE_IGNORE_ENTRY", { enumerable: true, get: function() {
|
|
11010
|
+
return files_1.DOT_BRAINFILE_STATE_IGNORE_ENTRY;
|
|
11011
|
+
} });
|
|
11012
|
+
var brief_1 = require_brief();
|
|
11013
|
+
Object.defineProperty(exports, "buildBrief", { enumerable: true, get: function() {
|
|
11014
|
+
return brief_1.buildBrief;
|
|
11015
|
+
} });
|
|
11016
|
+
Object.defineProperty(exports, "isEmptyBrief", { enumerable: true, get: function() {
|
|
11017
|
+
return brief_1.isEmptyBrief;
|
|
11018
|
+
} });
|
|
11019
|
+
Object.defineProperty(exports, "parseNoteLine", { enumerable: true, get: function() {
|
|
11020
|
+
return brief_1.parseNoteLine;
|
|
11021
|
+
} });
|
|
11022
|
+
Object.defineProperty(exports, "parseNotes", { enumerable: true, get: function() {
|
|
11023
|
+
return brief_1.parseNotes;
|
|
11024
|
+
} });
|
|
11025
|
+
Object.defineProperty(exports, "relativeTime", { enumerable: true, get: function() {
|
|
11026
|
+
return brief_1.relativeTime;
|
|
11027
|
+
} });
|
|
11028
|
+
var briefState_1 = require_briefState();
|
|
11029
|
+
Object.defineProperty(exports, "readBriefState", { enumerable: true, get: function() {
|
|
11030
|
+
return briefState_1.readBriefState;
|
|
11031
|
+
} });
|
|
11032
|
+
Object.defineProperty(exports, "writeBriefState", { enumerable: true, get: function() {
|
|
11033
|
+
return briefState_1.writeBriefState;
|
|
11034
|
+
} });
|
|
11035
|
+
Object.defineProperty(exports, "getBriefStateDir", { enumerable: true, get: function() {
|
|
11036
|
+
return briefState_1.getBriefStateDir;
|
|
11037
|
+
} });
|
|
11038
|
+
Object.defineProperty(exports, "getBriefStatePath", { enumerable: true, get: function() {
|
|
11039
|
+
return briefState_1.getBriefStatePath;
|
|
11040
|
+
} });
|
|
11041
|
+
Object.defineProperty(exports, "sanitizeAgentFilename", { enumerable: true, get: function() {
|
|
11042
|
+
return briefState_1.sanitizeAgentFilename;
|
|
11043
|
+
} });
|
|
11044
|
+
Object.defineProperty(exports, "BRIEF_STATE_VERSION", { enumerable: true, get: function() {
|
|
11045
|
+
return briefState_1.BRIEF_STATE_VERSION;
|
|
11046
|
+
} });
|
|
10637
11047
|
var formatters_1 = require_formatters();
|
|
10638
11048
|
Object.defineProperty(exports, "formatTaskForGitHub", { enumerable: true, get: function() {
|
|
10639
11049
|
return formatters_1.formatTaskForGitHub;
|
|
@@ -10918,16 +11328,6 @@ var require_dist = __commonJS({
|
|
|
10918
11328
|
static findTaskLocation(content, taskId) {
|
|
10919
11329
|
return parser_2.BrainfileParser.findTaskLocation(content, taskId);
|
|
10920
11330
|
}
|
|
10921
|
-
/**
|
|
10922
|
-
* Find the location of a rule in the file content
|
|
10923
|
-
* @param content - The markdown content
|
|
10924
|
-
* @param ruleId - The rule ID to find
|
|
10925
|
-
* @param ruleType - The type of rule
|
|
10926
|
-
* @returns Line and column location or null if not found
|
|
10927
|
-
*/
|
|
10928
|
-
static findRuleLocation(content, ruleId, ruleType) {
|
|
10929
|
-
return parser_2.BrainfileParser.findRuleLocation(content, ruleId, ruleType);
|
|
10930
|
-
}
|
|
10931
11331
|
};
|
|
10932
11332
|
exports.Brainfile = Brainfile2;
|
|
10933
11333
|
var parser_2 = require_parser();
|
|
@@ -10938,10 +11338,8 @@ var require_dist = __commonJS({
|
|
|
10938
11338
|
}
|
|
10939
11339
|
});
|
|
10940
11340
|
|
|
10941
|
-
// src/utils/
|
|
10942
|
-
var
|
|
10943
|
-
import * as fs2 from "fs";
|
|
10944
|
-
import * as path2 from "path";
|
|
11341
|
+
// src/utils/cli-error.ts
|
|
11342
|
+
var import_chalk2 = __toESM(require_source());
|
|
10945
11343
|
|
|
10946
11344
|
// src/utils/errorHandler.ts
|
|
10947
11345
|
var import_chalk = __toESM(require_source());
|
|
@@ -11107,6 +11505,23 @@ ${availableTasks.map((t) => ` - ${t}`).join("\n")}`;
|
|
|
11107
11505
|
function validationError2(message) {
|
|
11108
11506
|
return new CLIError(`Validation error: ${message}`, ExitCode.USER_ERROR);
|
|
11109
11507
|
}
|
|
11508
|
+
function renderCliError(error) {
|
|
11509
|
+
if (error instanceof CLIError) {
|
|
11510
|
+
console.error(import_chalk2.default.red(`Error: ${error.message}`));
|
|
11511
|
+
if (error.details) {
|
|
11512
|
+
console.error("");
|
|
11513
|
+
console.error(import_chalk2.default.gray(error.details));
|
|
11514
|
+
}
|
|
11515
|
+
process.exit(error.exitCode);
|
|
11516
|
+
}
|
|
11517
|
+
console.error(error instanceof Error ? error.stack : String(error));
|
|
11518
|
+
process.exit(ExitCode.USER_ERROR);
|
|
11519
|
+
}
|
|
11520
|
+
|
|
11521
|
+
// src/utils/brainfile-path.ts
|
|
11522
|
+
var import_core3 = __toESM(require_dist());
|
|
11523
|
+
import * as fs3 from "fs";
|
|
11524
|
+
import * as path3 from "path";
|
|
11110
11525
|
|
|
11111
11526
|
// src/utils/v2-only.ts
|
|
11112
11527
|
var import_core2 = __toESM(require_dist());
|
|
@@ -11127,78 +11542,415 @@ function assertV2Brainfile(brainfilePath) {
|
|
|
11127
11542
|
}
|
|
11128
11543
|
}
|
|
11129
11544
|
|
|
11545
|
+
// src/utils/board-repo.ts
|
|
11546
|
+
import * as fs2 from "fs";
|
|
11547
|
+
import * as os from "os";
|
|
11548
|
+
import * as path2 from "path";
|
|
11549
|
+
import { spawnSync } from "child_process";
|
|
11550
|
+
var DEFAULT_BOARD_BRANCH = "brainfile";
|
|
11551
|
+
var BOARD_BRANCH_CONFIG_KEY = "brainfile.branch";
|
|
11552
|
+
var EXCLUDE_ENTRY = ".brainfile/";
|
|
11553
|
+
var EXCLUDE_MARKER = "# brainfile: board worktree (managed by `brainfile`)";
|
|
11554
|
+
var FALLBACK_IDENTITY_NAME = "brainfile";
|
|
11555
|
+
var FALLBACK_IDENTITY_EMAIL = "brainfile@localhost";
|
|
11556
|
+
var MAX_MESSAGE_LENGTH = 72;
|
|
11557
|
+
var BOARD_SUBDIRS = ["board", "logs"];
|
|
11558
|
+
function git(args, cwd, env) {
|
|
11559
|
+
const result = spawnSync("git", args, {
|
|
11560
|
+
cwd,
|
|
11561
|
+
encoding: "utf-8",
|
|
11562
|
+
env: env ? { ...process.env, ...env } : process.env,
|
|
11563
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
11564
|
+
});
|
|
11565
|
+
return {
|
|
11566
|
+
ok: result.status === 0,
|
|
11567
|
+
status: result.status,
|
|
11568
|
+
stdout: (result.stdout ?? "").toString().trim(),
|
|
11569
|
+
stderr: (result.stderr ?? "").toString().trim()
|
|
11570
|
+
};
|
|
11571
|
+
}
|
|
11572
|
+
function gitToplevel(cwd) {
|
|
11573
|
+
const r = git(["rev-parse", "--show-toplevel"], cwd);
|
|
11574
|
+
return r.ok && r.stdout ? path2.resolve(r.stdout) : null;
|
|
11575
|
+
}
|
|
11576
|
+
function gitCommonDir(cwd) {
|
|
11577
|
+
const r = git(["rev-parse", "--git-common-dir"], cwd);
|
|
11578
|
+
if (!r.ok || !r.stdout) return null;
|
|
11579
|
+
return path2.resolve(cwd, r.stdout);
|
|
11580
|
+
}
|
|
11581
|
+
function listWorktrees(cwd) {
|
|
11582
|
+
const r = git(["worktree", "list", "--porcelain"], cwd);
|
|
11583
|
+
if (!r.ok) return [];
|
|
11584
|
+
const entries = [];
|
|
11585
|
+
let current = null;
|
|
11586
|
+
for (const line of r.stdout.split("\n")) {
|
|
11587
|
+
if (line.startsWith("worktree ")) {
|
|
11588
|
+
current = { path: path2.resolve(line.slice("worktree ".length)), bare: false, detached: false };
|
|
11589
|
+
entries.push(current);
|
|
11590
|
+
} else if (!current) {
|
|
11591
|
+
continue;
|
|
11592
|
+
} else if (line.startsWith("HEAD ")) {
|
|
11593
|
+
current.head = line.slice(5);
|
|
11594
|
+
} else if (line.startsWith("branch ")) {
|
|
11595
|
+
current.branch = line.slice(7);
|
|
11596
|
+
} else if (line === "bare") {
|
|
11597
|
+
current.bare = true;
|
|
11598
|
+
} else if (line === "detached") {
|
|
11599
|
+
current.detached = true;
|
|
11600
|
+
}
|
|
11601
|
+
}
|
|
11602
|
+
return entries;
|
|
11603
|
+
}
|
|
11604
|
+
function boardBranch(cwd) {
|
|
11605
|
+
const r = git(["config", "--get", BOARD_BRANCH_CONFIG_KEY], cwd);
|
|
11606
|
+
return r.ok && r.stdout ? r.stdout : DEFAULT_BOARD_BRANCH;
|
|
11607
|
+
}
|
|
11608
|
+
function boardRepoKind(dotDir) {
|
|
11609
|
+
try {
|
|
11610
|
+
const st = fs2.statSync(path2.join(dotDir, ".git"));
|
|
11611
|
+
if (st.isFile()) return "linked";
|
|
11612
|
+
if (st.isDirectory()) return "standalone";
|
|
11613
|
+
} catch {
|
|
11614
|
+
}
|
|
11615
|
+
return null;
|
|
11616
|
+
}
|
|
11617
|
+
function isTrackedBoard(dotDir) {
|
|
11618
|
+
return boardRepoKind(dotDir) !== null;
|
|
11619
|
+
}
|
|
11620
|
+
function findTrackedBoardDir(cwd) {
|
|
11621
|
+
const worktrees = listWorktrees(cwd);
|
|
11622
|
+
if (worktrees.length === 0) return null;
|
|
11623
|
+
const wanted = `refs/heads/${boardBranch(cwd)}`;
|
|
11624
|
+
const hit = worktrees.find((w) => w.branch === wanted);
|
|
11625
|
+
if (!hit) return null;
|
|
11626
|
+
return fs2.existsSync(path2.join(hit.path, "brainfile.md")) ? hit.path : null;
|
|
11627
|
+
}
|
|
11628
|
+
function materializeBoardWorktree(cwd) {
|
|
11629
|
+
const branch = boardBranch(cwd);
|
|
11630
|
+
const hasLocal = git(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], cwd).ok;
|
|
11631
|
+
const configuredRemote = git(["config", "--get", "brainfile.remote"], cwd).stdout || null;
|
|
11632
|
+
const configuredBranch = git(["config", "--get", "brainfile.remoteBranch"], cwd).stdout || branch;
|
|
11633
|
+
let upstream = null;
|
|
11634
|
+
if (!hasLocal) {
|
|
11635
|
+
if (configuredRemote) {
|
|
11636
|
+
const ref = `${configuredRemote}/${configuredBranch}`;
|
|
11637
|
+
if (!git(["rev-parse", "--verify", "--quiet", `refs/remotes/${ref}`], cwd).ok) {
|
|
11638
|
+
git(["fetch", "--quiet", configuredRemote, configuredBranch], cwd);
|
|
11639
|
+
}
|
|
11640
|
+
if (git(["rev-parse", "--verify", "--quiet", `refs/remotes/${ref}`], cwd).ok) upstream = ref;
|
|
11641
|
+
}
|
|
11642
|
+
if (!upstream && git(["rev-parse", "--verify", "--quiet", `refs/remotes/origin/${branch}`], cwd).ok) {
|
|
11643
|
+
upstream = `origin/${branch}`;
|
|
11644
|
+
}
|
|
11645
|
+
}
|
|
11646
|
+
if (!hasLocal && !upstream) return null;
|
|
11647
|
+
const worktrees = listWorktrees(cwd);
|
|
11648
|
+
if (worktrees.length === 0) return null;
|
|
11649
|
+
if (worktrees.some((w) => w.branch === `refs/heads/${branch}`)) return null;
|
|
11650
|
+
const main = worktrees[0];
|
|
11651
|
+
let target;
|
|
11652
|
+
if (main.bare) {
|
|
11653
|
+
const common = gitCommonDir(cwd);
|
|
11654
|
+
if (!common) return null;
|
|
11655
|
+
target = path2.join(common, "brainfile");
|
|
11656
|
+
} else {
|
|
11657
|
+
target = path2.join(main.path, ".brainfile");
|
|
11658
|
+
}
|
|
11659
|
+
if (fs2.existsSync(target)) return null;
|
|
11660
|
+
const r = hasLocal ? git(["worktree", "add", "--quiet", target, branch], cwd) : git(["worktree", "add", "--quiet", "--track", "-b", branch, target, upstream], cwd);
|
|
11661
|
+
if (!r.ok) return null;
|
|
11662
|
+
ensureExcludeEntry(cwd);
|
|
11663
|
+
for (const sub of BOARD_SUBDIRS) fs2.mkdirSync(path2.join(target, sub), { recursive: true });
|
|
11664
|
+
const cameFrom = upstream ? upstream.slice(0, upstream.indexOf("/")) : null;
|
|
11665
|
+
if (cameFrom && !configuredRemote) git(["config", "brainfile.remote", cameFrom], cwd);
|
|
11666
|
+
const relative3 = path2.relative(process.cwd(), target) || ".";
|
|
11667
|
+
process.stderr.write(
|
|
11668
|
+
cameFrom ? `Checked out the shared board from ${cameFrom} into ${relative3}/
|
|
11669
|
+
` : `Checked out the board from the '${branch}' branch into ${relative3}/
|
|
11670
|
+
`
|
|
11671
|
+
);
|
|
11672
|
+
return target;
|
|
11673
|
+
}
|
|
11674
|
+
function ensureExcludeEntry(cwd) {
|
|
11675
|
+
const common = gitCommonDir(cwd);
|
|
11676
|
+
if (!common) return false;
|
|
11677
|
+
const file = path2.join(common, "info", "exclude");
|
|
11678
|
+
const existing = fs2.existsSync(file) ? fs2.readFileSync(file, "utf-8") : "";
|
|
11679
|
+
const present = existing.split(/\r?\n/).some((line) => line.trim() === EXCLUDE_ENTRY || line.trim() === ".brainfile");
|
|
11680
|
+
if (present) return false;
|
|
11681
|
+
fs2.mkdirSync(path2.dirname(file), { recursive: true });
|
|
11682
|
+
const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
11683
|
+
fs2.appendFileSync(file, `${separator}${EXCLUDE_MARKER}
|
|
11684
|
+
${EXCLUDE_ENTRY}
|
|
11685
|
+
`, "utf-8");
|
|
11686
|
+
return true;
|
|
11687
|
+
}
|
|
11688
|
+
function removeExcludeEntry(cwd) {
|
|
11689
|
+
const common = gitCommonDir(cwd);
|
|
11690
|
+
if (!common) return false;
|
|
11691
|
+
const file = path2.join(common, "info", "exclude");
|
|
11692
|
+
if (!fs2.existsSync(file)) return false;
|
|
11693
|
+
const lines = fs2.readFileSync(file, "utf-8").split(/\r?\n/);
|
|
11694
|
+
const at = lines.indexOf(EXCLUDE_MARKER);
|
|
11695
|
+
if (at < 0) return false;
|
|
11696
|
+
const removeCount = lines[at + 1]?.trim() === EXCLUDE_ENTRY ? 2 : 1;
|
|
11697
|
+
lines.splice(at, removeCount);
|
|
11698
|
+
fs2.writeFileSync(file, lines.join("\n"), "utf-8");
|
|
11699
|
+
return true;
|
|
11700
|
+
}
|
|
11701
|
+
function createOrphanBoardWorktree(repoCwd, dotDir, branch) {
|
|
11702
|
+
const r = git(["worktree", "add", "--quiet", "--orphan", "-b", branch, dotDir], repoCwd);
|
|
11703
|
+
if (!r.ok) {
|
|
11704
|
+
throw new Error(
|
|
11705
|
+
`Could not create the board worktree on branch '${branch}' (git >= 2.42 is required for --orphan): ${r.stderr}`
|
|
11706
|
+
);
|
|
11707
|
+
}
|
|
11708
|
+
}
|
|
11709
|
+
function initStandaloneBoardRepo(dotDir) {
|
|
11710
|
+
const parent = path2.dirname(dotDir);
|
|
11711
|
+
let r = git(["init", "--quiet", "-b", "main", dotDir], parent);
|
|
11712
|
+
if (!r.ok) r = git(["init", "--quiet", dotDir], parent);
|
|
11713
|
+
if (!r.ok) throw new Error(`Could not initialize a git repository in ${dotDir}: ${r.stderr}`);
|
|
11714
|
+
}
|
|
11715
|
+
function boardIsDirty(dotDir) {
|
|
11716
|
+
const r = git(["status", "--porcelain"], dotDir);
|
|
11717
|
+
return r.ok && r.stdout.length > 0;
|
|
11718
|
+
}
|
|
11719
|
+
function unmergedFiles(dotDir) {
|
|
11720
|
+
const r = git(["diff", "--name-only", "--diff-filter=U"], dotDir);
|
|
11721
|
+
return r.ok ? r.stdout.split("\n").map((l) => l.trim()).filter(Boolean) : [];
|
|
11722
|
+
}
|
|
11723
|
+
function boardDirtyFiles(dotDir) {
|
|
11724
|
+
const r = git(["status", "--porcelain"], dotDir);
|
|
11725
|
+
if (!r.ok || !r.stdout) return [];
|
|
11726
|
+
return r.stdout.split("\n").map((line) => line.replace(/^[ MADRCU?!]{1,2}\s+/, "").replace(/^.* -> /, "").trim()).filter(Boolean);
|
|
11727
|
+
}
|
|
11728
|
+
function identityArgs(dotDir) {
|
|
11729
|
+
const args = [];
|
|
11730
|
+
if (!git(["config", "--get", "user.name"], dotDir).stdout) args.push("-c", `user.name=${FALLBACK_IDENTITY_NAME}`);
|
|
11731
|
+
if (!git(["config", "--get", "user.email"], dotDir).stdout) args.push("-c", `user.email=${FALLBACK_IDENTITY_EMAIL}`);
|
|
11732
|
+
return args;
|
|
11733
|
+
}
|
|
11734
|
+
function sanitizeAgent(agent) {
|
|
11735
|
+
return agent.replace(/[<>\r\n]/g, "").trim();
|
|
11736
|
+
}
|
|
11737
|
+
var commitListeners = [];
|
|
11738
|
+
function onBoardCommitted(listener) {
|
|
11739
|
+
if (!commitListeners.includes(listener)) commitListeners.push(listener);
|
|
11740
|
+
}
|
|
11741
|
+
function notifyCommitted(dotDir) {
|
|
11742
|
+
for (const listener of commitListeners) {
|
|
11743
|
+
try {
|
|
11744
|
+
listener(dotDir);
|
|
11745
|
+
} catch {
|
|
11746
|
+
}
|
|
11747
|
+
}
|
|
11748
|
+
}
|
|
11749
|
+
function ensureBoardDirs(dotDir) {
|
|
11750
|
+
let created = false;
|
|
11751
|
+
for (const sub of BOARD_SUBDIRS) {
|
|
11752
|
+
const dir = path2.join(dotDir, sub);
|
|
11753
|
+
try {
|
|
11754
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
11755
|
+
const keep = path2.join(dir, ".gitkeep");
|
|
11756
|
+
if (!fs2.existsSync(keep)) {
|
|
11757
|
+
fs2.writeFileSync(keep, "", "utf-8");
|
|
11758
|
+
created = true;
|
|
11759
|
+
}
|
|
11760
|
+
} catch {
|
|
11761
|
+
}
|
|
11762
|
+
}
|
|
11763
|
+
return created;
|
|
11764
|
+
}
|
|
11765
|
+
function commitBoard(dotDir, options) {
|
|
11766
|
+
if (!isTrackedBoard(dotDir)) return false;
|
|
11767
|
+
ensureBoardDirs(dotDir);
|
|
11768
|
+
if (unmergedFiles(dotDir).length > 0) return false;
|
|
11769
|
+
if (!git(["add", "-A"], dotDir).ok) return false;
|
|
11770
|
+
if (!boardIsDirty(dotDir)) return false;
|
|
11771
|
+
const env = {};
|
|
11772
|
+
const agent = options.agent ? sanitizeAgent(options.agent) : "";
|
|
11773
|
+
if (agent) {
|
|
11774
|
+
env.GIT_AUTHOR_NAME = agent;
|
|
11775
|
+
env.GIT_AUTHOR_EMAIL = `${agent}@brainfile.local`;
|
|
11776
|
+
}
|
|
11777
|
+
const message = oneLine(options.message);
|
|
11778
|
+
const r = git(
|
|
11779
|
+
[...identityArgs(dotDir), "-c", "commit.gpgsign=false", "commit", "--quiet", "--no-verify", "-m", message],
|
|
11780
|
+
dotDir,
|
|
11781
|
+
env
|
|
11782
|
+
);
|
|
11783
|
+
if (r.ok) notifyCommitted(dotDir);
|
|
11784
|
+
return r.ok;
|
|
11785
|
+
}
|
|
11786
|
+
function commitHandEdits(dotDir) {
|
|
11787
|
+
if (!isTrackedBoard(dotDir)) return false;
|
|
11788
|
+
const keepOnly = (f) => f.endsWith(".gitkeep") || BOARD_SUBDIRS.some((sub) => f === `${sub}/`);
|
|
11789
|
+
if (ensureBoardDirs(dotDir) && boardDirtyFiles(dotDir).every(keepOnly)) {
|
|
11790
|
+
commitBoard(dotDir, { message: "chore: keep board/ and logs/ in git" });
|
|
11791
|
+
}
|
|
11792
|
+
const files = boardDirtyFiles(dotDir);
|
|
11793
|
+
if (files.length === 0) return false;
|
|
11794
|
+
const summary = files.length <= 3 ? files.join(", ") : `${files.length} files`;
|
|
11795
|
+
return commitBoard(dotDir, { message: `edit: ${summary}` });
|
|
11796
|
+
}
|
|
11797
|
+
function resolveAgentName(argv = process.argv) {
|
|
11798
|
+
if (process.env.BRAINFILE_AGENT) return process.env.BRAINFILE_AGENT;
|
|
11799
|
+
const flag = argv.indexOf("--agent");
|
|
11800
|
+
if (flag >= 0 && argv[flag + 1] && !argv[flag + 1].startsWith("-")) return argv[flag + 1];
|
|
11801
|
+
const inline = argv.find((a) => a.startsWith("--agent="));
|
|
11802
|
+
return inline ? inline.slice("--agent=".length) : null;
|
|
11803
|
+
}
|
|
11804
|
+
function homeBoardDir() {
|
|
11805
|
+
return path2.join(os.homedir(), ".brainfile");
|
|
11806
|
+
}
|
|
11807
|
+
function isGlobalBoardRequested(argv = process.argv) {
|
|
11808
|
+
if (process.env.BRAINFILE_GLOBAL === "1") return true;
|
|
11809
|
+
return argv.includes("-g") || argv.includes("--global");
|
|
11810
|
+
}
|
|
11811
|
+
function oneLine(message) {
|
|
11812
|
+
const flat = message.replace(/\s+/g, " ").trim();
|
|
11813
|
+
return flat.length > MAX_MESSAGE_LENGTH ? `${flat.slice(0, MAX_MESSAGE_LENGTH - 1)}\u2026` : flat;
|
|
11814
|
+
}
|
|
11815
|
+
function describeCommandForCommit(command) {
|
|
11816
|
+
const names = [];
|
|
11817
|
+
let cursor = command;
|
|
11818
|
+
while (cursor && cursor.parent) {
|
|
11819
|
+
names.unshift(cursor.name());
|
|
11820
|
+
cursor = cursor.parent;
|
|
11821
|
+
}
|
|
11822
|
+
const opts = command.opts();
|
|
11823
|
+
const idValue = opts.task ?? opts.taskId;
|
|
11824
|
+
const id = Array.isArray(idValue) ? idValue.join(",") : typeof idValue === "string" ? idValue : "";
|
|
11825
|
+
const positional = command.args.filter((a) => typeof a === "string" && a.length > 0);
|
|
11826
|
+
const detail = [opts.title, opts.column, positional.join(" ")].find((v) => typeof v === "string" && v.length > 0) ?? "";
|
|
11827
|
+
const head = `${names.join(" ")}${id ? ` ${id}` : ""}`;
|
|
11828
|
+
return oneLine(detail ? `${head}: ${detail}` : head);
|
|
11829
|
+
}
|
|
11830
|
+
var pendingCommits = /* @__PURE__ */ new Map();
|
|
11831
|
+
var flushTimer = null;
|
|
11832
|
+
var exitHookInstalled = false;
|
|
11833
|
+
function scheduleBoardCommit(brainfilePath, message, delayMs = 2e3) {
|
|
11834
|
+
const dotDir = path2.dirname(path2.resolve(brainfilePath));
|
|
11835
|
+
if (!isTrackedBoard(dotDir)) return;
|
|
11836
|
+
const entry = pendingCommits.get(dotDir) ?? { messages: [], agent: resolveAgentName() };
|
|
11837
|
+
entry.messages.push(message);
|
|
11838
|
+
pendingCommits.set(dotDir, entry);
|
|
11839
|
+
if (flushTimer) clearTimeout(flushTimer);
|
|
11840
|
+
flushTimer = setTimeout(flushBoardCommits, delayMs);
|
|
11841
|
+
flushTimer.unref?.();
|
|
11842
|
+
if (!exitHookInstalled) {
|
|
11843
|
+
exitHookInstalled = true;
|
|
11844
|
+
process.once("exit", flushBoardCommits);
|
|
11845
|
+
}
|
|
11846
|
+
}
|
|
11847
|
+
function flushBoardCommits() {
|
|
11848
|
+
if (flushTimer) {
|
|
11849
|
+
clearTimeout(flushTimer);
|
|
11850
|
+
flushTimer = null;
|
|
11851
|
+
}
|
|
11852
|
+
for (const [dotDir, entry] of pendingCommits) {
|
|
11853
|
+
const [first, ...rest] = entry.messages;
|
|
11854
|
+
const message = rest.length === 0 ? first : `${first} (+${rest.length} more)`;
|
|
11855
|
+
commitBoard(dotDir, { message, agent: entry.agent });
|
|
11856
|
+
}
|
|
11857
|
+
pendingCommits.clear();
|
|
11858
|
+
}
|
|
11859
|
+
|
|
11130
11860
|
// src/utils/brainfile-path.ts
|
|
11131
11861
|
function isMigrationCommand() {
|
|
11132
11862
|
return process.argv.includes("migrate");
|
|
11133
11863
|
}
|
|
11134
11864
|
function migrationHintForPath2(brainfilePath) {
|
|
11135
|
-
const absolute =
|
|
11136
|
-
const dir =
|
|
11865
|
+
const absolute = path3.resolve(brainfilePath);
|
|
11866
|
+
const dir = path3.basename(path3.dirname(absolute)) === ".brainfile" ? path3.dirname(path3.dirname(absolute)) : path3.dirname(absolute);
|
|
11137
11867
|
return `Run: brainfile migrate --dir ${dir}`;
|
|
11138
11868
|
}
|
|
11139
11869
|
function rejectLegacyRuntimePath(resolvedPath) {
|
|
11140
|
-
if (!isMigrationCommand() &&
|
|
11870
|
+
if (!isMigrationCommand() && fs3.existsSync(resolvedPath) && !(0, import_core3.isV2)(resolvedPath)) {
|
|
11141
11871
|
throw new CLIError(V1_UNSUPPORTED_MESSAGE, void 0, migrationHintForPath2(resolvedPath));
|
|
11142
11872
|
}
|
|
11143
11873
|
return resolvedPath;
|
|
11144
11874
|
}
|
|
11875
|
+
function isPlaceholder(filePath) {
|
|
11876
|
+
return filePath === void 0 || filePath === import_core3.BRAINFILE_BASENAME || filePath === `./${import_core3.BRAINFILE_BASENAME}`;
|
|
11877
|
+
}
|
|
11145
11878
|
function resolveCliBrainfilePath(filePath) {
|
|
11879
|
+
if (isPlaceholder(filePath) && isGlobalBoardRequested()) {
|
|
11880
|
+
return rejectLegacyRuntimePath(path3.join(homeBoardDir(), import_core3.BRAINFILE_BASENAME));
|
|
11881
|
+
}
|
|
11146
11882
|
if (filePath) {
|
|
11147
|
-
const resolved =
|
|
11883
|
+
const resolved = path3.resolve(process.cwd(), filePath);
|
|
11148
11884
|
try {
|
|
11149
|
-
if (
|
|
11885
|
+
if (fs3.statSync(resolved).isDirectory()) {
|
|
11150
11886
|
const found = (0, import_core3.findBrainfile)(resolved);
|
|
11151
11887
|
if (found && found.projectRoot === resolved) {
|
|
11152
11888
|
return rejectLegacyRuntimePath(found.absolutePath);
|
|
11153
11889
|
}
|
|
11154
|
-
const dotDir =
|
|
11890
|
+
const dotDir = path3.join(resolved, ".brainfile", "brainfile.md");
|
|
11155
11891
|
return rejectLegacyRuntimePath(dotDir);
|
|
11156
11892
|
}
|
|
11157
11893
|
} catch {
|
|
11158
11894
|
}
|
|
11159
11895
|
}
|
|
11160
|
-
|
|
11896
|
+
const cwd = process.cwd();
|
|
11897
|
+
if (isPlaceholder(filePath)) {
|
|
11898
|
+
const found = (0, import_core3.findBrainfile)(cwd, { stopAtGitRoot: true });
|
|
11899
|
+
if (found) return rejectLegacyRuntimePath(found.absolutePath);
|
|
11900
|
+
const tracked = findTrackedBoardDir(cwd) ?? materializeBoardWorktree(cwd);
|
|
11901
|
+
if (tracked) return rejectLegacyRuntimePath(path3.join(tracked, import_core3.BRAINFILE_BASENAME));
|
|
11902
|
+
}
|
|
11903
|
+
return rejectLegacyRuntimePath((0, import_core3.resolveBrainfilePath)({ filePath, startDir: cwd, stopAtGitRoot: true }));
|
|
11904
|
+
}
|
|
11905
|
+
function tryResolveBoardDir(filePath) {
|
|
11906
|
+
try {
|
|
11907
|
+
const resolved = resolveCliBrainfilePath(filePath);
|
|
11908
|
+
if (!fs3.existsSync(resolved)) return null;
|
|
11909
|
+
return path3.dirname(resolved);
|
|
11910
|
+
} catch {
|
|
11911
|
+
return null;
|
|
11912
|
+
}
|
|
11161
11913
|
}
|
|
11162
11914
|
|
|
11163
11915
|
// src/utils/v2-detect.ts
|
|
11164
11916
|
var import_core4 = __toESM(require_dist());
|
|
11165
11917
|
var import_core5 = __toESM(require_dist());
|
|
11166
11918
|
var import_core6 = __toESM(require_dist());
|
|
11167
|
-
import * as
|
|
11168
|
-
import * as
|
|
11919
|
+
import * as fs5 from "fs";
|
|
11920
|
+
import * as path5 from "path";
|
|
11169
11921
|
|
|
11170
11922
|
// src/utils/workspace-format.ts
|
|
11171
|
-
import * as
|
|
11172
|
-
import * as
|
|
11923
|
+
import * as fs4 from "fs";
|
|
11924
|
+
import * as path4 from "path";
|
|
11173
11925
|
function existsFile(filePath) {
|
|
11174
11926
|
try {
|
|
11175
|
-
return
|
|
11927
|
+
return fs4.statSync(filePath).isFile();
|
|
11176
11928
|
} catch {
|
|
11177
11929
|
return false;
|
|
11178
11930
|
}
|
|
11179
11931
|
}
|
|
11180
11932
|
function existsDir(dirPath) {
|
|
11181
11933
|
try {
|
|
11182
|
-
return
|
|
11934
|
+
return fs4.statSync(dirPath).isDirectory();
|
|
11183
11935
|
} catch {
|
|
11184
11936
|
return false;
|
|
11185
11937
|
}
|
|
11186
11938
|
}
|
|
11187
11939
|
function workspaceRootFromBrainfilePath(brainfilePath) {
|
|
11188
|
-
const absolute =
|
|
11189
|
-
const dir =
|
|
11190
|
-
return
|
|
11940
|
+
const absolute = path4.resolve(brainfilePath);
|
|
11941
|
+
const dir = path4.dirname(absolute);
|
|
11942
|
+
return path4.basename(dir) === ".brainfile" ? path4.dirname(dir) : dir;
|
|
11191
11943
|
}
|
|
11192
11944
|
function probeWorkspaceFormat(rootDir = process.cwd()) {
|
|
11193
|
-
const resolvedRoot =
|
|
11194
|
-
const dotDir =
|
|
11945
|
+
const resolvedRoot = path4.resolve(rootDir);
|
|
11946
|
+
const dotDir = path4.join(resolvedRoot, ".brainfile");
|
|
11195
11947
|
const paths = {
|
|
11196
11948
|
rootDir: resolvedRoot,
|
|
11197
|
-
rootBrainfilePath:
|
|
11949
|
+
rootBrainfilePath: path4.join(resolvedRoot, "brainfile.md"),
|
|
11198
11950
|
dotDir,
|
|
11199
|
-
dotBrainfilePath:
|
|
11200
|
-
boardDir:
|
|
11201
|
-
logsDir:
|
|
11951
|
+
dotBrainfilePath: path4.join(dotDir, "brainfile.md"),
|
|
11952
|
+
boardDir: path4.join(dotDir, "board"),
|
|
11953
|
+
logsDir: path4.join(dotDir, "logs")
|
|
11202
11954
|
};
|
|
11203
11955
|
const presence = {
|
|
11204
11956
|
rootBrainfile: existsFile(paths.rootBrainfilePath),
|
|
@@ -11232,15 +11984,15 @@ function shouldSuggestMigration(probe) {
|
|
|
11232
11984
|
// src/utils/v2-detect.ts
|
|
11233
11985
|
var v2MigrationHintShown = /* @__PURE__ */ new Set();
|
|
11234
11986
|
function shouldSuggestV2Migration(brainfilePath) {
|
|
11235
|
-
const resolved =
|
|
11987
|
+
const resolved = path5.resolve(brainfilePath);
|
|
11236
11988
|
if (v2MigrationHintShown.has(resolved)) return false;
|
|
11237
11989
|
const probe = probeWorkspaceForBrainfile(resolved);
|
|
11238
11990
|
if (shouldSuggestMigration(probe)) {
|
|
11239
11991
|
return true;
|
|
11240
11992
|
}
|
|
11241
|
-
if (!(0, import_core6.isV2)(resolved) &&
|
|
11993
|
+
if (!(0, import_core6.isV2)(resolved) && fs5.existsSync(resolved)) {
|
|
11242
11994
|
try {
|
|
11243
|
-
const content =
|
|
11995
|
+
const content = fs5.readFileSync(resolved, "utf-8");
|
|
11244
11996
|
const parsed = import_core4.Brainfile.parseWithErrors(content);
|
|
11245
11997
|
if (parsed.board) return true;
|
|
11246
11998
|
} catch {
|
|
@@ -11249,42 +12001,568 @@ function shouldSuggestV2Migration(brainfilePath) {
|
|
|
11249
12001
|
return false;
|
|
11250
12002
|
}
|
|
11251
12003
|
function markV2MigrationHintShown(brainfilePath) {
|
|
11252
|
-
v2MigrationHintShown.add(
|
|
12004
|
+
v2MigrationHintShown.add(path5.resolve(brainfilePath));
|
|
12005
|
+
}
|
|
12006
|
+
|
|
12007
|
+
// src/commands/merge-driver.ts
|
|
12008
|
+
var import_core7 = __toESM(require_dist());
|
|
12009
|
+
import * as fs6 from "fs";
|
|
12010
|
+
import * as os2 from "os";
|
|
12011
|
+
import * as path6 from "path";
|
|
12012
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
12013
|
+
function parseDoc(content) {
|
|
12014
|
+
const parsed = (0, import_core7.parseFrontmatter)(content);
|
|
12015
|
+
if (!parsed) return null;
|
|
12016
|
+
return { data: parsed.data, body: parsed.body };
|
|
12017
|
+
}
|
|
12018
|
+
function same(a, b) {
|
|
12019
|
+
return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
|
|
12020
|
+
}
|
|
12021
|
+
function stamp(data) {
|
|
12022
|
+
const value = data.updatedAt;
|
|
12023
|
+
return typeof value === "string" ? value : "";
|
|
12024
|
+
}
|
|
12025
|
+
function mergeFields(base, ours, theirs) {
|
|
12026
|
+
const keys = [];
|
|
12027
|
+
for (const key of [...Object.keys(ours), ...Object.keys(theirs), ...Object.keys(base)]) {
|
|
12028
|
+
if (!keys.includes(key)) keys.push(key);
|
|
12029
|
+
}
|
|
12030
|
+
const oursWins = stamp(ours) > stamp(theirs);
|
|
12031
|
+
const out = {};
|
|
12032
|
+
for (const key of keys) {
|
|
12033
|
+
const b = base[key];
|
|
12034
|
+
const o = ours[key];
|
|
12035
|
+
const t = theirs[key];
|
|
12036
|
+
let pick;
|
|
12037
|
+
if (same(o, t)) pick = o;
|
|
12038
|
+
else if (same(b, o)) pick = t;
|
|
12039
|
+
else if (same(b, t)) pick = o;
|
|
12040
|
+
else if (key === "updatedAt") pick = String(o ?? "") > String(t ?? "") ? o : t;
|
|
12041
|
+
else pick = oursWins ? o : t;
|
|
12042
|
+
if (pick !== void 0) out[key] = pick;
|
|
12043
|
+
}
|
|
12044
|
+
return out;
|
|
12045
|
+
}
|
|
12046
|
+
var CONFLICT = /^<{7}[^\n]*\n([\s\S]*?)^={7}\n([\s\S]*?)^>{7}[^\n]*\n?/gm;
|
|
12047
|
+
var LIST_ITEM = /^\s*[-*]\s+/;
|
|
12048
|
+
var LEADING_STAMP = /^\s*[-*]\s+(\d{4}-\d{2}-\d{2}T[0-9:.]+Z?)\b/;
|
|
12049
|
+
function unionLists(ours, theirs) {
|
|
12050
|
+
const a = ours.split("\n").filter((l) => l.trim().length > 0);
|
|
12051
|
+
const b = theirs.split("\n").filter((l) => l.trim().length > 0);
|
|
12052
|
+
if (![...a, ...b].every((l) => LIST_ITEM.test(l))) return null;
|
|
12053
|
+
const merged = [...a];
|
|
12054
|
+
for (const line of b) if (!merged.includes(line)) merged.push(line);
|
|
12055
|
+
if (merged.every((l) => LEADING_STAMP.test(l))) {
|
|
12056
|
+
merged.sort((x, y) => {
|
|
12057
|
+
const sx = LEADING_STAMP.exec(x)?.[1] ?? "";
|
|
12058
|
+
const sy = LEADING_STAMP.exec(y)?.[1] ?? "";
|
|
12059
|
+
return sx < sy ? -1 : sx > sy ? 1 : 0;
|
|
12060
|
+
});
|
|
12061
|
+
}
|
|
12062
|
+
return `${merged.join("\n")}
|
|
12063
|
+
`;
|
|
12064
|
+
}
|
|
12065
|
+
function mergeBodies(base, ours, theirs) {
|
|
12066
|
+
if (ours === theirs) return { content: ours, clean: true };
|
|
12067
|
+
if (base === ours) return { content: theirs, clean: true };
|
|
12068
|
+
if (base === theirs) return { content: ours, clean: true };
|
|
12069
|
+
const dir = fs6.mkdtempSync(path6.join(os2.tmpdir(), "brainfile-merge-"));
|
|
12070
|
+
try {
|
|
12071
|
+
const files = { base: path6.join(dir, "base"), ours: path6.join(dir, "ours"), theirs: path6.join(dir, "theirs") };
|
|
12072
|
+
fs6.writeFileSync(files.base, base);
|
|
12073
|
+
fs6.writeFileSync(files.ours, ours);
|
|
12074
|
+
fs6.writeFileSync(files.theirs, theirs);
|
|
12075
|
+
const r = spawnSync2("git", ["merge-file", "-p", "-L", "ours", "-L", "base", "-L", "theirs", files.ours, files.base, files.theirs], {
|
|
12076
|
+
encoding: "utf-8",
|
|
12077
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
12078
|
+
});
|
|
12079
|
+
if (r.status === null || r.status < 0) {
|
|
12080
|
+
return { content: `<<<<<<< ours
|
|
12081
|
+
${ours}=======
|
|
12082
|
+
${theirs}>>>>>>> theirs
|
|
12083
|
+
`, clean: false };
|
|
12084
|
+
}
|
|
12085
|
+
if (r.status === 0) return { content: r.stdout, clean: true };
|
|
12086
|
+
let clean = true;
|
|
12087
|
+
const content = r.stdout.replace(CONFLICT, (whole, oursHunk, theirsHunk) => {
|
|
12088
|
+
const union = unionLists(oursHunk, theirsHunk);
|
|
12089
|
+
if (union === null) {
|
|
12090
|
+
clean = false;
|
|
12091
|
+
return whole;
|
|
12092
|
+
}
|
|
12093
|
+
return union;
|
|
12094
|
+
});
|
|
12095
|
+
return { content, clean };
|
|
12096
|
+
} finally {
|
|
12097
|
+
fs6.rmSync(dir, { recursive: true, force: true });
|
|
12098
|
+
}
|
|
12099
|
+
}
|
|
12100
|
+
function mergeBoardDocuments(base, ours, theirs) {
|
|
12101
|
+
const b = parseDoc(base);
|
|
12102
|
+
const o = parseDoc(ours);
|
|
12103
|
+
const t = parseDoc(theirs);
|
|
12104
|
+
if (!o || !t) return mergeBodies(base, ours, theirs);
|
|
12105
|
+
const data = mergeFields(b?.data ?? {}, o.data, t.data);
|
|
12106
|
+
const body = mergeBodies(b?.body ?? "", o.body, t.body);
|
|
12107
|
+
return { content: (0, import_core7.serializeFrontmatter)(data, body.content), clean: body.clean };
|
|
12108
|
+
}
|
|
12109
|
+
function summarizeFieldChanges(before, after) {
|
|
12110
|
+
const b = parseDoc(before)?.data ?? {};
|
|
12111
|
+
const a = parseDoc(after)?.data ?? {};
|
|
12112
|
+
const parts = [];
|
|
12113
|
+
for (const key of Object.keys(a)) {
|
|
12114
|
+
if (key === "updatedAt" || same(b[key], a[key])) continue;
|
|
12115
|
+
const render = (v) => typeof v === "string" ? v : JSON.stringify(v);
|
|
12116
|
+
parts.push(`${key}: ${b[key] === void 0 ? "\u2205" : render(b[key])} \u2192 ${render(a[key])}`);
|
|
12117
|
+
}
|
|
12118
|
+
return parts.join("; ");
|
|
12119
|
+
}
|
|
12120
|
+
function mergeDriverCommand(options) {
|
|
12121
|
+
const read = (p) => fs6.existsSync(p) ? fs6.readFileSync(p, "utf-8") : "";
|
|
12122
|
+
if (!options.ours || !options.theirs) return 2;
|
|
12123
|
+
const outcome = mergeBoardDocuments(read(options.base), read(options.ours), read(options.theirs));
|
|
12124
|
+
fs6.writeFileSync(options.ours, outcome.content, "utf-8");
|
|
12125
|
+
return outcome.clean ? 0 : 1;
|
|
12126
|
+
}
|
|
12127
|
+
|
|
12128
|
+
// src/utils/board-sync.ts
|
|
12129
|
+
import * as fs7 from "fs";
|
|
12130
|
+
import * as os3 from "os";
|
|
12131
|
+
import * as path7 from "path";
|
|
12132
|
+
var REMOTE_CONFIG_KEY = "brainfile.remote";
|
|
12133
|
+
var REMOTE_BRANCH_CONFIG_KEY = "brainfile.remoteBranch";
|
|
12134
|
+
var AUTOSYNC_CONFIG_KEY = "brainfile.autosync";
|
|
12135
|
+
var URL_REMOTE_NAME = "board";
|
|
12136
|
+
var MERGE_DRIVER_NAME = "brainfile";
|
|
12137
|
+
var DEFAULT_MERGE_DRIVER_COMMAND = "brainfile merge-driver %O %A %B";
|
|
12138
|
+
var SYNC_STATE_FILE = path7.join("state", "sync.json");
|
|
12139
|
+
var BOARD_GITATTRIBUTES = [
|
|
12140
|
+
"logs/ledger.jsonl merge=union",
|
|
12141
|
+
"board/*.md merge=brainfile",
|
|
12142
|
+
"logs/*.md merge=brainfile",
|
|
12143
|
+
"brainfile.md merge=brainfile"
|
|
12144
|
+
];
|
|
12145
|
+
function configGet(dotDir, key) {
|
|
12146
|
+
const r = git(["config", "--get", key], dotDir);
|
|
12147
|
+
return r.ok && r.stdout ? r.stdout : null;
|
|
12148
|
+
}
|
|
12149
|
+
function configSet(dotDir, key, value) {
|
|
12150
|
+
return git(["config", key, value], dotDir).ok;
|
|
12151
|
+
}
|
|
12152
|
+
function boardRemote(dotDir) {
|
|
12153
|
+
return configGet(dotDir, REMOTE_CONFIG_KEY);
|
|
12154
|
+
}
|
|
12155
|
+
function boardRemoteBranch(dotDir) {
|
|
12156
|
+
const configured = configGet(dotDir, REMOTE_BRANCH_CONFIG_KEY);
|
|
12157
|
+
if (configured) return configured;
|
|
12158
|
+
if (path7.resolve(dotDir) === path7.resolve(homeBoardDir())) return "home";
|
|
12159
|
+
if (boardRepoKind(dotDir) === "standalone" && path7.basename(path7.resolve(dotDir)) === ".brainfile") {
|
|
12160
|
+
return path7.basename(path7.dirname(path7.resolve(dotDir))) || boardBranch(dotDir);
|
|
12161
|
+
}
|
|
12162
|
+
return boardBranch(dotDir);
|
|
12163
|
+
}
|
|
12164
|
+
function boardAutosync(dotDir) {
|
|
12165
|
+
const value = configGet(dotDir, AUTOSYNC_CONFIG_KEY);
|
|
12166
|
+
if (value === "off" || value === "push" || value === "full") return value;
|
|
12167
|
+
return boardRemote(dotDir) ? "push" : "off";
|
|
12168
|
+
}
|
|
12169
|
+
function setBoardAutosync(dotDir, mode) {
|
|
12170
|
+
return configSet(dotDir, AUTOSYNC_CONFIG_KEY, mode);
|
|
12171
|
+
}
|
|
12172
|
+
function looksLikeRemoteUrl(target) {
|
|
12173
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(target)) return true;
|
|
12174
|
+
if (/^[^/\s]+@[^/\s]+:/.test(target)) return true;
|
|
12175
|
+
if (target.startsWith("/") || target.startsWith(".") || target.startsWith("~")) return true;
|
|
12176
|
+
if (target.includes("/") && fs7.existsSync(target)) return true;
|
|
12177
|
+
return false;
|
|
12178
|
+
}
|
|
12179
|
+
function setBoardRemote(cwd, target, remoteBranch) {
|
|
12180
|
+
const trimmed = target.trim();
|
|
12181
|
+
if (!trimmed) throw new Error("remote is required");
|
|
12182
|
+
let remote;
|
|
12183
|
+
if (looksLikeRemoteUrl(trimmed)) {
|
|
12184
|
+
remote = URL_REMOTE_NAME;
|
|
12185
|
+
const url = trimmed.startsWith("~/") ? path7.join(os3.homedir(), trimmed.slice(2)) : trimmed;
|
|
12186
|
+
const exists = git(["remote", "get-url", remote], cwd).ok;
|
|
12187
|
+
const r = exists ? git(["remote", "set-url", remote, url], cwd) : git(["remote", "add", remote, url], cwd);
|
|
12188
|
+
if (!r.ok) throw new Error(r.stderr || `could not register remote '${remote}'`);
|
|
12189
|
+
} else {
|
|
12190
|
+
remote = trimmed;
|
|
12191
|
+
if (!git(["remote", "get-url", remote], cwd).ok) {
|
|
12192
|
+
const known = git(["remote"], cwd).stdout.split("\n").filter(Boolean);
|
|
12193
|
+
const hint = known.length ? ` Known remotes: ${known.join(", ")}.` : "";
|
|
12194
|
+
throw new Error(`'${remote}' is not a git remote here.${hint} Pass a URL to add one.`);
|
|
12195
|
+
}
|
|
12196
|
+
}
|
|
12197
|
+
configSet(cwd, REMOTE_CONFIG_KEY, remote);
|
|
12198
|
+
if (remoteBranch) configSet(cwd, REMOTE_BRANCH_CONFIG_KEY, remoteBranch);
|
|
12199
|
+
registerMergeDriver(cwd);
|
|
12200
|
+
return {
|
|
12201
|
+
remote,
|
|
12202
|
+
url: git(["remote", "get-url", remote], cwd).stdout || null,
|
|
12203
|
+
remoteBranch: remoteBranch ?? boardRemoteBranch(cwd)
|
|
12204
|
+
};
|
|
12205
|
+
}
|
|
12206
|
+
function registerMergeDriver(cwd, command) {
|
|
12207
|
+
const current = configGet(cwd, `merge.${MERGE_DRIVER_NAME}.driver`);
|
|
12208
|
+
if (command === void 0) {
|
|
12209
|
+
if (current) return false;
|
|
12210
|
+
command = DEFAULT_MERGE_DRIVER_COMMAND;
|
|
12211
|
+
}
|
|
12212
|
+
if (current === command) return false;
|
|
12213
|
+
configSet(cwd, `merge.${MERGE_DRIVER_NAME}.name`, "brainfile board merge (field-level, last writer wins)");
|
|
12214
|
+
return configSet(cwd, `merge.${MERGE_DRIVER_NAME}.driver`, command);
|
|
12215
|
+
}
|
|
12216
|
+
function ensureBoardAttributes(dotDir) {
|
|
12217
|
+
const file = path7.join(dotDir, ".gitattributes");
|
|
12218
|
+
let existing = "";
|
|
12219
|
+
try {
|
|
12220
|
+
existing = fs7.readFileSync(file, "utf-8");
|
|
12221
|
+
} catch {
|
|
12222
|
+
}
|
|
12223
|
+
const lines = existing.split("\n").map((l) => l.trim());
|
|
12224
|
+
const missing = BOARD_GITATTRIBUTES.filter((l) => !lines.includes(l));
|
|
12225
|
+
if (missing.length === 0) return false;
|
|
12226
|
+
const prefix = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
|
|
12227
|
+
` : existing;
|
|
12228
|
+
fs7.writeFileSync(file, `${prefix}${missing.join("\n")}
|
|
12229
|
+
`, "utf-8");
|
|
12230
|
+
return true;
|
|
12231
|
+
}
|
|
12232
|
+
function readSyncState(dotDir) {
|
|
12233
|
+
try {
|
|
12234
|
+
const parsed = JSON.parse(fs7.readFileSync(path7.join(dotDir, SYNC_STATE_FILE), "utf-8"));
|
|
12235
|
+
return typeof parsed?.at === "string" ? parsed : null;
|
|
12236
|
+
} catch {
|
|
12237
|
+
return null;
|
|
12238
|
+
}
|
|
12239
|
+
}
|
|
12240
|
+
function writeSyncState(dotDir, state) {
|
|
12241
|
+
try {
|
|
12242
|
+
fs7.mkdirSync(path7.join(dotDir, "state"), { recursive: true });
|
|
12243
|
+
fs7.writeFileSync(path7.join(dotDir, SYNC_STATE_FILE), `${JSON.stringify(state, null, 2)}
|
|
12244
|
+
`, "utf-8");
|
|
12245
|
+
} catch {
|
|
12246
|
+
}
|
|
12247
|
+
}
|
|
12248
|
+
function firstLine(text) {
|
|
12249
|
+
return text.split("\n").map((l) => l.trim()).find(Boolean) ?? "";
|
|
12250
|
+
}
|
|
12251
|
+
function isMissingRemoteRef(stderr) {
|
|
12252
|
+
return /couldn't find remote ref|Remote branch .* not found|invalid refspec|no such ref/i.test(stderr);
|
|
12253
|
+
}
|
|
12254
|
+
function commitCount(dotDir, range) {
|
|
12255
|
+
const r = git(["rev-list", "--count", range], dotDir);
|
|
12256
|
+
return r.ok ? Number.parseInt(r.stdout, 10) || 0 : 0;
|
|
12257
|
+
}
|
|
12258
|
+
function identity(dotDir, agent) {
|
|
12259
|
+
const args = ["-c", "commit.gpgsign=false"];
|
|
12260
|
+
if (!git(["config", "--get", "user.email"], dotDir).ok) {
|
|
12261
|
+
args.push("-c", "user.name=brainfile", "-c", "user.email=brainfile@localhost");
|
|
12262
|
+
}
|
|
12263
|
+
const env = {};
|
|
12264
|
+
const name = agent?.replace(/[\r\n<>]/g, "").trim();
|
|
12265
|
+
if (name) {
|
|
12266
|
+
env.GIT_AUTHOR_NAME = name;
|
|
12267
|
+
env.GIT_AUTHOR_EMAIL = `${name}@brainfile.local`;
|
|
12268
|
+
}
|
|
12269
|
+
return { args, env };
|
|
12270
|
+
}
|
|
12271
|
+
function resolveCompleteVersusEdit(dotDir) {
|
|
12272
|
+
const status = git(["status", "--porcelain", "-z"], dotDir);
|
|
12273
|
+
if (!status.ok) return [];
|
|
12274
|
+
const resolved = [];
|
|
12275
|
+
for (const entry of status.stdout.split("\0")) {
|
|
12276
|
+
if (entry.length < 4) continue;
|
|
12277
|
+
const xy = entry.slice(0, 2);
|
|
12278
|
+
const file = entry.slice(3);
|
|
12279
|
+
if (xy !== "DU" && xy !== "UD") continue;
|
|
12280
|
+
if (!file.startsWith("board/")) continue;
|
|
12281
|
+
const editedStage = xy === "DU" ? 3 : 2;
|
|
12282
|
+
const base = git(["show", `:1:${file}`], dotDir);
|
|
12283
|
+
const edited = git(["show", `:${editedStage}:${file}`], dotDir);
|
|
12284
|
+
const archived = path7.join(dotDir, "logs", path7.basename(file));
|
|
12285
|
+
if (edited.ok && fs7.existsSync(archived)) {
|
|
12286
|
+
const summary = summarizeFieldChanges(base.ok ? base.stdout : "", edited.stdout);
|
|
12287
|
+
const entryLine = `- ${(/* @__PURE__ */ new Date()).toISOString()}: [sync] edited elsewhere after completion${summary ? ` (${summary})` : ""}`;
|
|
12288
|
+
let content = fs7.readFileSync(archived, "utf-8");
|
|
12289
|
+
if (/^## Log\s*$/m.test(content)) {
|
|
12290
|
+
content = `${content.replace(/\s+$/, "")}
|
|
12291
|
+
${entryLine}
|
|
12292
|
+
`;
|
|
12293
|
+
} else {
|
|
12294
|
+
content = `${content.replace(/\s+$/, "")}
|
|
12295
|
+
|
|
12296
|
+
## Log
|
|
12297
|
+
${entryLine}
|
|
12298
|
+
`;
|
|
12299
|
+
}
|
|
12300
|
+
fs7.writeFileSync(archived, content, "utf-8");
|
|
12301
|
+
git(["add", "--", path7.relative(dotDir, archived)], dotDir);
|
|
12302
|
+
}
|
|
12303
|
+
if (git(["rm", "--quiet", "--cached", "--", file], dotDir).ok) {
|
|
12304
|
+
try {
|
|
12305
|
+
fs7.rmSync(path7.join(dotDir, file), { force: true });
|
|
12306
|
+
} catch {
|
|
12307
|
+
}
|
|
12308
|
+
resolved.push(file);
|
|
12309
|
+
}
|
|
12310
|
+
}
|
|
12311
|
+
return resolved;
|
|
12312
|
+
}
|
|
12313
|
+
function syncBoard(dotDir, options = {}) {
|
|
12314
|
+
const pull = options.pull ?? true;
|
|
12315
|
+
const push = options.push ?? true;
|
|
12316
|
+
const result = { ok: true, pulled: 0, pushed: 0, conflicts: [] };
|
|
12317
|
+
if (!isTrackedBoard(dotDir)) return { ...result, skipped: "not-tracked" };
|
|
12318
|
+
const remote = boardRemote(dotDir);
|
|
12319
|
+
if (!remote) return { ...result, skipped: "no-remote" };
|
|
12320
|
+
const remoteBranch = boardRemoteBranch(dotDir);
|
|
12321
|
+
result.remote = remote;
|
|
12322
|
+
result.remoteBranch = remoteBranch;
|
|
12323
|
+
const stuck = unmergedFiles(dotDir);
|
|
12324
|
+
if (stuck.length > 0) {
|
|
12325
|
+
return finish(dotDir, { ...result, ok: false, failure: "conflict", conflicts: stuck, warning: `unresolved conflicts: ${stuck.join(", ")}` });
|
|
12326
|
+
}
|
|
12327
|
+
commitHandEdits(dotDir);
|
|
12328
|
+
if (ensureBoardAttributes(dotDir)) commitBoard(dotDir, { message: "chore: merge attributes" });
|
|
12329
|
+
registerMergeDriver(dotDir);
|
|
12330
|
+
let fetched = false;
|
|
12331
|
+
if (pull) {
|
|
12332
|
+
const fetch2 = git(["fetch", "--quiet", remote, remoteBranch], dotDir);
|
|
12333
|
+
if (fetch2.ok) {
|
|
12334
|
+
fetched = true;
|
|
12335
|
+
} else if (!isMissingRemoteRef(fetch2.stderr)) {
|
|
12336
|
+
return finish(dotDir, { ...result, ok: false, failure: "offline", warning: `fetch from ${remote} failed: ${firstLine(fetch2.stderr)}` });
|
|
12337
|
+
}
|
|
12338
|
+
if (fetched && !git(["merge-base", "--is-ancestor", "FETCH_HEAD", "HEAD"], dotDir).ok) {
|
|
12339
|
+
const before = git(["rev-parse", "HEAD"], dotDir).stdout;
|
|
12340
|
+
const id = identity(dotDir, options.agent);
|
|
12341
|
+
const merge = git([...id.args, "merge", "--quiet", "--no-edit", "FETCH_HEAD"], dotDir, id.env);
|
|
12342
|
+
if (!merge.ok) {
|
|
12343
|
+
resolveCompleteVersusEdit(dotDir);
|
|
12344
|
+
const remaining = unmergedFiles(dotDir);
|
|
12345
|
+
if (remaining.length > 0) {
|
|
12346
|
+
return finish(dotDir, {
|
|
12347
|
+
...result,
|
|
12348
|
+
ok: false,
|
|
12349
|
+
failure: "conflict",
|
|
12350
|
+
conflicts: remaining,
|
|
12351
|
+
warning: `merge left conflicts in ${remaining.join(", ")} \u2014 resolve them in ${dotDir}, then run sync again`
|
|
12352
|
+
});
|
|
12353
|
+
}
|
|
12354
|
+
const commit = git([...id.args, "commit", "--quiet", "--no-edit", "--no-verify"], dotDir, id.env);
|
|
12355
|
+
if (!commit.ok) {
|
|
12356
|
+
return finish(dotDir, { ...result, ok: false, failure: "error", warning: `merge commit failed: ${firstLine(commit.stderr)}` });
|
|
12357
|
+
}
|
|
12358
|
+
}
|
|
12359
|
+
result.pulled = commitCount(dotDir, `${before}..FETCH_HEAD`);
|
|
12360
|
+
}
|
|
12361
|
+
}
|
|
12362
|
+
if (push) {
|
|
12363
|
+
const ahead = fetched ? commitCount(dotDir, "FETCH_HEAD..HEAD") : pendingChanges(dotDir);
|
|
12364
|
+
if (ahead > 0) {
|
|
12365
|
+
const pushed = git(["push", "--quiet", remote, `HEAD:refs/heads/${remoteBranch}`], dotDir);
|
|
12366
|
+
if (!pushed.ok) {
|
|
12367
|
+
const rejected = /rejected|non-fast-forward|fetch first/i.test(pushed.stderr);
|
|
12368
|
+
return finish(dotDir, {
|
|
12369
|
+
...result,
|
|
12370
|
+
ok: false,
|
|
12371
|
+
failure: rejected ? "rejected" : "offline",
|
|
12372
|
+
warning: rejected ? `push to ${remote} rejected (the remote moved) \u2014 run sync again` : `push to ${remote} failed: ${firstLine(pushed.stderr)}`
|
|
12373
|
+
});
|
|
12374
|
+
}
|
|
12375
|
+
result.pushed = ahead;
|
|
12376
|
+
}
|
|
12377
|
+
}
|
|
12378
|
+
return finish(dotDir, result);
|
|
12379
|
+
}
|
|
12380
|
+
function finish(dotDir, result) {
|
|
12381
|
+
writeSyncState(dotDir, {
|
|
12382
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12383
|
+
remote: result.remote ?? "",
|
|
12384
|
+
remoteBranch: result.remoteBranch ?? "",
|
|
12385
|
+
ok: result.ok,
|
|
12386
|
+
...result.warning ? { warning: result.warning } : {}
|
|
12387
|
+
});
|
|
12388
|
+
return result;
|
|
12389
|
+
}
|
|
12390
|
+
function secondsSinceSync(dotDir, now = Date.now()) {
|
|
12391
|
+
const state = readSyncState(dotDir);
|
|
12392
|
+
if (!state) return null;
|
|
12393
|
+
const at = Date.parse(state.at);
|
|
12394
|
+
return Number.isNaN(at) ? null : Math.max(0, Math.round((now - at) / 1e3));
|
|
12395
|
+
}
|
|
12396
|
+
function syncStatusLabel(dotDir, now = Date.now()) {
|
|
12397
|
+
if (!isTrackedBoard(dotDir)) return null;
|
|
12398
|
+
if (!boardRemote(dotDir)) return "local only";
|
|
12399
|
+
const state = readSyncState(dotDir);
|
|
12400
|
+
if (!state) return "not synced yet";
|
|
12401
|
+
if (!state.ok) return "not synced \xB7 saved locally";
|
|
12402
|
+
const seconds = secondsSinceSync(dotDir, now) ?? 0;
|
|
12403
|
+
const age = seconds < 60 ? `${seconds}s` : seconds < 3600 ? `${Math.round(seconds / 60)}m` : `${Math.round(seconds / 3600)}h`;
|
|
12404
|
+
return `synced ${age} ago`;
|
|
12405
|
+
}
|
|
12406
|
+
function pendingChanges(dotDir) {
|
|
12407
|
+
const remote = boardRemote(dotDir);
|
|
12408
|
+
if (!remote) return 0;
|
|
12409
|
+
const tracking = `refs/remotes/${remote}/${boardRemoteBranch(dotDir)}`;
|
|
12410
|
+
const known = git(["rev-parse", "--verify", "--quiet", tracking], dotDir).ok;
|
|
12411
|
+
return commitCount(dotDir, known ? `${tracking}..HEAD` : "HEAD");
|
|
12412
|
+
}
|
|
12413
|
+
var plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
12414
|
+
function syncMessage(result) {
|
|
12415
|
+
if (result.skipped === "not-tracked") {
|
|
12416
|
+
return { tone: "warn", text: "This board is plain files on this machine and is not shared. To share it: brainfile migrate --to-branch" };
|
|
12417
|
+
}
|
|
12418
|
+
if (result.skipped === "no-remote") {
|
|
12419
|
+
return { tone: "warn", text: "This board is only on this machine. To share it: brainfile sync --set-remote origin" };
|
|
12420
|
+
}
|
|
12421
|
+
const remote = result.remote ?? "the remote";
|
|
12422
|
+
if (!result.ok) {
|
|
12423
|
+
switch (result.failure) {
|
|
12424
|
+
case "conflict":
|
|
12425
|
+
return {
|
|
12426
|
+
tone: "warn",
|
|
12427
|
+
text: `Two edits collided in ${result.conflicts.join(", ")}. Open the file in .brainfile/, keep the right version, then run brainfile sync. Nothing else is shared until then.`
|
|
12428
|
+
};
|
|
12429
|
+
case "rejected":
|
|
12430
|
+
return { tone: "warn", text: `Someone shared changes through ${remote} at the same moment. Run brainfile sync again to combine them. Nothing was lost.` };
|
|
12431
|
+
case "offline":
|
|
12432
|
+
return {
|
|
12433
|
+
tone: "warn",
|
|
12434
|
+
text: `Couldn't reach ${remote}. Nothing was lost: your changes are saved on this machine and will be sent on the next sync.`,
|
|
12435
|
+
detail: result.warning
|
|
12436
|
+
};
|
|
12437
|
+
default:
|
|
12438
|
+
return { tone: "warn", text: `Sync with ${remote} stopped. Your changes are saved on this machine.`, detail: result.warning };
|
|
12439
|
+
}
|
|
12440
|
+
}
|
|
12441
|
+
const parts = [];
|
|
12442
|
+
if (result.pulled > 0) parts.push(`received ${plural(result.pulled, "change")}`);
|
|
12443
|
+
if (result.pushed > 0) parts.push(`sent ${plural(result.pushed, "change")}`);
|
|
12444
|
+
return { tone: "ok", text: parts.length ? `Shared through ${remote}: ${parts.join(", ")}.` : `Up to date with ${remote}.` };
|
|
12445
|
+
}
|
|
12446
|
+
|
|
12447
|
+
// src/utils/board-autosync.ts
|
|
12448
|
+
import * as fs8 from "fs";
|
|
12449
|
+
import * as path8 from "path";
|
|
12450
|
+
import { spawn } from "child_process";
|
|
12451
|
+
var AUTOSYNC_DELAY_MS = 5e3;
|
|
12452
|
+
var FETCH_MAX_AGE_SECONDS = 60;
|
|
12453
|
+
var LOCK_FILE = path8.join("state", "autosync.lock");
|
|
12454
|
+
var LOCK_STALE_MS = 6e4;
|
|
12455
|
+
function effectiveAutosync(dotDir) {
|
|
12456
|
+
const override = process.env.BRAINFILE_AUTOSYNC;
|
|
12457
|
+
if (override === "off" || override === "push" || override === "full") return override;
|
|
12458
|
+
return boardAutosync(dotDir);
|
|
12459
|
+
}
|
|
12460
|
+
function autosyncCliPath() {
|
|
12461
|
+
const candidates = [
|
|
12462
|
+
path8.join(__dirname, "cli.js"),
|
|
12463
|
+
path8.join(__dirname, "..", "cli.js"),
|
|
12464
|
+
path8.join(__dirname, "..", "..", "dist", "cli.js")
|
|
12465
|
+
];
|
|
12466
|
+
return candidates.find((p) => fs8.existsSync(p)) ?? null;
|
|
12467
|
+
}
|
|
12468
|
+
function pidAlive(pid) {
|
|
12469
|
+
try {
|
|
12470
|
+
process.kill(pid, 0);
|
|
12471
|
+
return true;
|
|
12472
|
+
} catch {
|
|
12473
|
+
return false;
|
|
12474
|
+
}
|
|
12475
|
+
}
|
|
12476
|
+
function pushPending(dotDir) {
|
|
12477
|
+
const lock = path8.join(dotDir, LOCK_FILE);
|
|
12478
|
+
try {
|
|
12479
|
+
const st = fs8.statSync(lock);
|
|
12480
|
+
if (Date.now() - st.mtimeMs > LOCK_STALE_MS) return false;
|
|
12481
|
+
const pid = Number.parseInt(fs8.readFileSync(lock, "utf-8"), 10);
|
|
12482
|
+
return Number.isFinite(pid) && pidAlive(pid);
|
|
12483
|
+
} catch {
|
|
12484
|
+
return false;
|
|
12485
|
+
}
|
|
12486
|
+
}
|
|
12487
|
+
function clearPushLock(dotDir) {
|
|
12488
|
+
try {
|
|
12489
|
+
fs8.rmSync(path8.join(dotDir, LOCK_FILE), { force: true });
|
|
12490
|
+
} catch {
|
|
12491
|
+
}
|
|
12492
|
+
}
|
|
12493
|
+
function schedulePush(dotDir, delayMs = AUTOSYNC_DELAY_MS) {
|
|
12494
|
+
if (!isTrackedBoard(dotDir)) return false;
|
|
12495
|
+
const mode = effectiveAutosync(dotDir);
|
|
12496
|
+
if (mode === "off" || !boardRemote(dotDir)) return false;
|
|
12497
|
+
if (pushPending(dotDir)) return false;
|
|
12498
|
+
const cli = autosyncCliPath();
|
|
12499
|
+
if (!cli) return false;
|
|
12500
|
+
const delay = process.env.BRAINFILE_AUTOSYNC_DELAY_MS ? Number(process.env.BRAINFILE_AUTOSYNC_DELAY_MS) : delayMs;
|
|
12501
|
+
try {
|
|
12502
|
+
const child = spawn(
|
|
12503
|
+
process.execPath,
|
|
12504
|
+
[cli, "sync", "--push", "--file", path8.join(dotDir, "brainfile.md"), "--wait", String(delay)],
|
|
12505
|
+
{ cwd: dotDir, detached: true, stdio: "ignore", env: { ...process.env, BRAINFILE_AUTOSYNC: "off" } }
|
|
12506
|
+
);
|
|
12507
|
+
child.unref();
|
|
12508
|
+
if (child.pid) {
|
|
12509
|
+
fs8.mkdirSync(path8.join(dotDir, "state"), { recursive: true });
|
|
12510
|
+
fs8.writeFileSync(path8.join(dotDir, LOCK_FILE), String(child.pid), "utf-8");
|
|
12511
|
+
}
|
|
12512
|
+
return true;
|
|
12513
|
+
} catch {
|
|
12514
|
+
return false;
|
|
12515
|
+
}
|
|
12516
|
+
}
|
|
12517
|
+
function fetchBeforeRead(dotDir, maxAgeSeconds = FETCH_MAX_AGE_SECONDS) {
|
|
12518
|
+
if (!isTrackedBoard(dotDir)) return null;
|
|
12519
|
+
if (effectiveAutosync(dotDir) !== "full") return null;
|
|
12520
|
+
const age = secondsSinceSync(dotDir);
|
|
12521
|
+
if (age !== null && age < maxAgeSeconds) return null;
|
|
12522
|
+
return syncBoard(dotDir, { pull: true, push: false });
|
|
12523
|
+
}
|
|
12524
|
+
var installed = false;
|
|
12525
|
+
function installAutosync() {
|
|
12526
|
+
if (installed) return;
|
|
12527
|
+
installed = true;
|
|
12528
|
+
onBoardCommitted((dotDir) => {
|
|
12529
|
+
schedulePush(dotDir);
|
|
12530
|
+
});
|
|
11253
12531
|
}
|
|
11254
12532
|
|
|
11255
12533
|
// src/utils/config.ts
|
|
11256
|
-
import * as
|
|
11257
|
-
import * as
|
|
11258
|
-
import * as
|
|
12534
|
+
import * as fs9 from "fs";
|
|
12535
|
+
import * as path9 from "path";
|
|
12536
|
+
import * as os4 from "os";
|
|
11259
12537
|
function resolveHomeDir() {
|
|
11260
12538
|
const envHome = process.env.XDG_CONFIG_HOME?.trim();
|
|
11261
12539
|
if (envHome) {
|
|
11262
12540
|
return envHome;
|
|
11263
12541
|
}
|
|
11264
12542
|
const home = process.env.HOME?.trim();
|
|
11265
|
-
return home ||
|
|
12543
|
+
return home || os4.homedir();
|
|
11266
12544
|
}
|
|
11267
12545
|
function getConfigDir() {
|
|
11268
12546
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME?.trim();
|
|
11269
12547
|
if (xdgConfigHome) {
|
|
11270
|
-
return
|
|
12548
|
+
return path9.join(xdgConfigHome, "brainfile");
|
|
11271
12549
|
}
|
|
11272
|
-
return
|
|
12550
|
+
return path9.join(resolveHomeDir(), ".config", "brainfile");
|
|
11273
12551
|
}
|
|
11274
12552
|
function getConfigPath() {
|
|
11275
|
-
return
|
|
12553
|
+
return path9.join(getConfigDir(), "config.json");
|
|
11276
12554
|
}
|
|
11277
12555
|
function ensureConfigDir() {
|
|
11278
12556
|
const configDir = getConfigDir();
|
|
11279
|
-
if (!
|
|
11280
|
-
|
|
12557
|
+
if (!fs9.existsSync(configDir)) {
|
|
12558
|
+
fs9.mkdirSync(configDir, { recursive: true, mode: 448 });
|
|
11281
12559
|
}
|
|
11282
12560
|
}
|
|
11283
12561
|
function loadConfig() {
|
|
11284
12562
|
const configFile = getConfigPath();
|
|
11285
12563
|
try {
|
|
11286
|
-
if (
|
|
11287
|
-
const content =
|
|
12564
|
+
if (fs9.existsSync(configFile)) {
|
|
12565
|
+
const content = fs9.readFileSync(configFile, "utf-8");
|
|
11288
12566
|
return JSON.parse(content);
|
|
11289
12567
|
}
|
|
11290
12568
|
} catch (error) {
|
|
@@ -11295,7 +12573,7 @@ function loadConfig() {
|
|
|
11295
12573
|
function saveConfig(config) {
|
|
11296
12574
|
const configFile = getConfigPath();
|
|
11297
12575
|
ensureConfigDir();
|
|
11298
|
-
|
|
12576
|
+
fs9.writeFileSync(configFile, JSON.stringify(config, null, 2), {
|
|
11299
12577
|
encoding: "utf-8",
|
|
11300
12578
|
mode: 384
|
|
11301
12579
|
// Owner read/write only
|
|
@@ -11370,11 +12648,11 @@ function isValidDestination(dest) {
|
|
|
11370
12648
|
}
|
|
11371
12649
|
|
|
11372
12650
|
// src/utils/auth-store.ts
|
|
11373
|
-
import * as
|
|
11374
|
-
import * as
|
|
12651
|
+
import * as fs10 from "fs";
|
|
12652
|
+
import * as path10 from "path";
|
|
11375
12653
|
import { execSync } from "child_process";
|
|
11376
12654
|
var SERVICE_NAME = "brainfile";
|
|
11377
|
-
var AUTH_FILE =
|
|
12655
|
+
var AUTH_FILE = path10.join(getConfigDir(), "auth.json");
|
|
11378
12656
|
var ENV_VAR_MAP = {
|
|
11379
12657
|
github: ["GITHUB_TOKEN", "GH_TOKEN"],
|
|
11380
12658
|
linear: ["LINEAR_API_KEY", "LINEAR_TOKEN"]
|
|
@@ -11544,8 +12822,8 @@ var AuthStore = class {
|
|
|
11544
12822
|
}
|
|
11545
12823
|
loadAuthFile() {
|
|
11546
12824
|
try {
|
|
11547
|
-
if (
|
|
11548
|
-
const content =
|
|
12825
|
+
if (fs10.existsSync(AUTH_FILE)) {
|
|
12826
|
+
const content = fs10.readFileSync(AUTH_FILE, "utf-8");
|
|
11549
12827
|
return JSON.parse(content);
|
|
11550
12828
|
}
|
|
11551
12829
|
} catch {
|
|
@@ -11554,7 +12832,7 @@ var AuthStore = class {
|
|
|
11554
12832
|
}
|
|
11555
12833
|
saveAuthFile(data) {
|
|
11556
12834
|
ensureConfigDir();
|
|
11557
|
-
|
|
12835
|
+
fs10.writeFileSync(AUTH_FILE, JSON.stringify(data, null, 2), {
|
|
11558
12836
|
encoding: "utf-8",
|
|
11559
12837
|
mode: 384
|
|
11560
12838
|
// Owner read/write only
|
|
@@ -11578,7 +12856,7 @@ var AuthStore = class {
|
|
|
11578
12856
|
var authStore = new AuthStore();
|
|
11579
12857
|
|
|
11580
12858
|
// src/utils/github-auth.ts
|
|
11581
|
-
var
|
|
12859
|
+
var import_chalk3 = __toESM(require_source());
|
|
11582
12860
|
var GITHUB_CLIENT_ID = process.env.BRAINFILE_GITHUB_CLIENT_ID || "Ov23liYourClientId";
|
|
11583
12861
|
var GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
11584
12862
|
var GITHUB_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
@@ -11601,13 +12879,13 @@ async function authenticateGitHub(options) {
|
|
|
11601
12879
|
const ghToken = getGitHubCLIToken();
|
|
11602
12880
|
if (ghToken) {
|
|
11603
12881
|
if (!silent) {
|
|
11604
|
-
console.log(
|
|
12882
|
+
console.log(import_chalk3.default.green("\u2713") + " Found existing GitHub CLI authentication");
|
|
11605
12883
|
}
|
|
11606
12884
|
const user = await getGitHubUser(ghToken);
|
|
11607
12885
|
if (user) {
|
|
11608
12886
|
await authStore.set("github", ghToken, { username: user.login });
|
|
11609
12887
|
if (!silent) {
|
|
11610
|
-
console.log(
|
|
12888
|
+
console.log(import_chalk3.default.green("\u2713") + ` Authenticated as ${import_chalk3.default.cyan("@" + user.login)}`);
|
|
11611
12889
|
}
|
|
11612
12890
|
return { success: true, username: user.login };
|
|
11613
12891
|
}
|
|
@@ -11622,8 +12900,8 @@ async function verifyAndStoreToken(token, silent) {
|
|
|
11622
12900
|
}
|
|
11623
12901
|
await authStore.set("github", token, { username: user.login });
|
|
11624
12902
|
if (!silent) {
|
|
11625
|
-
console.log(
|
|
11626
|
-
console.log(
|
|
12903
|
+
console.log(import_chalk3.default.green("\u2713") + " Token verified");
|
|
12904
|
+
console.log(import_chalk3.default.green("\u2713") + ` Authenticated as ${import_chalk3.default.cyan("@" + user.login)}`);
|
|
11627
12905
|
}
|
|
11628
12906
|
return { success: true, username: user.login };
|
|
11629
12907
|
}
|
|
@@ -11636,16 +12914,16 @@ async function deviceFlowAuth(silent) {
|
|
|
11636
12914
|
try {
|
|
11637
12915
|
const deviceCode = await requestDeviceCode();
|
|
11638
12916
|
if (!silent) {
|
|
11639
|
-
console.log(
|
|
12917
|
+
console.log(import_chalk3.default.yellow("!") + ` First, copy your one-time code: ${import_chalk3.default.bold.cyan(deviceCode.user_code)}`);
|
|
11640
12918
|
console.log("");
|
|
11641
|
-
console.log(`Then visit: ${
|
|
12919
|
+
console.log(`Then visit: ${import_chalk3.default.underline(deviceCode.verification_uri)}`);
|
|
11642
12920
|
console.log("");
|
|
11643
12921
|
}
|
|
11644
12922
|
try {
|
|
11645
12923
|
const open = await import("./open-ZGSQIGEH.mjs");
|
|
11646
12924
|
await open.default(deviceCode.verification_uri);
|
|
11647
12925
|
if (!silent) {
|
|
11648
|
-
console.log(
|
|
12926
|
+
console.log(import_chalk3.default.gray("(Opening browser...)"));
|
|
11649
12927
|
}
|
|
11650
12928
|
} catch {
|
|
11651
12929
|
}
|
|
@@ -11802,11 +13080,11 @@ async function logoutGitHub() {
|
|
|
11802
13080
|
await authStore.clear("github");
|
|
11803
13081
|
}
|
|
11804
13082
|
function sleep(ms) {
|
|
11805
|
-
return new Promise((
|
|
13083
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
11806
13084
|
}
|
|
11807
13085
|
|
|
11808
13086
|
// src/utils/linear-auth.ts
|
|
11809
|
-
var
|
|
13087
|
+
var import_chalk4 = __toESM(require_source());
|
|
11810
13088
|
var LINEAR_API_URL = "https://api.linear.app/graphql";
|
|
11811
13089
|
async function isLinearAuthenticated() {
|
|
11812
13090
|
return await authStore.isAuthenticated("linear");
|
|
@@ -11821,7 +13099,7 @@ async function authenticateLinear(options) {
|
|
|
11821
13099
|
console.log("");
|
|
11822
13100
|
console.log("To authenticate with Linear, you need an API key.");
|
|
11823
13101
|
console.log("");
|
|
11824
|
-
console.log(`Get your API key from: ${
|
|
13102
|
+
console.log(`Get your API key from: ${import_chalk4.default.underline("https://linear.app/settings/api")}`);
|
|
11825
13103
|
console.log("");
|
|
11826
13104
|
}
|
|
11827
13105
|
return { success: false, error: "Linear API key required. Use --token flag." };
|
|
@@ -11837,8 +13115,8 @@ async function authenticateLinear(options) {
|
|
|
11837
13115
|
workspace
|
|
11838
13116
|
});
|
|
11839
13117
|
if (!silent) {
|
|
11840
|
-
console.log(
|
|
11841
|
-
console.log(
|
|
13118
|
+
console.log(import_chalk4.default.green("\u2713") + " API key verified");
|
|
13119
|
+
console.log(import_chalk4.default.green("\u2713") + ` Authenticated as ${import_chalk4.default.cyan(viewer.name)} in ${import_chalk4.default.cyan(workspace)}`);
|
|
11842
13120
|
}
|
|
11843
13121
|
return { success: true, workspace };
|
|
11844
13122
|
}
|
|
@@ -12039,6 +13317,91 @@ async function logoutLinear() {
|
|
|
12039
13317
|
await authStore.clear("linear");
|
|
12040
13318
|
}
|
|
12041
13319
|
|
|
13320
|
+
// src/tui/theme.ts
|
|
13321
|
+
var RAW_PALETTE = {
|
|
13322
|
+
// Text hierarchy
|
|
13323
|
+
text: "#ffffff",
|
|
13324
|
+
textSecondary: "#a0a0a0",
|
|
13325
|
+
textMuted: "#606060",
|
|
13326
|
+
textDim: "#404040",
|
|
13327
|
+
// Priority signal
|
|
13328
|
+
critical: "#ef4444",
|
|
13329
|
+
high: "#f59e0b",
|
|
13330
|
+
medium: "#3b82f6",
|
|
13331
|
+
low: "#6b7280",
|
|
13332
|
+
// Contract-state signal (design §3: draft dim · ready cyan · in_progress
|
|
13333
|
+
// yellow · delivered magenta · done green · failed/blocked red)
|
|
13334
|
+
contractDraft: "#606060",
|
|
13335
|
+
contractReady: "#06b6d4",
|
|
13336
|
+
contractInProgress: "#eab308",
|
|
13337
|
+
contractDelivered: "#c026d3",
|
|
13338
|
+
contractDone: "#22c55e",
|
|
13339
|
+
contractFailed: "#ef4444",
|
|
13340
|
+
// Feedback
|
|
13341
|
+
success: "#22c55e",
|
|
13342
|
+
warning: "#eab308",
|
|
13343
|
+
error: "#ef4444",
|
|
13344
|
+
info: "#3b82f6",
|
|
13345
|
+
accent: "#7c3aed"
|
|
13346
|
+
};
|
|
13347
|
+
function isNoColor(env = process.env) {
|
|
13348
|
+
return Boolean(env.NO_COLOR);
|
|
13349
|
+
}
|
|
13350
|
+
function makePalette(noColor) {
|
|
13351
|
+
if (!noColor) return RAW_PALETTE;
|
|
13352
|
+
return new Proxy(RAW_PALETTE, { get: () => void 0 });
|
|
13353
|
+
}
|
|
13354
|
+
var NO_COLOR = isNoColor();
|
|
13355
|
+
var PALETTE = makePalette(NO_COLOR);
|
|
13356
|
+
var RULE = "\u2500";
|
|
13357
|
+
var TYPE_GLYPHS = {
|
|
13358
|
+
epic: "\u25B8",
|
|
13359
|
+
spec: "\u25C6",
|
|
13360
|
+
adr: "\u25CF",
|
|
13361
|
+
plan: "\u2398",
|
|
13362
|
+
task: ""
|
|
13363
|
+
};
|
|
13364
|
+
function getTypeGlyph(type) {
|
|
13365
|
+
if (!type) return "";
|
|
13366
|
+
return TYPE_GLYPHS[type.toLowerCase()] ?? "";
|
|
13367
|
+
}
|
|
13368
|
+
var GLYPHS = {
|
|
13369
|
+
pointer: "\u25B8",
|
|
13370
|
+
cursor: "\u258C",
|
|
13371
|
+
collapsed: "\u25B6",
|
|
13372
|
+
success: "\u2713",
|
|
13373
|
+
error: "\u2717",
|
|
13374
|
+
warning: "\u26A0",
|
|
13375
|
+
live: "\u25CF",
|
|
13376
|
+
subtaskOpen: "\u25FB",
|
|
13377
|
+
subtaskDone: "\u2611",
|
|
13378
|
+
orphanParent: "\u2190",
|
|
13379
|
+
/** Board-list row glyph for a parent-with-children that is expanded (§A1). */
|
|
13380
|
+
parentExpanded: "\u25BE",
|
|
13381
|
+
/** Board-list row glyph for a parent-with-children that is collapsed (§A1). */
|
|
13382
|
+
parentCollapsed: "\u25B8",
|
|
13383
|
+
/** Detail body scroll indicator (§B2), e.g. `↕ 2/9`. */
|
|
13384
|
+
scroll: "\u2195"
|
|
13385
|
+
};
|
|
13386
|
+
function getContractStateColor(state) {
|
|
13387
|
+
switch (state?.toLowerCase()) {
|
|
13388
|
+
case "ready":
|
|
13389
|
+
return PALETTE.contractReady;
|
|
13390
|
+
case "in_progress":
|
|
13391
|
+
return PALETTE.contractInProgress;
|
|
13392
|
+
case "delivered":
|
|
13393
|
+
return PALETTE.contractDelivered;
|
|
13394
|
+
case "done":
|
|
13395
|
+
return PALETTE.contractDone;
|
|
13396
|
+
case "failed":
|
|
13397
|
+
case "blocked":
|
|
13398
|
+
return PALETTE.contractFailed;
|
|
13399
|
+
case "draft":
|
|
13400
|
+
default:
|
|
13401
|
+
return PALETTE.contractDraft;
|
|
13402
|
+
}
|
|
13403
|
+
}
|
|
13404
|
+
|
|
12042
13405
|
export {
|
|
12043
13406
|
require_source,
|
|
12044
13407
|
require_dist,
|
|
@@ -12061,14 +13424,54 @@ export {
|
|
|
12061
13424
|
columnNotFound,
|
|
12062
13425
|
taskNotFound,
|
|
12063
13426
|
validationError2,
|
|
13427
|
+
renderCliError,
|
|
12064
13428
|
V1_UNSUPPORTED_MESSAGE,
|
|
12065
13429
|
assertV2Brainfile,
|
|
13430
|
+
git,
|
|
13431
|
+
gitToplevel,
|
|
13432
|
+
listWorktrees,
|
|
13433
|
+
boardBranch,
|
|
13434
|
+
boardRepoKind,
|
|
13435
|
+
isTrackedBoard,
|
|
13436
|
+
findTrackedBoardDir,
|
|
13437
|
+
materializeBoardWorktree,
|
|
13438
|
+
ensureExcludeEntry,
|
|
13439
|
+
removeExcludeEntry,
|
|
13440
|
+
createOrphanBoardWorktree,
|
|
13441
|
+
initStandaloneBoardRepo,
|
|
13442
|
+
boardIsDirty,
|
|
13443
|
+
commitBoard,
|
|
13444
|
+
commitHandEdits,
|
|
13445
|
+
resolveAgentName,
|
|
13446
|
+
homeBoardDir,
|
|
13447
|
+
isGlobalBoardRequested,
|
|
13448
|
+
describeCommandForCommit,
|
|
13449
|
+
scheduleBoardCommit,
|
|
12066
13450
|
resolveCliBrainfilePath,
|
|
13451
|
+
tryResolveBoardDir,
|
|
12067
13452
|
workspaceRootFromBrainfilePath,
|
|
12068
13453
|
probeWorkspaceFormat,
|
|
12069
13454
|
shouldSuggestV2Migration,
|
|
12070
13455
|
markV2MigrationHintShown,
|
|
12071
13456
|
import_core5 as import_core,
|
|
13457
|
+
mergeDriverCommand,
|
|
13458
|
+
boardRemote,
|
|
13459
|
+
boardRemoteBranch,
|
|
13460
|
+
boardAutosync,
|
|
13461
|
+
setBoardAutosync,
|
|
13462
|
+
setBoardRemote,
|
|
13463
|
+
registerMergeDriver,
|
|
13464
|
+
ensureBoardAttributes,
|
|
13465
|
+
readSyncState,
|
|
13466
|
+
syncBoard,
|
|
13467
|
+
secondsSinceSync,
|
|
13468
|
+
syncStatusLabel,
|
|
13469
|
+
pendingChanges,
|
|
13470
|
+
syncMessage,
|
|
13471
|
+
effectiveAutosync,
|
|
13472
|
+
clearPushLock,
|
|
13473
|
+
fetchBeforeRead,
|
|
13474
|
+
installAutosync,
|
|
12072
13475
|
getConfigPath,
|
|
12073
13476
|
loadConfig,
|
|
12074
13477
|
saveConfig,
|
|
@@ -12085,5 +13488,10 @@ export {
|
|
|
12085
13488
|
authenticateLinear,
|
|
12086
13489
|
getLinearTeams,
|
|
12087
13490
|
createLinearIssue,
|
|
12088
|
-
logoutLinear
|
|
13491
|
+
logoutLinear,
|
|
13492
|
+
PALETTE,
|
|
13493
|
+
RULE,
|
|
13494
|
+
getTypeGlyph,
|
|
13495
|
+
GLYPHS,
|
|
13496
|
+
getContractStateColor
|
|
12089
13497
|
};
|