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
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.BOARD_GITATTRIBUTES = exports.DEFAULT_MERGE_DRIVER_COMMAND = exports.MERGE_DRIVER_NAME = exports.URL_REMOTE_NAME = exports.AUTOSYNC_CONFIG_KEY = exports.REMOTE_BRANCH_CONFIG_KEY = exports.REMOTE_CONFIG_KEY = void 0;
|
|
37
|
+
exports.boardRemote = boardRemote;
|
|
38
|
+
exports.boardRemoteBranch = boardRemoteBranch;
|
|
39
|
+
exports.boardAutosync = boardAutosync;
|
|
40
|
+
exports.setBoardAutosync = setBoardAutosync;
|
|
41
|
+
exports.looksLikeRemoteUrl = looksLikeRemoteUrl;
|
|
42
|
+
exports.setBoardRemote = setBoardRemote;
|
|
43
|
+
exports.registerMergeDriver = registerMergeDriver;
|
|
44
|
+
exports.ensureBoardAttributes = ensureBoardAttributes;
|
|
45
|
+
exports.readSyncState = readSyncState;
|
|
46
|
+
exports.resolveCompleteVersusEdit = resolveCompleteVersusEdit;
|
|
47
|
+
exports.syncBoard = syncBoard;
|
|
48
|
+
exports.secondsSinceSync = secondsSinceSync;
|
|
49
|
+
exports.syncStatusLabel = syncStatusLabel;
|
|
50
|
+
exports.pendingChanges = pendingChanges;
|
|
51
|
+
exports.syncMessage = syncMessage;
|
|
52
|
+
/**
|
|
53
|
+
* Board sync (spec-9 phase 2): remote configuration and the fetch → merge →
|
|
54
|
+
* push algorithm for tracked boards. Everything here runs inside the board
|
|
55
|
+
* directory, so the code tree is never touched, and nothing throws on network
|
|
56
|
+
* failure — a mutation must never fail because sync failed.
|
|
57
|
+
*
|
|
58
|
+
* Config keys live in the board's git config (the shared `.git/config` for a
|
|
59
|
+
* linked worktree, its own for a standalone repository):
|
|
60
|
+
*
|
|
61
|
+
* brainfile.remote remote name to sync with (never defaults to origin)
|
|
62
|
+
* brainfile.remoteBranch branch on that remote (see `boardRemoteBranch`)
|
|
63
|
+
* brainfile.autosync off | push | full
|
|
64
|
+
*/
|
|
65
|
+
const fs = __importStar(require("fs"));
|
|
66
|
+
const os = __importStar(require("os"));
|
|
67
|
+
const path = __importStar(require("path"));
|
|
68
|
+
const board_repo_1 = require("./board-repo");
|
|
69
|
+
const merge_driver_1 = require("../commands/merge-driver");
|
|
70
|
+
exports.REMOTE_CONFIG_KEY = 'brainfile.remote';
|
|
71
|
+
exports.REMOTE_BRANCH_CONFIG_KEY = 'brainfile.remoteBranch';
|
|
72
|
+
exports.AUTOSYNC_CONFIG_KEY = 'brainfile.autosync';
|
|
73
|
+
/** Remote name used when `--set-remote` is given a URL instead of a name. */
|
|
74
|
+
exports.URL_REMOTE_NAME = 'board';
|
|
75
|
+
exports.MERGE_DRIVER_NAME = 'brainfile';
|
|
76
|
+
exports.DEFAULT_MERGE_DRIVER_COMMAND = 'brainfile merge-driver %O %A %B';
|
|
77
|
+
const SYNC_STATE_FILE = path.join('state', 'sync.json');
|
|
78
|
+
exports.BOARD_GITATTRIBUTES = [
|
|
79
|
+
'logs/ledger.jsonl merge=union',
|
|
80
|
+
'board/*.md merge=brainfile',
|
|
81
|
+
'logs/*.md merge=brainfile',
|
|
82
|
+
'brainfile.md merge=brainfile',
|
|
83
|
+
];
|
|
84
|
+
function configGet(dotDir, key) {
|
|
85
|
+
const r = (0, board_repo_1.git)(['config', '--get', key], dotDir);
|
|
86
|
+
return r.ok && r.stdout ? r.stdout : null;
|
|
87
|
+
}
|
|
88
|
+
function configSet(dotDir, key, value) {
|
|
89
|
+
return (0, board_repo_1.git)(['config', key, value], dotDir).ok;
|
|
90
|
+
}
|
|
91
|
+
function boardRemote(dotDir) {
|
|
92
|
+
return configGet(dotDir, exports.REMOTE_CONFIG_KEY);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Branch name on the remote. Defaults keep the "one private boards repo, one
|
|
96
|
+
* branch per project" pattern from colliding: the board branch name inside a
|
|
97
|
+
* repo, the parent folder's basename for a standalone board, `home` for the
|
|
98
|
+
* global board.
|
|
99
|
+
*/
|
|
100
|
+
function boardRemoteBranch(dotDir) {
|
|
101
|
+
const configured = configGet(dotDir, exports.REMOTE_BRANCH_CONFIG_KEY);
|
|
102
|
+
if (configured)
|
|
103
|
+
return configured;
|
|
104
|
+
if (path.resolve(dotDir) === path.resolve((0, board_repo_1.homeBoardDir)()))
|
|
105
|
+
return 'home';
|
|
106
|
+
// A standalone board is named after the folder it sits in; anything else
|
|
107
|
+
// (a linked board, or a code repo whose board is not checked out yet) uses
|
|
108
|
+
// the board branch name.
|
|
109
|
+
if ((0, board_repo_1.boardRepoKind)(dotDir) === 'standalone' && path.basename(path.resolve(dotDir)) === '.brainfile') {
|
|
110
|
+
return path.basename(path.dirname(path.resolve(dotDir))) || (0, board_repo_1.boardBranch)(dotDir);
|
|
111
|
+
}
|
|
112
|
+
return (0, board_repo_1.boardBranch)(dotDir);
|
|
113
|
+
}
|
|
114
|
+
function boardAutosync(dotDir) {
|
|
115
|
+
const value = configGet(dotDir, exports.AUTOSYNC_CONFIG_KEY);
|
|
116
|
+
if (value === 'off' || value === 'push' || value === 'full')
|
|
117
|
+
return value;
|
|
118
|
+
return boardRemote(dotDir) ? 'push' : 'off';
|
|
119
|
+
}
|
|
120
|
+
function setBoardAutosync(dotDir, mode) {
|
|
121
|
+
return configSet(dotDir, exports.AUTOSYNC_CONFIG_KEY, mode);
|
|
122
|
+
}
|
|
123
|
+
/** True when `target` names a place rather than an existing git remote. */
|
|
124
|
+
function looksLikeRemoteUrl(target) {
|
|
125
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(target))
|
|
126
|
+
return true; // ssh://, https://, file://
|
|
127
|
+
if (/^[^/\s]+@[^/\s]+:/.test(target))
|
|
128
|
+
return true; // git@host:path
|
|
129
|
+
if (target.startsWith('/') || target.startsWith('.') || target.startsWith('~'))
|
|
130
|
+
return true;
|
|
131
|
+
if (target.includes('/') && fs.existsSync(target))
|
|
132
|
+
return true;
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Point the board at a remote: an existing remote name, or a URL/path that is
|
|
137
|
+
* registered as the `board` remote. Throws an Error naming an unknown remote.
|
|
138
|
+
* `cwd` may be the board directory or, when no board exists yet, the code
|
|
139
|
+
* repository the board will be materialized into.
|
|
140
|
+
*/
|
|
141
|
+
function setBoardRemote(cwd, target, remoteBranch) {
|
|
142
|
+
const trimmed = target.trim();
|
|
143
|
+
if (!trimmed)
|
|
144
|
+
throw new Error('remote is required');
|
|
145
|
+
let remote;
|
|
146
|
+
if (looksLikeRemoteUrl(trimmed)) {
|
|
147
|
+
remote = exports.URL_REMOTE_NAME;
|
|
148
|
+
const url = trimmed.startsWith('~/') ? path.join(os.homedir(), trimmed.slice(2)) : trimmed;
|
|
149
|
+
const exists = (0, board_repo_1.git)(['remote', 'get-url', remote], cwd).ok;
|
|
150
|
+
const r = exists ? (0, board_repo_1.git)(['remote', 'set-url', remote, url], cwd) : (0, board_repo_1.git)(['remote', 'add', remote, url], cwd);
|
|
151
|
+
if (!r.ok)
|
|
152
|
+
throw new Error(r.stderr || `could not register remote '${remote}'`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
remote = trimmed;
|
|
156
|
+
if (!(0, board_repo_1.git)(['remote', 'get-url', remote], cwd).ok) {
|
|
157
|
+
const known = (0, board_repo_1.git)(['remote'], cwd).stdout.split('\n').filter(Boolean);
|
|
158
|
+
const hint = known.length ? ` Known remotes: ${known.join(', ')}.` : '';
|
|
159
|
+
throw new Error(`'${remote}' is not a git remote here.${hint} Pass a URL to add one.`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
configSet(cwd, exports.REMOTE_CONFIG_KEY, remote);
|
|
163
|
+
if (remoteBranch)
|
|
164
|
+
configSet(cwd, exports.REMOTE_BRANCH_CONFIG_KEY, remoteBranch);
|
|
165
|
+
registerMergeDriver(cwd);
|
|
166
|
+
return {
|
|
167
|
+
remote,
|
|
168
|
+
url: (0, board_repo_1.git)(['remote', 'get-url', remote], cwd).stdout || null,
|
|
169
|
+
remoteBranch: remoteBranch ?? boardRemoteBranch(cwd),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Register the field-level merge driver in the board's git config.
|
|
174
|
+
*
|
|
175
|
+
* Without an explicit `command` this only fills in a missing driver: a
|
|
176
|
+
* driver someone configured on purpose (an absolute path to the CLI, or a
|
|
177
|
+
* test's built bundle) is never overwritten by the next sync.
|
|
178
|
+
*/
|
|
179
|
+
function registerMergeDriver(cwd, command) {
|
|
180
|
+
const current = configGet(cwd, `merge.${exports.MERGE_DRIVER_NAME}.driver`);
|
|
181
|
+
if (command === undefined) {
|
|
182
|
+
if (current)
|
|
183
|
+
return false;
|
|
184
|
+
command = exports.DEFAULT_MERGE_DRIVER_COMMAND;
|
|
185
|
+
}
|
|
186
|
+
if (current === command)
|
|
187
|
+
return false;
|
|
188
|
+
configSet(cwd, `merge.${exports.MERGE_DRIVER_NAME}.name`, 'brainfile board merge (field-level, last writer wins)');
|
|
189
|
+
return configSet(cwd, `merge.${exports.MERGE_DRIVER_NAME}.driver`, command);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Make sure `.gitattributes` on the board declares the merge strategies.
|
|
193
|
+
* Returns true when the file was created or extended (caller commits).
|
|
194
|
+
*/
|
|
195
|
+
function ensureBoardAttributes(dotDir) {
|
|
196
|
+
const file = path.join(dotDir, '.gitattributes');
|
|
197
|
+
let existing = '';
|
|
198
|
+
try {
|
|
199
|
+
existing = fs.readFileSync(file, 'utf-8');
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
/* absent */
|
|
203
|
+
}
|
|
204
|
+
const lines = existing.split('\n').map((l) => l.trim());
|
|
205
|
+
const missing = exports.BOARD_GITATTRIBUTES.filter((l) => !lines.includes(l));
|
|
206
|
+
if (missing.length === 0)
|
|
207
|
+
return false;
|
|
208
|
+
const prefix = existing.length > 0 && !existing.endsWith('\n') ? `${existing}\n` : existing;
|
|
209
|
+
fs.writeFileSync(file, `${prefix}${missing.join('\n')}\n`, 'utf-8');
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
function readSyncState(dotDir) {
|
|
213
|
+
try {
|
|
214
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(dotDir, SYNC_STATE_FILE), 'utf-8'));
|
|
215
|
+
return typeof parsed?.at === 'string' ? parsed : null;
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function writeSyncState(dotDir, state) {
|
|
222
|
+
try {
|
|
223
|
+
fs.mkdirSync(path.join(dotDir, 'state'), { recursive: true });
|
|
224
|
+
fs.writeFileSync(path.join(dotDir, SYNC_STATE_FILE), `${JSON.stringify(state, null, 2)}\n`, 'utf-8');
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
/* state is a convenience; never fail sync over it */
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function firstLine(text) {
|
|
231
|
+
return text.split('\n').map((l) => l.trim()).find(Boolean) ?? '';
|
|
232
|
+
}
|
|
233
|
+
function isMissingRemoteRef(stderr) {
|
|
234
|
+
return /couldn't find remote ref|Remote branch .* not found|invalid refspec|no such ref/i.test(stderr);
|
|
235
|
+
}
|
|
236
|
+
function commitCount(dotDir, range) {
|
|
237
|
+
const r = (0, board_repo_1.git)(['rev-list', '--count', range], dotDir);
|
|
238
|
+
return r.ok ? Number.parseInt(r.stdout, 10) || 0 : 0;
|
|
239
|
+
}
|
|
240
|
+
function identity(dotDir, agent) {
|
|
241
|
+
const args = ['-c', 'commit.gpgsign=false'];
|
|
242
|
+
if (!(0, board_repo_1.git)(['config', '--get', 'user.email'], dotDir).ok) {
|
|
243
|
+
args.push('-c', 'user.name=brainfile', '-c', 'user.email=brainfile@localhost');
|
|
244
|
+
}
|
|
245
|
+
const env = {};
|
|
246
|
+
const name = agent?.replace(/[\r\n<>]/g, '').trim();
|
|
247
|
+
if (name) {
|
|
248
|
+
env.GIT_AUTHOR_NAME = name;
|
|
249
|
+
env.GIT_AUTHOR_EMAIL = `${name}@brainfile.local`;
|
|
250
|
+
}
|
|
251
|
+
return { args, env };
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Complete-vs-edit: one side archived a task (deleted `board/<id>.md`, wrote
|
|
255
|
+
* `logs/<id>.md`) while the other edited it. Completion wins; the edit is
|
|
256
|
+
* appended to the archived file as a log entry. Returns the paths resolved.
|
|
257
|
+
*/
|
|
258
|
+
function resolveCompleteVersusEdit(dotDir) {
|
|
259
|
+
const status = (0, board_repo_1.git)(['status', '--porcelain', '-z'], dotDir);
|
|
260
|
+
if (!status.ok)
|
|
261
|
+
return [];
|
|
262
|
+
const resolved = [];
|
|
263
|
+
for (const entry of status.stdout.split('\0')) {
|
|
264
|
+
if (entry.length < 4)
|
|
265
|
+
continue;
|
|
266
|
+
const xy = entry.slice(0, 2);
|
|
267
|
+
const file = entry.slice(3);
|
|
268
|
+
if (xy !== 'DU' && xy !== 'UD')
|
|
269
|
+
continue;
|
|
270
|
+
if (!file.startsWith('board/'))
|
|
271
|
+
continue;
|
|
272
|
+
// DU: deleted by us, modified by them. UD: the reverse.
|
|
273
|
+
const editedStage = xy === 'DU' ? 3 : 2;
|
|
274
|
+
const base = (0, board_repo_1.git)(['show', `:1:${file}`], dotDir);
|
|
275
|
+
const edited = (0, board_repo_1.git)(['show', `:${editedStage}:${file}`], dotDir);
|
|
276
|
+
const archived = path.join(dotDir, 'logs', path.basename(file));
|
|
277
|
+
if (edited.ok && fs.existsSync(archived)) {
|
|
278
|
+
const summary = (0, merge_driver_1.summarizeFieldChanges)(base.ok ? base.stdout : '', edited.stdout);
|
|
279
|
+
const entryLine = `- ${new Date().toISOString()}: [sync] edited elsewhere after completion${summary ? ` (${summary})` : ''}`;
|
|
280
|
+
let content = fs.readFileSync(archived, 'utf-8');
|
|
281
|
+
if (/^## Log\s*$/m.test(content)) {
|
|
282
|
+
content = `${content.replace(/\s+$/, '')}\n${entryLine}\n`;
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
content = `${content.replace(/\s+$/, '')}\n\n## Log\n${entryLine}\n`;
|
|
286
|
+
}
|
|
287
|
+
fs.writeFileSync(archived, content, 'utf-8');
|
|
288
|
+
(0, board_repo_1.git)(['add', '--', path.relative(dotDir, archived)], dotDir);
|
|
289
|
+
}
|
|
290
|
+
if ((0, board_repo_1.git)(['rm', '--quiet', '--cached', '--', file], dotDir).ok) {
|
|
291
|
+
try {
|
|
292
|
+
fs.rmSync(path.join(dotDir, file), { force: true });
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
/* already gone */
|
|
296
|
+
}
|
|
297
|
+
resolved.push(file);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return resolved;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* fetch → fast-forward or merge → push. Runs entirely inside the board
|
|
304
|
+
* directory. Never throws; network failures come back as `warning`.
|
|
305
|
+
*/
|
|
306
|
+
function syncBoard(dotDir, options = {}) {
|
|
307
|
+
const pull = options.pull ?? true;
|
|
308
|
+
const push = options.push ?? true;
|
|
309
|
+
const result = { ok: true, pulled: 0, pushed: 0, conflicts: [] };
|
|
310
|
+
if (!(0, board_repo_1.isTrackedBoard)(dotDir))
|
|
311
|
+
return { ...result, skipped: 'not-tracked' };
|
|
312
|
+
const remote = boardRemote(dotDir);
|
|
313
|
+
if (!remote)
|
|
314
|
+
return { ...result, skipped: 'no-remote' };
|
|
315
|
+
const remoteBranch = boardRemoteBranch(dotDir);
|
|
316
|
+
result.remote = remote;
|
|
317
|
+
result.remoteBranch = remoteBranch;
|
|
318
|
+
// Never sync a board that is mid-merge: a human owns it until it is clean.
|
|
319
|
+
const stuck = (0, board_repo_1.unmergedFiles)(dotDir);
|
|
320
|
+
if (stuck.length > 0) {
|
|
321
|
+
return finish(dotDir, { ...result, ok: false, failure: 'conflict', conflicts: stuck, warning: `unresolved conflicts: ${stuck.join(', ')}` });
|
|
322
|
+
}
|
|
323
|
+
(0, board_repo_1.commitHandEdits)(dotDir);
|
|
324
|
+
if (ensureBoardAttributes(dotDir))
|
|
325
|
+
(0, board_repo_1.commitBoard)(dotDir, { message: 'chore: merge attributes' });
|
|
326
|
+
registerMergeDriver(dotDir);
|
|
327
|
+
let fetched = false;
|
|
328
|
+
if (pull) {
|
|
329
|
+
const fetch = (0, board_repo_1.git)(['fetch', '--quiet', remote, remoteBranch], dotDir);
|
|
330
|
+
if (fetch.ok) {
|
|
331
|
+
fetched = true;
|
|
332
|
+
}
|
|
333
|
+
else if (!isMissingRemoteRef(fetch.stderr)) {
|
|
334
|
+
return finish(dotDir, { ...result, ok: false, failure: 'offline', warning: `fetch from ${remote} failed: ${firstLine(fetch.stderr)}` });
|
|
335
|
+
}
|
|
336
|
+
if (fetched && !(0, board_repo_1.git)(['merge-base', '--is-ancestor', 'FETCH_HEAD', 'HEAD'], dotDir).ok) {
|
|
337
|
+
const before = (0, board_repo_1.git)(['rev-parse', 'HEAD'], dotDir).stdout;
|
|
338
|
+
const id = identity(dotDir, options.agent);
|
|
339
|
+
const merge = (0, board_repo_1.git)([...id.args, 'merge', '--quiet', '--no-edit', 'FETCH_HEAD'], dotDir, id.env);
|
|
340
|
+
if (!merge.ok) {
|
|
341
|
+
resolveCompleteVersusEdit(dotDir);
|
|
342
|
+
const remaining = (0, board_repo_1.unmergedFiles)(dotDir);
|
|
343
|
+
if (remaining.length > 0) {
|
|
344
|
+
return finish(dotDir, {
|
|
345
|
+
...result,
|
|
346
|
+
ok: false,
|
|
347
|
+
failure: 'conflict',
|
|
348
|
+
conflicts: remaining,
|
|
349
|
+
warning: `merge left conflicts in ${remaining.join(', ')} — resolve them in ${dotDir}, then run sync again`,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
const commit = (0, board_repo_1.git)([...id.args, 'commit', '--quiet', '--no-edit', '--no-verify'], dotDir, id.env);
|
|
353
|
+
if (!commit.ok) {
|
|
354
|
+
return finish(dotDir, { ...result, ok: false, failure: 'error', warning: `merge commit failed: ${firstLine(commit.stderr)}` });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// Count what came from the remote rather than our own merge commit.
|
|
358
|
+
result.pulled = commitCount(dotDir, `${before}..FETCH_HEAD`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (push) {
|
|
362
|
+
const ahead = fetched ? commitCount(dotDir, 'FETCH_HEAD..HEAD') : pendingChanges(dotDir);
|
|
363
|
+
if (ahead > 0) {
|
|
364
|
+
const pushed = (0, board_repo_1.git)(['push', '--quiet', remote, `HEAD:refs/heads/${remoteBranch}`], dotDir);
|
|
365
|
+
if (!pushed.ok) {
|
|
366
|
+
const rejected = /rejected|non-fast-forward|fetch first/i.test(pushed.stderr);
|
|
367
|
+
return finish(dotDir, {
|
|
368
|
+
...result,
|
|
369
|
+
ok: false,
|
|
370
|
+
failure: rejected ? 'rejected' : 'offline',
|
|
371
|
+
warning: rejected
|
|
372
|
+
? `push to ${remote} rejected (the remote moved) — run sync again`
|
|
373
|
+
: `push to ${remote} failed: ${firstLine(pushed.stderr)}`,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
result.pushed = ahead;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return finish(dotDir, result);
|
|
380
|
+
}
|
|
381
|
+
function finish(dotDir, result) {
|
|
382
|
+
writeSyncState(dotDir, {
|
|
383
|
+
at: new Date().toISOString(),
|
|
384
|
+
remote: result.remote ?? '',
|
|
385
|
+
remoteBranch: result.remoteBranch ?? '',
|
|
386
|
+
ok: result.ok,
|
|
387
|
+
...(result.warning ? { warning: result.warning } : {}),
|
|
388
|
+
});
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
/** Seconds since the last recorded sync attempt, or null when there was none. */
|
|
392
|
+
function secondsSinceSync(dotDir, now = Date.now()) {
|
|
393
|
+
const state = readSyncState(dotDir);
|
|
394
|
+
if (!state)
|
|
395
|
+
return null;
|
|
396
|
+
const at = Date.parse(state.at);
|
|
397
|
+
return Number.isNaN(at) ? null : Math.max(0, Math.round((now - at) / 1000));
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Short status for a header: `synced 12s ago`, `local only` for a tracked
|
|
401
|
+
* board nobody else has, `not synced · saved locally` after a failure. Null
|
|
402
|
+
* for a plain board.
|
|
403
|
+
*/
|
|
404
|
+
function syncStatusLabel(dotDir, now = Date.now()) {
|
|
405
|
+
if (!(0, board_repo_1.isTrackedBoard)(dotDir))
|
|
406
|
+
return null;
|
|
407
|
+
if (!boardRemote(dotDir))
|
|
408
|
+
return 'local only';
|
|
409
|
+
const state = readSyncState(dotDir);
|
|
410
|
+
if (!state)
|
|
411
|
+
return 'not synced yet';
|
|
412
|
+
if (!state.ok)
|
|
413
|
+
return 'not synced · saved locally';
|
|
414
|
+
const seconds = secondsSinceSync(dotDir, now) ?? 0;
|
|
415
|
+
const age = seconds < 60 ? `${seconds}s` : seconds < 3600 ? `${Math.round(seconds / 60)}m` : `${Math.round(seconds / 3600)}h`;
|
|
416
|
+
return `synced ${age} ago`;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Commits on this machine the remote has not seen yet, judged against the
|
|
420
|
+
* last-known remote position (no network). Null when the board is not shared.
|
|
421
|
+
*/
|
|
422
|
+
function pendingChanges(dotDir) {
|
|
423
|
+
const remote = boardRemote(dotDir);
|
|
424
|
+
if (!remote)
|
|
425
|
+
return 0;
|
|
426
|
+
const tracking = `refs/remotes/${remote}/${boardRemoteBranch(dotDir)}`;
|
|
427
|
+
const known = (0, board_repo_1.git)(['rev-parse', '--verify', '--quiet', tracking], dotDir).ok;
|
|
428
|
+
return commitCount(dotDir, known ? `${tracking}..HEAD` : 'HEAD');
|
|
429
|
+
}
|
|
430
|
+
const plural = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`;
|
|
431
|
+
/**
|
|
432
|
+
* The one sentence a person needs after a sync: what moved, or why nothing
|
|
433
|
+
* did and that nothing was lost. `detail` is the technical cause, if any.
|
|
434
|
+
*/
|
|
435
|
+
function syncMessage(result) {
|
|
436
|
+
if (result.skipped === 'not-tracked') {
|
|
437
|
+
return { tone: 'warn', text: 'This board is plain files on this machine and is not shared. To share it: brainfile migrate --to-branch' };
|
|
438
|
+
}
|
|
439
|
+
if (result.skipped === 'no-remote') {
|
|
440
|
+
return { tone: 'warn', text: 'This board is only on this machine. To share it: brainfile sync --set-remote origin' };
|
|
441
|
+
}
|
|
442
|
+
const remote = result.remote ?? 'the remote';
|
|
443
|
+
if (!result.ok) {
|
|
444
|
+
switch (result.failure) {
|
|
445
|
+
case 'conflict':
|
|
446
|
+
return {
|
|
447
|
+
tone: 'warn',
|
|
448
|
+
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.`,
|
|
449
|
+
};
|
|
450
|
+
case 'rejected':
|
|
451
|
+
return { tone: 'warn', text: `Someone shared changes through ${remote} at the same moment. Run brainfile sync again to combine them. Nothing was lost.` };
|
|
452
|
+
case 'offline':
|
|
453
|
+
return {
|
|
454
|
+
tone: 'warn',
|
|
455
|
+
text: `Couldn't reach ${remote}. Nothing was lost: your changes are saved on this machine and will be sent on the next sync.`,
|
|
456
|
+
detail: result.warning,
|
|
457
|
+
};
|
|
458
|
+
default:
|
|
459
|
+
return { tone: 'warn', text: `Sync with ${remote} stopped. Your changes are saved on this machine.`, detail: result.warning };
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
const parts = [];
|
|
463
|
+
if (result.pulled > 0)
|
|
464
|
+
parts.push(`received ${plural(result.pulled, 'change')}`);
|
|
465
|
+
if (result.pushed > 0)
|
|
466
|
+
parts.push(`sent ${plural(result.pushed, 'change')}`);
|
|
467
|
+
return { tone: 'ok', text: parts.length ? `Shared through ${remote}: ${parts.join(', ')}.` : `Up to date with ${remote}.` };
|
|
468
|
+
}
|
|
469
|
+
//# sourceMappingURL=board-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"board-sync.js","sourceRoot":"","sources":["../../src/utils/board-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,19 @@
|
|
|
2
2
|
* Resolve a brainfile path for CLI commands.
|
|
3
3
|
*
|
|
4
4
|
* Supports three input forms:
|
|
5
|
-
* - Default (omitted): auto-discover from cwd upward
|
|
5
|
+
* - Default (omitted): auto-discover from cwd upward, stopping at the
|
|
6
|
+
* repository root; then, inside a repo, the worktree on the board branch
|
|
7
|
+
* (spec-9), creating it when the branch exists but has no checkout.
|
|
6
8
|
* - Directory path (`cli/`, `./projects/foo`): find brainfile inside that directory
|
|
7
9
|
* - File path (`path/to/brainfile.md`): use as-is
|
|
10
|
+
*
|
|
11
|
+
* `-g` / `--global` (or `BRAINFILE_GLOBAL=1`) targets the home board at
|
|
12
|
+
* `~/.brainfile` instead of discovering one.
|
|
8
13
|
*/
|
|
9
14
|
export declare function resolveCliBrainfilePath(filePath?: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* The `.brainfile/` directory a command will operate on, or null when there
|
|
17
|
+
* is no board (or resolution itself fails). Never throws.
|
|
18
|
+
*/
|
|
19
|
+
export declare function tryResolveBoardDir(filePath?: string): string | null;
|
|
10
20
|
//# sourceMappingURL=brainfile-path.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brainfile-path.d.ts","sourceRoot":"","sources":["../../src/utils/brainfile-path.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"brainfile-path.d.ts","sourceRoot":"","sources":["../../src/utils/brainfile-path.ts"],"names":[],"mappings":"AAmCA;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAkCjE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQnE"}
|
|
@@ -34,11 +34,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.resolveCliBrainfilePath = resolveCliBrainfilePath;
|
|
37
|
+
exports.tryResolveBoardDir = tryResolveBoardDir;
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
38
39
|
const path = __importStar(require("path"));
|
|
39
40
|
const core_1 = require("@brainfile/core");
|
|
40
41
|
const cli_error_1 = require("./cli-error");
|
|
41
42
|
const v2_only_1 = require("./v2-only");
|
|
43
|
+
const board_repo_1 = require("./board-repo");
|
|
42
44
|
function isMigrationCommand() {
|
|
43
45
|
return process.argv.includes('migrate');
|
|
44
46
|
}
|
|
@@ -55,15 +57,26 @@ function rejectLegacyRuntimePath(resolvedPath) {
|
|
|
55
57
|
}
|
|
56
58
|
return resolvedPath;
|
|
57
59
|
}
|
|
60
|
+
function isPlaceholder(filePath) {
|
|
61
|
+
return filePath === undefined || filePath === core_1.BRAINFILE_BASENAME || filePath === `./${core_1.BRAINFILE_BASENAME}`;
|
|
62
|
+
}
|
|
58
63
|
/**
|
|
59
64
|
* Resolve a brainfile path for CLI commands.
|
|
60
65
|
*
|
|
61
66
|
* Supports three input forms:
|
|
62
|
-
* - Default (omitted): auto-discover from cwd upward
|
|
67
|
+
* - Default (omitted): auto-discover from cwd upward, stopping at the
|
|
68
|
+
* repository root; then, inside a repo, the worktree on the board branch
|
|
69
|
+
* (spec-9), creating it when the branch exists but has no checkout.
|
|
63
70
|
* - Directory path (`cli/`, `./projects/foo`): find brainfile inside that directory
|
|
64
71
|
* - File path (`path/to/brainfile.md`): use as-is
|
|
72
|
+
*
|
|
73
|
+
* `-g` / `--global` (or `BRAINFILE_GLOBAL=1`) targets the home board at
|
|
74
|
+
* `~/.brainfile` instead of discovering one.
|
|
65
75
|
*/
|
|
66
76
|
function resolveCliBrainfilePath(filePath) {
|
|
77
|
+
if (isPlaceholder(filePath) && (0, board_repo_1.isGlobalBoardRequested)()) {
|
|
78
|
+
return rejectLegacyRuntimePath(path.join((0, board_repo_1.homeBoardDir)(), core_1.BRAINFILE_BASENAME));
|
|
79
|
+
}
|
|
67
80
|
// If a path was given and it's a directory, look for a brainfile inside it
|
|
68
81
|
if (filePath) {
|
|
69
82
|
const resolved = path.resolve(process.cwd(), filePath);
|
|
@@ -83,6 +96,30 @@ function resolveCliBrainfilePath(filePath) {
|
|
|
83
96
|
// Not a directory, fall through to normal resolution
|
|
84
97
|
}
|
|
85
98
|
}
|
|
86
|
-
|
|
99
|
+
const cwd = process.cwd();
|
|
100
|
+
if (isPlaceholder(filePath)) {
|
|
101
|
+
const found = (0, core_1.findBrainfile)(cwd, { stopAtGitRoot: true });
|
|
102
|
+
if (found)
|
|
103
|
+
return rejectLegacyRuntimePath(found.absolutePath);
|
|
104
|
+
const tracked = (0, board_repo_1.findTrackedBoardDir)(cwd) ?? (0, board_repo_1.materializeBoardWorktree)(cwd);
|
|
105
|
+
if (tracked)
|
|
106
|
+
return rejectLegacyRuntimePath(path.join(tracked, core_1.BRAINFILE_BASENAME));
|
|
107
|
+
}
|
|
108
|
+
return rejectLegacyRuntimePath((0, core_1.resolveBrainfilePath)({ filePath, startDir: cwd, stopAtGitRoot: true }));
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The `.brainfile/` directory a command will operate on, or null when there
|
|
112
|
+
* is no board (or resolution itself fails). Never throws.
|
|
113
|
+
*/
|
|
114
|
+
function tryResolveBoardDir(filePath) {
|
|
115
|
+
try {
|
|
116
|
+
const resolved = resolveCliBrainfilePath(filePath);
|
|
117
|
+
if (!fs.existsSync(resolved))
|
|
118
|
+
return null;
|
|
119
|
+
return path.dirname(resolved);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
87
124
|
}
|
|
88
125
|
//# sourceMappingURL=brainfile-path.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brainfile-path.js","sourceRoot":"","sources":["../../src/utils/brainfile-path.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"brainfile-path.js","sourceRoot":"","sources":["../../src/utils/brainfile-path.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,0DAkCC;AAMD,gDAQC;AAhGD,uCAAyB;AACzB,2CAA6B;AAC7B,0CAAgG;AAChG,2CAAuC;AACvC,uCAAmD;AACnD,6CAKsB;AAEtB,SAAS,kBAAkB;IACzB,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,oBAAoB,CAAC,aAAqB;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,YAAY;QAChE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3B,OAAO,gCAAgC,GAAG,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,uBAAuB,CAAC,YAAoB;IACnD,IAAI,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,IAAA,WAAI,EAAC,YAAY,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,oBAAQ,CAAC,gCAAsB,EAAE,SAAS,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,aAAa,CAAC,QAAiB;IACtC,OAAO,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,yBAAkB,IAAI,QAAQ,KAAK,KAAK,yBAAkB,EAAE,CAAC;AAC7G,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,uBAAuB,CAAC,QAAiB;IACvD,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,IAAA,mCAAsB,GAAE,EAAE,CAAC;QACxD,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAA,yBAAY,GAAE,EAAE,yBAAkB,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,2EAA2E;IAC3E,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;QACvD,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxC,oEAAoE;gBACpE,MAAM,KAAK,GAAG,IAAA,oBAAa,EAAC,QAAQ,CAAC,CAAC;gBACtC,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;oBAC5C,OAAO,uBAAuB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;gBACrD,CAAC;gBACD,mDAAmD;gBACnD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;gBACjE,OAAO,uBAAuB,CAAC,MAAM,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,IAAA,oBAAa,EAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,IAAI,KAAK;YAAE,OAAO,uBAAuB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAE9D,MAAM,OAAO,GAAG,IAAA,gCAAmB,EAAC,GAAG,CAAC,IAAI,IAAA,qCAAwB,EAAC,GAAG,CAAC,CAAC;QAC1E,IAAI,OAAO;YAAE,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAkB,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,OAAO,uBAAuB,CAAC,IAAA,2BAAoB,EAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACzG,CAAC;AAED;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,QAAiB;IAClD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -41,4 +41,24 @@ export declare function subtaskNotFound(subtaskId: string, availableSubtasks?: s
|
|
|
41
41
|
* Create a CLIError for validation errors.
|
|
42
42
|
*/
|
|
43
43
|
export declare function validationError(message: string): CLIError;
|
|
44
|
+
/**
|
|
45
|
+
* Renders a failure that escaped a command and exits.
|
|
46
|
+
*
|
|
47
|
+
* This is the CLI's outermost error boundary, wired to `program.parseAsync()`
|
|
48
|
+
* in cli.ts. Commands throw `CLIError` rather than exiting themselves, and
|
|
49
|
+
* nothing used to catch those throws — so a missing `--task` surfaced as
|
|
50
|
+
* Node's raw uncaught-exception stack trace instead of the message and usage
|
|
51
|
+
* hint the error already carried.
|
|
52
|
+
*
|
|
53
|
+
* Two branches, deliberately:
|
|
54
|
+
*
|
|
55
|
+
* - `CLIError` is an expected, user-facing failure: print the message and its
|
|
56
|
+
* usage `details`, exit with the code the error carries, and show no stack
|
|
57
|
+
* (a stack tells the user nothing about a missing flag).
|
|
58
|
+
* - Anything else is a genuine bug: print the real stack, unmodified, and
|
|
59
|
+
* exit 1. This is what Node already printed, just under our control so the
|
|
60
|
+
* exit code is deterministic rather than depending on Node's
|
|
61
|
+
* version-specific unhandled-rejection default.
|
|
62
|
+
*/
|
|
63
|
+
export declare function renderCliError(error: unknown): never;
|
|
44
64
|
//# sourceMappingURL=cli-error.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-error.d.ts","sourceRoot":"","sources":["../../src/utils/cli-error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli-error.d.ts","sourceRoot":"","sources":["../../src/utils/cli-error.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAC/B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,YAAkC,EAAE,OAAO,CAAC,EAAE,MAAM;CAM9F;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAMvD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAOrD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAMvE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAEvD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,QAAQ,CAOrF;AACD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAO,GAAG,QAAQ,CAMpF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,GAAE,MAAM,EAAO,GAAG,QAAQ,CAM7F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAEzD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAYpD"}
|