@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.
- package/README.md +24 -1
- package/dist/bin.js +128 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[](https://nodejs.org)
|
|
14
14
|

|
|
15
|
-
[](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
|
|
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
|
|
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
|
|
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
|
|
1765
|
-
import { dirname as dirname3, join as
|
|
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(
|
|
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
|
|
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(
|
|
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:
|
|
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
|
|
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
|
|
3109
|
-
import { dirname as dirname4, join as
|
|
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 (
|
|
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(
|
|
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(
|
|
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(
|
|
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 (
|
|
3396
|
-
|
|
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(
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
5062
|
-
if (
|
|
5063
|
-
const
|
|
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(
|
|
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 ${
|
|
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(
|
|
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 (!
|
|
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
|
|
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)`;
|