@hasna/brains 0.0.28 → 0.0.30

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
@@ -18128,7 +18128,7 @@ function printInfo(message) {
18128
18128
  }
18129
18129
 
18130
18130
  // src/cli/commands/models.ts
18131
- import { randomUUID as randomUUID3 } from "crypto";
18131
+ import { randomUUID as randomUUID5 } from "crypto";
18132
18132
 
18133
18133
  // node_modules/openai/internal/qs/formats.mjs
18134
18134
  var default_format = "RFC3986";
@@ -23618,16 +23618,48 @@ var openai_default = OpenAI;
23618
23618
  import { readFileSync as readFileSync5 } from "fs";
23619
23619
 
23620
23620
  // src/lib/config.ts
23621
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync7, readdirSync as readdirSync4, copyFileSync as copyFileSync2, statSync } from "fs";
23621
+ import {
23622
+ chmodSync,
23623
+ copyFileSync as copyFileSync2,
23624
+ existsSync as existsSync7,
23625
+ lstatSync,
23626
+ mkdirSync as mkdirSync4,
23627
+ readFileSync as readFileSync3,
23628
+ readdirSync as readdirSync4,
23629
+ renameSync,
23630
+ statSync,
23631
+ unlinkSync as unlinkSync2,
23632
+ writeFileSync as writeFileSync3
23633
+ } from "fs";
23634
+ import { randomUUID as randomUUID3 } from "crypto";
23622
23635
  import { join as join7, dirname as dirname2 } from "path";
23623
23636
  import { homedir as homedir6 } from "os";
23624
23637
  var CONFIG_KEYS = ["OPENAI_API_KEY", "THINKER_LABS_API_KEY", "THINKER_LABS_BASE_URL"];
