@hasna/brains 0.0.5 → 0.0.6

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/cli/index.js CHANGED
@@ -5,25 +5,43 @@ var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ function __accessProp(key) {
9
+ return this[key];
10
+ }
11
+ var __toESMCache_node;
12
+ var __toESMCache_esm;
8
13
  var __toESM = (mod, isNodeMode, target) => {
14
+ var canCache = mod != null && typeof mod === "object";
15
+ if (canCache) {
16
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
+ var cached = cache.get(mod);
18
+ if (cached)
19
+ return cached;
20
+ }
9
21
  target = mod != null ? __create(__getProtoOf(mod)) : {};
10
22
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
23
  for (let key of __getOwnPropNames(mod))
12
24
  if (!__hasOwnProp.call(to, key))
13
25
  __defProp(to, key, {
14
- get: () => mod[key],
26
+ get: __accessProp.bind(mod, key),
15
27
  enumerable: true
16
28
  });
29
+ if (canCache)
30
+ cache.set(mod, to);
17
31
  return to;
18
32
  };
19
33
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
+ var __returnValue = (v) => v;
35
+ function __exportSetter(name, newValue) {
36
+ this[name] = __returnValue.bind(null, newValue);
37
+ }
20
38
  var __export = (target, all) => {
21
39
  for (var name in all)
22
40
  __defProp(target, name, {
23
41
  get: all[name],
24
42
  enumerable: true,
25
43
  configurable: true,
26
- set: (newValue) => all[name] = () => newValue
44
+ set: __exportSetter.bind(all, name)
27
45
  });
28
46
  };
29
47
  var __require = import.meta.require;
@@ -12247,4 +12265,35 @@ collectionsCmd.command("rename <oldName> <newName>").description("Rename a colle
12247
12265
  process.exit(1);
12248
12266
  }
12249
12267
  });
12268
+ program2.command("remove <id>").alias("rm").alias("uninstall").description("Remove a fine-tuned model or training job by ID").option("--type <type>", "Type: model | job (default: auto-detect)").action(async (id, opts) => {
12269
+ const db = getDb();
12270
+ try {
12271
+ const type = opts.type?.toLowerCase();
12272
+ if (type === "job" || !type && !type) {
12273
+ const job = db.select().from(trainingJobs).where(eq(trainingJobs.id, id)).get();
12274
+ if (job || type === "job") {
12275
+ if (!job) {
12276
+ printError(`Job not found: ${id}`);
12277
+ process.exit(1);
12278
+ }
12279
+ db.delete(trainingJobs).where(eq(trainingJobs.id, id)).run();
12280
+ printSuccess(`Training job ${id} removed`);
12281
+ return;
12282
+ }
12283
+ }
12284
+ if (type === "model" || !type) {
12285
+ const model = db.select().from(fineTunedModels).where(eq(fineTunedModels.id, id)).get();
12286
+ if (model) {
12287
+ db.delete(fineTunedModels).where(eq(fineTunedModels.id, id)).run();
12288
+ printSuccess(`Model ${id} removed`);
12289
+ return;
12290
+ }
12291
+ }
12292
+ printError(`Not found: ${id}. Use --type model|job`);
12293
+ process.exit(1);
12294
+ } catch (err) {
12295
+ printError(err instanceof Error ? err.message : String(err));
12296
+ process.exit(1);
12297
+ }
12298
+ });
12250
12299
  program2.parse();
package/dist/index.js CHANGED
@@ -1,12 +1,16 @@
1
1
  // @bun
2
2
  var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
3
7
  var __export = (target, all) => {
4
8
  for (var name in all)
5
9
  __defProp(target, name, {
6
10
  get: all[name],
7
11
  enumerable: true,
8
12
  configurable: true,
9
- set: (newValue) => all[name] = () => newValue
13
+ set: __exportSetter.bind(all, name)
10
14
  });
11
15
  };
12
16
  // node_modules/drizzle-orm/bun-sqlite/driver.js
@@ -9403,6 +9407,32 @@ class ThinkerLabsProvider {
9403
9407
  return cancelJob(jobId);
9404
9408
  }
9405
9409
  }
