brainjar 0.3.709 → 0.3.713
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/brainjar.js +411 -118
- package/package.json +1 -1
package/brainjar.js
CHANGED
|
@@ -107,7 +107,7 @@ var CLI_VERSION, CACHE, DAY;
|
|
|
107
107
|
var init_version_check = __esm({
|
|
108
108
|
"packages/cli/src/version-check.ts"() {
|
|
109
109
|
"use strict";
|
|
110
|
-
CLI_VERSION = "0.3.
|
|
110
|
+
CLI_VERSION = "0.3.713";
|
|
111
111
|
CACHE = path.join(os.homedir(), ".brainjar", "version-check.json");
|
|
112
112
|
DAY = 864e5;
|
|
113
113
|
}
|
|
@@ -238,8 +238,8 @@ var init_github = __esm({
|
|
|
238
238
|
if (this.opts.token) h.Authorization = `Bearer ${this.opts.token}`;
|
|
239
239
|
return h;
|
|
240
240
|
}
|
|
241
|
-
async *paginate(
|
|
242
|
-
let url = this.buildUrl(
|
|
241
|
+
async *paginate(path20, params) {
|
|
242
|
+
let url = this.buildUrl(path20, params);
|
|
243
243
|
while (url) {
|
|
244
244
|
const res = await this.fetchImpl(url, { headers: this.headers() });
|
|
245
245
|
if (!res.ok) {
|
|
@@ -250,9 +250,9 @@ var init_github = __esm({
|
|
|
250
250
|
url = parseNextLink(res.headers.get("link"));
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
|
-
buildUrl(
|
|
253
|
+
buildUrl(path20, params) {
|
|
254
254
|
const url = new URL(
|
|
255
|
-
`${this.baseUrl}/repos/${this.opts.owner}/${this.opts.repo}${
|
|
255
|
+
`${this.baseUrl}/repos/${this.opts.owner}/${this.opts.repo}${path20}`
|
|
256
256
|
);
|
|
257
257
|
url.searchParams.set("per_page", String(this.perPage));
|
|
258
258
|
for (const [k, v] of Object.entries(params)) {
|
|
@@ -3735,7 +3735,7 @@ var require_split2 = __commonJS({
|
|
|
3735
3735
|
var require_helper = __commonJS({
|
|
3736
3736
|
"node_modules/pgpass/lib/helper.js"(exports, module) {
|
|
3737
3737
|
"use strict";
|
|
3738
|
-
var
|
|
3738
|
+
var path20 = __require("path");
|
|
3739
3739
|
var Stream2 = __require("stream").Stream;
|
|
3740
3740
|
var split = require_split2();
|
|
3741
3741
|
var util = __require("util");
|
|
@@ -3774,7 +3774,7 @@ var require_helper = __commonJS({
|
|
|
3774
3774
|
};
|
|
3775
3775
|
module.exports.getFileName = function(rawEnv) {
|
|
3776
3776
|
var env = rawEnv || process.env;
|
|
3777
|
-
var file = env.PGPASSFILE || (isWin ?
|
|
3777
|
+
var file = env.PGPASSFILE || (isWin ? path20.join(env.APPDATA || "./", "postgresql", "pgpass.conf") : path20.join(env.HOME || "./", ".pgpass"));
|
|
3778
3778
|
return file;
|
|
3779
3779
|
};
|
|
3780
3780
|
module.exports.usePgPass = function(stats, fname) {
|
|
@@ -3906,7 +3906,7 @@ var require_helper = __commonJS({
|
|
|
3906
3906
|
var require_lib = __commonJS({
|
|
3907
3907
|
"node_modules/pgpass/lib/index.js"(exports, module) {
|
|
3908
3908
|
"use strict";
|
|
3909
|
-
var
|
|
3909
|
+
var path20 = __require("path");
|
|
3910
3910
|
var fs = __require("fs");
|
|
3911
3911
|
var helper = require_helper();
|
|
3912
3912
|
module.exports = function(connInfo, cb) {
|
|
@@ -4587,7 +4587,7 @@ var require_pg_pool = __commonJS({
|
|
|
4587
4587
|
function throwOnDoubleRelease() {
|
|
4588
4588
|
throw new Error("Release called on client which has already been released to the pool.");
|
|
4589
4589
|
}
|
|
4590
|
-
function
|
|
4590
|
+
function promisify7(Promise2, callback) {
|
|
4591
4591
|
if (callback) {
|
|
4592
4592
|
return { callback, result: void 0 };
|
|
4593
4593
|
}
|
|
@@ -4725,7 +4725,7 @@ var require_pg_pool = __commonJS({
|
|
|
4725
4725
|
const err = new Error("Cannot use a pool after calling end on the pool");
|
|
4726
4726
|
return cb ? cb(err) : this.Promise.reject(err);
|
|
4727
4727
|
}
|
|
4728
|
-
const response =
|
|
4728
|
+
const response = promisify7(this.Promise, cb);
|
|
4729
4729
|
const result = response.result;
|
|
4730
4730
|
if (this._isFull() || this._idle.length) {
|
|
4731
4731
|
if (this._idle.length) {
|
|
@@ -4910,7 +4910,7 @@ var require_pg_pool = __commonJS({
|
|
|
4910
4910
|
}
|
|
4911
4911
|
query(text, values, cb) {
|
|
4912
4912
|
if (typeof text === "function") {
|
|
4913
|
-
const response2 =
|
|
4913
|
+
const response2 = promisify7(this.Promise, text);
|
|
4914
4914
|
setImmediate(function() {
|
|
4915
4915
|
return response2.callback(new Error("Passing a function as the first parameter to pool.query is not supported"));
|
|
4916
4916
|
});
|
|
@@ -4920,7 +4920,7 @@ var require_pg_pool = __commonJS({
|
|
|
4920
4920
|
cb = values;
|
|
4921
4921
|
values = void 0;
|
|
4922
4922
|
}
|
|
4923
|
-
const response =
|
|
4923
|
+
const response = promisify7(this.Promise, cb);
|
|
4924
4924
|
cb = response.callback;
|
|
4925
4925
|
this.connect((err, client) => {
|
|
4926
4926
|
if (err) {
|
|
@@ -4965,7 +4965,7 @@ var require_pg_pool = __commonJS({
|
|
|
4965
4965
|
return cb ? cb(err) : this.Promise.reject(err);
|
|
4966
4966
|
}
|
|
4967
4967
|
this.ending = true;
|
|
4968
|
-
const promised =
|
|
4968
|
+
const promised = promisify7(this.Promise, cb);
|
|
4969
4969
|
this._endCallback = promised.callback;
|
|
4970
4970
|
this._pulseQueue();
|
|
4971
4971
|
return promised.result;
|
|
@@ -8852,12 +8852,12 @@ var init_path = __esm({
|
|
|
8852
8852
|
"node_modules/@anthropic-ai/sdk/internal/utils/path.mjs"() {
|
|
8853
8853
|
init_error();
|
|
8854
8854
|
EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
8855
|
-
createPathTagFunction = (pathEncoder = encodeURIPath) => function
|
|
8855
|
+
createPathTagFunction = (pathEncoder = encodeURIPath) => function path20(statics, ...params) {
|
|
8856
8856
|
if (statics.length === 1)
|
|
8857
8857
|
return statics[0];
|
|
8858
8858
|
let postPath = false;
|
|
8859
8859
|
const invalidSegments = [];
|
|
8860
|
-
const
|
|
8860
|
+
const path21 = statics.reduce((previousValue, currentValue, index) => {
|
|
8861
8861
|
if (/[?#]/.test(currentValue)) {
|
|
8862
8862
|
postPath = true;
|
|
8863
8863
|
}
|
|
@@ -8874,7 +8874,7 @@ var init_path = __esm({
|
|
|
8874
8874
|
}
|
|
8875
8875
|
return previousValue + currentValue + (index === params.length ? "" : encoded);
|
|
8876
8876
|
}, "");
|
|
8877
|
-
const pathOnly =
|
|
8877
|
+
const pathOnly = path21.split(/[?#]/, 1)[0];
|
|
8878
8878
|
const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
|
|
8879
8879
|
let match;
|
|
8880
8880
|
while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
|
|
@@ -8895,10 +8895,10 @@ var init_path = __esm({
|
|
|
8895
8895
|
}, "");
|
|
8896
8896
|
throw new AnthropicError(`Path parameters result in path with invalid segments:
|
|
8897
8897
|
${invalidSegments.map((e) => e.error).join("\n")}
|
|
8898
|
-
${
|
|
8898
|
+
${path21}
|
|
8899
8899
|
${underline}`);
|
|
8900
8900
|
}
|
|
8901
|
-
return
|
|
8901
|
+
return path21;
|
|
8902
8902
|
};
|
|
8903
8903
|
path3 = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
|
|
8904
8904
|
}
|
|
@@ -11884,9 +11884,9 @@ var init_client = __esm({
|
|
|
11884
11884
|
makeStatusError(status, error, message, headers) {
|
|
11885
11885
|
return APIError.generate(status, error, message, headers);
|
|
11886
11886
|
}
|
|
11887
|
-
buildURL(
|
|
11887
|
+
buildURL(path20, query, defaultBaseURL) {
|
|
11888
11888
|
const baseURL = !__classPrivateFieldGet(this, _BaseAnthropic_instances, "m", _BaseAnthropic_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
|
|
11889
|
-
const url = isAbsoluteURL(
|
|
11889
|
+
const url = isAbsoluteURL(path20) ? new URL(path20) : new URL(baseURL + (baseURL.endsWith("/") && path20.startsWith("/") ? path20.slice(1) : path20));
|
|
11890
11890
|
const defaultQuery = this.defaultQuery();
|
|
11891
11891
|
if (!isEmptyObj(defaultQuery)) {
|
|
11892
11892
|
query = { ...defaultQuery, ...query };
|
|
@@ -11917,24 +11917,24 @@ var init_client = __esm({
|
|
|
11917
11917
|
*/
|
|
11918
11918
|
async prepareRequest(request, { url, options }) {
|
|
11919
11919
|
}
|
|
11920
|
-
get(
|
|
11921
|
-
return this.methodRequest("get",
|
|
11920
|
+
get(path20, opts) {
|
|
11921
|
+
return this.methodRequest("get", path20, opts);
|
|
11922
11922
|
}
|
|
11923
|
-
post(
|
|
11924
|
-
return this.methodRequest("post",
|
|
11923
|
+
post(path20, opts) {
|
|
11924
|
+
return this.methodRequest("post", path20, opts);
|
|
11925
11925
|
}
|
|
11926
|
-
patch(
|
|
11927
|
-
return this.methodRequest("patch",
|
|
11926
|
+
patch(path20, opts) {
|
|
11927
|
+
return this.methodRequest("patch", path20, opts);
|
|
11928
11928
|
}
|
|
11929
|
-
put(
|
|
11930
|
-
return this.methodRequest("put",
|
|
11929
|
+
put(path20, opts) {
|
|
11930
|
+
return this.methodRequest("put", path20, opts);
|
|
11931
11931
|
}
|
|
11932
|
-
delete(
|
|
11933
|
-
return this.methodRequest("delete",
|
|
11932
|
+
delete(path20, opts) {
|
|
11933
|
+
return this.methodRequest("delete", path20, opts);
|
|
11934
11934
|
}
|
|
11935
|
-
methodRequest(method,
|
|
11935
|
+
methodRequest(method, path20, opts) {
|
|
11936
11936
|
return this.request(Promise.resolve(opts).then((opts2) => {
|
|
11937
|
-
return { method, path:
|
|
11937
|
+
return { method, path: path20, ...opts2 };
|
|
11938
11938
|
}));
|
|
11939
11939
|
}
|
|
11940
11940
|
request(options, remainingRetries = null) {
|
|
@@ -12038,8 +12038,8 @@ var init_client = __esm({
|
|
|
12038
12038
|
}));
|
|
12039
12039
|
return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
|
|
12040
12040
|
}
|
|
12041
|
-
getAPIList(
|
|
12042
|
-
return this.requestAPIList(Page2, { method: "get", path:
|
|
12041
|
+
getAPIList(path20, Page2, opts) {
|
|
12042
|
+
return this.requestAPIList(Page2, { method: "get", path: path20, ...opts });
|
|
12043
12043
|
}
|
|
12044
12044
|
requestAPIList(Page2, options) {
|
|
12045
12045
|
const request = this.makeRequest(options, null, void 0);
|
|
@@ -12126,8 +12126,8 @@ var init_client = __esm({
|
|
|
12126
12126
|
}
|
|
12127
12127
|
async buildRequest(inputOptions, { retryCount = 0 } = {}) {
|
|
12128
12128
|
const options = { ...inputOptions };
|
|
12129
|
-
const { method, path:
|
|
12130
|
-
const url = this.buildURL(
|
|
12129
|
+
const { method, path: path20, query, defaultBaseURL } = options;
|
|
12130
|
+
const url = this.buildURL(path20, query, defaultBaseURL);
|
|
12131
12131
|
if ("timeout" in options)
|
|
12132
12132
|
validatePositiveInteger("timeout", options.timeout);
|
|
12133
12133
|
options.timeout = options.timeout ?? this.timeout;
|
|
@@ -13511,10 +13511,242 @@ exec ${captureHookCommand(subcommand)}${flag}
|
|
|
13511
13511
|
}
|
|
13512
13512
|
});
|
|
13513
13513
|
|
|
13514
|
-
// packages/ingest/src/
|
|
13515
|
-
import {
|
|
13514
|
+
// packages/ingest/src/mcp-config.ts
|
|
13515
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
13516
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11, realpathSync } from "node:fs";
|
|
13517
|
+
import { mkdir as mkdir9, writeFile as writeFile9 } from "node:fs/promises";
|
|
13516
13518
|
import os4 from "node:os";
|
|
13517
13519
|
import path13 from "node:path";
|
|
13520
|
+
import { promisify as promisify3 } from "node:util";
|
|
13521
|
+
function brainOf(url) {
|
|
13522
|
+
try {
|
|
13523
|
+
return new URL(url).searchParams.get("brain");
|
|
13524
|
+
} catch {
|
|
13525
|
+
return null;
|
|
13526
|
+
}
|
|
13527
|
+
}
|
|
13528
|
+
function readJson(file) {
|
|
13529
|
+
if (!existsSync10(file)) return null;
|
|
13530
|
+
try {
|
|
13531
|
+
return JSON.parse(readFileSync11(file, "utf8"));
|
|
13532
|
+
} catch {
|
|
13533
|
+
throw new Error(`${file} is not valid JSON`);
|
|
13534
|
+
}
|
|
13535
|
+
}
|
|
13536
|
+
function urlIn(entry) {
|
|
13537
|
+
const e = entry;
|
|
13538
|
+
if (typeof e?.url === "string") return e.url;
|
|
13539
|
+
if (typeof e?.httpUrl === "string") return e.httpUrl;
|
|
13540
|
+
return null;
|
|
13541
|
+
}
|
|
13542
|
+
function jsonMcp(file, top, signIn, entry) {
|
|
13543
|
+
const servers = (cfg) => cfg[top];
|
|
13544
|
+
return {
|
|
13545
|
+
where: file,
|
|
13546
|
+
signIn,
|
|
13547
|
+
url: (root) => {
|
|
13548
|
+
try {
|
|
13549
|
+
return urlIn(
|
|
13550
|
+
servers(readJson(path13.join(root, file)) ?? {})?.[MCP_NAME]
|
|
13551
|
+
);
|
|
13552
|
+
} catch {
|
|
13553
|
+
return null;
|
|
13554
|
+
}
|
|
13555
|
+
},
|
|
13556
|
+
install: async (root, url) => {
|
|
13557
|
+
const f = path13.join(root, file);
|
|
13558
|
+
const cfg = readJson(f) ?? {};
|
|
13559
|
+
const all = cfg[top] ??= {};
|
|
13560
|
+
const before = JSON.stringify(all[MCP_NAME] ?? null);
|
|
13561
|
+
all[MCP_NAME] = { ...all[MCP_NAME], ...entry(url) };
|
|
13562
|
+
if (JSON.stringify(all[MCP_NAME]) === before) return false;
|
|
13563
|
+
await mkdir9(path13.dirname(f), { recursive: true });
|
|
13564
|
+
await writeFile9(f, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
13565
|
+
return true;
|
|
13566
|
+
},
|
|
13567
|
+
remove: async (root) => {
|
|
13568
|
+
const f = path13.join(root, file);
|
|
13569
|
+
const cfg = readJson(f);
|
|
13570
|
+
const all = cfg && servers(cfg);
|
|
13571
|
+
if (!cfg || !all || !(MCP_NAME in all)) return false;
|
|
13572
|
+
delete all[MCP_NAME];
|
|
13573
|
+
if (Object.keys(all).length === 0) delete cfg[top];
|
|
13574
|
+
await writeFile9(f, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
13575
|
+
return true;
|
|
13576
|
+
}
|
|
13577
|
+
};
|
|
13578
|
+
}
|
|
13579
|
+
function codexSection(lines) {
|
|
13580
|
+
const start = lines.findIndex((l) => l.trim() === CODEX_HEADER);
|
|
13581
|
+
if (start < 0) return null;
|
|
13582
|
+
let end = start + 1;
|
|
13583
|
+
while (end < lines.length && !lines[end].trim().startsWith("[")) end++;
|
|
13584
|
+
return [start + 1, end];
|
|
13585
|
+
}
|
|
13586
|
+
function claudeConfigFile() {
|
|
13587
|
+
return path13.join(
|
|
13588
|
+
process.env.CLAUDE_CONFIG_DIR?.trim() || os4.homedir(),
|
|
13589
|
+
".claude.json"
|
|
13590
|
+
);
|
|
13591
|
+
}
|
|
13592
|
+
function claudeLocalUrl(root) {
|
|
13593
|
+
try {
|
|
13594
|
+
const cfg = readJson(claudeConfigFile());
|
|
13595
|
+
const projects = cfg?.projects;
|
|
13596
|
+
const p = projects?.[root] ?? projects?.[path13.resolve(root)] ?? projects?.[realpathSync(root)];
|
|
13597
|
+
return urlIn(p?.mcpServers?.[MCP_NAME]);
|
|
13598
|
+
} catch {
|
|
13599
|
+
return null;
|
|
13600
|
+
}
|
|
13601
|
+
}
|
|
13602
|
+
function claudeAddCommand(url) {
|
|
13603
|
+
return `claude mcp add --transport http ${MCP_NAME} '${url}'`;
|
|
13604
|
+
}
|
|
13605
|
+
var run3, MCP_NAME, cursorMcp, vscodeMcp, geminiMcp, kiroMcp, opencodeMcp, CODEX_FILE, CODEX_HEADER, codexMcp, claudeCli, claudeMcp;
|
|
13606
|
+
var init_mcp_config = __esm({
|
|
13607
|
+
"packages/ingest/src/mcp-config.ts"() {
|
|
13608
|
+
"use strict";
|
|
13609
|
+
run3 = promisify3(execFile3);
|
|
13610
|
+
MCP_NAME = "brainjar";
|
|
13611
|
+
cursorMcp = jsonMcp(
|
|
13612
|
+
path13.join(".cursor", "mcp.json"),
|
|
13613
|
+
"mcpServers",
|
|
13614
|
+
"Cursor Settings > MCP, sign in on brainjar",
|
|
13615
|
+
(url) => ({ url })
|
|
13616
|
+
);
|
|
13617
|
+
vscodeMcp = jsonMcp(
|
|
13618
|
+
path13.join(".vscode", "mcp.json"),
|
|
13619
|
+
"servers",
|
|
13620
|
+
"VS Code asks you to sign in when the server starts",
|
|
13621
|
+
(url) => ({ type: "http", url })
|
|
13622
|
+
);
|
|
13623
|
+
geminiMcp = jsonMcp(
|
|
13624
|
+
path13.join(".gemini", "settings.json"),
|
|
13625
|
+
"mcpServers",
|
|
13626
|
+
"Gemini opens the browser on first use, or /mcp auth brainjar",
|
|
13627
|
+
(url) => ({ httpUrl: url })
|
|
13628
|
+
);
|
|
13629
|
+
kiroMcp = jsonMcp(
|
|
13630
|
+
path13.join(".kiro", "settings", "mcp.json"),
|
|
13631
|
+
"mcpServers",
|
|
13632
|
+
"Kiro opens the browser on first use",
|
|
13633
|
+
(url) => ({ url })
|
|
13634
|
+
);
|
|
13635
|
+
opencodeMcp = jsonMcp(
|
|
13636
|
+
"opencode.json",
|
|
13637
|
+
"mcp",
|
|
13638
|
+
"run: opencode mcp auth brainjar",
|
|
13639
|
+
(url) => ({ type: "remote", url, enabled: true })
|
|
13640
|
+
);
|
|
13641
|
+
CODEX_FILE = path13.join(".codex", "config.toml");
|
|
13642
|
+
CODEX_HEADER = `[mcp_servers.${MCP_NAME}]`;
|
|
13643
|
+
codexMcp = {
|
|
13644
|
+
where: CODEX_FILE,
|
|
13645
|
+
signIn: "run: codex mcp login brainjar",
|
|
13646
|
+
url: (root) => {
|
|
13647
|
+
const f = path13.join(root, CODEX_FILE);
|
|
13648
|
+
if (!existsSync10(f)) return null;
|
|
13649
|
+
const lines = readFileSync11(f, "utf8").split("\n");
|
|
13650
|
+
const range = codexSection(lines);
|
|
13651
|
+
if (!range) return null;
|
|
13652
|
+
for (const l of lines.slice(...range)) {
|
|
13653
|
+
const m = /^\s*url\s*=\s*"([^"]*)"/.exec(l);
|
|
13654
|
+
if (m) return m[1];
|
|
13655
|
+
}
|
|
13656
|
+
return null;
|
|
13657
|
+
},
|
|
13658
|
+
install: async (root, url) => {
|
|
13659
|
+
const f = path13.join(root, CODEX_FILE);
|
|
13660
|
+
const text = existsSync10(f) ? readFileSync11(f, "utf8") : "";
|
|
13661
|
+
const lines = text.split("\n");
|
|
13662
|
+
const line = `url = "${url}"`;
|
|
13663
|
+
const range = codexSection(lines);
|
|
13664
|
+
let next;
|
|
13665
|
+
if (!range) {
|
|
13666
|
+
const body = text.length === 0 || text.endsWith("\n") ? text : text + "\n";
|
|
13667
|
+
next = `${body}${body ? "\n" : ""}${CODEX_HEADER}
|
|
13668
|
+
${line}
|
|
13669
|
+
`.split("\n");
|
|
13670
|
+
} else {
|
|
13671
|
+
const i = lines.findIndex(
|
|
13672
|
+
(l, n) => n >= range[0] && n < range[1] && /^\s*url\s*=/.test(l)
|
|
13673
|
+
);
|
|
13674
|
+
next = [...lines];
|
|
13675
|
+
if (i >= 0) next[i] = line;
|
|
13676
|
+
else next.splice(range[0], 0, line);
|
|
13677
|
+
}
|
|
13678
|
+
const out = next.join("\n");
|
|
13679
|
+
if (out === text) return false;
|
|
13680
|
+
await mkdir9(path13.dirname(f), { recursive: true });
|
|
13681
|
+
await writeFile9(f, out, "utf8");
|
|
13682
|
+
return true;
|
|
13683
|
+
},
|
|
13684
|
+
remove: async (root) => {
|
|
13685
|
+
const f = path13.join(root, CODEX_FILE);
|
|
13686
|
+
if (!existsSync10(f)) return false;
|
|
13687
|
+
const lines = readFileSync11(f, "utf8").split("\n");
|
|
13688
|
+
const ours3 = (l) => l.trim() === CODEX_HEADER || l.trim().startsWith(`[mcp_servers.${MCP_NAME}.`);
|
|
13689
|
+
const kept = [];
|
|
13690
|
+
let skipping = false;
|
|
13691
|
+
for (const l of lines) {
|
|
13692
|
+
if (l.trim().startsWith("[")) skipping = ours3(l);
|
|
13693
|
+
if (!skipping) kept.push(l);
|
|
13694
|
+
}
|
|
13695
|
+
if (kept.length === lines.length) return false;
|
|
13696
|
+
await writeFile9(f, kept.join("\n").replace(/\n{3,}/g, "\n\n"), "utf8");
|
|
13697
|
+
return true;
|
|
13698
|
+
}
|
|
13699
|
+
};
|
|
13700
|
+
claudeCli = (args, cwd) => run3("claude", args, {
|
|
13701
|
+
cwd,
|
|
13702
|
+
shell: process.platform === "win32",
|
|
13703
|
+
// claude.cmd
|
|
13704
|
+
windowsHide: true,
|
|
13705
|
+
timeout: 3e4
|
|
13706
|
+
});
|
|
13707
|
+
claudeMcp = {
|
|
13708
|
+
where: "Claude Code, this folder",
|
|
13709
|
+
signIn: "type /mcp in Claude Code and sign in",
|
|
13710
|
+
url: (root) => {
|
|
13711
|
+
const local = claudeLocalUrl(root);
|
|
13712
|
+
if (local) return local;
|
|
13713
|
+
try {
|
|
13714
|
+
const project = readJson(path13.join(root, ".mcp.json"));
|
|
13715
|
+
const fromProject = urlIn(
|
|
13716
|
+
project?.mcpServers?.[MCP_NAME]
|
|
13717
|
+
);
|
|
13718
|
+
if (fromProject) return fromProject;
|
|
13719
|
+
const user = readJson(claudeConfigFile());
|
|
13720
|
+
return urlIn(user?.mcpServers?.[MCP_NAME]);
|
|
13721
|
+
} catch {
|
|
13722
|
+
return null;
|
|
13723
|
+
}
|
|
13724
|
+
},
|
|
13725
|
+
install: async (root, url) => {
|
|
13726
|
+
if (claudeLocalUrl(root) === url) return false;
|
|
13727
|
+
await claudeCli(["mcp", "remove", "-s", "local", MCP_NAME], root).catch(
|
|
13728
|
+
() => {
|
|
13729
|
+
}
|
|
13730
|
+
);
|
|
13731
|
+
await claudeCli(
|
|
13732
|
+
["mcp", "add", "-s", "local", "--transport", "http", MCP_NAME, url],
|
|
13733
|
+
root
|
|
13734
|
+
);
|
|
13735
|
+
return true;
|
|
13736
|
+
},
|
|
13737
|
+
remove: async (root) => {
|
|
13738
|
+
if (!claudeLocalUrl(root)) return false;
|
|
13739
|
+
await claudeCli(["mcp", "remove", "-s", "local", MCP_NAME], root);
|
|
13740
|
+
return true;
|
|
13741
|
+
}
|
|
13742
|
+
};
|
|
13743
|
+
}
|
|
13744
|
+
});
|
|
13745
|
+
|
|
13746
|
+
// packages/ingest/src/tools.ts
|
|
13747
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
13748
|
+
import os5 from "node:os";
|
|
13749
|
+
import path14 from "node:path";
|
|
13518
13750
|
function detectedTools(root) {
|
|
13519
13751
|
return CAPTURE_TOOLS.filter((t) => t.detect(root));
|
|
13520
13752
|
}
|
|
@@ -13530,66 +13762,74 @@ var init_tools = __esm({
|
|
|
13530
13762
|
init_kiro_hooks();
|
|
13531
13763
|
init_opencode_plugin();
|
|
13532
13764
|
init_cline_hooks();
|
|
13765
|
+
init_mcp_config();
|
|
13533
13766
|
claudeCode = {
|
|
13534
13767
|
id: "claude-code",
|
|
13535
13768
|
name: "Claude Code",
|
|
13536
|
-
detect: (root) =>
|
|
13769
|
+
detect: (root) => existsSync11(path14.join(os5.homedir(), ".claude")) || existsSync11(path14.join(root, ".claude")),
|
|
13537
13770
|
install: installCaptureHook,
|
|
13538
13771
|
installed: captureHookInstalled,
|
|
13539
|
-
remove: removeCaptureHook
|
|
13772
|
+
remove: removeCaptureHook,
|
|
13773
|
+
mcp: claudeMcp
|
|
13540
13774
|
};
|
|
13541
13775
|
cursor = {
|
|
13542
13776
|
id: "cursor",
|
|
13543
13777
|
name: "Cursor",
|
|
13544
|
-
detect: (root) =>
|
|
13778
|
+
detect: (root) => existsSync11(path14.join(os5.homedir(), ".cursor")) || existsSync11(path14.join(root, ".cursor")),
|
|
13545
13779
|
install: installCursorHooks,
|
|
13546
13780
|
installed: cursorHooksInstalled,
|
|
13547
|
-
remove: removeCursorHooks
|
|
13781
|
+
remove: removeCursorHooks,
|
|
13782
|
+
mcp: cursorMcp
|
|
13548
13783
|
};
|
|
13549
13784
|
codex = {
|
|
13550
13785
|
id: "codex",
|
|
13551
13786
|
name: "Codex",
|
|
13552
|
-
detect: (root) =>
|
|
13787
|
+
detect: (root) => existsSync11(path14.join(os5.homedir(), ".codex")) || existsSync11(path14.join(root, ".codex")),
|
|
13553
13788
|
install: installCodexHooks,
|
|
13554
13789
|
installed: codexHooksInstalled,
|
|
13555
|
-
remove: removeCodexHooks
|
|
13790
|
+
remove: removeCodexHooks,
|
|
13791
|
+
mcp: codexMcp
|
|
13556
13792
|
};
|
|
13557
13793
|
copilot = {
|
|
13558
13794
|
id: "copilot",
|
|
13559
13795
|
name: "GitHub Copilot",
|
|
13560
|
-
detect: (root) =>
|
|
13796
|
+
detect: (root) => existsSync11(path14.join(os5.homedir(), ".copilot")) || existsSync11(path14.join(root, ".github", "hooks")),
|
|
13561
13797
|
install: installCopilotHooks,
|
|
13562
13798
|
installed: copilotHooksInstalled,
|
|
13563
|
-
remove: removeCopilotHooks
|
|
13799
|
+
remove: removeCopilotHooks,
|
|
13800
|
+
mcp: vscodeMcp
|
|
13564
13801
|
};
|
|
13565
13802
|
gemini = {
|
|
13566
13803
|
id: "gemini",
|
|
13567
13804
|
name: "Gemini CLI",
|
|
13568
|
-
detect: (root) =>
|
|
13805
|
+
detect: (root) => existsSync11(path14.join(os5.homedir(), ".gemini")) || existsSync11(path14.join(root, ".gemini")),
|
|
13569
13806
|
install: installGeminiHooks,
|
|
13570
13807
|
installed: geminiHooksInstalled,
|
|
13571
|
-
remove: removeGeminiHooks
|
|
13808
|
+
remove: removeGeminiHooks,
|
|
13809
|
+
mcp: geminiMcp
|
|
13572
13810
|
};
|
|
13573
13811
|
kiro = {
|
|
13574
13812
|
id: "kiro",
|
|
13575
13813
|
name: "Kiro",
|
|
13576
|
-
detect: (root) =>
|
|
13814
|
+
detect: (root) => existsSync11(path14.join(os5.homedir(), ".kiro")) || existsSync11(path14.join(root, ".kiro")),
|
|
13577
13815
|
install: installKiroHooks,
|
|
13578
13816
|
installed: kiroHooksInstalled,
|
|
13579
|
-
remove: removeKiroHooks
|
|
13817
|
+
remove: removeKiroHooks,
|
|
13818
|
+
mcp: kiroMcp
|
|
13580
13819
|
};
|
|
13581
13820
|
opencode = {
|
|
13582
13821
|
id: "opencode",
|
|
13583
13822
|
name: "OpenCode",
|
|
13584
|
-
detect: (root) =>
|
|
13823
|
+
detect: (root) => existsSync11(path14.join(os5.homedir(), ".config", "opencode")) || existsSync11(path14.join(root, ".opencode")),
|
|
13585
13824
|
install: installOpencodePlugin,
|
|
13586
13825
|
installed: opencodePluginInstalled,
|
|
13587
|
-
remove: removeOpencodePlugin
|
|
13826
|
+
remove: removeOpencodePlugin,
|
|
13827
|
+
mcp: opencodeMcp
|
|
13588
13828
|
};
|
|
13589
13829
|
cline = {
|
|
13590
13830
|
id: "cline",
|
|
13591
13831
|
name: "Cline",
|
|
13592
|
-
detect: (root) =>
|
|
13832
|
+
detect: (root) => existsSync11(path14.join(os5.homedir(), "Documents", "Cline")) || existsSync11(path14.join(os5.homedir(), ".cline")) || existsSync11(path14.join(root, ".clinerules")),
|
|
13593
13833
|
install: installClineHooks,
|
|
13594
13834
|
installed: clineHooksInstalled,
|
|
13595
13835
|
remove: removeClineHooks
|
|
@@ -14079,8 +14319,8 @@ var init_doku_model = __esm({
|
|
|
14079
14319
|
|
|
14080
14320
|
// packages/ingest/src/doku.ts
|
|
14081
14321
|
import { createHash as createHash2 } from "node:crypto";
|
|
14082
|
-
import { mkdir as
|
|
14083
|
-
import
|
|
14322
|
+
import { mkdir as mkdir10, readFile as readFile10, rm as rm6, stat, writeFile as writeFile10 } from "node:fs/promises";
|
|
14323
|
+
import path15 from "node:path";
|
|
14084
14324
|
function bodyLocations(o) {
|
|
14085
14325
|
return Array.isArray(o.body.location) ? o.body.location.map(String) : [];
|
|
14086
14326
|
}
|
|
@@ -14146,7 +14386,7 @@ async function loadDokuData(brainId, root) {
|
|
|
14146
14386
|
if (root) {
|
|
14147
14387
|
try {
|
|
14148
14388
|
const pkg = JSON.parse(
|
|
14149
|
-
await readFile10(
|
|
14389
|
+
await readFile10(path15.join(root, "package.json"), "utf8")
|
|
14150
14390
|
);
|
|
14151
14391
|
description = pkg.description ?? null;
|
|
14152
14392
|
scripts = pkg.scripts ?? null;
|
|
@@ -14729,8 +14969,8 @@ function dokuFilePath(kind, slug) {
|
|
|
14729
14969
|
return `${DOKU_DIR}/${slug}.md`;
|
|
14730
14970
|
}
|
|
14731
14971
|
async function writeDokuTree(root, files) {
|
|
14732
|
-
const dir =
|
|
14733
|
-
const manifestPath =
|
|
14972
|
+
const dir = path15.join(root, DOKU_DIR);
|
|
14973
|
+
const manifestPath = path15.join(dir, MANIFEST);
|
|
14734
14974
|
let old = { files: {} };
|
|
14735
14975
|
try {
|
|
14736
14976
|
old = JSON.parse(await readFile10(manifestPath, "utf8"));
|
|
@@ -14743,21 +14983,21 @@ async function writeDokuTree(root, files) {
|
|
|
14743
14983
|
for (const file of files) {
|
|
14744
14984
|
const hash = sha1(file.markdown);
|
|
14745
14985
|
next[file.relPath] = { hash };
|
|
14746
|
-
const abs =
|
|
14986
|
+
const abs = path15.join(root, file.relPath);
|
|
14747
14987
|
if (old.files[file.relPath]?.hash === hash && await exists(abs)) continue;
|
|
14748
|
-
await
|
|
14749
|
-
await
|
|
14988
|
+
await mkdir10(path15.dirname(abs), { recursive: true });
|
|
14989
|
+
await writeFile10(abs, file.markdown, "utf8");
|
|
14750
14990
|
written++;
|
|
14751
14991
|
}
|
|
14752
14992
|
let deleted = 0;
|
|
14753
14993
|
for (const rel of Object.keys(old.files)) {
|
|
14754
14994
|
if (next[rel]) continue;
|
|
14755
14995
|
if (rel !== DOKU_FILENAME && !rel.startsWith(`${DOKU_DIR}/`)) continue;
|
|
14756
|
-
await rm6(
|
|
14996
|
+
await rm6(path15.join(root, rel), { force: true });
|
|
14757
14997
|
deleted++;
|
|
14758
14998
|
}
|
|
14759
|
-
await
|
|
14760
|
-
await
|
|
14999
|
+
await mkdir10(dir, { recursive: true });
|
|
15000
|
+
await writeFile10(
|
|
14761
15001
|
manifestPath,
|
|
14762
15002
|
JSON.stringify({ files: next }, null, 2),
|
|
14763
15003
|
"utf8"
|
|
@@ -14910,8 +15150,8 @@ var init_ponytail_brief = __esm({
|
|
|
14910
15150
|
});
|
|
14911
15151
|
|
|
14912
15152
|
// packages/ingest/src/ponytail-debt.ts
|
|
14913
|
-
function isDebtScannable(
|
|
14914
|
-
return !/\.(md|mdx|markdown|txt|jsonl|log|lock)$/i.test(
|
|
15153
|
+
function isDebtScannable(path20) {
|
|
15154
|
+
return !/\.(md|mdx|markdown|txt|jsonl|log|lock)$/i.test(path20);
|
|
14915
15155
|
}
|
|
14916
15156
|
function scanPonytailComments(files) {
|
|
14917
15157
|
const out = [];
|
|
@@ -15086,6 +15326,7 @@ var init_src3 = __esm({
|
|
|
15086
15326
|
init_session_ingest();
|
|
15087
15327
|
init_capture_events2();
|
|
15088
15328
|
init_tools();
|
|
15329
|
+
init_mcp_config();
|
|
15089
15330
|
init_cursor_hooks();
|
|
15090
15331
|
init_codex_hooks();
|
|
15091
15332
|
init_copilot_hooks();
|
|
@@ -15192,10 +15433,10 @@ __export(brief_exports, {
|
|
|
15192
15433
|
upsertBriefBlock: () => upsertBriefBlock,
|
|
15193
15434
|
withExcluded: () => withExcluded
|
|
15194
15435
|
});
|
|
15195
|
-
import { readFileSync as
|
|
15196
|
-
import
|
|
15197
|
-
import { execFile as
|
|
15198
|
-
import { promisify as
|
|
15436
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync3 } from "node:fs";
|
|
15437
|
+
import path16 from "node:path";
|
|
15438
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
15439
|
+
import { promisify as promisify4 } from "node:util";
|
|
15199
15440
|
function claudeMdWithImport(existing) {
|
|
15200
15441
|
let text = existing;
|
|
15201
15442
|
const start = text.indexOf(BRIEF_START);
|
|
@@ -15241,12 +15482,12 @@ ${BRIEF_END}
|
|
|
15241
15482
|
}
|
|
15242
15483
|
function installPointer(root) {
|
|
15243
15484
|
if (loadEnv().BRAINJAR_NO_BRIEF === "1") return "skipped";
|
|
15244
|
-
const file =
|
|
15245
|
-
const existing =
|
|
15485
|
+
const file = path16.join(root, BRIEF_FILE);
|
|
15486
|
+
const existing = existsSync12(file) ? readFileSync12(file, "utf8") : "";
|
|
15246
15487
|
const next = upsertBriefBlock(existing, POINTER);
|
|
15247
15488
|
if (next !== null) writeFileSync3(file, next);
|
|
15248
|
-
const claudeFile =
|
|
15249
|
-
const claude =
|
|
15489
|
+
const claudeFile = path16.join(root, "CLAUDE.md");
|
|
15490
|
+
const claude = existsSync12(claudeFile) ? readFileSync12(claudeFile, "utf8") : "";
|
|
15250
15491
|
const claudeNext = claudeMdWithImport(claude);
|
|
15251
15492
|
if (claudeNext !== null) writeFileSync3(claudeFile, claudeNext);
|
|
15252
15493
|
return next !== null || claudeNext !== null ? "updated" : "unchanged";
|
|
@@ -15278,24 +15519,24 @@ async function refreshCursorRules(root) {
|
|
|
15278
15519
|
`/capture/brief?brain=${link.brainId}`
|
|
15279
15520
|
);
|
|
15280
15521
|
if (!text) return "skipped";
|
|
15281
|
-
const file =
|
|
15522
|
+
const file = path16.join(root, CURSOR_RULE_FILE);
|
|
15282
15523
|
const next = cursorRule(text);
|
|
15283
|
-
const changed = !
|
|
15524
|
+
const changed = !existsSync12(file) || readFileSync12(file, "utf8") !== next;
|
|
15284
15525
|
if (changed) {
|
|
15285
|
-
mkdirSync3(
|
|
15526
|
+
mkdirSync3(path16.dirname(file), { recursive: true });
|
|
15286
15527
|
writeFileSync3(file, next);
|
|
15287
15528
|
}
|
|
15288
15529
|
try {
|
|
15289
|
-
const { stdout } = await
|
|
15530
|
+
const { stdout } = await run4(
|
|
15290
15531
|
"git",
|
|
15291
15532
|
["rev-parse", "--path-format=absolute", "--git-path", "info/exclude"],
|
|
15292
15533
|
{ cwd: root, windowsHide: true }
|
|
15293
15534
|
);
|
|
15294
15535
|
const exclude = stdout.trim();
|
|
15295
|
-
const current =
|
|
15536
|
+
const current = existsSync12(exclude) ? readFileSync12(exclude, "utf8") : "";
|
|
15296
15537
|
const withLine = withExcluded(current, CURSOR_RULE_FILE);
|
|
15297
15538
|
if (withLine !== null) {
|
|
15298
|
-
mkdirSync3(
|
|
15539
|
+
mkdirSync3(path16.dirname(exclude), { recursive: true });
|
|
15299
15540
|
writeFileSync3(exclude, withLine);
|
|
15300
15541
|
}
|
|
15301
15542
|
} catch {
|
|
@@ -15322,14 +15563,14 @@ async function briefMain() {
|
|
|
15322
15563
|
process.exitCode = 1;
|
|
15323
15564
|
}
|
|
15324
15565
|
}
|
|
15325
|
-
var
|
|
15566
|
+
var run4, BRIEF_START, BRIEF_END, BRIEF_FILE, CLAUDE_IMPORT, CURSOR_RULE_FILE, POINTER;
|
|
15326
15567
|
var init_brief = __esm({
|
|
15327
15568
|
"packages/cli/src/brief.ts"() {
|
|
15328
15569
|
"use strict";
|
|
15329
15570
|
init_src3();
|
|
15330
15571
|
init_src();
|
|
15331
15572
|
init_api_client();
|
|
15332
|
-
|
|
15573
|
+
run4 = promisify4(execFile4);
|
|
15333
15574
|
BRIEF_START = "<!-- brainjar:brief:start -->";
|
|
15334
15575
|
BRIEF_END = "<!-- brainjar:brief:end -->";
|
|
15335
15576
|
BRIEF_FILE = "AGENTS.md";
|
|
@@ -15349,12 +15590,12 @@ __export(debt_exports, {
|
|
|
15349
15590
|
debtMain: () => debtMain,
|
|
15350
15591
|
scanDebtInRepo: () => scanDebtInRepo
|
|
15351
15592
|
});
|
|
15352
|
-
import { execFile as
|
|
15593
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
15353
15594
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
15354
|
-
import { promisify as
|
|
15355
|
-
import
|
|
15595
|
+
import { promisify as promisify5 } from "node:util";
|
|
15596
|
+
import path17 from "node:path";
|
|
15356
15597
|
async function scanDebtInRepo(root) {
|
|
15357
|
-
const { stdout } = await
|
|
15598
|
+
const { stdout } = await run5("git", ["-C", root, "ls-files"], {
|
|
15358
15599
|
maxBuffer: 16 * 1048576
|
|
15359
15600
|
});
|
|
15360
15601
|
const files = [];
|
|
@@ -15362,7 +15603,7 @@ async function scanDebtInRepo(root) {
|
|
|
15362
15603
|
const p = rel.trim();
|
|
15363
15604
|
if (!p || !isDebtScannable(p)) continue;
|
|
15364
15605
|
try {
|
|
15365
|
-
const buf = await readFile11(
|
|
15606
|
+
const buf = await readFile11(path17.join(root, p));
|
|
15366
15607
|
if (buf.length > 512 * 1024 || buf.includes(0)) continue;
|
|
15367
15608
|
files.push({ path: p, content: buf.toString("utf8") });
|
|
15368
15609
|
} catch {
|
|
@@ -15393,13 +15634,13 @@ async function debtMain() {
|
|
|
15393
15634
|
`);
|
|
15394
15635
|
}
|
|
15395
15636
|
}
|
|
15396
|
-
var
|
|
15637
|
+
var run5;
|
|
15397
15638
|
var init_debt = __esm({
|
|
15398
15639
|
"packages/cli/src/debt.ts"() {
|
|
15399
15640
|
"use strict";
|
|
15400
15641
|
init_src3();
|
|
15401
15642
|
init_api_client();
|
|
15402
|
-
|
|
15643
|
+
run5 = promisify5(execFile5);
|
|
15403
15644
|
}
|
|
15404
15645
|
});
|
|
15405
15646
|
|
|
@@ -15787,11 +16028,11 @@ var init_codex = __esm({
|
|
|
15787
16028
|
...commits.length ? { commits } : {}
|
|
15788
16029
|
});
|
|
15789
16030
|
files.forEach(
|
|
15790
|
-
(
|
|
16031
|
+
(path20, i) => events.push({
|
|
15791
16032
|
...base,
|
|
15792
16033
|
event_id: `file:${id}:${i}`,
|
|
15793
16034
|
kind: "file_changed",
|
|
15794
|
-
path:
|
|
16035
|
+
path: path20
|
|
15795
16036
|
})
|
|
15796
16037
|
);
|
|
15797
16038
|
}
|
|
@@ -16515,18 +16756,18 @@ __export(hook_exports, {
|
|
|
16515
16756
|
});
|
|
16516
16757
|
import {
|
|
16517
16758
|
appendFileSync,
|
|
16518
|
-
existsSync as
|
|
16759
|
+
existsSync as existsSync13,
|
|
16519
16760
|
mkdirSync as mkdirSync4,
|
|
16520
16761
|
readdirSync,
|
|
16521
|
-
readFileSync as
|
|
16762
|
+
readFileSync as readFileSync13,
|
|
16522
16763
|
rmSync,
|
|
16523
16764
|
statSync as statSync2
|
|
16524
16765
|
} from "node:fs";
|
|
16525
|
-
import
|
|
16526
|
-
import
|
|
16766
|
+
import os6 from "node:os";
|
|
16767
|
+
import path18 from "node:path";
|
|
16527
16768
|
function spoolPath(tool, sessionId) {
|
|
16528
|
-
return
|
|
16529
|
-
|
|
16769
|
+
return path18.join(
|
|
16770
|
+
os6.homedir(),
|
|
16530
16771
|
".brainjar",
|
|
16531
16772
|
"spool",
|
|
16532
16773
|
tool,
|
|
@@ -16535,7 +16776,7 @@ function spoolPath(tool, sessionId) {
|
|
|
16535
16776
|
}
|
|
16536
16777
|
function readSpool(file) {
|
|
16537
16778
|
const out = [];
|
|
16538
|
-
for (const line of
|
|
16779
|
+
for (const line of readFileSync13(file, "utf8").split("\n")) {
|
|
16539
16780
|
if (!line.trim()) continue;
|
|
16540
16781
|
try {
|
|
16541
16782
|
out.push(clampCaptureEvent(JSON.parse(line)));
|
|
@@ -16547,7 +16788,7 @@ function readSpool(file) {
|
|
|
16547
16788
|
function pruneSpool(dir, keep, maxAgeMs = 7 * 864e5) {
|
|
16548
16789
|
try {
|
|
16549
16790
|
for (const f of readdirSync(dir)) {
|
|
16550
|
-
const file =
|
|
16791
|
+
const file = path18.join(dir, f);
|
|
16551
16792
|
if (file === keep) continue;
|
|
16552
16793
|
if (Date.now() - statSync2(file).mtimeMs > maxAgeMs)
|
|
16553
16794
|
rmSync(file, { force: true });
|
|
@@ -16557,7 +16798,7 @@ function pruneSpool(dir, keep, maxAgeMs = 7 * 864e5) {
|
|
|
16557
16798
|
}
|
|
16558
16799
|
function staleSpools(dir, keep, minAgeMs = 36e5) {
|
|
16559
16800
|
try {
|
|
16560
|
-
return readdirSync(dir).map((f) =>
|
|
16801
|
+
return readdirSync(dir).map((f) => path18.join(dir, f)).filter(
|
|
16561
16802
|
(file) => file !== keep && Date.now() - statSync2(file).mtimeMs > minAgeMs
|
|
16562
16803
|
).sort();
|
|
16563
16804
|
} catch {
|
|
@@ -16602,7 +16843,7 @@ async function hookMain(argv) {
|
|
|
16602
16843
|
}
|
|
16603
16844
|
let payload = null;
|
|
16604
16845
|
try {
|
|
16605
|
-
payload = JSON.parse(
|
|
16846
|
+
payload = JSON.parse(readFileSync13(0, "utf8"));
|
|
16606
16847
|
} catch {
|
|
16607
16848
|
return;
|
|
16608
16849
|
}
|
|
@@ -16611,7 +16852,7 @@ async function hookMain(argv) {
|
|
|
16611
16852
|
if (out.reply) process.stdout.write(out.reply);
|
|
16612
16853
|
const file = spoolPath(adapter.id, out.sessionId);
|
|
16613
16854
|
if (out.events.length) {
|
|
16614
|
-
mkdirSync4(
|
|
16855
|
+
mkdirSync4(path18.dirname(file), { recursive: true });
|
|
16615
16856
|
appendFileSync(
|
|
16616
16857
|
file,
|
|
16617
16858
|
out.events.map((e) => JSON.stringify(clampCaptureEvent(e))).join("\n") + "\n"
|
|
@@ -16625,9 +16866,9 @@ async function hookMain(argv) {
|
|
|
16625
16866
|
if (out.end) rmSync(file, { force: true });
|
|
16626
16867
|
return;
|
|
16627
16868
|
}
|
|
16628
|
-
if (
|
|
16869
|
+
if (existsSync13(file)) await shipSpool(file, link);
|
|
16629
16870
|
if (out.end) rmSync(file, { force: true });
|
|
16630
|
-
const dir =
|
|
16871
|
+
const dir = path18.dirname(file);
|
|
16631
16872
|
for (const other of staleSpools(dir, file)) {
|
|
16632
16873
|
const otherLink = await linkForSpool(other);
|
|
16633
16874
|
if (!otherLink) continue;
|
|
@@ -16874,18 +17115,31 @@ async function init(argv) {
|
|
|
16874
17115
|
}
|
|
16875
17116
|
step(5, "Semantic search\u2026");
|
|
16876
17117
|
ok("embedding runs on the server after every capture");
|
|
16877
|
-
step(6, "Installing continuous capture (agent hooks)\u2026");
|
|
17118
|
+
step(6, "Installing continuous capture (agent hooks) and the memory\u2026");
|
|
16878
17119
|
const tools = detectedTools(root);
|
|
16879
17120
|
if (tools.length === 0) {
|
|
16880
17121
|
ok(
|
|
16881
17122
|
"no coding agent detected (looked for Claude Code, Cursor, Codex, GitHub Copilot, Gemini CLI, Kiro, OpenCode, Cline); rerun init after installing one"
|
|
16882
17123
|
);
|
|
16883
17124
|
}
|
|
17125
|
+
const memoryUrl = `${serverUrl()}/mcp?brain=${conn.brainId}`;
|
|
16884
17126
|
for (const tool of tools) {
|
|
16885
17127
|
const changed = await tool.install(root);
|
|
16886
17128
|
ok(
|
|
16887
17129
|
`${tool.name}: ${changed ? "hooks installed" : "hooks already present"}`
|
|
16888
17130
|
);
|
|
17131
|
+
if (!tool.mcp) continue;
|
|
17132
|
+
try {
|
|
17133
|
+
const wrote = await tool.mcp.install(root, memoryUrl);
|
|
17134
|
+
ok(
|
|
17135
|
+
`${tool.name}: memory ${wrote ? "added to" : "already in"} ${tool.mcp.where}; sign in once: ${tool.mcp.signIn}`
|
|
17136
|
+
);
|
|
17137
|
+
} catch (e) {
|
|
17138
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
17139
|
+
ok(
|
|
17140
|
+
`${tool.name}: memory not added (${msg.slice(0, 120)}). ` + (tool.id === "claude-code" ? `Run: ${claudeAddCommand(memoryUrl)}` : `Add it yourself in ${tool.mcp.where}`)
|
|
17141
|
+
);
|
|
17142
|
+
}
|
|
16889
17143
|
}
|
|
16890
17144
|
const gitHook = await installGitPostCommitHook(root);
|
|
16891
17145
|
ok(
|
|
@@ -16925,7 +17179,8 @@ async function init(argv) {
|
|
|
16925
17179
|
console.log(
|
|
16926
17180
|
`
|
|
16927
17181
|
\u2705 Brain "${name}" is live \u2014 ${final.objects} memory objects.
|
|
16928
|
-
Open the web app and visit Docs. Approve the hooks in your coding agent when prompted
|
|
17182
|
+
Open the web app and visit Docs. Approve the hooks in your coding agent when prompted,
|
|
17183
|
+
and sign in to the memory once (see the lines above).
|
|
16929
17184
|
Optional: \`npx brainjar deepscan\` reads the repo's key files so the docs start full.
|
|
16930
17185
|
`
|
|
16931
17186
|
);
|
|
@@ -16963,7 +17218,7 @@ __export(constraints_exports, {
|
|
|
16963
17218
|
constraintsMain: () => constraintsMain,
|
|
16964
17219
|
sessionStartEnvelope: () => sessionStartEnvelope
|
|
16965
17220
|
});
|
|
16966
|
-
import { readFileSync as
|
|
17221
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
16967
17222
|
function sessionStartEnvelope(text) {
|
|
16968
17223
|
return JSON.stringify({
|
|
16969
17224
|
hookSpecificOutput: {
|
|
@@ -16982,7 +17237,7 @@ async function constraintsMain(argv) {
|
|
|
16982
17237
|
if (hook) {
|
|
16983
17238
|
let cwd;
|
|
16984
17239
|
try {
|
|
16985
|
-
const payload = JSON.parse(
|
|
17240
|
+
const payload = JSON.parse(readFileSync14(0, "utf8"));
|
|
16986
17241
|
cwd = payload.cwd ?? payload.workspace_roots?.[0] ?? payload.workspaceRoots?.[0];
|
|
16987
17242
|
} catch {
|
|
16988
17243
|
}
|
|
@@ -17051,11 +17306,12 @@ var init_failure = __esm({
|
|
|
17051
17306
|
var doctor_exports = {};
|
|
17052
17307
|
__export(doctor_exports, {
|
|
17053
17308
|
doctorMain: () => doctorMain,
|
|
17309
|
+
memoryCheck: () => memoryCheck,
|
|
17054
17310
|
renderDoctorReport: () => renderDoctorReport,
|
|
17055
17311
|
runDoctor: () => runDoctor
|
|
17056
17312
|
});
|
|
17057
|
-
import { execFile as
|
|
17058
|
-
import { promisify as
|
|
17313
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
17314
|
+
import { promisify as promisify6 } from "node:util";
|
|
17059
17315
|
async function runDoctor(root, opts = {}) {
|
|
17060
17316
|
const checks = [];
|
|
17061
17317
|
const add = (name, ok2, detail) => checks.push({ name, ok: ok2, detail });
|
|
@@ -17108,6 +17364,9 @@ async function runDoctor(root, opts = {}) {
|
|
|
17108
17364
|
installed ? "installed" : detected ? "not installed. Run npx brainjar init" : "skipped (tool not detected on this machine)"
|
|
17109
17365
|
);
|
|
17110
17366
|
}
|
|
17367
|
+
for (const tool of CAPTURE_TOOLS) {
|
|
17368
|
+
if (tool.mcp) checks.push(memoryCheck(tool, root, link?.brainId ?? null));
|
|
17369
|
+
}
|
|
17111
17370
|
add(
|
|
17112
17371
|
"git post-commit hook",
|
|
17113
17372
|
gitHookInstalled(root),
|
|
@@ -17125,7 +17384,7 @@ async function runDoctor(root, opts = {}) {
|
|
|
17125
17384
|
}
|
|
17126
17385
|
if (opts.runtime === false) return { checks, ok: checks.every((c) => c.ok) };
|
|
17127
17386
|
try {
|
|
17128
|
-
const { stdout } = await
|
|
17387
|
+
const { stdout } = await run6("npx", ["--yes", "tsx", "--version"], {
|
|
17129
17388
|
cwd: root,
|
|
17130
17389
|
shell: true,
|
|
17131
17390
|
// Windows resolves npx.cmd
|
|
@@ -17138,6 +17397,37 @@ async function runDoctor(root, opts = {}) {
|
|
|
17138
17397
|
}
|
|
17139
17398
|
return { checks, ok: checks.every((c) => c.ok) };
|
|
17140
17399
|
}
|
|
17400
|
+
function memoryCheck(tool, root, brainId) {
|
|
17401
|
+
const name = `${tool.name} memory`;
|
|
17402
|
+
const mcp = tool.mcp;
|
|
17403
|
+
if (!tool.detect(root))
|
|
17404
|
+
return {
|
|
17405
|
+
name,
|
|
17406
|
+
ok: true,
|
|
17407
|
+
detail: "skipped (tool not detected on this machine)"
|
|
17408
|
+
};
|
|
17409
|
+
const url = mcp.url(root);
|
|
17410
|
+
if (!brainId)
|
|
17411
|
+
return {
|
|
17412
|
+
name,
|
|
17413
|
+
ok: true,
|
|
17414
|
+
detail: url ? `points to Brain ${brainOf(url) ?? "?"}` : "skipped (not connected)"
|
|
17415
|
+
};
|
|
17416
|
+
if (!url)
|
|
17417
|
+
return {
|
|
17418
|
+
name,
|
|
17419
|
+
ok: false,
|
|
17420
|
+
detail: `no entry in ${mcp.where}. Run npx brainjar init`
|
|
17421
|
+
};
|
|
17422
|
+
const brain = brainOf(url);
|
|
17423
|
+
if (brain !== brainId)
|
|
17424
|
+
return {
|
|
17425
|
+
name,
|
|
17426
|
+
ok: false,
|
|
17427
|
+
detail: `${mcp.where} points to Brain ${brain ?? "?"}, capture uses ${brainId}. Run npx brainjar init`
|
|
17428
|
+
};
|
|
17429
|
+
return { name, ok: true, detail: `${mcp.where} points to this Brain` };
|
|
17430
|
+
}
|
|
17141
17431
|
function renderDoctorReport(report) {
|
|
17142
17432
|
const lines = report.checks.map(
|
|
17143
17433
|
(c) => ` ${c.ok ? "\u2713" : "\u2717"} ${c.name.padEnd(20)} ${c.detail}`
|
|
@@ -17161,14 +17451,14 @@ brainjar doctor. repo: ${root}
|
|
|
17161
17451
|
process.exitCode = 1;
|
|
17162
17452
|
}
|
|
17163
17453
|
}
|
|
17164
|
-
var
|
|
17454
|
+
var run6;
|
|
17165
17455
|
var init_doctor = __esm({
|
|
17166
17456
|
"packages/cli/src/doctor.ts"() {
|
|
17167
17457
|
"use strict";
|
|
17168
17458
|
init_src3();
|
|
17169
17459
|
init_api_client();
|
|
17170
17460
|
init_version_check();
|
|
17171
|
-
|
|
17461
|
+
run6 = promisify6(execFile6);
|
|
17172
17462
|
}
|
|
17173
17463
|
});
|
|
17174
17464
|
|
|
@@ -17179,7 +17469,7 @@ __export(deepscan_exports, {
|
|
|
17179
17469
|
selectDeepScanFiles: () => selectDeepScanFiles
|
|
17180
17470
|
});
|
|
17181
17471
|
import { readdir as readdir3, readFile as readFile13, stat as stat2 } from "node:fs/promises";
|
|
17182
|
-
import
|
|
17472
|
+
import path19 from "node:path";
|
|
17183
17473
|
function selectDeepScanFiles(candidates, graph, maxFiles = MAX_FILES) {
|
|
17184
17474
|
const picked = [];
|
|
17185
17475
|
const has = /* @__PURE__ */ new Set();
|
|
@@ -17216,7 +17506,7 @@ async function walkCandidates(root) {
|
|
|
17216
17506
|
for (const e of entries) {
|
|
17217
17507
|
if (!e.isFile()) continue;
|
|
17218
17508
|
const parent = e.parentPath ?? e.path ?? root;
|
|
17219
|
-
const rel =
|
|
17509
|
+
const rel = path19.relative(root, path19.join(parent, e.name)).split(path19.sep).join("/");
|
|
17220
17510
|
if (rel.split("/").some((seg) => SKIP_DIRS.has(seg))) continue;
|
|
17221
17511
|
out.push(rel);
|
|
17222
17512
|
}
|
|
@@ -17239,7 +17529,7 @@ async function deepscanMain() {
|
|
|
17239
17529
|
const artifacts = [];
|
|
17240
17530
|
for (const rel of files) {
|
|
17241
17531
|
try {
|
|
17242
|
-
const abs =
|
|
17532
|
+
const abs = path19.join(root, rel);
|
|
17243
17533
|
const info = await stat2(abs);
|
|
17244
17534
|
if (info.size > RAW_SKIP_BYTES) continue;
|
|
17245
17535
|
const content = await readFile13(abs, "utf8");
|
|
@@ -17351,6 +17641,9 @@ async function unhookMain() {
|
|
|
17351
17641
|
console.log(
|
|
17352
17642
|
removed ? `${tool.name}: BrainJar hooks removed` : `${tool.name}: no BrainJar hooks`
|
|
17353
17643
|
);
|
|
17644
|
+
if (!tool.mcp) continue;
|
|
17645
|
+
const memory = await tool.mcp.remove(root).catch(() => false);
|
|
17646
|
+
if (memory) console.log(`${tool.name}: memory entry removed`);
|
|
17354
17647
|
}
|
|
17355
17648
|
const git = await removeGitPostCommitHook(root);
|
|
17356
17649
|
console.log(
|
|
@@ -17458,7 +17751,7 @@ async function main() {
|
|
|
17458
17751
|
return;
|
|
17459
17752
|
}
|
|
17460
17753
|
try {
|
|
17461
|
-
await
|
|
17754
|
+
await run7(cmd, argv);
|
|
17462
17755
|
} finally {
|
|
17463
17756
|
if (cmd !== "hook" && !argv.includes("--hook")) {
|
|
17464
17757
|
const { noticeNewerVersion: noticeNewerVersion2 } = await Promise.resolve().then(() => (init_version_check(), version_check_exports));
|
|
@@ -17466,7 +17759,7 @@ async function main() {
|
|
|
17466
17759
|
}
|
|
17467
17760
|
}
|
|
17468
17761
|
}
|
|
17469
|
-
async function
|
|
17762
|
+
async function run7(cmd, argv) {
|
|
17470
17763
|
switch (cmd) {
|
|
17471
17764
|
case "brief": {
|
|
17472
17765
|
const { briefMain: briefMain2 } = await Promise.resolve().then(() => (init_brief(), brief_exports));
|