brainfile 0.21.0 → 0.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-FOLBAGJS.mjs → chunk-7KU2R7QC.mjs} +245 -101
- package/dist/cli.mjs +324 -207
- package/dist/commands/brief.js +1 -1
- package/dist/commands/brief.js.map +1 -1
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +4 -1
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/sync.d.ts +3 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +23 -14
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/where.d.ts +4 -1
- package/dist/commands/where.d.ts.map +1 -1
- package/dist/commands/where.js +9 -3
- package/dist/commands/where.js.map +1 -1
- package/dist/mcp/helpers.d.ts +3 -2
- package/dist/mcp/helpers.d.ts.map +1 -1
- package/dist/mcp/helpers.js +5 -6
- package/dist/mcp/helpers.js.map +1 -1
- package/dist/mcp/tools/brief_tool.js +1 -1
- package/dist/mcp/tools/brief_tool.js.map +1 -1
- package/dist/{tui-M2KWIG2E.mjs → tui-3Z7ZJV7M.mjs} +1 -1
- package/dist/utils/actor.d.ts +22 -0
- package/dist/utils/actor.d.ts.map +1 -0
- package/dist/utils/actor.js +200 -0
- package/dist/utils/actor.js.map +1 -0
- package/dist/utils/board-commit-hooks.d.ts.map +1 -1
- package/dist/utils/board-commit-hooks.js +3 -2
- package/dist/utils/board-commit-hooks.js.map +1 -1
- package/dist/utils/board-repo.d.ts +33 -9
- package/dist/utils/board-repo.d.ts.map +1 -1
- package/dist/utils/board-repo.js +162 -61
- package/dist/utils/board-repo.js.map +1 -1
- package/dist/utils/board-sync.d.ts +26 -11
- package/dist/utils/board-sync.d.ts.map +1 -1
- package/dist/utils/board-sync.js +141 -56
- package/dist/utils/board-sync.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -18,8 +18,9 @@ import {
|
|
|
18
18
|
boardBranch,
|
|
19
19
|
boardIsDirty,
|
|
20
20
|
boardRemote,
|
|
21
|
-
|
|
21
|
+
boardRemoteRef,
|
|
22
22
|
boardRepoKind,
|
|
23
|
+
boardWebUrl,
|
|
23
24
|
clearPushLock,
|
|
24
25
|
columnNotFound,
|
|
25
26
|
columnNotFoundError,
|
|
@@ -74,7 +75,6 @@ import {
|
|
|
74
75
|
renderCliError,
|
|
75
76
|
require_dist,
|
|
76
77
|
require_source,
|
|
77
|
-
resolveAgentName,
|
|
78
78
|
resolveCliBrainfilePath,
|
|
79
79
|
saveConfig,
|
|
80
80
|
secondsSinceSync,
|
|
@@ -91,7 +91,7 @@ import {
|
|
|
91
91
|
validationError,
|
|
92
92
|
validationError2,
|
|
93
93
|
workspaceRootFromBrainfilePath
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-7KU2R7QC.mjs";
|
|
95
95
|
import {
|
|
96
96
|
__commonJS,
|
|
97
97
|
__export,
|
|
@@ -1263,7 +1263,7 @@ var require_command = __commonJS({
|
|
|
1263
1263
|
var EventEmitter = __require("node:events").EventEmitter;
|
|
1264
1264
|
var childProcess = __require("node:child_process");
|
|
1265
1265
|
var path27 = __require("node:path");
|
|
1266
|
-
var
|
|
1266
|
+
var fs25 = __require("node:fs");
|
|
1267
1267
|
var process4 = __require("node:process");
|
|
1268
1268
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
1269
1269
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -2257,7 +2257,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2257
2257
|
* @param {string} subcommandName
|
|
2258
2258
|
*/
|
|
2259
2259
|
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
2260
|
-
if (
|
|
2260
|
+
if (fs25.existsSync(executableFile)) return;
|
|
2261
2261
|
const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
|
|
2262
2262
|
const executableMissing = `'${executableFile}' does not exist
|
|
2263
2263
|
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
@@ -2276,10 +2276,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2276
2276
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
2277
2277
|
function findFile(baseDir, baseName) {
|
|
2278
2278
|
const localBin = path27.resolve(baseDir, baseName);
|
|
2279
|
-
if (
|
|
2279
|
+
if (fs25.existsSync(localBin)) return localBin;
|
|
2280
2280
|
if (sourceExt.includes(path27.extname(baseName))) return void 0;
|
|
2281
2281
|
const foundExt = sourceExt.find(
|
|
2282
|
-
(ext) =>
|
|
2282
|
+
(ext) => fs25.existsSync(`${localBin}${ext}`)
|
|
2283
2283
|
);
|
|
2284
2284
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
2285
2285
|
return void 0;
|
|
@@ -2291,7 +2291,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2291
2291
|
if (this._scriptPath) {
|
|
2292
2292
|
let resolvedScriptPath;
|
|
2293
2293
|
try {
|
|
2294
|
-
resolvedScriptPath =
|
|
2294
|
+
resolvedScriptPath = fs25.realpathSync(this._scriptPath);
|
|
2295
2295
|
} catch {
|
|
2296
2296
|
resolvedScriptPath = this._scriptPath;
|
|
2297
2297
|
}
|
|
@@ -3530,7 +3530,7 @@ var require_package = __commonJS({
|
|
|
3530
3530
|
"package.json"(exports, module) {
|
|
3531
3531
|
module.exports = {
|
|
3532
3532
|
name: "brainfile",
|
|
3533
|
-
version: "0.21.
|
|
3533
|
+
version: "0.21.2",
|
|
3534
3534
|
description: "Command-line interface for Brainfile task management",
|
|
3535
3535
|
main: "dist/index.js",
|
|
3536
3536
|
types: "dist/index.d.ts",
|
|
@@ -3567,7 +3567,7 @@ var require_package = __commonJS({
|
|
|
3567
3567
|
access: "public"
|
|
3568
3568
|
},
|
|
3569
3569
|
dependencies: {
|
|
3570
|
-
"@brainfile/core": "^0.21.
|
|
3570
|
+
"@brainfile/core": "^0.21.2",
|
|
3571
3571
|
chalk: "^4.1.2",
|
|
3572
3572
|
chokidar: "^4.0.3",
|
|
3573
3573
|
commander: "^14.0.3",
|
|
@@ -3626,7 +3626,7 @@ var {
|
|
|
3626
3626
|
} = import_index.default;
|
|
3627
3627
|
|
|
3628
3628
|
// src/cli.ts
|
|
3629
|
-
import { readFileSync as
|
|
3629
|
+
import { readFileSync as readFileSync11, existsSync as existsSync20 } from "fs";
|
|
3630
3630
|
import { join as join18, sep as sep3 } from "path";
|
|
3631
3631
|
|
|
3632
3632
|
// src/commands/list.ts
|
|
@@ -4139,6 +4139,111 @@ function logAddSuccess(options, taskId, columnTitle, logger, createdChildren = [
|
|
|
4139
4139
|
}
|
|
4140
4140
|
}
|
|
4141
4141
|
|
|
4142
|
+
// src/utils/actor.ts
|
|
4143
|
+
import * as fs from "fs";
|
|
4144
|
+
import { spawnSync } from "child_process";
|
|
4145
|
+
var AGENT_BINARIES = {
|
|
4146
|
+
claude: "claude",
|
|
4147
|
+
codex: "codex",
|
|
4148
|
+
"cursor-agent": "cursor",
|
|
4149
|
+
gemini: "gemini",
|
|
4150
|
+
opencode: "opencode",
|
|
4151
|
+
goose: "goose",
|
|
4152
|
+
droid: "droid",
|
|
4153
|
+
crush: "crush",
|
|
4154
|
+
aider: "aider",
|
|
4155
|
+
cline: "cline",
|
|
4156
|
+
amp: "amp",
|
|
4157
|
+
qwen: "qwen",
|
|
4158
|
+
copilot: "copilot"
|
|
4159
|
+
};
|
|
4160
|
+
var MAX_DEPTH = 32;
|
|
4161
|
+
function sanitize(name) {
|
|
4162
|
+
return name.replace(/[[\]<>\r\n]/g, "").trim();
|
|
4163
|
+
}
|
|
4164
|
+
function agentFromCommand(words) {
|
|
4165
|
+
for (const word of words.slice(0, 2)) {
|
|
4166
|
+
const base = word.split("/").pop()?.replace(/\.(c|m)?js$/, "") ?? "";
|
|
4167
|
+
if (AGENT_BINARIES[base]) return AGENT_BINARIES[base];
|
|
4168
|
+
}
|
|
4169
|
+
return null;
|
|
4170
|
+
}
|
|
4171
|
+
function linuxProc(pid) {
|
|
4172
|
+
try {
|
|
4173
|
+
const stat = fs.readFileSync(`/proc/${pid}/stat`, "utf-8");
|
|
4174
|
+
const ppid = Number.parseInt(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1], 10);
|
|
4175
|
+
const comm = stat.slice(stat.indexOf("(") + 1, stat.lastIndexOf(")"));
|
|
4176
|
+
const cmdline = fs.readFileSync(`/proc/${pid}/cmdline`, "utf-8").split("\0").filter(Boolean);
|
|
4177
|
+
return { ppid, words: [comm, ...cmdline] };
|
|
4178
|
+
} catch {
|
|
4179
|
+
return null;
|
|
4180
|
+
}
|
|
4181
|
+
}
|
|
4182
|
+
function psTable() {
|
|
4183
|
+
const r = spawnSync("ps", ["-A", "-o", "pid=,ppid=,args="], { encoding: "utf-8", timeout: 2e3 });
|
|
4184
|
+
if (r.status !== 0 || !r.stdout) return null;
|
|
4185
|
+
const table = /* @__PURE__ */ new Map();
|
|
4186
|
+
for (const line of r.stdout.split("\n")) {
|
|
4187
|
+
const m = /^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(line);
|
|
4188
|
+
if (m) table.set(Number(m[1]), { ppid: Number(m[2]), words: m[3].split(/\s+/) });
|
|
4189
|
+
}
|
|
4190
|
+
return table;
|
|
4191
|
+
}
|
|
4192
|
+
function agentFromProcessTree(startPid = process.ppid) {
|
|
4193
|
+
const useProc = process.platform === "linux" && fs.existsSync("/proc/self/stat");
|
|
4194
|
+
const table = useProc ? null : process.platform === "win32" ? null : psTable();
|
|
4195
|
+
if (!useProc && !table) return null;
|
|
4196
|
+
let pid = startPid;
|
|
4197
|
+
for (let depth = 0; depth < MAX_DEPTH && pid > 1; depth++) {
|
|
4198
|
+
const info = useProc ? linuxProc(pid) : table?.get(pid) ?? null;
|
|
4199
|
+
if (!info) return null;
|
|
4200
|
+
const agent = agentFromCommand(info.words);
|
|
4201
|
+
if (agent) return agent;
|
|
4202
|
+
pid = info.ppid;
|
|
4203
|
+
}
|
|
4204
|
+
return null;
|
|
4205
|
+
}
|
|
4206
|
+
function agentFromEnvironment(env = process.env) {
|
|
4207
|
+
if (env.CODEX_THREAD_ID || env.CODEX_SESSION_ID) return "codex";
|
|
4208
|
+
if (env.GEMINI_CLI === "1") return "gemini";
|
|
4209
|
+
if (env.CLAUDECODE === "1") return "claude";
|
|
4210
|
+
const generic = env.AI_AGENT?.split("_")[0];
|
|
4211
|
+
if (generic) return generic === "claude-code" ? "claude" : sanitize(generic) || null;
|
|
4212
|
+
return null;
|
|
4213
|
+
}
|
|
4214
|
+
function flagValue(argv) {
|
|
4215
|
+
const at = argv.indexOf("--agent");
|
|
4216
|
+
if (at >= 0 && argv[at + 1] && !argv[at + 1].startsWith("-")) return argv[at + 1];
|
|
4217
|
+
const inline = argv.find((a) => a.startsWith("--agent="));
|
|
4218
|
+
return inline ? inline.slice("--agent=".length) : null;
|
|
4219
|
+
}
|
|
4220
|
+
var detected = null;
|
|
4221
|
+
function detectAgent(argv = process.argv, env = process.env) {
|
|
4222
|
+
const flag = sanitize(flagValue(argv) ?? "");
|
|
4223
|
+
if (flag) return { name: flag, source: "flag" };
|
|
4224
|
+
const named = sanitize(env.BRAINFILE_AGENT ?? "");
|
|
4225
|
+
if (named) return { name: named, source: "env" };
|
|
4226
|
+
if (env.BRAINFILE_DETECT_AGENT === "off") return null;
|
|
4227
|
+
if (!detected) {
|
|
4228
|
+
let value = null;
|
|
4229
|
+
try {
|
|
4230
|
+
value = agentFromProcessTree();
|
|
4231
|
+
} catch {
|
|
4232
|
+
value = null;
|
|
4233
|
+
}
|
|
4234
|
+
detected = { value };
|
|
4235
|
+
}
|
|
4236
|
+
if (detected.value) return { name: detected.value, source: "process" };
|
|
4237
|
+
const fingerprint = agentFromEnvironment(env);
|
|
4238
|
+
return fingerprint ? { name: fingerprint, source: "fingerprint" } : null;
|
|
4239
|
+
}
|
|
4240
|
+
function resolveActor(cwd = process.cwd(), argv = process.argv) {
|
|
4241
|
+
const agent = detectAgent(argv);
|
|
4242
|
+
if (agent) return agent;
|
|
4243
|
+
const user = sanitize(git(["config", "--get", "user.name"], cwd).stdout);
|
|
4244
|
+
return user ? { name: user, source: "git" } : null;
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4142
4247
|
// src/utils/board-commit-hooks.ts
|
|
4143
4248
|
var SKIP_COMMANDS = /* @__PURE__ */ new Set(["mcp", "tui", "hooks", "auth", "sync", "merge-driver", "where"]);
|
|
4144
4249
|
function topLevelCommandName(command) {
|
|
@@ -4167,7 +4272,7 @@ function beforeCommand(command) {
|
|
|
4167
4272
|
function afterCommand(command) {
|
|
4168
4273
|
const dotDir = boardDirForCommand(command);
|
|
4169
4274
|
if (!dotDir) return false;
|
|
4170
|
-
return commitBoard(dotDir, { message: describeCommandForCommit(command), agent:
|
|
4275
|
+
return commitBoard(dotDir, { message: describeCommandForCommit(command), agent: detectAgent()?.name });
|
|
4171
4276
|
}
|
|
4172
4277
|
|
|
4173
4278
|
// src/commands/move.ts
|
|
@@ -4254,7 +4359,7 @@ function moveCommandV2(options, filePath, logger) {
|
|
|
4254
4359
|
|
|
4255
4360
|
// src/commands/template.ts
|
|
4256
4361
|
var import_core7 = __toESM(require_dist());
|
|
4257
|
-
import * as
|
|
4362
|
+
import * as fs2 from "fs";
|
|
4258
4363
|
import * as path4 from "path";
|
|
4259
4364
|
function templateCommand(options, logger = defaultLogger) {
|
|
4260
4365
|
if (options.list) {
|
|
@@ -4282,7 +4387,7 @@ function templateCommand(options, logger = defaultLogger) {
|
|
|
4282
4387
|
throw missingRequired("--title", 'brainfile template --use <template-id> --title "Task title"');
|
|
4283
4388
|
}
|
|
4284
4389
|
const filePath = resolveCliBrainfilePath(options.file);
|
|
4285
|
-
if (!
|
|
4390
|
+
if (!fs2.existsSync(filePath)) {
|
|
4286
4391
|
throw fileNotFound(filePath);
|
|
4287
4392
|
}
|
|
4288
4393
|
const board = (0, import_core.readV2BoardConfig)(filePath);
|
|
@@ -4358,13 +4463,13 @@ ${availableTemplates}`
|
|
|
4358
4463
|
// src/commands/lint.ts
|
|
4359
4464
|
var import_core8 = __toESM(require_dist());
|
|
4360
4465
|
var import_chalk4 = __toESM(require_source());
|
|
4361
|
-
import * as
|
|
4466
|
+
import * as fs3 from "fs";
|
|
4362
4467
|
function lintCommand(options, logger = defaultLogger) {
|
|
4363
4468
|
const filePath = resolveCliBrainfilePath(options.file);
|
|
4364
|
-
if (!
|
|
4469
|
+
if (!fs3.existsSync(filePath)) {
|
|
4365
4470
|
throw fileNotFound(filePath);
|
|
4366
4471
|
}
|
|
4367
|
-
const content =
|
|
4472
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
4368
4473
|
logger.log(import_chalk4.default.blue(`
|
|
4369
4474
|
\u{1F50D} Linting: ${filePath}
|
|
4370
4475
|
`));
|
|
@@ -4395,7 +4500,7 @@ function lintCommand(options, logger = defaultLogger) {
|
|
|
4395
4500
|
let fixedCount = 0;
|
|
4396
4501
|
let fixed = false;
|
|
4397
4502
|
if (options.fix && result.fixedContent) {
|
|
4398
|
-
|
|
4503
|
+
fs3.writeFileSync(filePath, result.fixedContent, "utf-8");
|
|
4399
4504
|
fixedCount = fixable.length;
|
|
4400
4505
|
fixed = true;
|
|
4401
4506
|
logger.log(import_chalk4.default.green(`\u2713 Fixed ${fixable.length} issue${fixable.length > 1 ? "s" : ""}!
|
|
@@ -4430,11 +4535,11 @@ function lintCommand(options, logger = defaultLogger) {
|
|
|
4430
4535
|
// src/commands/init.ts
|
|
4431
4536
|
var import_chalk5 = __toESM(require_source());
|
|
4432
4537
|
var import_core9 = __toESM(require_dist());
|
|
4433
|
-
import * as
|
|
4538
|
+
import * as fs5 from "fs";
|
|
4434
4539
|
import * as path6 from "path";
|
|
4435
4540
|
|
|
4436
4541
|
// src/utils/dot-brainfile.ts
|
|
4437
|
-
import * as
|
|
4542
|
+
import * as fs4 from "fs";
|
|
4438
4543
|
import * as path5 from "path";
|
|
4439
4544
|
function getDotBrainfileDir(brainfilePath) {
|
|
4440
4545
|
const abs = path5.resolve(brainfilePath);
|
|
@@ -4445,8 +4550,8 @@ function getDotBrainfileDir(brainfilePath) {
|
|
|
4445
4550
|
function removeLegacyStateFile(brainfilePath) {
|
|
4446
4551
|
const dotDir = getDotBrainfileDir(brainfilePath);
|
|
4447
4552
|
const statePath = path5.join(dotDir, "state.json");
|
|
4448
|
-
if (
|
|
4449
|
-
|
|
4553
|
+
if (fs4.existsSync(statePath)) {
|
|
4554
|
+
fs4.rmSync(statePath, { force: true });
|
|
4450
4555
|
}
|
|
4451
4556
|
return statePath;
|
|
4452
4557
|
}
|
|
@@ -4514,7 +4619,7 @@ function planInit(options) {
|
|
|
4514
4619
|
}
|
|
4515
4620
|
function isNonEmptyDir(dir) {
|
|
4516
4621
|
try {
|
|
4517
|
-
return
|
|
4622
|
+
return fs5.statSync(dir).isDirectory() && fs5.readdirSync(dir).length > 0;
|
|
4518
4623
|
} catch {
|
|
4519
4624
|
return false;
|
|
4520
4625
|
}
|
|
@@ -4531,11 +4636,11 @@ function initCommand(options) {
|
|
|
4531
4636
|
console.log(import_chalk5.default.gray("Run ") + import_chalk5.default.cyan("brainfile migrate") + import_chalk5.default.gray(" before running init."));
|
|
4532
4637
|
process.exit(1);
|
|
4533
4638
|
}
|
|
4534
|
-
if (probe.format === "v2" &&
|
|
4639
|
+
if (probe.format === "v2" && fs5.existsSync(filePath) && !options.force) {
|
|
4535
4640
|
(0, import_core9.ensureDotBrainfileGitignore)(filePath);
|
|
4536
4641
|
removeLegacyStateFile(filePath);
|
|
4537
|
-
|
|
4538
|
-
|
|
4642
|
+
fs5.mkdirSync(path6.join(dotDir, "board"), { recursive: true });
|
|
4643
|
+
fs5.mkdirSync(path6.join(dotDir, "logs"), { recursive: true });
|
|
4539
4644
|
console.log(import_chalk5.default.green(`A board already exists at ${displayPath(dotDir)}/`));
|
|
4540
4645
|
if (mode !== "plain" && boardRepoKind(dotDir) === null) {
|
|
4541
4646
|
console.log(import_chalk5.default.gray(" It is plain files. To keep it on its own branch and share it: ") + import_chalk5.default.cyan("brainfile migrate --to-branch"));
|
|
@@ -4543,7 +4648,7 @@ function initCommand(options) {
|
|
|
4543
4648
|
console.log(import_chalk5.default.gray(" Where it lives and who has it: ") + import_chalk5.default.cyan("brainfile where"));
|
|
4544
4649
|
return;
|
|
4545
4650
|
}
|
|
4546
|
-
if (
|
|
4651
|
+
if (fs5.existsSync(filePath) && !options.force) {
|
|
4547
4652
|
console.error(import_chalk5.default.red(`Error: File already exists: ${filePath}`));
|
|
4548
4653
|
console.log(import_chalk5.default.gray("Use --force to overwrite"));
|
|
4549
4654
|
process.exit(1);
|
|
@@ -4557,12 +4662,12 @@ function initCommand(options) {
|
|
|
4557
4662
|
createOrphanBoardWorktree(plan.repoRoot, dotDir, boardBranch(plan.repoRoot));
|
|
4558
4663
|
}
|
|
4559
4664
|
(0, import_core9.ensureDotBrainfileGitignore)(filePath);
|
|
4560
|
-
|
|
4665
|
+
fs5.mkdirSync(dotDir, { recursive: true });
|
|
4561
4666
|
const boardDir = path6.join(dotDir, "board");
|
|
4562
4667
|
const logsDir = path6.join(dotDir, "logs");
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4668
|
+
fs5.mkdirSync(boardDir, { recursive: true });
|
|
4669
|
+
fs5.mkdirSync(logsDir, { recursive: true });
|
|
4670
|
+
fs5.writeFileSync(filePath, DEFAULT_BRAINFILE_V2, "utf-8");
|
|
4566
4671
|
removeLegacyStateFile(filePath);
|
|
4567
4672
|
if (mode === "standalone") {
|
|
4568
4673
|
initStandaloneBoardRepo(dotDir);
|
|
@@ -4614,16 +4719,16 @@ var import_chalk7 = __toESM(require_source());
|
|
|
4614
4719
|
var import_core11 = __toESM(require_dist());
|
|
4615
4720
|
var import_core12 = __toESM(require_dist());
|
|
4616
4721
|
var import_core13 = __toESM(require_dist());
|
|
4617
|
-
import * as
|
|
4722
|
+
import * as fs7 from "fs";
|
|
4618
4723
|
import * as path8 from "path";
|
|
4619
4724
|
|
|
4620
4725
|
// src/commands/migrate-tracked.ts
|
|
4621
4726
|
var import_chalk6 = __toESM(require_source());
|
|
4622
4727
|
var import_core10 = __toESM(require_dist());
|
|
4623
4728
|
import * as crypto2 from "crypto";
|
|
4624
|
-
import * as
|
|
4729
|
+
import * as fs6 from "fs";
|
|
4625
4730
|
import * as path7 from "path";
|
|
4626
|
-
import { spawnSync } from "child_process";
|
|
4731
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
4627
4732
|
var SKIP_TOP_LEVEL = /* @__PURE__ */ new Set([".git"]);
|
|
4628
4733
|
var STATE_DIR = "state";
|
|
4629
4734
|
function locateBoard(rootDir) {
|
|
@@ -4634,28 +4739,28 @@ function locateBoard(rootDir) {
|
|
|
4634
4739
|
return path7.dirname(found.absolutePath);
|
|
4635
4740
|
}
|
|
4636
4741
|
function copyBoardContents(from, to) {
|
|
4637
|
-
for (const entry of
|
|
4742
|
+
for (const entry of fs6.readdirSync(from)) {
|
|
4638
4743
|
if (SKIP_TOP_LEVEL.has(entry)) continue;
|
|
4639
|
-
|
|
4744
|
+
fs6.cpSync(path7.join(from, entry), path7.join(to, entry), { recursive: true, force: true, verbatimSymlinks: true });
|
|
4640
4745
|
}
|
|
4641
4746
|
}
|
|
4642
4747
|
function mirrorBoardContents(from, to) {
|
|
4643
|
-
for (const entry of
|
|
4748
|
+
for (const entry of fs6.readdirSync(to)) {
|
|
4644
4749
|
if (SKIP_TOP_LEVEL.has(entry)) continue;
|
|
4645
|
-
|
|
4750
|
+
fs6.rmSync(path7.join(to, entry), { recursive: true, force: true });
|
|
4646
4751
|
}
|
|
4647
4752
|
copyBoardContents(from, to);
|
|
4648
4753
|
}
|
|
4649
4754
|
function hashBoardFiles(dir) {
|
|
4650
4755
|
const out = /* @__PURE__ */ new Map();
|
|
4651
4756
|
const walk = (current, prefix) => {
|
|
4652
|
-
for (const entry of
|
|
4757
|
+
for (const entry of fs6.readdirSync(current, { withFileTypes: true })) {
|
|
4653
4758
|
if (prefix === "" && (SKIP_TOP_LEVEL.has(entry.name) || entry.name === STATE_DIR)) continue;
|
|
4654
4759
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
4655
4760
|
const full = path7.join(current, entry.name);
|
|
4656
4761
|
if (entry.isDirectory()) walk(full, rel);
|
|
4657
|
-
else if (entry.isSymbolicLink()) out.set(rel, `link:${
|
|
4658
|
-
else out.set(rel, crypto2.createHash("sha256").update(
|
|
4762
|
+
else if (entry.isSymbolicLink()) out.set(rel, `link:${fs6.readlinkSync(full)}`);
|
|
4763
|
+
else out.set(rel, crypto2.createHash("sha256").update(fs6.readFileSync(full)).digest("hex"));
|
|
4659
4764
|
}
|
|
4660
4765
|
};
|
|
4661
4766
|
walk(dir, "");
|
|
@@ -4663,12 +4768,12 @@ function hashBoardFiles(dir) {
|
|
|
4663
4768
|
}
|
|
4664
4769
|
function asidePath(dotDir) {
|
|
4665
4770
|
const candidate = `${dotDir}.migrating`;
|
|
4666
|
-
if (
|
|
4771
|
+
if (fs6.existsSync(candidate)) throw new Error(`${candidate} already exists; remove it before migrating.`);
|
|
4667
4772
|
return candidate;
|
|
4668
4773
|
}
|
|
4669
4774
|
function restoreAside(aside, dotDir) {
|
|
4670
|
-
if (
|
|
4671
|
-
|
|
4775
|
+
if (fs6.existsSync(dotDir)) fs6.rmSync(dotDir, { recursive: true, force: true });
|
|
4776
|
+
fs6.renameSync(aside, dotDir);
|
|
4672
4777
|
}
|
|
4673
4778
|
function verifyBoardContents(aside, dotDir) {
|
|
4674
4779
|
const before = hashBoardFiles(aside);
|
|
@@ -4692,16 +4797,16 @@ function verifyBoardContents(aside, dotDir) {
|
|
|
4692
4797
|
}
|
|
4693
4798
|
}
|
|
4694
4799
|
function attributesExtend(aside, dotDir) {
|
|
4695
|
-
const lines = (dir) =>
|
|
4800
|
+
const lines = (dir) => fs6.readFileSync(path7.join(dir, ".gitattributes"), "utf-8").split("\n").map((l) => l.trim());
|
|
4696
4801
|
const after = new Set(lines(dotDir));
|
|
4697
4802
|
return lines(aside).every((line) => after.has(line));
|
|
4698
4803
|
}
|
|
4699
4804
|
function stagedPatch(relPath, repoRoot) {
|
|
4700
|
-
const r =
|
|
4805
|
+
const r = spawnSync2("git", ["diff", "--cached", "--binary", "--", relPath], { cwd: repoRoot, encoding: "utf-8" });
|
|
4701
4806
|
return r.status === 0 ? r.stdout : "";
|
|
4702
4807
|
}
|
|
4703
4808
|
function applyToIndex(patch, repoRoot) {
|
|
4704
|
-
const r =
|
|
4809
|
+
const r = spawnSync2("git", ["apply", "--cached", "--binary", "-"], { cwd: repoRoot, input: patch, encoding: "utf-8" });
|
|
4705
4810
|
return r.status === 0;
|
|
4706
4811
|
}
|
|
4707
4812
|
var MigrationRollback = class {
|
|
@@ -4726,7 +4831,7 @@ var MigrationRollback = class {
|
|
|
4726
4831
|
this.indexChanged = true;
|
|
4727
4832
|
}
|
|
4728
4833
|
moveAside() {
|
|
4729
|
-
|
|
4834
|
+
fs6.renameSync(this.dotDir, this.aside);
|
|
4730
4835
|
this.movedAside = true;
|
|
4731
4836
|
}
|
|
4732
4837
|
/** Reverse every recorded step. Returns what could not be undone (empty when fully restored). */
|
|
@@ -4742,7 +4847,7 @@ var MigrationRollback = class {
|
|
|
4742
4847
|
if (this.movedAside && boardRepoKind(this.dotDir) === "linked") {
|
|
4743
4848
|
attempt("remove the board worktree", () => {
|
|
4744
4849
|
const removed = git(["worktree", "remove", "--force", this.dotDir], this.repoRoot);
|
|
4745
|
-
if (!removed.ok)
|
|
4850
|
+
if (!removed.ok) fs6.rmSync(this.dotDir, { recursive: true, force: true });
|
|
4746
4851
|
});
|
|
4747
4852
|
}
|
|
4748
4853
|
if (this.movedAside) attempt(`move ${this.aside} back`, () => restoreAside(this.aside, this.dotDir));
|
|
@@ -4864,10 +4969,10 @@ function migrateToBranch(options = {}) {
|
|
|
4864
4969
|
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
4865
4970
|
const leftovers = rollback.undo();
|
|
4866
4971
|
throw new Error(
|
|
4867
|
-
leftovers.length === 0 ? `${message} Nothing was changed: the board is back where it was.` : `${message} Rolling back was incomplete; could not ${leftovers.join("; ")}. The original board is in ${
|
|
4972
|
+
leftovers.length === 0 ? `${message} Nothing was changed: the board is back where it was.` : `${message} Rolling back was incomplete; could not ${leftovers.join("; ")}. The original board is in ${fs6.existsSync(aside) ? aside : dotDir}.`
|
|
4868
4973
|
);
|
|
4869
4974
|
}
|
|
4870
|
-
|
|
4975
|
+
fs6.rmSync(aside, { recursive: true, force: true });
|
|
4871
4976
|
ensureExcludeEntry(repoRoot);
|
|
4872
4977
|
console.log(import_chalk6.default.green(done));
|
|
4873
4978
|
if (uncommittedImported) {
|
|
@@ -4909,7 +5014,7 @@ function migrateToPlain(options = {}) {
|
|
|
4909
5014
|
return;
|
|
4910
5015
|
}
|
|
4911
5016
|
if (kind === "standalone") {
|
|
4912
|
-
|
|
5017
|
+
fs6.rmSync(path7.join(dotDir, ".git"), { recursive: true, force: true });
|
|
4913
5018
|
console.log(import_chalk6.default.green("Board is now a plain directory (its git history was removed)."));
|
|
4914
5019
|
return;
|
|
4915
5020
|
}
|
|
@@ -4917,14 +5022,14 @@ function migrateToPlain(options = {}) {
|
|
|
4917
5022
|
if (!repoRoot) throw new Error("Could not find the repository that owns this board worktree.");
|
|
4918
5023
|
const branch = boardBranch(repoRoot);
|
|
4919
5024
|
const aside = asidePath(dotDir);
|
|
4920
|
-
|
|
5025
|
+
fs6.mkdirSync(aside);
|
|
4921
5026
|
copyBoardContents(dotDir, aside);
|
|
4922
5027
|
const remove = git(["worktree", "remove", "--force", dotDir], repoRoot);
|
|
4923
5028
|
if (!remove.ok) {
|
|
4924
|
-
|
|
5029
|
+
fs6.rmSync(aside, { recursive: true, force: true });
|
|
4925
5030
|
throw new Error(`git worktree remove failed: ${remove.stderr}`);
|
|
4926
5031
|
}
|
|
4927
|
-
|
|
5032
|
+
fs6.renameSync(aside, dotDir);
|
|
4928
5033
|
removeExcludeEntry(repoRoot);
|
|
4929
5034
|
console.log(import_chalk6.default.green("Board is now a plain directory."));
|
|
4930
5035
|
console.log(import_chalk6.default.gray(` Branch '${branch}' still holds its history. Delete it with: git branch -D ${branch}`));
|
|
@@ -5008,42 +5113,42 @@ function migrateMixedWorkspace(probe, options) {
|
|
|
5008
5113
|
}
|
|
5009
5114
|
function migrateRootBrainfileToDotDir(probe, options) {
|
|
5010
5115
|
const { rootBrainfilePath, dotDir, dotBrainfilePath } = probe.paths;
|
|
5011
|
-
if (!
|
|
5116
|
+
if (!fs7.existsSync(rootBrainfilePath)) {
|
|
5012
5117
|
throw new Error(`File not found: ${rootBrainfilePath}`);
|
|
5013
5118
|
}
|
|
5014
|
-
if (
|
|
5119
|
+
if (fs7.existsSync(dotBrainfilePath) && !options.force) {
|
|
5015
5120
|
throw new Error(
|
|
5016
5121
|
`Target already exists: ${dotBrainfilePath}. Run \`brainfile migrate\` again after resolving conflicts, or use --force.`
|
|
5017
5122
|
);
|
|
5018
5123
|
}
|
|
5019
|
-
|
|
5020
|
-
if (
|
|
5021
|
-
|
|
5124
|
+
fs7.mkdirSync(dotDir, { recursive: true });
|
|
5125
|
+
if (fs7.existsSync(dotBrainfilePath) && options.force) {
|
|
5126
|
+
fs7.rmSync(dotBrainfilePath, { force: true });
|
|
5022
5127
|
}
|
|
5023
5128
|
try {
|
|
5024
|
-
|
|
5129
|
+
fs7.renameSync(rootBrainfilePath, dotBrainfilePath);
|
|
5025
5130
|
} catch {
|
|
5026
|
-
const contents =
|
|
5027
|
-
|
|
5028
|
-
|
|
5131
|
+
const contents = fs7.readFileSync(rootBrainfilePath);
|
|
5132
|
+
fs7.writeFileSync(dotBrainfilePath, contents);
|
|
5133
|
+
fs7.rmSync(rootBrainfilePath, { force: true });
|
|
5029
5134
|
}
|
|
5030
5135
|
(0, import_core13.ensureDotBrainfileGitignore)(dotBrainfilePath);
|
|
5031
5136
|
removeLegacyStateFile(dotBrainfilePath);
|
|
5032
5137
|
console.log(import_chalk7.default.gray(`Moved: ${rootBrainfilePath} -> ${dotBrainfilePath}`));
|
|
5033
5138
|
}
|
|
5034
5139
|
function migrateBrainfileToV2(brainfilePath, options) {
|
|
5035
|
-
if (!
|
|
5140
|
+
if (!fs7.existsSync(brainfilePath)) {
|
|
5036
5141
|
throw new Error(`File not found: ${brainfilePath}`);
|
|
5037
5142
|
}
|
|
5038
|
-
const content =
|
|
5143
|
+
const content = fs7.readFileSync(brainfilePath, "utf-8");
|
|
5039
5144
|
const parsed = import_core11.Brainfile.parseWithErrors(content);
|
|
5040
5145
|
if (!parsed.board) {
|
|
5041
5146
|
throw new Error(`Failed to parse brainfile: ${parsed.error}`);
|
|
5042
5147
|
}
|
|
5043
5148
|
const board = parsed.board;
|
|
5044
5149
|
const dotDir = path8.dirname(path8.resolve(brainfilePath));
|
|
5045
|
-
const hasBoardDir =
|
|
5046
|
-
const hasLogsDir =
|
|
5150
|
+
const hasBoardDir = fs7.existsSync(path8.join(dotDir, "board"));
|
|
5151
|
+
const hasLogsDir = fs7.existsSync(path8.join(dotDir, "logs"));
|
|
5047
5152
|
const hasEmbeddedColumnTasks = board.columns.some((column) => column.tasks.length > 0);
|
|
5048
5153
|
const hasEmbeddedArchiveTasks = Array.isArray(board.archive) && (board.archive?.length ?? 0) > 0;
|
|
5049
5154
|
if (hasBoardDir && hasLogsDir && !hasEmbeddedColumnTasks && !hasEmbeddedArchiveTasks) {
|
|
@@ -5051,15 +5156,15 @@ function migrateBrainfileToV2(brainfilePath, options) {
|
|
|
5051
5156
|
return;
|
|
5052
5157
|
}
|
|
5053
5158
|
const backupPath = brainfilePath + ".v1.bak";
|
|
5054
|
-
if (!
|
|
5055
|
-
|
|
5159
|
+
if (!fs7.existsSync(backupPath) || options.force) {
|
|
5160
|
+
fs7.copyFileSync(brainfilePath, backupPath);
|
|
5056
5161
|
console.log(import_chalk7.default.gray(`Backup: ${backupPath}`));
|
|
5057
5162
|
} else {
|
|
5058
5163
|
console.log(import_chalk7.default.gray(`Backup already exists: ${backupPath}`));
|
|
5059
5164
|
}
|
|
5060
5165
|
const dirs = (0, import_core.ensureV2Dirs)(brainfilePath);
|
|
5061
|
-
const existingTaskFiles =
|
|
5062
|
-
const existingLogFiles =
|
|
5166
|
+
const existingTaskFiles = fs7.existsSync(dirs.boardDir) ? fs7.readdirSync(dirs.boardDir).filter((f) => f.endsWith(".md")) : [];
|
|
5167
|
+
const existingLogFiles = fs7.existsSync(dirs.logsDir) ? fs7.readdirSync(dirs.logsDir).filter((f) => f.endsWith(".md")) : [];
|
|
5063
5168
|
if ((existingTaskFiles.length > 0 || existingLogFiles.length > 0) && !options.force) {
|
|
5064
5169
|
throw new Error(
|
|
5065
5170
|
"board/ or logs/ already contains task files. Use --force to replace existing .md files in those directories."
|
|
@@ -5067,10 +5172,10 @@ function migrateBrainfileToV2(brainfilePath, options) {
|
|
|
5067
5172
|
}
|
|
5068
5173
|
if (options.force) {
|
|
5069
5174
|
for (const name of existingTaskFiles) {
|
|
5070
|
-
|
|
5175
|
+
fs7.rmSync(path8.join(dirs.boardDir, name), { force: true });
|
|
5071
5176
|
}
|
|
5072
5177
|
for (const name of existingLogFiles) {
|
|
5073
|
-
|
|
5178
|
+
fs7.rmSync(path8.join(dirs.logsDir, name), { force: true });
|
|
5074
5179
|
}
|
|
5075
5180
|
}
|
|
5076
5181
|
let activeCount = 0;
|
|
@@ -5131,7 +5236,7 @@ function migrateBrainfileToV2(brainfilePath, options) {
|
|
|
5131
5236
|
delete configBoard.rules;
|
|
5132
5237
|
configBoard.schema = "https://brainfile.md/v2/board.json";
|
|
5133
5238
|
const configContent = import_core11.Brainfile.serialize(configBoard);
|
|
5134
|
-
|
|
5239
|
+
fs7.writeFileSync(brainfilePath, configContent, "utf-8");
|
|
5135
5240
|
(0, import_core13.ensureDotBrainfileGitignore)(brainfilePath);
|
|
5136
5241
|
removeLegacyStateFile(brainfilePath);
|
|
5137
5242
|
console.log(import_chalk7.default.green("Migration to v2 complete!"));
|
|
@@ -5154,7 +5259,7 @@ function migrateLogsToLedger(options) {
|
|
|
5154
5259
|
return;
|
|
5155
5260
|
}
|
|
5156
5261
|
const { logsDir, boardDir } = probe.paths;
|
|
5157
|
-
if (!
|
|
5262
|
+
if (!fs7.existsSync(logsDir)) {
|
|
5158
5263
|
console.log(import_chalk7.default.gray("No logs/ directory found. Nothing to migrate."));
|
|
5159
5264
|
return;
|
|
5160
5265
|
}
|
|
@@ -5165,8 +5270,8 @@ function migrateLogsToLedger(options) {
|
|
|
5165
5270
|
}
|
|
5166
5271
|
const ledgerPath = path8.join(logsDir, "ledger.jsonl");
|
|
5167
5272
|
const existingLedgerIds = /* @__PURE__ */ new Set();
|
|
5168
|
-
if (
|
|
5169
|
-
const lines =
|
|
5273
|
+
if (fs7.existsSync(ledgerPath)) {
|
|
5274
|
+
const lines = fs7.readFileSync(ledgerPath, "utf-8").split("\n");
|
|
5170
5275
|
for (const line of lines) {
|
|
5171
5276
|
const trimmed = line.trim();
|
|
5172
5277
|
if (!trimmed) continue;
|
|
@@ -5177,7 +5282,7 @@ function migrateLogsToLedger(options) {
|
|
|
5177
5282
|
}
|
|
5178
5283
|
}
|
|
5179
5284
|
}
|
|
5180
|
-
const boardDocs =
|
|
5285
|
+
const boardDocs = fs7.existsSync(boardDir) ? (0, import_core12.readTasksDir)(boardDir) : [];
|
|
5181
5286
|
const boardIdMap = new Map(boardDocs.map((d) => [d.task.id, d]));
|
|
5182
5287
|
let migratedCount = 0;
|
|
5183
5288
|
let skippedCount = 0;
|
|
@@ -5202,7 +5307,7 @@ function migrateLogsToLedger(options) {
|
|
|
5202
5307
|
const renamedTask = { ...boardDoc.task, id: newId };
|
|
5203
5308
|
const newBoardPath = path8.join(boardDir, (0, import_core12.taskFileName)(newId));
|
|
5204
5309
|
(0, import_core12.writeTaskFile)(newBoardPath, renamedTask, boardDoc.body);
|
|
5205
|
-
|
|
5310
|
+
fs7.rmSync(boardDoc.filePath, { force: true });
|
|
5206
5311
|
console.log(import_chalk7.default.yellow(` Conflict: board/${taskId} \u2192 ${newId} (completed task takes precedence)`));
|
|
5207
5312
|
conflictCount++;
|
|
5208
5313
|
}
|
|
@@ -5220,19 +5325,19 @@ function migrateLogsToLedger(options) {
|
|
|
5220
5325
|
}
|
|
5221
5326
|
function backupAndRemoveLegacyRoot(rootBrainfilePath, dotDir) {
|
|
5222
5327
|
const backupPath = uniquePath(path8.join(dotDir, "brainfile.root.legacy.bak"));
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5328
|
+
fs7.mkdirSync(dotDir, { recursive: true });
|
|
5329
|
+
fs7.copyFileSync(rootBrainfilePath, backupPath);
|
|
5330
|
+
fs7.rmSync(rootBrainfilePath, { force: true });
|
|
5226
5331
|
return backupPath;
|
|
5227
5332
|
}
|
|
5228
5333
|
function uniquePath(basePath) {
|
|
5229
|
-
if (!
|
|
5334
|
+
if (!fs7.existsSync(basePath)) return basePath;
|
|
5230
5335
|
const ext = path8.extname(basePath);
|
|
5231
5336
|
const stem = basePath.slice(0, basePath.length - ext.length);
|
|
5232
5337
|
let i = 1;
|
|
5233
5338
|
while (true) {
|
|
5234
5339
|
const candidate = `${stem}.${i}${ext}`;
|
|
5235
|
-
if (!
|
|
5340
|
+
if (!fs7.existsSync(candidate)) return candidate;
|
|
5236
5341
|
i++;
|
|
5237
5342
|
}
|
|
5238
5343
|
}
|
|
@@ -5240,21 +5345,27 @@ function uniquePath(basePath) {
|
|
|
5240
5345
|
// src/commands/sync.ts
|
|
5241
5346
|
var import_chalk8 = __toESM(require_source());
|
|
5242
5347
|
var import_core14 = __toESM(require_dist());
|
|
5243
|
-
import * as
|
|
5348
|
+
import * as fs8 from "fs";
|
|
5244
5349
|
import * as path9 from "path";
|
|
5245
5350
|
var SYNC_COMMAND_HELP = `
|
|
5246
5351
|
Examples:
|
|
5247
|
-
brainfile sync Fetch, merge and push the board
|
|
5352
|
+
brainfile sync Fetch, merge and push the board
|
|
5248
5353
|
brainfile sync --pull Bring in other machines' changes only
|
|
5249
5354
|
brainfile sync --set-remote origin Share the board through the code remote
|
|
5250
|
-
brainfile sync --set-remote git@host:me/boards.git --
|
|
5355
|
+
brainfile sync --set-remote git@host:me/boards.git --board-name myproject
|
|
5251
5356
|
brainfile sync --autosync full Also fetch before reads (default: push after writes)
|
|
5252
5357
|
|
|
5253
|
-
Nothing leaves this machine until you choose a remote.
|
|
5254
|
-
|
|
5358
|
+
Nothing leaves this machine until you choose a remote. On the remote the board
|
|
5359
|
+
is stored as refs/brainfile/<name>, not as a branch, so it never appears in the
|
|
5360
|
+
branch list or pull requests. \`brainfile where\` shows where the board lives
|
|
5361
|
+
and who has it.`;
|
|
5255
5362
|
function describe(result) {
|
|
5256
5363
|
const message = syncMessage(result);
|
|
5257
|
-
|
|
5364
|
+
let text = message.tone === "ok" ? import_chalk8.default.green(message.text) : import_chalk8.default.yellow(message.text);
|
|
5365
|
+
if (result.movedFromBranch && result.remoteRef) {
|
|
5366
|
+
text += `
|
|
5367
|
+
${import_chalk8.default.gray(` Moved the board off the '${result.movedFromBranch}' branch on ${result.remote}; it now lives in ${result.remoteRef}, outside your branches.`)}`;
|
|
5368
|
+
}
|
|
5258
5369
|
return message.detail ? `${text}
|
|
5259
5370
|
${import_chalk8.default.gray(` (${message.detail})`)}` : text;
|
|
5260
5371
|
}
|
|
@@ -5266,6 +5377,7 @@ function syncCommand(options, logger = defaultLogger) {
|
|
|
5266
5377
|
if (Number.isFinite(wait) && wait > 0) sleep(wait);
|
|
5267
5378
|
let dotDir = tryResolveBoardDir(options.file);
|
|
5268
5379
|
if (dotDir && options.wait !== void 0) clearPushLock(dotDir);
|
|
5380
|
+
const boardName = options.boardName ?? options.remoteBranch;
|
|
5269
5381
|
if (options.setRemote !== void 0) {
|
|
5270
5382
|
const cwd = dotDir ?? gitToplevel(process.cwd());
|
|
5271
5383
|
if (!cwd) {
|
|
@@ -5273,25 +5385,28 @@ function syncCommand(options, logger = defaultLogger) {
|
|
|
5273
5385
|
}
|
|
5274
5386
|
let setting;
|
|
5275
5387
|
try {
|
|
5276
|
-
setting = setBoardRemote(cwd, options.setRemote,
|
|
5388
|
+
setting = setBoardRemote(cwd, options.setRemote, boardName);
|
|
5277
5389
|
} catch (error48) {
|
|
5278
5390
|
throw validationError2(error48 instanceof Error ? error48.message : String(error48));
|
|
5279
5391
|
}
|
|
5280
|
-
logger.log(import_chalk8.default.green(`This board is now shared through ${setting.remote}${setting.url ? ` (${setting.url})` : ""}
|
|
5392
|
+
logger.log(import_chalk8.default.green(`This board is now shared through ${setting.remote}${setting.url ? ` (${setting.url})` : ""}.`));
|
|
5393
|
+
logger.log(import_chalk8.default.gray(` It is stored there as ${setting.remoteRef}, not a branch, so it stays out of branch lists and pull requests.`));
|
|
5281
5394
|
logger.log(import_chalk8.default.gray(` Changes are sent automatically after each edit. Anyone who can read ${setting.remote} can read the board.`));
|
|
5395
|
+
const web = boardWebUrl(setting.url, setting.remoteRef);
|
|
5396
|
+
if (web) logger.log(import_chalk8.default.gray(` See it on the web: ${web}`));
|
|
5282
5397
|
if (!dotDir) {
|
|
5283
|
-
dotDir = materializeBoardWorktree(cwd);
|
|
5398
|
+
dotDir = materializeBoardWorktree(cwd, { fresh: true });
|
|
5284
5399
|
if (!dotDir) {
|
|
5285
|
-
logger.log(import_chalk8.default.yellow(`There is no board on ${setting.remote} yet (looked for
|
|
5400
|
+
logger.log(import_chalk8.default.yellow(`There is no board on ${setting.remote} yet (looked for ${setting.remoteRef}).`) + import_chalk8.default.gray(" Start one with: brainfile init"));
|
|
5286
5401
|
return void 0;
|
|
5287
5402
|
}
|
|
5288
5403
|
}
|
|
5289
|
-
} else if (
|
|
5290
|
-
throw validationError2("--
|
|
5404
|
+
} else if (boardName !== void 0) {
|
|
5405
|
+
throw validationError2("--board-name needs --set-remote");
|
|
5291
5406
|
}
|
|
5292
5407
|
if (!dotDir) {
|
|
5293
5408
|
const resolved = resolveCliBrainfilePath(options.file);
|
|
5294
|
-
if (!
|
|
5409
|
+
if (!fs8.existsSync(resolved)) throw operationFailed(`No board found (looked for ${path9.join(".brainfile", import_core14.BRAINFILE_BASENAME)}). Run: brainfile init`);
|
|
5295
5410
|
dotDir = path9.dirname(resolved);
|
|
5296
5411
|
}
|
|
5297
5412
|
if (options.autosync !== void 0) {
|
|
@@ -5305,14 +5420,13 @@ function syncCommand(options, logger = defaultLogger) {
|
|
|
5305
5420
|
const pushOnly = options.push === true && options.pull !== true;
|
|
5306
5421
|
const result = syncBoard(dotDir, {
|
|
5307
5422
|
pull: !pushOnly,
|
|
5308
|
-
push: !pullOnly
|
|
5309
|
-
agent: resolveAgentName()
|
|
5423
|
+
push: !pullOnly
|
|
5310
5424
|
});
|
|
5311
5425
|
if (options.json) {
|
|
5312
5426
|
logger.log(JSON.stringify({
|
|
5313
5427
|
...result,
|
|
5314
5428
|
remote: result.remote ?? boardRemote(dotDir),
|
|
5315
|
-
|
|
5429
|
+
remoteRef: result.remoteRef ?? boardRemoteRef(dotDir),
|
|
5316
5430
|
autosync: boardAutosync(dotDir)
|
|
5317
5431
|
}, null, 2));
|
|
5318
5432
|
} else {
|
|
@@ -5324,7 +5438,7 @@ function syncCommand(options, logger = defaultLogger) {
|
|
|
5324
5438
|
|
|
5325
5439
|
// src/commands/where.ts
|
|
5326
5440
|
var import_chalk9 = __toESM(require_source());
|
|
5327
|
-
import * as
|
|
5441
|
+
import * as fs9 from "fs";
|
|
5328
5442
|
import * as path10 from "path";
|
|
5329
5443
|
function ago(seconds) {
|
|
5330
5444
|
if (seconds < 60) return `${seconds}s ago`;
|
|
@@ -5337,14 +5451,17 @@ function whereReport(dotDir) {
|
|
|
5337
5451
|
const storage = kind === "linked" ? "branch" : kind === "standalone" ? "repository" : "plain";
|
|
5338
5452
|
const remote = kind ? boardRemote(dotDir) : null;
|
|
5339
5453
|
const state = remote ? readSyncState(dotDir) : null;
|
|
5454
|
+
const remoteUrl = remote ? git(["remote", "get-url", remote], dotDir).stdout || null : null;
|
|
5455
|
+
const remoteRef = remote ? boardRemoteRef(dotDir) : null;
|
|
5340
5456
|
return {
|
|
5341
5457
|
path: dotDir,
|
|
5342
5458
|
storage,
|
|
5343
5459
|
branch: kind === "linked" ? boardBranch(dotDir) : null,
|
|
5344
5460
|
repository: kind === "linked" ? gitToplevel(path10.dirname(dotDir)) : null,
|
|
5345
5461
|
remote,
|
|
5346
|
-
remoteUrl
|
|
5347
|
-
|
|
5462
|
+
remoteUrl,
|
|
5463
|
+
remoteRef,
|
|
5464
|
+
webUrl: remoteRef ? boardWebUrl(remoteUrl, remoteRef) : null,
|
|
5348
5465
|
autosync: remote ? effectiveAutosync(dotDir) : null,
|
|
5349
5466
|
lastSyncSecondsAgo: remote ? secondsSinceSync(dotDir) : null,
|
|
5350
5467
|
lastSyncOk: state ? state.ok : null,
|
|
@@ -5353,7 +5470,7 @@ function whereReport(dotDir) {
|
|
|
5353
5470
|
}
|
|
5354
5471
|
function whereCommand(options, logger = defaultLogger) {
|
|
5355
5472
|
const filePath = resolveCliBrainfilePath(options.file);
|
|
5356
|
-
if (!
|
|
5473
|
+
if (!fs9.existsSync(filePath)) throw fileNotFound(filePath);
|
|
5357
5474
|
const dotDir = path10.dirname(filePath);
|
|
5358
5475
|
const report = whereReport(dotDir);
|
|
5359
5476
|
if (options.json) {
|
|
@@ -5379,7 +5496,9 @@ function whereCommand(options, logger = defaultLogger) {
|
|
|
5379
5496
|
return report;
|
|
5380
5497
|
}
|
|
5381
5498
|
const url2 = report.remoteUrl ? ` (${report.remoteUrl})` : "";
|
|
5382
|
-
logger.log(`${label("Shared")} through ${report.remote}${url2}
|
|
5499
|
+
logger.log(`${label("Shared")} through ${report.remote}${url2}`);
|
|
5500
|
+
more(import_chalk9.default.gray(`Stored there as ${report.remoteRef}, not a branch, so it stays out of branch lists and pull requests.`));
|
|
5501
|
+
if (report.webUrl) more(import_chalk9.default.gray(`On the web: ${report.webUrl}`));
|
|
5383
5502
|
const last = report.lastSyncSecondsAgo === null ? "" : report.lastSyncOk === false ? import_chalk9.default.yellow(`Last sync failed ${ago(report.lastSyncSecondsAgo)}; your changes are safe on this machine.`) : `Last synced ${ago(report.lastSyncSecondsAgo)}.`;
|
|
5384
5503
|
const waiting = report.pendingChanges > 0 ? `${report.pendingChanges} change${report.pendingChanges === 1 ? "" : "s"} waiting to be sent.` : "Nothing waiting to be sent.";
|
|
5385
5504
|
more([last, waiting].filter(Boolean).join(" "));
|
|
@@ -5500,7 +5619,7 @@ function patchCommand(options) {
|
|
|
5500
5619
|
|
|
5501
5620
|
// src/commands/delete.ts
|
|
5502
5621
|
var import_chalk11 = __toESM(require_source());
|
|
5503
|
-
import * as
|
|
5622
|
+
import * as fs10 from "fs";
|
|
5504
5623
|
import * as path12 from "path";
|
|
5505
5624
|
function isUnsafeTaskId2(taskId) {
|
|
5506
5625
|
const trimmed = taskId.trim();
|
|
@@ -5540,7 +5659,7 @@ function deleteCommand(options) {
|
|
|
5540
5659
|
console.log(import_chalk11.default.gray('Use --force to confirm deletion, or use "brainfile archive" to archive instead.'));
|
|
5541
5660
|
process.exit(0);
|
|
5542
5661
|
}
|
|
5543
|
-
|
|
5662
|
+
fs10.unlinkSync(taskPath);
|
|
5544
5663
|
console.log(import_chalk11.default.green("Task deleted successfully!"));
|
|
5545
5664
|
console.log("");
|
|
5546
5665
|
console.log(import_chalk11.default.gray(` Task: ${task.id} - ${task.title}`));
|
|
@@ -5553,7 +5672,7 @@ function deleteCommand(options) {
|
|
|
5553
5672
|
// src/commands/archive.ts
|
|
5554
5673
|
var import_core16 = __toESM(require_dist());
|
|
5555
5674
|
var import_chalk12 = __toESM(require_source());
|
|
5556
|
-
import * as
|
|
5675
|
+
import * as fs11 from "fs";
|
|
5557
5676
|
import * as path13 from "path";
|
|
5558
5677
|
async function archiveCommand(options) {
|
|
5559
5678
|
try {
|
|
@@ -5636,7 +5755,7 @@ function completeLocalV2(filePath, taskId, dryRun) {
|
|
|
5636
5755
|
async function archiveSingleFromLogsV2(filePath, board, taskId, destination, dryRun, parsedDest) {
|
|
5637
5756
|
const dirs = (0, import_core.getV2Dirs)(filePath);
|
|
5638
5757
|
const logPath = path13.join(dirs.logsDir, (0, import_core16.taskFileName)(taskId));
|
|
5639
|
-
if (!
|
|
5758
|
+
if (!fs11.existsSync(logPath)) {
|
|
5640
5759
|
operationError(`Task not found in logs: ${taskId}`);
|
|
5641
5760
|
return;
|
|
5642
5761
|
}
|
|
@@ -5654,10 +5773,10 @@ async function archiveSingleFromLogsV2(filePath, board, taskId, destination, dry
|
|
|
5654
5773
|
}
|
|
5655
5774
|
if (destination === "github") {
|
|
5656
5775
|
await archiveToGitHub(board, task, "Completed", dryRun, parsedDest);
|
|
5657
|
-
|
|
5776
|
+
fs11.unlinkSync(logPath);
|
|
5658
5777
|
} else if (destination === "linear") {
|
|
5659
5778
|
await archiveToLinear(board, task, "Completed", dryRun, parsedDest);
|
|
5660
|
-
|
|
5779
|
+
fs11.unlinkSync(logPath);
|
|
5661
5780
|
}
|
|
5662
5781
|
}
|
|
5663
5782
|
async function archiveAllFromLogsV2(filePath, board, destination, dryRun) {
|
|
@@ -5707,7 +5826,7 @@ async function archiveAllFromLogsV2(filePath, board, destination, dryRun) {
|
|
|
5707
5826
|
});
|
|
5708
5827
|
if (result.success) {
|
|
5709
5828
|
const logPath = path13.join(dirs.logsDir, (0, import_core16.taskFileName)(task.id));
|
|
5710
|
-
|
|
5829
|
+
fs11.unlinkSync(logPath);
|
|
5711
5830
|
console.log(import_chalk12.default.green(" OK") + ` #${result.issueNumber}`);
|
|
5712
5831
|
successCount++;
|
|
5713
5832
|
} else {
|
|
@@ -5736,7 +5855,7 @@ async function archiveAllFromLogsV2(filePath, board, destination, dryRun) {
|
|
|
5736
5855
|
});
|
|
5737
5856
|
if (result.success) {
|
|
5738
5857
|
const logPath = path13.join(dirs.logsDir, (0, import_core16.taskFileName)(task.id));
|
|
5739
|
-
|
|
5858
|
+
fs11.unlinkSync(logPath);
|
|
5740
5859
|
console.log(import_chalk12.default.green(" OK") + ` ${result.issueId}`);
|
|
5741
5860
|
successCount++;
|
|
5742
5861
|
} else {
|
|
@@ -5898,12 +6017,12 @@ async function archiveToLinear(board, task, columnTitle, dryRun, parsedDest) {
|
|
|
5898
6017
|
// src/commands/restore.ts
|
|
5899
6018
|
var import_core18 = __toESM(require_dist());
|
|
5900
6019
|
var import_chalk13 = __toESM(require_source());
|
|
5901
|
-
import * as
|
|
6020
|
+
import * as fs13 from "fs";
|
|
5902
6021
|
import * as path15 from "path";
|
|
5903
6022
|
|
|
5904
6023
|
// src/utils/archive.ts
|
|
5905
6024
|
var import_core17 = __toESM(require_dist());
|
|
5906
|
-
import * as
|
|
6025
|
+
import * as fs12 from "fs";
|
|
5907
6026
|
import * as path14 from "path";
|
|
5908
6027
|
function getArchivePath(filePath) {
|
|
5909
6028
|
const dir = path14.dirname(filePath);
|
|
@@ -5913,11 +6032,11 @@ function getArchivePath(filePath) {
|
|
|
5913
6032
|
}
|
|
5914
6033
|
function loadArchivedTasks(filePath) {
|
|
5915
6034
|
const archivePath = getArchivePath(filePath);
|
|
5916
|
-
if (!
|
|
6035
|
+
if (!fs12.existsSync(archivePath)) {
|
|
5917
6036
|
return { tasks: [], archivePath };
|
|
5918
6037
|
}
|
|
5919
6038
|
try {
|
|
5920
|
-
const archiveContent =
|
|
6039
|
+
const archiveContent = fs12.readFileSync(archivePath, "utf-8");
|
|
5921
6040
|
const parseResult = import_core17.Brainfile.parseWithErrors(archiveContent);
|
|
5922
6041
|
if (parseResult.board && Array.isArray(parseResult.board.archive)) {
|
|
5923
6042
|
return { tasks: parseResult.board.archive, archivePath };
|
|
@@ -5933,12 +6052,12 @@ function loadArchivedTasks(filePath) {
|
|
|
5933
6052
|
}
|
|
5934
6053
|
function restoreFromArchive(filePath, taskId, toColumnId) {
|
|
5935
6054
|
const archivePath = getArchivePath(filePath);
|
|
5936
|
-
if (!
|
|
6055
|
+
if (!fs12.existsSync(archivePath)) {
|
|
5937
6056
|
return { success: false, error: "Archive file not found" };
|
|
5938
6057
|
}
|
|
5939
6058
|
let archiveBoard;
|
|
5940
6059
|
try {
|
|
5941
|
-
const archiveContent =
|
|
6060
|
+
const archiveContent = fs12.readFileSync(archivePath, "utf-8");
|
|
5942
6061
|
const parseResult = import_core17.Brainfile.parseWithErrors(archiveContent);
|
|
5943
6062
|
if (!parseResult.board) {
|
|
5944
6063
|
return { success: false, error: "Failed to parse archive file" };
|
|
@@ -5956,7 +6075,7 @@ function restoreFromArchive(filePath, taskId, toColumnId) {
|
|
|
5956
6075
|
}
|
|
5957
6076
|
let board;
|
|
5958
6077
|
try {
|
|
5959
|
-
const mainContent =
|
|
6078
|
+
const mainContent = fs12.readFileSync(filePath, "utf-8");
|
|
5960
6079
|
const parseResult = import_core17.Brainfile.parseWithErrors(mainContent);
|
|
5961
6080
|
if (!parseResult.board) {
|
|
5962
6081
|
return { success: false, error: "Failed to parse main brainfile" };
|
|
@@ -5976,9 +6095,9 @@ function restoreFromArchive(filePath, taskId, toColumnId) {
|
|
|
5976
6095
|
archiveBoard.archive = archiveBoard.archive.filter((t) => t.id !== taskId);
|
|
5977
6096
|
try {
|
|
5978
6097
|
const mainContent = import_core17.Brainfile.serialize(board);
|
|
5979
|
-
|
|
6098
|
+
fs12.writeFileSync(filePath, mainContent, "utf-8");
|
|
5980
6099
|
const archiveContent = import_core17.Brainfile.serialize(archiveBoard);
|
|
5981
|
-
|
|
6100
|
+
fs12.writeFileSync(archivePath, archiveContent, "utf-8");
|
|
5982
6101
|
} catch (err) {
|
|
5983
6102
|
return {
|
|
5984
6103
|
success: false,
|
|
@@ -5998,10 +6117,10 @@ function restoreCommand(options) {
|
|
|
5998
6117
|
missingRequiredError("--column", "brainfile restore --task <task-id> --column <column-name>");
|
|
5999
6118
|
}
|
|
6000
6119
|
const filePath = resolveCliBrainfilePath(options.file);
|
|
6001
|
-
if (!
|
|
6120
|
+
if (!fs13.existsSync(filePath)) {
|
|
6002
6121
|
fileNotFoundError(filePath);
|
|
6003
6122
|
}
|
|
6004
|
-
const content =
|
|
6123
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
6005
6124
|
const result = import_core18.Brainfile.parseWithErrors(content);
|
|
6006
6125
|
if (!result.board) {
|
|
6007
6126
|
parseError(result.error);
|
|
@@ -6110,12 +6229,12 @@ function completeV2(filePath, taskId, force, logger) {
|
|
|
6110
6229
|
|
|
6111
6230
|
// src/commands/log.ts
|
|
6112
6231
|
var import_chalk15 = __toESM(require_source());
|
|
6113
|
-
import * as
|
|
6232
|
+
import * as fs14 from "fs";
|
|
6114
6233
|
import * as path17 from "path";
|
|
6115
6234
|
var import_core20 = __toESM(require_dist());
|
|
6116
6235
|
function logCommand(options, logger = defaultLogger) {
|
|
6117
6236
|
const filePath = resolveCliBrainfilePath(options.file);
|
|
6118
|
-
if (!
|
|
6237
|
+
if (!fs14.existsSync(filePath)) {
|
|
6119
6238
|
throw fileNotFound(filePath);
|
|
6120
6239
|
}
|
|
6121
6240
|
if (!(0, import_core.isV2)(filePath)) {
|
|
@@ -6138,7 +6257,7 @@ function logNoteCommand(options, logger = defaultLogger) {
|
|
|
6138
6257
|
throw missingRequired("message", 'brainfile log note --task <task-id> "message"');
|
|
6139
6258
|
}
|
|
6140
6259
|
const filePath = resolveCliBrainfilePath(options.file);
|
|
6141
|
-
if (!
|
|
6260
|
+
if (!fs14.existsSync(filePath)) {
|
|
6142
6261
|
throw fileNotFound(filePath);
|
|
6143
6262
|
}
|
|
6144
6263
|
if (!(0, import_core.isV2)(filePath)) {
|
|
@@ -6151,7 +6270,8 @@ function logNoteCommand(options, logger = defaultLogger) {
|
|
|
6151
6270
|
}
|
|
6152
6271
|
const { doc, filePath: taskPath } = found;
|
|
6153
6272
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
6154
|
-
const
|
|
6273
|
+
const actor = options.agent?.trim() || resolveActor(path17.dirname(filePath))?.name;
|
|
6274
|
+
const agentPrefix = actor ? `[${actor}] ` : "";
|
|
6155
6275
|
const entry = `- ${timestamp2}: ${agentPrefix}${options.message}`;
|
|
6156
6276
|
const existingDesc = (0, import_core.extractDescription)(doc.body);
|
|
6157
6277
|
const existingLog = (0, import_core.extractLog)(doc.body);
|
|
@@ -6248,8 +6368,8 @@ function listRecentLogs(dirs, logger) {
|
|
|
6248
6368
|
const seenIds = new Set(logDocs.map((d) => d.task.id));
|
|
6249
6369
|
const entries = logDocs.map((d) => ({ id: d.task.id, title: d.task.title, completedAt: d.task.completedAt }));
|
|
6250
6370
|
const ledgerPath = path17.join(dirs.logsDir, "ledger.jsonl");
|
|
6251
|
-
if (
|
|
6252
|
-
for (const line of
|
|
6371
|
+
if (fs14.existsSync(ledgerPath)) {
|
|
6372
|
+
for (const line of fs14.readFileSync(ledgerPath, "utf-8").split("\n")) {
|
|
6253
6373
|
const trimmed = line.trim();
|
|
6254
6374
|
if (!trimmed) continue;
|
|
6255
6375
|
try {
|
|
@@ -6287,7 +6407,7 @@ function listRecentLogs(dirs, logger) {
|
|
|
6287
6407
|
// src/commands/brief.ts
|
|
6288
6408
|
var import_chalk16 = __toESM(require_source());
|
|
6289
6409
|
var import_core21 = __toESM(require_dist());
|
|
6290
|
-
import * as
|
|
6410
|
+
import * as fs15 from "fs";
|
|
6291
6411
|
import * as path18 from "path";
|
|
6292
6412
|
var BRIEF_JSON_VERSION = "0.1";
|
|
6293
6413
|
function briefCommand(options, logger = defaultLogger) {
|
|
@@ -6327,7 +6447,7 @@ function runBrief(options) {
|
|
|
6327
6447
|
throw missingRequired("--agent", "brainfile brief --agent <name>");
|
|
6328
6448
|
}
|
|
6329
6449
|
const filePath = resolveCliBrainfilePath(options.file);
|
|
6330
|
-
if (!
|
|
6450
|
+
if (!fs15.existsSync(filePath)) {
|
|
6331
6451
|
throw fileNotFound(filePath);
|
|
6332
6452
|
}
|
|
6333
6453
|
if (!(0, import_core.isV2)(filePath)) {
|
|
@@ -6336,7 +6456,7 @@ function runBrief(options) {
|
|
|
6336
6456
|
);
|
|
6337
6457
|
}
|
|
6338
6458
|
if (!options.offline) {
|
|
6339
|
-
const sync = syncBoard(path18.dirname(filePath)
|
|
6459
|
+
const sync = syncBoard(path18.dirname(filePath));
|
|
6340
6460
|
if (!sync.skipped && !sync.ok) {
|
|
6341
6461
|
process.stderr.write(`${syncMessage(sync).text}
|
|
6342
6462
|
`);
|
|
@@ -32992,11 +33112,11 @@ var require_dist2 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
32992
33112
|
if (!f) throw new Error(`Unknown format "${name}"`);
|
|
32993
33113
|
return f;
|
|
32994
33114
|
};
|
|
32995
|
-
function addFormats2(ajv, list,
|
|
33115
|
+
function addFormats2(ajv, list, fs25, exportName) {
|
|
32996
33116
|
var _a2;
|
|
32997
33117
|
var _b;
|
|
32998
33118
|
(_a2 = (_b = ajv.opts.code).formats) !== null && _a2 !== void 0 || (_b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`);
|
|
32999
|
-
for (const f of list) ajv.addFormat(f,
|
|
33119
|
+
for (const f of list) ajv.addFormat(f, fs25[f]);
|
|
33000
33120
|
}
|
|
33001
33121
|
module.exports = exports = formatsPlugin;
|
|
33002
33122
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -35089,14 +35209,14 @@ import * as path23 from "path";
|
|
|
35089
35209
|
|
|
35090
35210
|
// src/mcp/helpers.ts
|
|
35091
35211
|
var import_core31 = __toESM(require_dist());
|
|
35092
|
-
import * as
|
|
35212
|
+
import * as fs16 from "fs";
|
|
35093
35213
|
import * as path19 from "path";
|
|
35094
35214
|
function resolveBrainfile(filePath) {
|
|
35095
35215
|
return path19.resolve(filePath);
|
|
35096
35216
|
}
|
|
35097
35217
|
function requireV2(filePath) {
|
|
35098
35218
|
const resolvedPath = resolveBrainfile(filePath);
|
|
35099
|
-
if (!
|
|
35219
|
+
if (!fs16.existsSync(resolvedPath)) {
|
|
35100
35220
|
return { content: [{ type: "text", text: `Error: File not found: ${resolvedPath}` }], isError: true };
|
|
35101
35221
|
}
|
|
35102
35222
|
if (!(0, import_core31.isV2)(resolvedPath)) {
|
|
@@ -35124,7 +35244,7 @@ function findGitRoot(startDir) {
|
|
|
35124
35244
|
const root = path19.parse(currentDir).root;
|
|
35125
35245
|
while (currentDir !== root) {
|
|
35126
35246
|
const gitPath = path19.join(currentDir, ".git");
|
|
35127
|
-
if (
|
|
35247
|
+
if (fs16.existsSync(gitPath)) {
|
|
35128
35248
|
return currentDir;
|
|
35129
35249
|
}
|
|
35130
35250
|
const parentDir = path19.dirname(currentDir);
|
|
@@ -35151,10 +35271,7 @@ function withBoardCommit(toolName, defaultFile, handler) {
|
|
|
35151
35271
|
const filePath = typeof input.file === "string" && input.file ? input.file : defaultFile;
|
|
35152
35272
|
const dotDir = path19.dirname(resolveBrainfile(filePath));
|
|
35153
35273
|
if (isTrackedBoard(dotDir)) {
|
|
35154
|
-
commitBoard(dotDir, {
|
|
35155
|
-
message: describeToolCall(toolName, input),
|
|
35156
|
-
agent: process.env.BRAINFILE_AGENT ?? null
|
|
35157
|
-
});
|
|
35274
|
+
commitBoard(dotDir, { message: describeToolCall(toolName, input), agent: detectAgent()?.name });
|
|
35158
35275
|
}
|
|
35159
35276
|
}
|
|
35160
35277
|
} catch {
|
|
@@ -35859,7 +35976,7 @@ function registerTaskPatchTool(server, defaultFile) {
|
|
|
35859
35976
|
}
|
|
35860
35977
|
|
|
35861
35978
|
// src/mcp/tools/task_delete_tool.ts
|
|
35862
|
-
import * as
|
|
35979
|
+
import * as fs17 from "fs";
|
|
35863
35980
|
function registerTaskDeleteTool(server, defaultFile) {
|
|
35864
35981
|
server.registerTool(
|
|
35865
35982
|
"task_delete",
|
|
@@ -35885,7 +36002,7 @@ function registerTaskDeleteTool(server, defaultFile) {
|
|
|
35885
36002
|
return { content: [{ type: "text", text: `Error: Task not found: ${task}` }], isError: true };
|
|
35886
36003
|
}
|
|
35887
36004
|
try {
|
|
35888
|
-
|
|
36005
|
+
fs17.unlinkSync(found.filePath);
|
|
35889
36006
|
return {
|
|
35890
36007
|
content: [{ type: "text", text: `Task ${task} deleted successfully` }],
|
|
35891
36008
|
structuredContent: { id: task, deleted: true }
|
|
@@ -36079,9 +36196,9 @@ var import_core43 = __toESM(require_dist());
|
|
|
36079
36196
|
|
|
36080
36197
|
// src/lib/contractRunner.ts
|
|
36081
36198
|
var import_core40 = __toESM(require_dist());
|
|
36082
|
-
import * as
|
|
36199
|
+
import * as fs18 from "fs";
|
|
36083
36200
|
import * as path21 from "path";
|
|
36084
|
-
import { spawnSync as
|
|
36201
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
36085
36202
|
function detectDirectoryChangeWarning(command) {
|
|
36086
36203
|
const patterns = [
|
|
36087
36204
|
/\bcd\s+[^\s;|&]+/,
|
|
@@ -36099,7 +36216,7 @@ function detectDirectoryChangeWarning(command) {
|
|
|
36099
36216
|
return void 0;
|
|
36100
36217
|
}
|
|
36101
36218
|
function requireV2Runner(resolvedFilePath) {
|
|
36102
|
-
if (!
|
|
36219
|
+
if (!fs18.existsSync(resolvedFilePath)) {
|
|
36103
36220
|
return { error: `File not found: ${resolvedFilePath}` };
|
|
36104
36221
|
}
|
|
36105
36222
|
if (!(0, import_core.isV2)(resolvedFilePath)) {
|
|
@@ -36259,7 +36376,7 @@ function validateContractV2(ctx, resolvedFilePath) {
|
|
|
36259
36376
|
continue;
|
|
36260
36377
|
}
|
|
36261
36378
|
const resolved = path21.isAbsolute(normalized.value) ? normalized.value : path21.join(baseDir, normalized.value);
|
|
36262
|
-
if (!
|
|
36379
|
+
if (!fs18.existsSync(resolved)) {
|
|
36263
36380
|
deliverableChecks.push({ deliverable: d, ok: false, resolvedPath: resolved, error: "File not found" });
|
|
36264
36381
|
} else {
|
|
36265
36382
|
deliverableChecks.push({ deliverable: d, ok: true, resolvedPath: resolved });
|
|
@@ -36282,7 +36399,7 @@ function validateContractV2(ctx, resolvedFilePath) {
|
|
|
36282
36399
|
if (dirWarning) {
|
|
36283
36400
|
warnings.push({ command: normalized.value, message: dirWarning });
|
|
36284
36401
|
}
|
|
36285
|
-
const res =
|
|
36402
|
+
const res = spawnSync3(normalized.value, {
|
|
36286
36403
|
shell: true,
|
|
36287
36404
|
cwd: baseDir,
|
|
36288
36405
|
encoding: "utf-8"
|
|
@@ -36937,7 +37054,7 @@ function registerContractTool(server, defaultFile) {
|
|
|
36937
37054
|
|
|
36938
37055
|
// src/mcp/tools/task_complete_tool.ts
|
|
36939
37056
|
var import_core44 = __toESM(require_dist());
|
|
36940
|
-
import * as
|
|
37057
|
+
import * as fs19 from "fs";
|
|
36941
37058
|
function registerTaskCompleteTool(server, defaultFile) {
|
|
36942
37059
|
server.registerTool(
|
|
36943
37060
|
"task_complete",
|
|
@@ -37029,7 +37146,7 @@ ${result.incompleteChildren.map((c) => ` - ${c.id}: ${c.title}`).join("\n")}` :
|
|
|
37029
37146
|
if (!ghResult.success) {
|
|
37030
37147
|
return { content: [{ type: "text", text: `Error creating GitHub issue: ${ghResult.error}` }], isError: true };
|
|
37031
37148
|
}
|
|
37032
|
-
|
|
37149
|
+
fs19.unlinkSync(found.filePath);
|
|
37033
37150
|
return {
|
|
37034
37151
|
content: [{ type: "text", text: `Task ${task} archived to GitHub Issue #${ghResult.issueNumber} (closed)
|
|
37035
37152
|
|
|
@@ -37081,7 +37198,7 @@ ${teamList}` }], isError: true };
|
|
|
37081
37198
|
if (!linearResult.success) {
|
|
37082
37199
|
return { content: [{ type: "text", text: `Error creating Linear issue: ${linearResult.error}` }], isError: true };
|
|
37083
37200
|
}
|
|
37084
|
-
|
|
37201
|
+
fs19.unlinkSync(found.filePath);
|
|
37085
37202
|
return {
|
|
37086
37203
|
content: [{ type: "text", text: `Task ${task} archived to Linear Issue ${linearResult.issueId} (Done)
|
|
37087
37204
|
|
|
@@ -37130,7 +37247,7 @@ function registerBriefTool(server, defaultFile) {
|
|
|
37130
37247
|
};
|
|
37131
37248
|
}
|
|
37132
37249
|
const resolvedPath = resolveBrainfile(filePath);
|
|
37133
|
-
if (!offline) syncBoard(path22.dirname(resolvedPath)
|
|
37250
|
+
if (!offline) syncBoard(path22.dirname(resolvedPath));
|
|
37134
37251
|
const dirs = (0, import_core.getV2Dirs)(resolvedPath);
|
|
37135
37252
|
const isPeek = peek === true;
|
|
37136
37253
|
const state = (0, import_core45.readBriefState)(resolvedPath, agentName);
|
|
@@ -37234,7 +37351,7 @@ var import_chalk20 = __toESM(require_source());
|
|
|
37234
37351
|
import * as readline2 from "readline";
|
|
37235
37352
|
|
|
37236
37353
|
// src/utils/hook-settings.ts
|
|
37237
|
-
import * as
|
|
37354
|
+
import * as fs20 from "fs";
|
|
37238
37355
|
import * as path24 from "path";
|
|
37239
37356
|
import * as os from "os";
|
|
37240
37357
|
function resolveHomeDir() {
|
|
@@ -37266,24 +37383,24 @@ function getSettingsPath(tool, scope) {
|
|
|
37266
37383
|
function readToolSettings(tool, scope) {
|
|
37267
37384
|
const settingsPath = getSettingsPath(tool, scope);
|
|
37268
37385
|
if (tool === "cline") {
|
|
37269
|
-
if (!
|
|
37386
|
+
if (!fs20.existsSync(settingsPath)) {
|
|
37270
37387
|
return { hooks: {} };
|
|
37271
37388
|
}
|
|
37272
37389
|
const hooks = {};
|
|
37273
37390
|
const hookFiles = ["PostToolUse", "UserPromptSubmit", "TaskStart"];
|
|
37274
37391
|
for (const hookFile of hookFiles) {
|
|
37275
37392
|
const hookPath = path24.join(settingsPath, hookFile);
|
|
37276
|
-
if (
|
|
37393
|
+
if (fs20.existsSync(hookPath)) {
|
|
37277
37394
|
hooks[hookFile] = true;
|
|
37278
37395
|
}
|
|
37279
37396
|
}
|
|
37280
37397
|
return { hooks };
|
|
37281
37398
|
}
|
|
37282
|
-
if (!
|
|
37399
|
+
if (!fs20.existsSync(settingsPath)) {
|
|
37283
37400
|
return tool === "cursor" ? { version: 1, hooks: {} } : {};
|
|
37284
37401
|
}
|
|
37285
37402
|
try {
|
|
37286
|
-
const content =
|
|
37403
|
+
const content = fs20.readFileSync(settingsPath, "utf-8");
|
|
37287
37404
|
return JSON.parse(content);
|
|
37288
37405
|
} catch {
|
|
37289
37406
|
return tool === "cursor" ? { version: 1, hooks: {} } : {};
|
|
@@ -37292,10 +37409,10 @@ function readToolSettings(tool, scope) {
|
|
|
37292
37409
|
function writeToolSettings(tool, scope, settings) {
|
|
37293
37410
|
const settingsPath = getSettingsPath(tool, scope);
|
|
37294
37411
|
const settingsDir = path24.dirname(settingsPath);
|
|
37295
|
-
if (!
|
|
37296
|
-
|
|
37412
|
+
if (!fs20.existsSync(settingsDir)) {
|
|
37413
|
+
fs20.mkdirSync(settingsDir, { recursive: true });
|
|
37297
37414
|
}
|
|
37298
|
-
|
|
37415
|
+
fs20.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
37299
37416
|
}
|
|
37300
37417
|
function createClineHookScript(hookType) {
|
|
37301
37418
|
const commandMap = {
|
|
@@ -37345,8 +37462,8 @@ function installBrainfileHooks(tool, scope) {
|
|
|
37345
37462
|
const settings = readToolSettings(tool, scope);
|
|
37346
37463
|
if (tool === "cline") {
|
|
37347
37464
|
const hooksDir = getSettingsPath(tool, scope);
|
|
37348
|
-
if (!
|
|
37349
|
-
|
|
37465
|
+
if (!fs20.existsSync(hooksDir)) {
|
|
37466
|
+
fs20.mkdirSync(hooksDir, { recursive: true });
|
|
37350
37467
|
}
|
|
37351
37468
|
const hookTypes = [
|
|
37352
37469
|
"PostToolUse",
|
|
@@ -37356,7 +37473,7 @@ function installBrainfileHooks(tool, scope) {
|
|
|
37356
37473
|
for (const hookType of hookTypes) {
|
|
37357
37474
|
const hookPath = path24.join(hooksDir, hookType);
|
|
37358
37475
|
const scriptContent = createClineHookScript(hookType);
|
|
37359
|
-
|
|
37476
|
+
fs20.writeFileSync(hookPath, scriptContent, { mode: 493 });
|
|
37360
37477
|
}
|
|
37361
37478
|
return;
|
|
37362
37479
|
}
|
|
@@ -37446,16 +37563,16 @@ function installBrainfileHooks(tool, scope) {
|
|
|
37446
37563
|
function uninstallBrainfileHooks(tool, scope) {
|
|
37447
37564
|
if (tool === "cline") {
|
|
37448
37565
|
const hooksDir = getSettingsPath(tool, scope);
|
|
37449
|
-
if (!
|
|
37566
|
+
if (!fs20.existsSync(hooksDir)) {
|
|
37450
37567
|
return;
|
|
37451
37568
|
}
|
|
37452
37569
|
const hookFiles = ["PostToolUse", "UserPromptSubmit", "TaskStart"];
|
|
37453
37570
|
for (const hookFile of hookFiles) {
|
|
37454
37571
|
const hookPath = path24.join(hooksDir, hookFile);
|
|
37455
|
-
if (
|
|
37456
|
-
const content =
|
|
37572
|
+
if (fs20.existsSync(hookPath)) {
|
|
37573
|
+
const content = fs20.readFileSync(hookPath, "utf-8");
|
|
37457
37574
|
if (content.includes("brainfile hooks")) {
|
|
37458
|
-
|
|
37575
|
+
fs20.unlinkSync(hookPath);
|
|
37459
37576
|
}
|
|
37460
37577
|
}
|
|
37461
37578
|
}
|
|
@@ -37502,15 +37619,15 @@ function uninstallBrainfileHooks(tool, scope) {
|
|
|
37502
37619
|
}
|
|
37503
37620
|
function areBrainfileHooksInstalled(tool, scope) {
|
|
37504
37621
|
const settingsPath = getSettingsPath(tool, scope);
|
|
37505
|
-
if (!
|
|
37622
|
+
if (!fs20.existsSync(settingsPath)) {
|
|
37506
37623
|
return false;
|
|
37507
37624
|
}
|
|
37508
37625
|
if (tool === "cline") {
|
|
37509
37626
|
const hookFiles = ["PostToolUse", "UserPromptSubmit", "TaskStart"];
|
|
37510
37627
|
for (const hookFile of hookFiles) {
|
|
37511
37628
|
const hookPath = path24.join(settingsPath, hookFile);
|
|
37512
|
-
if (
|
|
37513
|
-
const content =
|
|
37629
|
+
if (fs20.existsSync(hookPath)) {
|
|
37630
|
+
const content = fs20.readFileSync(hookPath, "utf-8");
|
|
37514
37631
|
if (content.includes("brainfile hooks")) {
|
|
37515
37632
|
return true;
|
|
37516
37633
|
}
|
|
@@ -37550,7 +37667,7 @@ function areBrainfileHooksInstalled(tool, scope) {
|
|
|
37550
37667
|
|
|
37551
37668
|
// src/utils/brainfile-finder.ts
|
|
37552
37669
|
var import_core47 = __toESM(require_dist());
|
|
37553
|
-
import * as
|
|
37670
|
+
import * as fs21 from "fs";
|
|
37554
37671
|
function findBrainfile3() {
|
|
37555
37672
|
const found = (0, import_core47.findBrainfile)(process.cwd());
|
|
37556
37673
|
if (found && found.kind !== "dotdir") return null;
|
|
@@ -37558,7 +37675,7 @@ function findBrainfile3() {
|
|
|
37558
37675
|
}
|
|
37559
37676
|
function getFileAgeMinutes(filePath) {
|
|
37560
37677
|
try {
|
|
37561
|
-
const stats =
|
|
37678
|
+
const stats = fs21.statSync(filePath);
|
|
37562
37679
|
const now = Date.now();
|
|
37563
37680
|
const modifiedTime = stats.mtimeMs;
|
|
37564
37681
|
const ageMs = now - modifiedTime;
|
|
@@ -38021,17 +38138,17 @@ function flattenConfig(obj, prefix = "") {
|
|
|
38021
38138
|
|
|
38022
38139
|
// src/commands/schema.ts
|
|
38023
38140
|
var import_chalk22 = __toESM(require_source());
|
|
38024
|
-
import * as
|
|
38141
|
+
import * as fs22 from "fs";
|
|
38025
38142
|
import * as path25 from "path";
|
|
38026
38143
|
var SCHEMA_BASE_URL = "https://brainfile.md/v1";
|
|
38027
38144
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
38028
38145
|
function getBundledSchemasDir() {
|
|
38029
38146
|
const distPath = path25.join(__dirname, "..", "schemas");
|
|
38030
38147
|
const srcPath = path25.join(__dirname, "..", "..", "src", "schemas");
|
|
38031
|
-
if (
|
|
38148
|
+
if (fs22.existsSync(distPath)) {
|
|
38032
38149
|
return distPath;
|
|
38033
38150
|
}
|
|
38034
|
-
if (
|
|
38151
|
+
if (fs22.existsSync(srcPath)) {
|
|
38035
38152
|
return srcPath;
|
|
38036
38153
|
}
|
|
38037
38154
|
return path25.join(__dirname, "schemas");
|
|
@@ -38117,14 +38234,14 @@ function schemaShowCommand(name, options, logger) {
|
|
|
38117
38234
|
}
|
|
38118
38235
|
const schemasDir = getBundledSchemasDir();
|
|
38119
38236
|
const schemaPath = path25.join(schemasDir, schemaInfo.file);
|
|
38120
|
-
if (!
|
|
38237
|
+
if (!fs22.existsSync(schemaPath)) {
|
|
38121
38238
|
throw new CLIError(
|
|
38122
38239
|
`Schema file not found: ${schemaInfo.file}`,
|
|
38123
38240
|
ExitCode.USER_ERROR,
|
|
38124
38241
|
`Expected at: ${schemaPath}`
|
|
38125
38242
|
);
|
|
38126
38243
|
}
|
|
38127
|
-
const content =
|
|
38244
|
+
const content = fs22.readFileSync(schemaPath, "utf-8");
|
|
38128
38245
|
const schema2 = JSON.parse(content);
|
|
38129
38246
|
if (options.json) {
|
|
38130
38247
|
logger.log(JSON.stringify(schema2, null, 2));
|
|
@@ -38190,14 +38307,14 @@ async function schemaUpdateAsync(options, logger) {
|
|
|
38190
38307
|
const remoteContent = await response.text();
|
|
38191
38308
|
const remoteSchema = JSON.parse(remoteContent);
|
|
38192
38309
|
let localSchema = null;
|
|
38193
|
-
if (
|
|
38194
|
-
const localContent =
|
|
38310
|
+
if (fs22.existsSync(localPath)) {
|
|
38311
|
+
const localContent = fs22.readFileSync(localPath, "utf-8");
|
|
38195
38312
|
localSchema = JSON.parse(localContent);
|
|
38196
38313
|
}
|
|
38197
38314
|
const remoteStr = JSON.stringify(remoteSchema);
|
|
38198
38315
|
const localStr = localSchema ? JSON.stringify(localSchema) : "";
|
|
38199
38316
|
if (remoteStr !== localStr) {
|
|
38200
|
-
|
|
38317
|
+
fs22.writeFileSync(localPath, JSON.stringify(remoteSchema, null, 2));
|
|
38201
38318
|
results.push({ id: schemaInfo.id, status: "updated" });
|
|
38202
38319
|
} else {
|
|
38203
38320
|
results.push({ id: schemaInfo.id, status: "current" });
|
|
@@ -38274,8 +38391,8 @@ async function checkForUpdatesAsync(logger) {
|
|
|
38274
38391
|
}
|
|
38275
38392
|
const remoteContent = await response.text();
|
|
38276
38393
|
const remoteSchema = JSON.parse(remoteContent);
|
|
38277
|
-
if (
|
|
38278
|
-
const localContent =
|
|
38394
|
+
if (fs22.existsSync(localPath)) {
|
|
38395
|
+
const localContent = fs22.readFileSync(localPath, "utf-8");
|
|
38279
38396
|
const localSchema = JSON.parse(localContent);
|
|
38280
38397
|
const remoteStr = JSON.stringify(remoteSchema);
|
|
38281
38398
|
const localStr = JSON.stringify(localSchema);
|
|
@@ -38299,7 +38416,7 @@ async function checkForUpdatesAsync(logger) {
|
|
|
38299
38416
|
// src/commands/adr.ts
|
|
38300
38417
|
var import_chalk23 = __toESM(require_source());
|
|
38301
38418
|
var import_core48 = __toESM(require_dist());
|
|
38302
|
-
import * as
|
|
38419
|
+
import * as fs23 from "fs";
|
|
38303
38420
|
import * as path26 from "path";
|
|
38304
38421
|
var ADR_COMMAND_HELP = `
|
|
38305
38422
|
Examples:
|
|
@@ -38326,7 +38443,7 @@ function adrPromoteCommand(options, logger = defaultLogger) {
|
|
|
38326
38443
|
);
|
|
38327
38444
|
}
|
|
38328
38445
|
const resolvedPath = resolveCliBrainfilePath(options.file);
|
|
38329
|
-
if (!
|
|
38446
|
+
if (!fs23.existsSync(resolvedPath)) {
|
|
38330
38447
|
throw fileNotFound(resolvedPath);
|
|
38331
38448
|
}
|
|
38332
38449
|
if (!(0, import_core.isV2)(resolvedPath)) {
|
|
@@ -38353,13 +38470,13 @@ function adrPromoteCommand(options, logger = defaultLogger) {
|
|
|
38353
38470
|
};
|
|
38354
38471
|
delete promotedTask.column;
|
|
38355
38472
|
delete promotedTask.position;
|
|
38356
|
-
|
|
38473
|
+
fs23.mkdirSync(dirs.logsDir, { recursive: true });
|
|
38357
38474
|
const logPath = path26.join(dirs.logsDir, (0, import_core48.taskFileName)(task.id));
|
|
38358
|
-
if (
|
|
38475
|
+
if (fs23.existsSync(logPath)) {
|
|
38359
38476
|
throw operationFailed(`Log already exists for ADR: ${task.id}`);
|
|
38360
38477
|
}
|
|
38361
38478
|
(0, import_core48.writeTaskFile)(logPath, promotedTask, doc.body);
|
|
38362
|
-
|
|
38479
|
+
fs23.unlinkSync(taskPath);
|
|
38363
38480
|
logger.log(import_chalk23.default.green("ADR promoted!"));
|
|
38364
38481
|
logger.log("");
|
|
38365
38482
|
logger.log(import_chalk23.default.gray(` ADR: ${task.id} - ${task.title}`));
|
|
@@ -38546,7 +38663,7 @@ function planLinkCommand(options, logger = defaultLogger) {
|
|
|
38546
38663
|
}
|
|
38547
38664
|
|
|
38548
38665
|
// src/commands/types.ts
|
|
38549
|
-
import * as
|
|
38666
|
+
import * as fs24 from "fs";
|
|
38550
38667
|
|
|
38551
38668
|
// ../node_modules/js-yaml/dist/js-yaml.mjs
|
|
38552
38669
|
function getDefaultExportFromCjs(x) {
|
|
@@ -40315,7 +40432,7 @@ function requireLoader() {
|
|
|
40315
40432
|
const _tag = state.tag;
|
|
40316
40433
|
const _anchor = state.anchor;
|
|
40317
40434
|
const _result = [];
|
|
40318
|
-
let
|
|
40435
|
+
let detected2 = false;
|
|
40319
40436
|
if (state.firstTabInLine !== -1) return false;
|
|
40320
40437
|
if (state.anchor !== null) {
|
|
40321
40438
|
storeAnchor(state, state.anchor, _result);
|
|
@@ -40333,7 +40450,7 @@ function requireLoader() {
|
|
|
40333
40450
|
if (!isWsOrEol(following)) {
|
|
40334
40451
|
break;
|
|
40335
40452
|
}
|
|
40336
|
-
|
|
40453
|
+
detected2 = true;
|
|
40337
40454
|
state.position++;
|
|
40338
40455
|
if (skipSeparationSpace(state, true, -1)) {
|
|
40339
40456
|
if (state.lineIndent <= nodeIndent) {
|
|
@@ -40353,7 +40470,7 @@ function requireLoader() {
|
|
|
40353
40470
|
break;
|
|
40354
40471
|
}
|
|
40355
40472
|
}
|
|
40356
|
-
if (
|
|
40473
|
+
if (detected2) {
|
|
40357
40474
|
state.tag = _tag;
|
|
40358
40475
|
state.anchor = _anchor;
|
|
40359
40476
|
state.kind = "sequence";
|
|
@@ -40375,7 +40492,7 @@ function requireLoader() {
|
|
|
40375
40492
|
let keyNode = null;
|
|
40376
40493
|
let valueNode = null;
|
|
40377
40494
|
let atExplicitKey = false;
|
|
40378
|
-
let
|
|
40495
|
+
let detected2 = false;
|
|
40379
40496
|
if (state.firstTabInLine !== -1) return false;
|
|
40380
40497
|
if (state.anchor !== null) {
|
|
40381
40498
|
storeAnchor(state, state.anchor, _result);
|
|
@@ -40394,7 +40511,7 @@ function requireLoader() {
|
|
|
40394
40511
|
storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos);
|
|
40395
40512
|
keyTag = keyNode = valueNode = null;
|
|
40396
40513
|
}
|
|
40397
|
-
|
|
40514
|
+
detected2 = true;
|
|
40398
40515
|
atExplicitKey = true;
|
|
40399
40516
|
allowCompact = true;
|
|
40400
40517
|
} else if (atExplicitKey) {
|
|
@@ -40426,19 +40543,19 @@ function requireLoader() {
|
|
|
40426
40543
|
storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos);
|
|
40427
40544
|
keyTag = keyNode = valueNode = null;
|
|
40428
40545
|
}
|
|
40429
|
-
|
|
40546
|
+
detected2 = true;
|
|
40430
40547
|
atExplicitKey = false;
|
|
40431
40548
|
allowCompact = false;
|
|
40432
40549
|
keyTag = state.tag;
|
|
40433
40550
|
keyNode = state.result;
|
|
40434
|
-
} else if (
|
|
40551
|
+
} else if (detected2) {
|
|
40435
40552
|
throwError(state, "can not read an implicit mapping pair; a colon is missed");
|
|
40436
40553
|
} else {
|
|
40437
40554
|
state.tag = _tag;
|
|
40438
40555
|
state.anchor = _anchor;
|
|
40439
40556
|
return true;
|
|
40440
40557
|
}
|
|
40441
|
-
} else if (
|
|
40558
|
+
} else if (detected2) {
|
|
40442
40559
|
throwError(state, "can not read a block mapping entry; a multiline key may not be an implicit key");
|
|
40443
40560
|
} else {
|
|
40444
40561
|
state.tag = _tag;
|
|
@@ -40475,13 +40592,13 @@ function requireLoader() {
|
|
|
40475
40592
|
if (atExplicitKey) {
|
|
40476
40593
|
storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos);
|
|
40477
40594
|
}
|
|
40478
|
-
if (
|
|
40595
|
+
if (detected2) {
|
|
40479
40596
|
state.tag = _tag;
|
|
40480
40597
|
state.anchor = _anchor;
|
|
40481
40598
|
state.kind = "mapping";
|
|
40482
40599
|
state.result = _result;
|
|
40483
40600
|
}
|
|
40484
|
-
return
|
|
40601
|
+
return detected2;
|
|
40485
40602
|
}
|
|
40486
40603
|
function readTagProperty(state) {
|
|
40487
40604
|
let isVerbatim = false;
|
|
@@ -41647,11 +41764,11 @@ ${yamlContent}---
|
|
|
41647
41764
|
${doc.body}`;
|
|
41648
41765
|
}
|
|
41649
41766
|
function readFrontmatter(filePath) {
|
|
41650
|
-
const content =
|
|
41767
|
+
const content = fs24.readFileSync(filePath, "utf-8");
|
|
41651
41768
|
return parseFrontmatter(content);
|
|
41652
41769
|
}
|
|
41653
41770
|
function writeFrontmatter(filePath, doc) {
|
|
41654
|
-
|
|
41771
|
+
fs24.writeFileSync(filePath, serializeFrontmatter(doc), "utf-8");
|
|
41655
41772
|
}
|
|
41656
41773
|
function sanitizeTypesConfig(raw) {
|
|
41657
41774
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
@@ -41773,11 +41890,11 @@ function typesAddCommand(options, logger = defaultLogger) {
|
|
|
41773
41890
|
|
|
41774
41891
|
// src/cli.ts
|
|
41775
41892
|
async function runTui(options) {
|
|
41776
|
-
const { tuiCommand } = await import("./tui-
|
|
41893
|
+
const { tuiCommand } = await import("./tui-3Z7ZJV7M.mjs");
|
|
41777
41894
|
return tuiCommand(options);
|
|
41778
41895
|
}
|
|
41779
41896
|
var packageJson = JSON.parse(
|
|
41780
|
-
|
|
41897
|
+
readFileSync11(join18(__dirname, "..", "package.json"), "utf8")
|
|
41781
41898
|
);
|
|
41782
41899
|
var SUBCOMMANDS = ["init", "migrate", "list", "show", "add", "move", "patch", "delete", "archive", "restore", "complete", "log", "note", "brief", "search", "subtask", "template", "lint", "tui", "hooks", "mcp", "auth", "config", "contract", "schema", "adr", "plan", "types", "sync", "where", "merge-driver", "help"];
|
|
41783
41900
|
function shouldLaunchTUI() {
|
|
@@ -41795,7 +41912,7 @@ function shouldLaunchTUI() {
|
|
|
41795
41912
|
if (SUBCOMMANDS.includes(firstArg)) {
|
|
41796
41913
|
return { launch: false, file: "" };
|
|
41797
41914
|
}
|
|
41798
|
-
if (firstArg.includes(".") || firstArg.includes("/") || firstArg.endsWith(sep3) ||
|
|
41915
|
+
if (firstArg.includes(".") || firstArg.includes("/") || firstArg.endsWith(sep3) || existsSync20(firstArg)) {
|
|
41799
41916
|
return { launch: true, file: firstArg };
|
|
41800
41917
|
}
|
|
41801
41918
|
return { launch: false, file: "" };
|
|
@@ -41892,13 +42009,13 @@ ${ADD_COMMAND_HELP}`);
|
|
|
41892
42009
|
program2.command("log").description("View, search, and manage completed task logs (v2 only)").option("-f, --file <path>", "Path to brainfile file (auto-detect by default)", "brainfile.md").option("-t, --task <id>", "View a specific task log").option("-s, --search <query>", "Search across all logs").option("--recent", "List recently completed tasks").action((options) => {
|
|
41893
42010
|
logCommand(options);
|
|
41894
42011
|
});
|
|
41895
|
-
program2.command("note").description("Append a timestamped note to a task log").option("-f, --file <path>", "Path to brainfile file (auto-detect by default)", "brainfile.md").option("-t, --task <id>", "Task ID to add note to (required)").option("--agent <name>", "
|
|
42012
|
+
program2.command("note").description("Append a timestamped note to a task log").option("-f, --file <path>", "Path to brainfile file (auto-detect by default)", "brainfile.md").option("-t, --task <id>", "Task ID to add note to (required)").option("--agent <name>", "Who wrote it (default: the detected agent, else your git user.name)").argument("[message]", "Log message to append").action((message, options) => {
|
|
41896
42013
|
logNoteCommand({ ...options, message });
|
|
41897
42014
|
});
|
|
41898
42015
|
program2.command("brief").description("Per-agent brief: what changed since this agent last checked in").option("-f, --file <path>", "Path to brainfile file (auto-detect by default)", "brainfile.md").option("--agent <name>", "Agent identifier (required \u2014 brief state is per-agent)").option("--peek", "Read the brief without marking it as seen").option("--offline", "Skip syncing a shared board before the brief").option("--json", "Output as JSON").action((options) => {
|
|
41899
42016
|
briefCommand(options);
|
|
41900
42017
|
});
|
|
41901
|
-
const syncCmd = program2.command("sync").description("Share a tracked board through a git remote: fetch, merge, push").option("-f, --file <path>", "Path to brainfile file (auto-detect by default)", "brainfile.md").option("--pull", "Fetch and merge only").option("--push", "Push only").option("--set-remote <name|url>", 'Remote to sync with: an existing remote name, or a URL registered as remote "board"').option("--
|
|
42018
|
+
const syncCmd = program2.command("sync").description("Share a tracked board through a git remote: fetch, merge, push").option("-f, --file <path>", "Path to brainfile file (auto-detect by default)", "brainfile.md").option("--pull", "Fetch and merge only").option("--push", "Push only").option("--set-remote <name|url>", 'Remote to sync with: an existing remote name, or a URL registered as remote "board"').option("--board-name <name>", 'Name on the remote, stored as refs/brainfile/<name> (default: "board"; folder name for a standalone board; "home" for -g)').addOption(new Option("--remote-branch <name>", "0.21.0 spelling of --board-name").hideHelp()).option("--autosync <mode>", "off | push (after writes, default once a remote is set) | full (also fetch before reads)").option("--json", "Output as JSON").addOption(new Option("--wait <ms>", "Sleep before syncing (autosync child)").hideHelp()).action((options) => {
|
|
41902
42019
|
syncCommand(options);
|
|
41903
42020
|
});
|
|
41904
42021
|
syncCmd.addHelpText("after", `
|