9410
+ // src/lib/package-metadata.ts
9411
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
9412
+ import { dirname as dirname2, resolve } from "path";
9413
+ import { fileURLToPath } from "url";
9414
+ var DEFAULT_VERSION = "0.0.0";
9415
+ var cachedVersion;
9416
+ function getPackageJsonPath() {
9417
+ return resolve(dirname2(fileURLToPath(import.meta.url)), "../../package.json");
9418
+ }
9419
+ function getPackageVersion() {
9420
+ if (cachedVersion) {
9421
+ return cachedVersion;
9422
+ }
9423
+ const packageJsonPath = getPackageJsonPath();
9424
+ if (!existsSync(packageJsonPath)) {
9425
+ cachedVersion = DEFAULT_VERSION;
9426
+ return cachedVersion;
9427
+ }
9428
+ try {
9429
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
9430
+ cachedVersion = typeof packageJson.version === "string" ? packageJson.version : DEFAULT_VERSION;
9431
+ } catch {
9432
+ cachedVersion = DEFAULT_VERSION;
9433
+ }
9434
+ return cachedVersion;
9435
+ }
9406
9436
  export {
9407
9437
  uploadTrainingFile,
9408
9438
  uploadTrainingData,
@@ -9412,6 +9442,7 @@ export {
9412
9442
  listModels,
9413
9443
  listFineTunedModels,
9414
9444
  getStatus,
9445
+ getPackageVersion,
9415
9446
  getFineTuneStatus,
9416
9447
  getDb,
9417
9448
  fineTunedModels,
@@ -1,2 +1,3 @@
1
1
  export * from "./providers/index.js";
2
+ export * from "./package-metadata.js";
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function getPackageVersion(): string;
2
+ //# sourceMappingURL=package-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-metadata.d.ts","sourceRoot":"","sources":["../../src/lib/package-metadata.ts"],"names":[],"mappings":"AAYA,wBAAgB,iBAAiB,IAAI,MAAM,CAmB1C"}
@@ -1,3 +1,76 @@
1
1
  #!/usr/bin/env bun
2
- export {};
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ export declare const MCP_SERVER_INFO: {
5
+ readonly name: "brains";
6
+ readonly version: string;
7
+ };
8
+ export declare function createMcpServer(): Server<{
9
+ method: string;
10
+ params?: {
11
+ [x: string]: unknown;
12
+ _meta?: {
13
+ [x: string]: unknown;
14
+ progressToken?: string | number | undefined;
15
+ "io.modelcontextprotocol/related-task"?: {
16
+ taskId: string;
17
+ } | undefined;
18
+ } | undefined;
19
+ } | undefined;
20
+ }, {
21
+ method: string;
22
+ params?: {
23
+ [x: string]: unknown;
24
+ _meta?: {
25
+ [x: string]: unknown;
26
+ progressToken?: string | number | undefined;
27
+ "io.modelcontextprotocol/related-task"?: {
28
+ taskId: string;
29
+ } | undefined;
30
+ } | undefined;
31
+ } | undefined;
32
+ }, {
33
+ [x: string]: unknown;
34
+ _meta?: {
35
+ [x: string]: unknown;
36
+ progressToken?: string | number | undefined;
37
+ "io.modelcontextprotocol/related-task"?: {
38
+ taskId: string;
39
+ } | undefined;
40
+ } | undefined;
41
+ }>;
42
+ export declare function startMcpServer(transport?: StdioServerTransport): Promise<Server<{
43
+ method: string;
44
+ params?: {
45
+ [x: string]: unknown;
46
+ _meta?: {
47
+ [x: string]: unknown;
48
+ progressToken?: string | number | undefined;
49
+ "io.modelcontextprotocol/related-task"?: {
50
+ taskId: string;
51
+ } | undefined;
52
+ } | undefined;
53
+ } | undefined;
54
+ }, {
55
+ method: string;
56
+ params?: {
57
+ [x: string]: unknown;
58
+ _meta?: {
59
+ [x: string]: unknown;
60
+ progressToken?: string | number | undefined;
61
+ "io.modelcontextprotocol/related-task"?: {
62
+ taskId: string;
63
+ } | undefined;
64
+ } | undefined;
65
+ } | undefined;
66
+ }, {
67
+ [x: string]: unknown;
68
+ _meta?: {
69
+ [x: string]: unknown;
70
+ progressToken?: string | number | undefined;
71
+ "io.modelcontextprotocol/related-task"?: {
72
+ taskId: string;
73
+ } | undefined;
74
+ } | undefined;
75
+ }>>;
3
76
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AA8BjF,eAAO,MAAM,eAAe;;;CAGlB,CAAC;AAEX,wBAAgB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4X9B;AAED,wBAAsB,cAAc,CAAC,SAAS,uBAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAI1E"}
package/dist/mcp/index.js CHANGED
@@ -1,13 +1,17 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
  var __defProp = Object.defineProperty;
4
+ var __returnValue = (v) => v;
5
+ function __exportSetter(name, newValue) {
6
+ this[name] = __returnValue.bind(null, newValue);
7
+ }
4
8
  var __export = (target, all) => {
5
9
  for (var name in all)
6
10
  __defProp(target, name, {
7
11
  get: all[name],
8
12
  enumerable: true,
9
13
  configurable: true,
10
- set: (newValue) => all[name] = () => newValue
14
+ set: __exportSetter.bind(all, name)
11
15
  });
12
16
  };
13
17
  var __require = import.meta.require;
@@ -19,8 +23,8 @@ import {
19
23
  CallToolRequestSchema,
20
24
  ListToolsRequestSchema
21
25
  } from "@modelcontextprotocol/sdk/types.js";
22
- import { readFileSync as readFileSync2, existsSync } from "fs";
23
- import { resolve } from "path";
26
+ import { readFileSync as readFileSync3, existsSync as existsSync2 } from "fs";
27
+ import { resolve as resolve2 } from "path";
24
28
  import { homedir as homedir3 } from "os";
25
29
 
26
30
  // node_modules/drizzle-orm/entity.js
@@ -9511,6 +9515,33 @@ async function gatherFromTodos(options = {}) {
9511
9515
  }
9512
9516
  }
9513
9517
 
9518
+ // src/lib/package-metadata.ts
9519
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
9520
+ import { dirname as dirname2, resolve } from "path";
9521
+ import { fileURLToPath } from "url";
9522
+ var DEFAULT_VERSION = "0.0.0";
9523
+ var cachedVersion;
9524
+ function getPackageJsonPath() {
9525
+ return resolve(dirname2(fileURLToPath(import.meta.url)), "../../package.json");
9526
+ }
9527
+ function getPackageVersion() {
9528
+ if (cachedVersion) {
9529
+ return cachedVersion;
9530
+ }
9531
+ const packageJsonPath = getPackageJsonPath();
9532
+ if (!existsSync(packageJsonPath)) {
9533
+ cachedVersion = DEFAULT_VERSION;
9534
+ return cachedVersion;
9535
+ }
9536
+ try {
9537
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
9538
+ cachedVersion = typeof packageJson.version === "string" ? packageJson.version : DEFAULT_VERSION;
9539
+ } catch {
9540
+ cachedVersion = DEFAULT_VERSION;
9541
+ }
9542
+ return cachedVersion;
9543
+ }
9544
+
9514
9545
  // src/mcp/index.ts
9515
9546
  function getProvider(provider) {
9516
9547
  if (provider === "openai")
@@ -9520,312 +9551,330 @@ function getProvider(provider) {
9520
9551
  throw new Error(`Unknown provider: ${provider}`);
9521
9552
  }
9522
9553
  function defaultOutputDir() {
9523
- return resolve(homedir3(), ".brains", "datasets");
9524
- }
9525
- var server = new Server({ name: "brains", version: "0.0.1" }, { capabilities: { tools: {} } });
9526
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
9527
- tools: [
9528
- {
9529
- name: "list_models",
9530
- description: "List all fine-tuned models tracked in the local DB",
9531
- inputSchema: {
9532
- type: "object",
9533
- properties: {},
9534
- required: []
9535
- }
9536
- },
9537
- {
9538
- name: "get_model",
9539
- description: "Get details for a specific fine-tuned model",
9540
- inputSchema: {
9541
- type: "object",
9542
- properties: {
9543
- model_id: { type: "string", description: "Model ID" }
9544
- },
9545
- required: ["model_id"]
9546
- }
9547
- },
9548
- {
9549
- name: "start_finetune",
9550
- description: "Upload a training file and start a fine-tuning job",
9551
- inputSchema: {
9552
- type: "object",
9553
- properties: {
9554
- provider: {
9555
- type: "string",
9556
- enum: ["openai", "thinker-labs"],
9557
- description: "Provider to use for fine-tuning"
9554
+ return resolve2(homedir3(), ".brains", "datasets");
9555
+ }
9556
+ var MCP_SERVER_INFO = {
9557
+ name: "brains",
9558
+ version: getPackageVersion()
9559
+ };
9560
+ function createMcpServer() {
9561
+ const server = new Server(MCP_SERVER_INFO, { capabilities: { tools: {} } });
9562
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
9563
+ tools: [
9564
+ {
9565
+ name: "list_models",
9566
+ description: "List all fine-tuned models tracked in the local DB",
9567
+ inputSchema: {
9568
+ type: "object",
9569
+ properties: {},
9570
+ required: []
9571
+ }
9572
+ },
9573
+ {
9574
+ name: "get_model",
9575
+ description: "Get details for a specific fine-tuned model",
9576
+ inputSchema: {
9577
+ type: "object",
9578
+ properties: {
9579
+ model_id: { type: "string", description: "Model ID" }
9558
9580
  },
9559
- base_model: {
9560
- type: "string",
9561
- description: "Base model identifier (e.g. gpt-4o-mini-2024-07-18)"
9581
+ required: ["model_id"]
9582
+ }
9583
+ },
9584
+ {
9585
+ name: "start_finetune",
9586
+ description: "Upload a training file and start a fine-tuning job",
9587
+ inputSchema: {
9588
+ type: "object",
9589
+ properties: {
9590
+ provider: {
9591
+ type: "string",
9592
+ enum: ["openai", "thinker-labs"],
9593
+ description: "Provider to use for fine-tuning"
9594
+ },
9595
+ base_model: {
9596
+ type: "string",
9597
+ description: "Base model identifier (e.g. gpt-4o-mini-2024-07-18)"
9598
+ },
9599
+ dataset_path: {
9600
+ type: "string",
9601
+ description: "Absolute path to the JSONL training file"
9602
+ },
9603
+ name: {
9604
+ type: "string",
9605
+ description: "Optional friendly name for this model"
9606
+ }
9562
9607
  },
9563
- dataset_path: {
9564
- type: "string",
9565
- description: "Absolute path to the JSONL training file"
9608
+ required: ["provider", "base_model", "dataset_path"]
9609
+ }
9610
+ },
9611
+ {
9612
+ name: "get_finetune_status",
9613
+ description: "Check the status of a fine-tuning job",
9614
+ inputSchema: {
9615
+ type: "object",
9616
+ properties: {
9617
+ job_id: { type: "string", description: "Fine-tune job ID" },
9618
+ provider: {
9619
+ type: "string",
9620
+ enum: ["openai", "thinker-labs"],
9621
+ description: "Provider that owns the job"
9622
+ }
9566
9623
  },
9567
- name: {
9568
- type: "string",
9569
- description: "Optional friendly name for this model"
9570
- }
9571
- },
9572
- required: ["provider", "base_model", "dataset_path"]
9573
- }
9574
- },
9575
- {
9576
- name: "get_finetune_status",
9577
- description: "Check the status of a fine-tuning job",
9578
- inputSchema: {
9579
- type: "object",
9580
- properties: {
9581
- job_id: { type: "string", description: "Fine-tune job ID" },
9582
- provider: {
9583
- type: "string",
9584
- enum: ["openai", "thinker-labs"],
9585
- description: "Provider that owns the job"
9586
- }
9587
- },
9588
- required: ["job_id", "provider"]
9589
- }
9590
- },
9591
- {
9592
- name: "gather_training_data",
9593
- description: "Gather training data from ecosystem sources (todos, mementos, conversations, sessions)",
9594
- inputSchema: {
9595
- type: "object",
9596
- properties: {
9597
- sources: {
9598
- type: "array",
9599
- items: { type: "string" },
9600
- description: "Sources to gather from: todos, mementos, conversations, sessions"
9624
+ required: ["job_id", "provider"]
9625
+ }
9626
+ },
9627
+ {
9628
+ name: "gather_training_data",
9629
+ description: "Gather training data from ecosystem sources (todos, mementos, conversations, sessions)",
9630
+ inputSchema: {
9631
+ type: "object",
9632
+ properties: {
9633
+ sources: {
9634
+ type: "array",
9635
+ items: { type: "string" },
9636
+ description: "Sources to gather from: todos, mementos, conversations, sessions"
9637
+ },
9638
+ limit: {
9639
+ type: "number",
9640
+ description: "Max examples per source (default: unlimited)"
9641
+ },
9642
+ output_dir: {
9643
+ type: "string",
9644
+ description: "Directory to write JSONL files (default: ~/.brains/datasets/)"
9645
+ }
9601
9646
  },
9602
- limit: {
9603
- type: "number",
9604
- description: "Max examples per source (default: unlimited)"
9647
+ required: ["sources"]
9648
+ }
9649
+ },
9650
+ {
9651
+ name: "preview_training_data",
9652
+ description: "Preview examples from a JSONL training file",
9653
+ inputSchema: {
9654
+ type: "object",
9655
+ properties: {
9656
+ file_path: {
9657
+ type: "string",
9658
+ description: "Absolute path to the JSONL file to preview"
9659
+ },
9660
+ limit: {
9661
+ type: "number",
9662
+ description: "Max number of examples to return (default: 5)"
9663
+ }
9605
9664
  },
9606
- output_dir: {
9607
- type: "string",
9608
- description: "Directory to write JSONL files (default: ~/.brains/datasets/)"
9609
- }
9610
- },
9611
- required: ["sources"]
9665
+ required: ["file_path"]
9666
+ }
9612
9667
  }
9613
- },
9614
- {
9615
- name: "preview_training_data",
9616
- description: "Preview examples from a JSONL training file",
9617
- inputSchema: {
9618
- type: "object",
9619
- properties: {
9620
- file_path: {
9621
- type: "string",
9622
- description: "Absolute path to the JSONL file to preview"
9623
- },
9624
- limit: {
9625
- type: "number",
9626
- description: "Max number of examples to return (default: 5)"
9668
+ ]
9669
+ }));
9670
+ server.setRequestHandler(CallToolRequestSchema, async (request2) => {
9671
+ const { name, arguments: args } = request2.params;
9672
+ try {
9673
+ switch (name) {
9674
+ case "list_models": {
9675
+ const db = getDb();
9676
+ const models = await db.select({
9677
+ id: fineTunedModels.id,
9678
+ name: fineTunedModels.name,
9679
+ provider: fineTunedModels.provider,
9680
+ status: fineTunedModels.status,
9681
+ base_model: fineTunedModels.baseModel,
9682
+ created_at: fineTunedModels.createdAt
9683
+ }).from(fineTunedModels).orderBy(fineTunedModels.createdAt);
9684
+ return {
9685
+ content: [
9686
+ {
9687
+ type: "text",
9688
+ text: JSON.stringify(models, null, 2)
9689
+ }
9690
+ ]
9691
+ };
9692
+ }
9693
+ case "get_model": {
9694
+ const { model_id } = args;
9695
+ const db = getDb();
9696
+ const results = await db.select().from(fineTunedModels).where(eq(fineTunedModels.id, model_id));
9697
+ if (results.length === 0) {
9698
+ return {
9699
+ content: [{ type: "text", text: `Model not found: ${model_id}` }],
9700
+ isError: true
9701
+ };
9627
9702
  }
9628
- },
9629
- required: ["file_path"]
9630
- }
9631
- }
9632
- ]
9633
- }));
9634
- server.setRequestHandler(CallToolRequestSchema, async (request2) => {
9635
- const { name, arguments: args } = request2.params;
9636
- try {
9637
- switch (name) {
9638
- case "list_models": {
9639
- const db = getDb();
9640
- const models = await db.select({
9641
- id: fineTunedModels.id,
9642
- name: fineTunedModels.name,
9643
- provider: fineTunedModels.provider,
9644
- status: fineTunedModels.status,
9645
- base_model: fineTunedModels.baseModel,
9646
- created_at: fineTunedModels.createdAt
9647
- }).from(fineTunedModels).orderBy(fineTunedModels.createdAt);
9648
- return {
9649
- content: [
9650
- {
9651
- type: "text",
9652
- text: JSON.stringify(models, null, 2)
9653
- }
9654
- ]
9655
- };
9656
- }
9657
- case "get_model": {
9658
- const { model_id } = args;
9659
- const db = getDb();
9660
- const results = await db.select().from(fineTunedModels).where(eq(fineTunedModels.id, model_id));
9661
- if (results.length === 0) {
9662
9703
  return {
9663
- content: [{ type: "text", text: `Model not found: ${model_id}` }],
9664
- isError: true
9704
+ content: [
9705
+ { type: "text", text: JSON.stringify(results[0], null, 2) }
9706
+ ]
9665
9707
  };
9666
9708
  }
9667
- return {
9668
- content: [
9669
- { type: "text", text: JSON.stringify(results[0], null, 2) }
9670
- ]
9671
- };
9672
- }
9673
- case "start_finetune": {
9674
- const {
9675
- provider,
9676
- base_model,
9677
- dataset_path,
9678
- name: modelName
9679
- } = args;
9680
- const resolvedPath = resolve(dataset_path);
9681
- if (!existsSync(resolvedPath)) {
9709
+ case "start_finetune": {
9710
+ const {
9711
+ provider,
9712
+ base_model,
9713
+ dataset_path,
9714
+ name: modelName
9715
+ } = args;
9716
+ const resolvedPath = resolve2(dataset_path);
9717
+ if (!existsSync2(resolvedPath)) {
9718
+ return {
9719
+ content: [
9720
+ {
9721
+ type: "text",
9722
+ text: `Dataset file not found: ${resolvedPath}`
9723
+ }
9724
+ ],
9725
+ isError: true
9726
+ };
9727
+ }
9728
+ const p = getProvider(provider);
9729
+ const { fileId } = await p.uploadTrainingFile(resolvedPath);
9730
+ const { jobId, status } = await p.createFineTuneJob(fileId, base_model, modelName);
9731
+ const db = getDb();
9732
+ const now = Date.now();
9733
+ const id = `${provider}-${jobId}`;
9734
+ await db.insert(fineTunedModels).values({
9735
+ id,
9736
+ name: modelName ?? `${base_model}-finetune-${now}`,
9737
+ provider,
9738
+ baseModel: base_model,
9739
+ status: "pending",
9740
+ fineTuneJobId: jobId,
9741
+ createdAt: now,
9742
+ updatedAt: now
9743
+ });
9682
9744
  return {
9683
9745
  content: [
9684
9746
  {
9685
9747
  type: "text",
9686
- text: `Dataset file not found: ${resolvedPath}`
9748
+ text: JSON.stringify({ job_id: jobId, status, model_db_id: id }, null, 2)
9687
9749
  }
9688
- ],
9689
- isError: true
9750
+ ]
9690
9751
  };
9691
9752
  }
9692
- const p = getProvider(provider);
9693
- const { fileId } = await p.uploadTrainingFile(resolvedPath);
9694
- const { jobId, status } = await p.createFineTuneJob(fileId, base_model, modelName);
9695
- const db = getDb();
9696
- const now = Date.now();
9697
- const id = `${provider}-${jobId}`;
9698
- await db.insert(fineTunedModels).values({
9699
- id,
9700
- name: modelName ?? `${base_model}-finetune-${now}`,
9701
- provider,
9702
- baseModel: base_model,
9703
- status: "pending",
9704
- fineTuneJobId: jobId,
9705
- createdAt: now,
9706
- updatedAt: now
9707
- });
9708
- return {
9709
- content: [
9710
- {
9711
- type: "text",
9712
- text: JSON.stringify({ job_id: jobId, status, model_db_id: id }, null, 2)
9713
- }
9714
- ]
9715
- };
9716
- }
9717
- case "get_finetune_status": {
9718
- const { job_id, provider } = args;
9719
- const p = getProvider(provider);
9720
- const result = await p.getFineTuneStatus(job_id);
9721
- const db = getDb();
9722
- const dbId = `${provider}-${job_id}`;
9723
- const existing = await db.select().from(fineTunedModels).where(eq(fineTunedModels.id, dbId));
9724
- if (existing.length > 0) {
9725
- const mappedStatus = (() => {
9726
- if (result.status === "succeeded")
9727
- return "succeeded";
9728
- if (result.status === "failed")
9729
- return "failed";
9730
- if (result.status === "cancelled")
9731
- return "cancelled";
9732
- if (result.status === "running")
9733
- return "running";
9734
- return "pending";
9735
- })();
9736
- await db.update(fineTunedModels).set({
9737
- status: mappedStatus,
9738
- updatedAt: Date.now()
9739
- }).where(eq(fineTunedModels.id, dbId));
9740
- }
9741
- return {
9742
- content: [
9743
- {
9744
- type: "text",
9745
- text: JSON.stringify({
9746
- job_id: result.jobId,
9747
- status: result.status,
9748
- model_id: result.fineTunedModel,
9749
- error: result.error
9750
- }, null, 2)
9751
- }
9752
- ]
9753
- };
9754
- }
9755
- case "gather_training_data": {
9756
- const {
9757
- sources,
9758
- limit: limit2,
9759
- output_dir
9760
- } = args;
9761
- const { mkdirSync: mkdirSync2, writeFileSync } = await import("fs");
9762
- const { join: join3 } = await import("path");
9763
- const outDir = output_dir ?? defaultOutputDir();
9764
- mkdirSync2(outDir, { recursive: true });
9765
- const datasets = [];
9766
- let totalExamples = 0;
9767
- for (const source of sources) {
9768
- let examples = [];
9769
- if (source === "todos") {
9770
- const result = await gatherFromTodos({ limit: limit2 });
9771
- examples = result.examples;
9772
- } else {
9773
- examples = [];
9753
+ case "get_finetune_status": {
9754
+ const { job_id, provider } = args;
9755
+ const p = getProvider(provider);
9756
+ const result = await p.getFineTuneStatus(job_id);
9757
+ const db = getDb();
9758
+ const dbId = `${provider}-${job_id}`;
9759
+ const existing = await db.select().from(fineTunedModels).where(eq(fineTunedModels.id, dbId));
9760
+ if (existing.length > 0) {
9761
+ const mappedStatus = (() => {
9762
+ if (result.status === "succeeded")
9763
+ return "succeeded";
9764
+ if (result.status === "failed")
9765
+ return "failed";
9766
+ if (result.status === "cancelled")
9767
+ return "cancelled";
9768
+ if (result.status === "running")
9769
+ return "running";
9770
+ return "pending";
9771
+ })();
9772
+ await db.update(fineTunedModels).set({
9773
+ status: mappedStatus,
9774
+ updatedAt: Date.now()
9775
+ }).where(eq(fineTunedModels.id, dbId));
9774
9776
  }
9775
- const filePath = join3(outDir, `${source}-${Date.now()}.jsonl`);
9776
- const jsonl = examples.map((ex) => JSON.stringify(ex)).join(`
9777
- `);
9778
- writeFileSync(filePath, jsonl, "utf-8");
9779
- datasets.push({ source, count: examples.length, file_path: filePath });
9780
- totalExamples += examples.length;
9777
+ return {
9778
+ content: [
9779
+ {
9780
+ type: "text",
9781
+ text: JSON.stringify({
9782
+ job_id: result.jobId,
9783
+ status: result.status,
9784
+ model_id: result.fineTunedModel,
9785
+ error: result.error
9786
+ }, null, 2)
9787
+ }
9788
+ ]
9789
+ };
9781
9790
  }
9782
- return {
9783
- content: [
9784
- {
9785
- type: "text",
9786
- text: JSON.stringify({ datasets, total_examples: totalExamples }, null, 2)
9791
+ case "gather_training_data": {
9792
+ const {
9793
+ sources,
9794
+ limit: limit2,
9795
+ output_dir
9796
+ } = args;
9797
+ const { mkdirSync: mkdirSync2, writeFileSync } = await import("fs");
9798
+ const { join: join3 } = await import("path");
9799
+ const outDir = output_dir ?? defaultOutputDir();
9800
+ mkdirSync2(outDir, { recursive: true });
9801
+ const datasets = [];
9802
+ let totalExamples = 0;
9803
+ for (const source of sources) {
9804
+ let examples = [];
9805
+ if (source === "todos") {
9806
+ const result = await gatherFromTodos({ limit: limit2 });
9807
+ examples = result.examples;
9808
+ } else {
9809
+ examples = [];
9787
9810
  }
9788
- ]
9789
- };
9790
- }
9791
- case "preview_training_data": {
9792
- const { file_path, limit: limit2 = 5 } = args;
9793
- const resolvedPath = resolve(file_path);
9794
- if (!existsSync(resolvedPath)) {
9811
+ const filePath = join3(outDir, `${source}-${Date.now()}.jsonl`);
9812
+ const jsonl = examples.map((ex) => JSON.stringify(ex)).join(`
9813
+ `);
9814
+ writeFileSync(filePath, jsonl, "utf-8");
9815
+ datasets.push({ source, count: examples.length, file_path: filePath });
9816
+ totalExamples += examples.length;
9817
+ }
9795
9818
  return {
9796
9819
  content: [
9797
- { type: "text", text: `File not found: ${resolvedPath}` }
9798
- ],
9799
- isError: true
9820
+ {
9821
+ type: "text",
9822
+ text: JSON.stringify({ datasets, total_examples: totalExamples }, null, 2)
9823
+ }
9824
+ ]
9800
9825
  };
9801
9826
  }
9802
- const content = readFileSync2(resolvedPath, "utf-8");
9803
- const lines = content.split(`
9827
+ case "preview_training_data": {
9828
+ const { file_path, limit: limit2 = 5 } = args;
9829
+ const resolvedPath = resolve2(file_path);
9830
+ if (!existsSync2(resolvedPath)) {
9831
+ return {
9832
+ content: [
9833
+ { type: "text", text: `File not found: ${resolvedPath}` }
9834
+ ],
9835
+ isError: true
9836
+ };
9837
+ }
9838
+ const content = readFileSync3(resolvedPath, "utf-8");
9839
+ const lines = content.split(`
9804
9840
  `).map((l) => l.trim()).filter(Boolean);
9805
- const total = lines.length;
9806
- const examples = lines.slice(0, limit2).map((line) => JSON.parse(line));
9807
- return {
9808
- content: [
9809
- {
9810
- type: "text",
9811
- text: JSON.stringify({ examples, total }, null, 2)
9812
- }
9813
- ]
9814
- };
9841
+ const total = lines.length;
9842
+ const examples = lines.slice(0, limit2).map((line) => JSON.parse(line));
9843
+ return {
9844
+ content: [
9845
+ {
9846
+ type: "text",
9847
+ text: JSON.stringify({ examples, total }, null, 2)
9848
+ }
9849
+ ]
9850
+ };
9851
+ }
9852
+ default:
9853
+ return {
9854
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
9855
+ isError: true
9856
+ };
9815
9857
  }
9816
- default:
9817
- return {
9818
- content: [{ type: "text", text: `Unknown tool: ${name}` }],
9819
- isError: true
9820
- };
9858
+ } catch (err) {
9859
+ const message = err instanceof Error ? err.message : String(err);
9860
+ return {
9861
+ content: [{ type: "text", text: `Error: ${message}` }],
9862
+ isError: true
9863
+ };
9821
9864
  }
9822
- } catch (err) {
9823
- const message = err instanceof Error ? err.message : String(err);
9824
- return {
9825
- content: [{ type: "text", text: `Error: ${message}` }],
9826
- isError: true
9827
- };
9828
- }
9829
- });
9830
- var transport = new StdioServerTransport;
9831
- await server.connect(transport);
9865
+ });
9866
+ return server;
9867
+ }
9868
+ async function startMcpServer(transport = new StdioServerTransport) {
9869
+ const server = createMcpServer();
9870
+ await server.connect(transport);
9871
+ return server;
9872
+ }
9873
+ if (import.meta.main) {
9874
+ await startMcpServer();
9875
+ }
9876
+ export {
9877
+ startMcpServer,
9878
+ createMcpServer,
9879
+ MCP_SERVER_INFO
9880
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/brains",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Fine-tuned model tracker and trainer — wraps OpenAI + Thinker Labs, gathers training data from todos/mementos/conversations/sessions",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",