23638
+ var CONFIG_FILE_NAME = "config.json";
23639
+ function restrictConfigFilePermissions(configPath) {
23640
+ try {
23641
+ if (!lstatSync(configPath).isFile())
23642
+ return;
23643
+ chmodSync(configPath, 384);
23644
+ } catch {}
23645
+ }
23646
+ function ensureConfigDirectory(dirPath) {
23647
+ mkdirSync4(dirPath, { recursive: true, mode: 448 });
23648
+ try {
23649
+ if (!statSync(dirPath).isDirectory())
23650
+ return;
23651
+ chmodSync(dirPath, 448);
23652
+ } catch {}
23653
+ }
23625
23654
  function resolveConfigPath() {
23626
23655
  const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir6();
23627
- const newDir = join7(home, ".hasna", "brains");
23656
+ const hasnaDir = join7(home, ".hasna");
23657
+ const newDir = join7(hasnaDir, "brains");
23628
23658
  const oldDir = join7(home, ".brains");
23659
+ const configPath = join7(newDir, CONFIG_FILE_NAME);
23660
+ ensureConfigDirectory(hasnaDir);
23629
23661
  if (existsSync7(oldDir) && !existsSync7(newDir)) {
23630
- mkdirSync4(newDir, { recursive: true });
23662
+ ensureConfigDirectory(newDir);
23631
23663
  try {
23632
23664
  for (const file of readdirSync4(oldDir)) {
23633
23665
  const oldPath = join7(oldDir, file);
@@ -23635,28 +23667,46 @@ function resolveConfigPath() {
23635
23667
  try {
23636
23668
  if (statSync(oldPath).isFile()) {
23637
23669
  copyFileSync2(oldPath, newPath);
23670
+ if (file === CONFIG_FILE_NAME)
23671
+ restrictConfigFilePermissions(newPath);
23638
23672
  }
23639
23673
  } catch {}
23640
23674
  }
23641
23675
  } catch {}
23642
23676
  }
23643
- mkdirSync4(newDir, { recursive: true });
23644
- return join7(newDir, "config.json");
23677
+ ensureConfigDirectory(newDir);
23678
+ return configPath;
23645
23679
  }
23646
- var CONFIG_PATH2 = resolveConfigPath();
23647
23680
  function readConfigFile() {
23648
- if (!existsSync7(CONFIG_PATH2))
23681
+ const configPath = resolveConfigPath();
23682
+ if (!existsSync7(configPath))
23649
23683
  return {};
23650
23684
  try {
23651
- return JSON.parse(readFileSync3(CONFIG_PATH2, "utf-8"));
23685
+ return JSON.parse(readFileSync3(configPath, "utf-8"));
23652
23686
  } catch {
23653
23687
  return {};
23654
23688
  }
23655
23689
  }
23656
23690
  function writeConfigFile(data) {
23657
- mkdirSync4(dirname2(CONFIG_PATH2), { recursive: true });
23658
- writeFileSync3(CONFIG_PATH2, JSON.stringify(data, null, 2) + `
23659
- `, "utf-8");
23691
+ const configPath = resolveConfigPath();
23692
+ const configDir = dirname2(configPath);
23693
+ const tempPath = join7(configDir, `.config.json.${randomUUID3()}.tmp`);
23694
+ ensureConfigDirectory(configDir);
23695
+ if (existsSync7(configPath))
23696
+ restrictConfigFilePermissions(configPath);
23697
+ try {
23698
+ writeFileSync3(tempPath, JSON.stringify(data, null, 2) + `
23699
+ `, { encoding: "utf-8", mode: 384, flag: "wx" });
23700
+ restrictConfigFilePermissions(tempPath);
23701
+ renameSync(tempPath, configPath);
23702
+ restrictConfigFilePermissions(configPath);
23703
+ } catch (err) {
23704
+ try {
23705
+ if (existsSync7(tempPath))
23706
+ unlinkSync2(tempPath);
23707
+ } catch {}
23708
+ throw err;
23709
+ }
23660
23710
  }
23661
23711
  function getConfigValue(key) {
23662
23712
  if (process.env[key])
@@ -24068,7 +24118,7 @@ function registerModelsCommands(program2) {
24068
24118
  printInfo(`Model already tracked as: ${existing.id}`);
24069
24119
  return;
24070
24120
  }
24071
- const modelId = randomUUID3();
24121
+ const modelId = randomUUID5();
24072
24122
  const now2 = Date.now();
24073
24123
  const name = opts.name ?? result.fineTunedModel ?? `imported-${jobId}`;
24074
24124
  await db.insert(fineTunedModels).values({
@@ -24082,7 +24132,7 @@ function registerModelsCommands(program2) {
24082
24132
  updatedAt: now2
24083
24133
  });
24084
24134
  await db.insert(trainingJobs).values({
24085
- id: randomUUID3(),
24135
+ id: randomUUID5(),
24086
24136
  modelId,
24087
24137
  provider: opts.provider,
24088
24138
  status: result.status,
@@ -24105,7 +24155,7 @@ function registerModelsCommands(program2) {
24105
24155
  }
24106
24156
 
24107
24157
  // src/cli/commands/finetune.ts
24108
- import { randomUUID as randomUUID5 } from "crypto";
24158
+ import { randomUUID as randomUUID6 } from "crypto";
24109
24159
  import { existsSync as existsSync9 } from "fs";
24110
24160
  function registerFinetuneCommands(program2) {
24111
24161
  const finetuneCmd = program2.command("finetune").description("Manage fine-tuning jobs");
@@ -24147,7 +24197,7 @@ function registerFinetuneCommands(program2) {
24147
24197
  ({ jobId, status: jobStatus } = await tl.createFineTuneJob(fileId, opts.baseModel, opts.name));
24148
24198
  }
24149
24199
  const db = getDb();
24150
- const modelId = randomUUID5();
24200
+ const modelId = randomUUID6();
24151
24201
  const now2 = Date.now();
24152
24202
  await db.insert(fineTunedModels).values({
24153
24203
  id: modelId,
@@ -24159,7 +24209,7 @@ function registerFinetuneCommands(program2) {
24159
24209
  createdAt: now2,
24160
24210
  updatedAt: now2
24161
24211
  });
24162
- const trainingJobId = randomUUID5();
24212
+ const trainingJobId = randomUUID6();
24163
24213
  await db.insert(trainingJobs).values({
24164
24214
  id: trainingJobId,
24165
24215
  modelId,
@@ -24299,7 +24349,7 @@ function registerFinetuneCommands(program2) {
24299
24349
  }
24300
24350
 
24301
24351
  // src/cli/commands/data.ts
24302
- import { randomUUID as randomUUID6 } from "crypto";
24352
+ import { randomUUID as randomUUID7 } from "crypto";
24303
24353
  import { readFileSync as readFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "fs";
24304
24354
  import { dirname as dirname3, join as join13 } from "path";
24305
24355
  import { homedir as homedir12 } from "os";
@@ -24349,7 +24399,7 @@ function registerDataCommands(program2) {
24349
24399
  `) + `
24350
24400
  `, "utf8");
24351
24401
  await db.insert(trainingDatasets).values({
24352
- id: randomUUID6(),
24402
+ id: randomUUID7(),
24353
24403
  source,
24354
24404
  filePath,
24355
24405
  exampleCount: count,
@@ -24439,7 +24489,7 @@ function registerDataCommands(program2) {
24439
24489
  `, "utf8");
24440
24490
  const db = getDb();
24441
24491
  await db.insert(trainingDatasets).values({
24442
- id: randomUUID6(),
24492
+ id: randomUUID7(),
24443
24493
  source: "mixed",
24444
24494
  filePath: opts.output,
24445
24495
  exampleCount: finalLines.length,
package/dist/index.js CHANGED
@@ -18984,16 +18984,48 @@ var openai_default = OpenAI;
18984
18984
  import { readFileSync as readFileSync3 } from "fs";
18985
18985
 
18986
18986
  // src/lib/config.ts
18987
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync3, readdirSync as readdirSync2, copyFileSync as copyFileSync2, statSync } from "fs";
18987
+ import {
18988
+ chmodSync,
18989
+ copyFileSync as copyFileSync2,
18990
+ existsSync as existsSync3,
18991
+ lstatSync,
18992
+ mkdirSync as mkdirSync3,
18993
+ readFileSync as readFileSync2,
18994
+ readdirSync as readdirSync2,
18995
+ renameSync,
18996
+ statSync,
18997
+ unlinkSync,
18998
+ writeFileSync as writeFileSync2
18999
+ } from "fs";
19000
+ import { randomUUID } from "crypto";
18988
19001
  import { join as join4, dirname as dirname2 } from "path";
18989
19002
  import { homedir as homedir6 } from "os";
18990
19003
  var CONFIG_KEYS = ["OPENAI_API_KEY", "THINKER_LABS_API_KEY", "THINKER_LABS_BASE_URL"];
19004
+ var CONFIG_FILE_NAME = "config.json";
19005
+ function restrictConfigFilePermissions(configPath) {
19006
+ try {
19007
+ if (!lstatSync(configPath).isFile())
19008
+ return;
19009
+ chmodSync(configPath, 384);
19010
+ } catch {}
19011
+ }
19012
+ function ensureConfigDirectory(dirPath) {
19013
+ mkdirSync3(dirPath, { recursive: true, mode: 448 });
19014
+ try {
19015
+ if (!statSync(dirPath).isDirectory())
19016
+ return;
19017
+ chmodSync(dirPath, 448);
19018
+ } catch {}
19019
+ }
18991
19020
  function resolveConfigPath() {
18992
19021
  const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir6();
18993
- const newDir = join4(home, ".hasna", "brains");
19022
+ const hasnaDir = join4(home, ".hasna");
19023
+ const newDir = join4(hasnaDir, "brains");
18994
19024
  const oldDir = join4(home, ".brains");
19025
+ const configPath = join4(newDir, CONFIG_FILE_NAME);
19026
+ ensureConfigDirectory(hasnaDir);
18995
19027
  if (existsSync3(oldDir) && !existsSync3(newDir)) {
18996
- mkdirSync3(newDir, { recursive: true });
19028
+ ensureConfigDirectory(newDir);
18997
19029
  try {
18998
19030
  for (const file of readdirSync2(oldDir)) {
18999
19031
  const oldPath = join4(oldDir, file);
@@ -19001,28 +19033,46 @@ function resolveConfigPath() {
19001
19033
  try {
19002
19034
  if (statSync(oldPath).isFile()) {
19003
19035
  copyFileSync2(oldPath, newPath);
19036
+ if (file === CONFIG_FILE_NAME)
19037
+ restrictConfigFilePermissions(newPath);
19004
19038
  }
19005
19039
  } catch {}
19006
19040
  }
19007
19041
  } catch {}
19008
19042
  }
19009
- mkdirSync3(newDir, { recursive: true });
19010
- return join4(newDir, "config.json");
19043
+ ensureConfigDirectory(newDir);
19044
+ return configPath;
19011
19045
  }
19012
- var CONFIG_PATH2 = resolveConfigPath();
19013
19046
  function readConfigFile() {
19014
- if (!existsSync3(CONFIG_PATH2))
19047
+ const configPath = resolveConfigPath();
19048
+ if (!existsSync3(configPath))
19015
19049
  return {};
19016
19050
  try {
19017
- return JSON.parse(readFileSync2(CONFIG_PATH2, "utf-8"));
19051
+ return JSON.parse(readFileSync2(configPath, "utf-8"));
19018
19052
  } catch {
19019
19053
  return {};
19020
19054
  }
19021
19055
  }
19022
19056
  function writeConfigFile(data) {
19023
- mkdirSync3(dirname2(CONFIG_PATH2), { recursive: true });
19024
- writeFileSync2(CONFIG_PATH2, JSON.stringify(data, null, 2) + `
19025
- `, "utf-8");
19057
+ const configPath = resolveConfigPath();
19058
+ const configDir = dirname2(configPath);
19059
+ const tempPath = join4(configDir, `.config.json.${randomUUID()}.tmp`);
19060
+ ensureConfigDirectory(configDir);
19061
+ if (existsSync3(configPath))
19062
+ restrictConfigFilePermissions(configPath);
19063
+ try {
19064
+ writeFileSync2(tempPath, JSON.stringify(data, null, 2) + `
19065
+ `, { encoding: "utf-8", mode: 384, flag: "wx" });
19066
+ restrictConfigFilePermissions(tempPath);
19067
+ renameSync(tempPath, configPath);
19068
+ restrictConfigFilePermissions(configPath);
19069
+ } catch (err) {
19070
+ try {
19071
+ if (existsSync3(tempPath))
19072
+ unlinkSync(tempPath);
19073
+ } catch {}
19074
+ throw err;
19075
+ }
19026
19076
  }
19027
19077
  function getConfigValue(key) {
19028
19078
  if (process.env[key])
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,WAAW,8EAA+E,CAAC;AACxG,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AA+CrD,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAIjE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAIlE;AAED,wBAAgB,UAAU,IAAI,KAAK,CAAC;IAAE,GAAG,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC,CAOvG;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAItD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,WAAW,8EAA+E,CAAC;AACxG,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAuFrD,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAIjE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAIlE;AAED,wBAAgB,UAAU,IAAI,KAAK,CAAC;IAAE,GAAG,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC,CAOvG;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAItD"}
package/dist/mcp/index.js CHANGED
@@ -19495,15 +19495,46 @@ var openai_default = OpenAI;
19495
19495
  import { readFileSync as readFileSync3 } from "fs";
19496
19496
 
19497
19497
  // src/lib/config.ts
19498
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync3, readdirSync as readdirSync2, copyFileSync as copyFileSync2, statSync } from "fs";
19498
+ import {
19499
+ chmodSync,
19500
+ copyFileSync as copyFileSync2,
19501
+ existsSync as existsSync3,
19502
+ lstatSync,
19503
+ mkdirSync as mkdirSync3,
19504
+ readFileSync as readFileSync2,
19505
+ readdirSync as readdirSync2,
19506
+ renameSync,
19507
+ statSync,
19508
+ unlinkSync,
19509
+ writeFileSync as writeFileSync2
19510
+ } from "fs";
19499
19511
  import { join as join4, dirname as dirname2 } from "path";
19500
19512
  import { homedir as homedir6 } from "os";
19513
+ var CONFIG_FILE_NAME = "config.json";
19514
+ function restrictConfigFilePermissions(configPath) {
19515
+ try {
19516
+ if (!lstatSync(configPath).isFile())
19517
+ return;
19518
+ chmodSync(configPath, 384);
19519
+ } catch {}
19520
+ }
19521
+ function ensureConfigDirectory(dirPath) {
19522
+ mkdirSync3(dirPath, { recursive: true, mode: 448 });
19523
+ try {
19524
+ if (!statSync(dirPath).isDirectory())
19525
+ return;
19526
+ chmodSync(dirPath, 448);
19527
+ } catch {}
19528
+ }
19501
19529
  function resolveConfigPath() {
19502
19530
  const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir6();
19503
- const newDir = join4(home, ".hasna", "brains");
19531
+ const hasnaDir = join4(home, ".hasna");
19532
+ const newDir = join4(hasnaDir, "brains");
19504
19533
  const oldDir = join4(home, ".brains");
19534
+ const configPath = join4(newDir, CONFIG_FILE_NAME);
19535
+ ensureConfigDirectory(hasnaDir);
19505
19536
  if (existsSync3(oldDir) && !existsSync3(newDir)) {
19506
- mkdirSync3(newDir, { recursive: true });
19537
+ ensureConfigDirectory(newDir);
19507
19538
  try {
19508
19539
  for (const file of readdirSync2(oldDir)) {
19509
19540
  const oldPath = join4(oldDir, file);
@@ -19511,20 +19542,22 @@ function resolveConfigPath() {
19511
19542
  try {
19512
19543
  if (statSync(oldPath).isFile()) {
19513
19544
  copyFileSync2(oldPath, newPath);
19545
+ if (file === CONFIG_FILE_NAME)
19546
+ restrictConfigFilePermissions(newPath);
19514
19547
  }
19515
19548
  } catch {}
19516
19549
  }
19517
19550
  } catch {}
19518
19551
  }
19519
- mkdirSync3(newDir, { recursive: true });
19520
- return join4(newDir, "config.json");
19552
+ ensureConfigDirectory(newDir);
19553
+ return configPath;
19521
19554
  }
19522
- var CONFIG_PATH2 = resolveConfigPath();
19523
19555
  function readConfigFile() {
19524
- if (!existsSync3(CONFIG_PATH2))
19556
+ const configPath = resolveConfigPath();
19557
+ if (!existsSync3(configPath))
19525
19558
  return {};
19526
19559
  try {
19527
- return JSON.parse(readFileSync2(CONFIG_PATH2, "utf-8"));
19560
+ return JSON.parse(readFileSync2(configPath, "utf-8"));
19528
19561
  } catch {
19529
19562
  return {};
19530
19563
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/brains",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
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",