@ziamana/bruine 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +24 -1
  2. package/dist/bin.js +128 -34
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
  [![License: MIT](https://img.shields.io/badge/license-MIT-b4a7ff)](LICENSE)
13
13
  [![Node 22+](https://img.shields.io/badge/node-22%2B-7dcfff)](https://nodejs.org)
14
14
  ![Windows · macOS · Linux](https://img.shields.io/badge/Windows%20%C2%B7%20macOS%20%C2%B7%20Linux-supported-8fe3a3)
15
- [![Changelog](https://img.shields.io/badge/version-0.1.0-ff9ed2)](CHANGELOG.md)
15
+ [![Changelog](https://img.shields.io/badge/version-0.1.2-ff9ed2)](CHANGELOG.md)
16
16
 
17
17
  <a href="docs/media/bruine-film.mp4"><img src="docs/media/hero.webp" alt="The bruine film: the word bruine becomes the logo in the rain, then the effort climbs from low to max and the rain turns into a storm" width="100%"></a>
18
18
 
@@ -35,6 +35,29 @@ bruine
35
35
  The first launch opens a setup wizard: it finds a local model server if you run one, asks for API
36
36
  keys if you want a cloud route, lets you pick skills, and writes `~/.bruine/`.
37
37
 
38
+ ## Install
39
+
40
+ You need **Node 22 or newer** and npm (it comes with Node). Check with `node --version`.
41
+
42
+ | | Get Node 22+ | Install bruine | Open it in |
43
+ |---|---|---|---|
44
+ | **Linux** | your package manager (`sudo pacman -S nodejs npm`, `sudo apt install nodejs npm` if it is 22+) or [nvm](https://github.com/nvm-sh/nvm) | `npm install -g @ziamana/bruine` | any terminal |
45
+ | **macOS** | `brew install node`, or the installer from [nodejs.org](https://nodejs.org) | `npm install -g @ziamana/bruine` | Terminal or iTerm2 |
46
+ | **Windows** | `winget install OpenJS.NodeJS.LTS`, or the installer from [nodejs.org](https://nodejs.org) | `npm install -g @ziamana/bruine` | Windows Terminal (PowerShell) |
47
+
48
+ Then type `bruine` in your project's folder. The command is `bruine`; `@ziamana/bruine` is only the
49
+ name npm knows it by.
50
+
51
+ - **Permission denied (`EACCES`) on Linux or macOS**: do not use `sudo`. Point npm at a folder you own:
52
+ `npm config set prefix ~/.local`, and make sure `~/.local/bin` is on your `PATH`.
53
+ - **Update**: `bruine update` (or `/update` in a session). **Remove**: `npm uninstall -g @ziamana/bruine`,
54
+ and delete `~/.bruine` if you want your settings gone too.
55
+ - **Where it was tested**: Linux every day. On macOS the unit tests pass on the CI runner and the
56
+ terminal tests are being fixed; on Windows both are being fixed, and it has not yet been run by hand
57
+ on a real Windows machine. If something breaks there,
58
+ [open an issue](https://github.com/ziamana/bruine/issues) with your terminal and `bruine --version`.
59
+ [docs/PLATFORMS.md](docs/PLATFORMS.md) lists what was checked.
60
+
38
61
  ## See it
39
62
 
40
63
  <img src="docs/demo/bruine.svg" alt="bruine in a terminal: a prompt, the model's reasoning streaming then folding away, a file read, an edit shown as a diff, two permission prompts, the tests passing, and a second prompt that was queued while it worked going out after" width="100%">
package/dist/bin.js CHANGED
@@ -1180,6 +1180,48 @@ var init_skills = __esm({
1180
1180
  }
1181
1181
  });
1182
1182
 
1183
+ // src/setup/default-skills.ts
1184
+ import { existsSync as existsSync6 } from "fs";
1185
+ import { readFile as readFile4 } from "fs/promises";
1186
+ import { homedir as homedir3 } from "os";
1187
+ import { join as join4 } from "path";
1188
+ function defaultSkills(bundled) {
1189
+ return bundled.map((s) => s.name).filter((name) => !NOT_BY_DEFAULT.includes(name));
1190
+ }
1191
+ async function ensureDefaultSkills(opts) {
1192
+ const homeSkillsDir = join4(opts.dshHome, "skills");
1193
+ let doc = {};
1194
+ try {
1195
+ doc = JSON.parse(await readFile4(configReadPath(opts.dshHome), "utf8"));
1196
+ } catch {
1197
+ doc = {};
1198
+ }
1199
+ const nothing = { installed: [], kept: [] };
1200
+ if (Array.isArray(doc.skills)) return nothing;
1201
+ if (existsSync6(manifestReadPath(homeSkillsDir))) return nothing;
1202
+ const bundled = await readBundledSkills(opts.bundledRoot);
1203
+ if (bundled.length === 0) return nothing;
1204
+ const shipped = new Set(bundled.map((s) => s.name));
1205
+ const home = opts.home ?? homedir3();
1206
+ const mine = (await scanFoundSkills(home)).filter((s) => s.source === "agents" && !shipped.has(s.name));
1207
+ const chosen = [...defaultSkills(bundled), ...mine.map((s) => s.name)];
1208
+ const result = await syncSkills({ homeSkillsDir, bundledRoot: opts.bundledRoot, chosen, home });
1209
+ doc.skills = chosen;
1210
+ await writeAtomic2(configWritePath(opts.dshHome), `${JSON.stringify(doc, null, 2)}
1211
+ `);
1212
+ return { installed: result.installed, kept: mine.map((s) => s.name).filter((n) => result.installed.includes(n)) };
1213
+ }
1214
+ var NOT_BY_DEFAULT;
1215
+ var init_default_skills = __esm({
1216
+ "src/setup/default-skills.ts"() {
1217
+ "use strict";
1218
+ init_compat();
1219
+ init_simple();
1220
+ init_skills();
1221
+ NOT_BY_DEFAULT = ["remotion", "remotion-best-practices"];
1222
+ }
1223
+ });
1224
+
1183
1225
  // src/render/chars.ts
1184
1226
  function iconsFor(env = process.env, platform = process.platform) {
1185
1227
  if (appEnv("ASCII", env) === "1") return ASCII_ICONS;
@@ -1518,7 +1560,7 @@ var init_theme = __esm({
1518
1560
  // src/update.ts
1519
1561
  import { spawn } from "child_process";
1520
1562
  import { realpathSync } from "fs";
1521
- import { mkdir as mkdir4, readFile as readFile4, rename as rename4, writeFile as writeFile4 } from "fs/promises";
1563
+ import { mkdir as mkdir4, readFile as readFile5, rename as rename4, writeFile as writeFile4 } from "fs/promises";
1522
1564
  import path5 from "path";
1523
1565
  function updateCachePath(dshHome, pathMod = path5) {
1524
1566
  return pathMod.join(dshHome, UPDATE_CACHE_FILE);
@@ -1533,7 +1575,7 @@ function updateCheckEnabled(opts) {
1533
1575
  async function readUpdateCache(dshHome, pathMod = path5) {
1534
1576
  try {
1535
1577
  const doc = JSON.parse(
1536
- await readFile4(updateCachePath(dshHome, pathMod), "utf8")
1578
+ await readFile5(updateCachePath(dshHome, pathMod), "utf8")
1537
1579
  );
1538
1580
  if (typeof doc.checkedAt !== "number" || typeof doc.latest !== "string") return void 0;
1539
1581
  return { checkedAt: doc.checkedAt, latest: doc.latest };
@@ -1552,7 +1594,7 @@ async function writeUpdateCache(dshHome, cache, pathMod) {
1552
1594
  async function readBruineJsonDoc(dshHome) {
1553
1595
  try {
1554
1596
  return JSON.parse(
1555
- await readFile4(configReadPath(dshHome), "utf8")
1597
+ await readFile5(configReadPath(dshHome), "utf8")
1556
1598
  );
1557
1599
  } catch {
1558
1600
  return {};
@@ -1761,8 +1803,8 @@ var init_keys = __esm({
1761
1803
  });
1762
1804
 
1763
1805
  // src/setup/flow.ts
1764
- import { chmod as chmod2, mkdir as mkdir5, readFile as readFile5, rename as rename5, writeFile as writeFile5 } from "fs/promises";
1765
- import { dirname as dirname3, join as join5 } from "path";
1806
+ import { chmod as chmod2, mkdir as mkdir5, readFile as readFile6, rename as rename5, writeFile as writeFile5 } from "fs/promises";
1807
+ import { dirname as dirname3, join as join6 } from "path";
1766
1808
  function roleFromModelRef(ref) {
1767
1809
  if (ref.provider === "deepseek-official") return { cloud: "deepseek-official", model: ref.model };
1768
1810
  if (typeof ref.baseUrl === "string" && ref.baseUrl !== "") {
@@ -1811,10 +1853,10 @@ function usesLocalServer(answers) {
1811
1853
  }
1812
1854
  async function commitPlan(dshHome, plan) {
1813
1855
  if (plan.env.some(([name]) => name === void 0)) throw new Error("bad env entry");
1814
- await writeAtom(join5(dshHome, "settings.yaml"), plan.settingsYaml, 384);
1856
+ await writeAtom(join6(dshHome, "settings.yaml"), plan.settingsYaml, 384);
1815
1857
  let bruineJson = plan.bruineJson;
1816
1858
  try {
1817
- const previous = JSON.parse(await readFile5(configReadPath(dshHome), "utf8"));
1859
+ const previous = JSON.parse(await readFile6(configReadPath(dshHome), "utf8"));
1818
1860
  if (previous.reasoningEffort !== void 0) {
1819
1861
  const doc = JSON.parse(bruineJson);
1820
1862
  doc.reasoningEffort = previous.reasoningEffort;
@@ -1825,7 +1867,7 @@ async function commitPlan(dshHome, plan) {
1825
1867
  }
1826
1868
  await writeAtom(configWritePath(dshHome), bruineJson, 384);
1827
1869
  for (const [name, value] of plan.env) {
1828
- await writeEnvVar(join5(dshHome, ".env"), name, value);
1870
+ await writeEnvVar(join6(dshHome, ".env"), name, value);
1829
1871
  }
1830
1872
  await syncSkills(plan.skills);
1831
1873
  }
@@ -2141,7 +2183,7 @@ var init_flow = __esm({
2141
2183
  `,
2142
2184
  env,
2143
2185
  skills: {
2144
- homeSkillsDir: join5(opts.dshHome, "skills"),
2186
+ homeSkillsDir: join6(opts.dshHome, "skills"),
2145
2187
  bundledRoot: opts.bundledSkillsRoot,
2146
2188
  chosen: a.skills
2147
2189
  }
@@ -3103,10 +3145,10 @@ import {
3103
3145
  isKeyRelease as isKeyRelease4,
3104
3146
  matchesKey as matchesKey4
3105
3147
  } from "@earendil-works/pi-tui";
3106
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
3148
+ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
3107
3149
  import { mkdir as mkdir6, rename as rename6, writeFile as writeFile6 } from "fs/promises";
3108
- import { homedir as homedir3 } from "os";
3109
- import { dirname as dirname4, join as join6, resolve } from "path";
3150
+ import { homedir as homedir4 } from "os";
3151
+ import { dirname as dirname4, join as join7, resolve } from "path";
3110
3152
  import { fileURLToPath } from "url";
3111
3153
  import { parse as parseYaml3 } from "yaml";
3112
3154
  async function setSuggestionsChoice(dshHome, value) {
@@ -3123,7 +3165,7 @@ function bundledSkillsRoot() {
3123
3165
  const dir = dirname4(fileURLToPath(import.meta.url));
3124
3166
  for (const up of [1, 2, 3]) {
3125
3167
  const candidate = resolve(dir, "..".repeat(up), "skills");
3126
- if (existsSync6(join6(candidate, "git-workflow", "SKILL.md"))) return candidate;
3168
+ if (existsSync7(join7(candidate, "git-workflow", "SKILL.md"))) return candidate;
3127
3169
  }
3128
3170
  return resolve(dir, "..", "skills");
3129
3171
  }
@@ -3144,7 +3186,7 @@ function isExistingInstall(prefill) {
3144
3186
  function readEnvFile(dshHome) {
3145
3187
  const out = {};
3146
3188
  try {
3147
- for (const line of readFileSync4(join6(dshHome, ".env"), "utf8").split(/\r?\n/)) {
3189
+ for (const line of readFileSync4(join7(dshHome, ".env"), "utf8").split(/\r?\n/)) {
3148
3190
  const m = /^([A-Z][A-Z0-9_]*)=(.*)$/.exec(line);
3149
3191
  if (m !== null && m[1] !== void 0 && m[2] !== void 0) out[m[1]] = m[2];
3150
3192
  }
@@ -3161,7 +3203,7 @@ function loadPrefill(dshHome) {
3161
3203
  }
3162
3204
  let settingsDoc;
3163
3205
  try {
3164
- settingsDoc = parseSettingsYaml(readFileSync4(join6(dshHome, "settings.yaml"), "utf8"));
3206
+ settingsDoc = parseSettingsYaml(readFileSync4(join7(dshHome, "settings.yaml"), "utf8"));
3165
3207
  } catch {
3166
3208
  settingsDoc = void 0;
3167
3209
  }
@@ -3379,7 +3421,7 @@ function savedSkillsList(dshHome) {
3379
3421
  }
3380
3422
  function installedSkillsList(dshHome) {
3381
3423
  try {
3382
- const raw = JSON.parse(readFileSync4(manifestReadPath(join6(dshHome, "skills")), "utf8"));
3424
+ const raw = JSON.parse(readFileSync4(manifestReadPath(join7(dshHome, "skills")), "utf8"));
3383
3425
  const names = Object.keys(raw).filter((n) => n !== "" && typeof raw[n] !== "undefined");
3384
3426
  return names.length > 0 ? names.sort((a, b) => a.localeCompare(b)) : [];
3385
3427
  } catch {
@@ -3392,8 +3434,10 @@ function initialSkillChecks(items, saved, found) {
3392
3434
  if (item.disabled === true) return;
3393
3435
  if (saved !== void 0) {
3394
3436
  if (saved.includes(item.value)) checked.add(i);
3395
- } else if (item.value !== "remotion" && item.value !== "remotion-best-practices" && (RECOMMENDED_SKILLS.includes(item.value) || found.some((f) => f.name === item.value && f.source === "agents"))) {
3396
- checked.add(i);
3437
+ } else if (!NOT_BY_DEFAULT.includes(item.value)) {
3438
+ const foundRow = found.find((f) => f.name === item.value);
3439
+ const shipped = !item.value.startsWith("#") && foundRow === void 0;
3440
+ if (shipped || RECOMMENDED_SKILLS.includes(item.value) || foundRow?.source === "agents") checked.add(i);
3397
3441
  }
3398
3442
  });
3399
3443
  return checked;
@@ -3588,6 +3632,9 @@ async function runFullSetup(dshHome, opts = {}) {
3588
3632
  async function drive() {
3589
3633
  const bundledRoot = opts.bundledSkillsRoot ?? bundledSkillsRoot();
3590
3634
  const bundled = await readBundledSkills(bundledRoot);
3635
+ if (flow.answers.skills.length === 0 && savedSkillsList(dshHome) === void 0 && installedSkillsList(dshHome) === void 0) {
3636
+ flow.answers.skills = defaultSkills(bundled);
3637
+ }
3591
3638
  const showWelcome = async () => {
3592
3639
  keyHelp = "Enter continue \xB7 Ctrl+C quit";
3593
3640
  status = "Bruine setup";
@@ -4208,7 +4255,7 @@ async function runFullSetup(dshHome, opts = {}) {
4208
4255
  }
4209
4256
  async function stepSkills(bundled) {
4210
4257
  displayStep = "skills";
4211
- const allFound = await scanFoundSkills(homedir3());
4258
+ const allFound = await scanFoundSkills(homedir4());
4212
4259
  const shippedNames = new Set(bundled.map((s) => s.name));
4213
4260
  const found = allFound.filter((s) => !shippedNames.has(s.name));
4214
4261
  const project2 = await scanProjectSkills(process.cwd());
@@ -4232,7 +4279,7 @@ async function runFullSetup(dshHome, opts = {}) {
4232
4279
  const saved = skillsSubmitted ? flow.answers.skills : savedSkillsList(dshHome);
4233
4280
  const checked = initialSkillChecks(items, saved, found);
4234
4281
  const sel = await checkStep(
4235
- saved !== void 0 && saved.length > 0 ? `Skills: Space toggles, Enter continues, s skips (keeps ${String(saved.length)} enabled)` : "Skills: Space toggles, Enter continues, s skips (enables none)",
4282
+ saved !== void 0 && saved.length > 0 ? `Skills: Space toggles, Enter continues, s skips (keeps ${String(saved.length)} enabled)` : "Skills: Space toggles, Enter continues, s skips (keeps the recommended ones)",
4236
4283
  items,
4237
4284
  checked
4238
4285
  );
@@ -4457,6 +4504,7 @@ var init_full = __esm({
4457
4504
  init_cloud();
4458
4505
  init_spacebunny();
4459
4506
  init_discover();
4507
+ init_default_skills();
4460
4508
  init_skills();
4461
4509
  init_simple();
4462
4510
  init_update();
@@ -4625,7 +4673,7 @@ var init_config = __esm({
4625
4673
  });
4626
4674
 
4627
4675
  // src/mcp/state.ts
4628
- import { mkdirSync, readFileSync as readFileSync6, renameSync, writeFileSync } from "fs";
4676
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, renameSync, writeFileSync } from "fs";
4629
4677
  import path7 from "path";
4630
4678
  function projectKey(dir, platform = process.platform) {
4631
4679
  const abs = path7.resolve(dir);
@@ -4643,7 +4691,7 @@ function readMcpState(home) {
4643
4691
  }
4644
4692
  }
4645
4693
  function writeMcpState(home, state2) {
4646
- mkdirSync(home, { recursive: true });
4694
+ mkdirSync2(home, { recursive: true });
4647
4695
  const target = path7.join(home, MCP_STATE_FILE);
4648
4696
  const temp = `${target}.${String(process.pid)}.tmp`;
4649
4697
  writeFileSync(temp, `${JSON.stringify(state2, null, 2)}
@@ -4730,10 +4778,10 @@ var init_approve = __esm({
4730
4778
  // src/bin.ts
4731
4779
  init_compat();
4732
4780
  import { spawn as spawn2, spawnSync as spawnSync3 } from "child_process";
4733
- import { existsSync as existsSync7, readFileSync as readFileSync7, realpathSync as realpathSync2 } from "fs";
4781
+ import { existsSync as existsSync8, readFileSync as readFileSync7, realpathSync as realpathSync2 } from "fs";
4734
4782
  import { createInterface } from "readline";
4735
4783
  import os from "os";
4736
- import { dirname as dirname5, join as join7, resolve as resolve2 } from "path";
4784
+ import { dirname as dirname5, join as join8, resolve as resolve2 } from "path";
4737
4785
  import { fileURLToPath as fileURLToPath2 } from "url";
4738
4786
  import { createRequire as createRequire3 } from "module";
4739
4787
 
@@ -4802,7 +4850,7 @@ function flagMode(argv) {
4802
4850
  // src/profile.ts
4803
4851
  import { createRequire as createRequire2 } from "module";
4804
4852
  import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
4805
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
4853
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, rmSync, symlinkSync } from "fs";
4806
4854
  import path3 from "path";
4807
4855
  import { parse as parseYaml } from "yaml";
4808
4856
  var require3 = createRequire2(import.meta.url);
@@ -4934,10 +4982,35 @@ async function ensureProfile(dshHome, pathMod = path3) {
4934
4982
  await writePersonaPatch(p.patchYml, dshHome, pathMod);
4935
4983
  return { created: true, dir };
4936
4984
  }
4985
+ function linkProfileBundles(profileDir, own, dshBaseDir) {
4986
+ const type = process.platform === "win32" ? "junction" : "dir";
4987
+ const link = (target, at) => {
4988
+ mkdirSync(path3.dirname(at), { recursive: true });
4989
+ rmSync(at, { recursive: true, force: true });
4990
+ symlinkSync(target, at, type);
4991
+ };
4992
+ try {
4993
+ const modules = path3.join(profileDir, "node_modules");
4994
+ link(own.root, path3.join(modules, own.name));
4995
+ link(dshBaseDir, path3.join(modules, "@deepseek-ai", "dsh-base"));
4996
+ return true;
4997
+ } catch {
4998
+ return false;
4999
+ }
5000
+ }
5001
+ function resolveDshBaseDir() {
5002
+ try {
5003
+ const dshRequire = createRequire2(require3.resolve("@deepseek-ai/dsh/package.json"));
5004
+ return path3.dirname(dshRequire.resolve("@deepseek-ai/dsh-base/package.json"));
5005
+ } catch {
5006
+ return void 0;
5007
+ }
5008
+ }
4937
5009
 
4938
5010
  // src/bin.ts
4939
5011
  init_simple();
4940
5012
  init_skills();
5013
+ init_default_skills();
4941
5014
  init_discover();
4942
5015
  init_theme();
4943
5016
 
@@ -5051,17 +5124,23 @@ var DSH_MISSING = "bruine: could not launch dsh (missing or broken install). Rei
5051
5124
  function selfPackageRoot() {
5052
5125
  try {
5053
5126
  const root = resolve2(dirname5(fileURLToPath2(import.meta.url)), "..");
5054
- const manifest = JSON.parse(readFileSync7(join7(root, "package.json"), "utf8"));
5127
+ const manifest = JSON.parse(readFileSync7(join8(root, "package.json"), "utf8"));
5055
5128
  return manifest.name === pkg2.name ? root : void 0;
5056
5129
  } catch {
5057
5130
  return void 0;
5058
5131
  }
5059
5132
  }
5060
5133
  function ensureBundleInstalled(profileDir, dshEntry, env, headless = false) {
5061
- const marker = join7(profileDir, "node_modules", pkg2.name, "package.json");
5062
- if (existsSync7(marker)) return;
5063
- const spec = selfPackageRoot() ?? `${pkg2.name}@${pkg2.version}`;
5134
+ const marker = join8(profileDir, "node_modules", pkg2.name, "package.json");
5135
+ if (existsSync8(marker)) return;
5136
+ const root = selfPackageRoot();
5064
5137
  if (!headless) console.log("Setting up bruine (one time)\u2026");
5138
+ const dshBase = resolveDshBaseDir();
5139
+ if (root !== void 0 && dshBase !== void 0 && linkProfileBundles(profileDir, { name: pkg2.name, root }, dshBase)) {
5140
+ if (!headless) console.log("Ready.");
5141
+ return;
5142
+ }
5143
+ const spec = root ?? `${pkg2.name}@${pkg2.version}`;
5065
5144
  const { status, error, output } = runDsh(
5066
5145
  dshEntry,
5067
5146
  ["plugin", "--profile", "bruine", "add", spec],
@@ -5090,12 +5169,12 @@ function readBruineJson(dshHome) {
5090
5169
  }
5091
5170
  async function printSkills(dshHome) {
5092
5171
  const { readInstalledSkills: readInstalledSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
5093
- const skills = await readInstalledSkills2(join7(dshHome, "skills"));
5172
+ const skills = await readInstalledSkills2(join8(dshHome, "skills"));
5094
5173
  if (skills.length === 0) {
5095
5174
  console.log("No skills enabled. Run `bruine setup` to pick skills.");
5096
5175
  return;
5097
5176
  }
5098
- console.log(`Skills enabled in ${join7(dshHome, "skills")}:`);
5177
+ console.log(`Skills enabled in ${join8(dshHome, "skills")}:`);
5099
5178
  for (const s of skills) {
5100
5179
  const kind = s.copied === true ? "linked-copy" : s.kind;
5101
5180
  console.log(` ${s.name} ${kind}${s.source !== "" ? ` ${s.source}` : ""}`);
@@ -5139,7 +5218,7 @@ async function runUpdate() {
5139
5218
  let version = "unknown";
5140
5219
  try {
5141
5220
  const manifest = JSON.parse(
5142
- readFileSync7(join7(dirname5(real), "..", "package.json"), "utf8")
5221
+ readFileSync7(join8(dirname5(real), "..", "package.json"), "utf8")
5143
5222
  );
5144
5223
  version = manifest.version ?? "unknown";
5145
5224
  } catch {
@@ -5273,7 +5352,7 @@ async function main() {
5273
5352
  console.error("bruine: --continue cannot be combined with -p");
5274
5353
  process.exit(2);
5275
5354
  }
5276
- if (!existsSync7(join7(dshHome, "settings.yaml"))) {
5355
+ if (!existsSync8(join8(dshHome, "settings.yaml"))) {
5277
5356
  if (headless) {
5278
5357
  console.error("bruine: run `bruine setup` before using -p");
5279
5358
  process.exit(2);
@@ -5307,7 +5386,22 @@ async function main() {
5307
5386
  });
5308
5387
  const { dir } = await ensureProfile(dshHome);
5309
5388
  ensureBundleInstalled(dir, dshEntry, env, headless);
5310
- const migrated = await migrateAgentsSkills({ homeSkillsDir: join7(dshHome, "skills") });
5389
+ const defaults = await ensureDefaultSkills({
5390
+ dshHome,
5391
+ bundledRoot: resolve2(dirname5(fileURLToPath2(import.meta.url)), "..", "skills")
5392
+ });
5393
+ const shipped = defaults.installed.filter((name) => !defaults.kept.includes(name));
5394
+ const sayDefault = (said) => {
5395
+ const line = process.stdout.isTTY === true ? ansi.dim(said) : said;
5396
+ if (headless) console.error(line);
5397
+ else console.log(line);
5398
+ };
5399
+ if (shipped.length > 0) sayDefault(`bruine: ${String(shipped.length)} skills are on (turn any off with bruine setup)`);
5400
+ if (defaults.kept.length > 0) {
5401
+ const k = String(defaults.kept.length);
5402
+ sayDefault(`bruine: kept your ${k} skill${defaults.kept.length === 1 ? "" : "s"} from .agents/skills (manage them with bruine setup)`);
5403
+ }
5404
+ const migrated = await migrateAgentsSkills({ homeSkillsDir: join8(dshHome, "skills") });
5311
5405
  if (migrated.linked.length > 0) {
5312
5406
  const n = String(migrated.linked.length);
5313
5407
  const kept = `bruine: kept your ${n} skill${migrated.linked.length === 1 ? "" : "s"} from .agents/skills (manage them with bruine setup)`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziamana/bruine",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Interactive terminal coding agent that runs your own models, local or OpenAI-compatible",
5
5
  "type": "module",
6
6
  "license": "MIT",