@ziamana/bruine 0.1.1 → 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 +1 -1
- package/dist/bin.js +94 -30
- 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
|
|
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();
|
|
@@ -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
|
|
|
@@ -4962,6 +5010,7 @@ function resolveDshBaseDir() {
|
|
|
4962
5010
|
// src/bin.ts
|
|
4963
5011
|
init_simple();
|
|
4964
5012
|
init_skills();
|
|
5013
|
+
init_default_skills();
|
|
4965
5014
|
init_discover();
|
|
4966
5015
|
init_theme();
|
|
4967
5016
|
|
|
@@ -5075,15 +5124,15 @@ var DSH_MISSING = "bruine: could not launch dsh (missing or broken install). Rei
|
|
|
5075
5124
|
function selfPackageRoot() {
|
|
5076
5125
|
try {
|
|
5077
5126
|
const root = resolve2(dirname5(fileURLToPath2(import.meta.url)), "..");
|
|
5078
|
-
const manifest = JSON.parse(readFileSync7(
|
|
5127
|
+
const manifest = JSON.parse(readFileSync7(join8(root, "package.json"), "utf8"));
|
|
5079
5128
|
return manifest.name === pkg2.name ? root : void 0;
|
|
5080
5129
|
} catch {
|
|
5081
5130
|
return void 0;
|
|
5082
5131
|
}
|
|
5083
5132
|
}
|
|
5084
5133
|
function ensureBundleInstalled(profileDir, dshEntry, env, headless = false) {
|
|
5085
|
-
const marker =
|
|
5086
|
-
if (
|
|
5134
|
+
const marker = join8(profileDir, "node_modules", pkg2.name, "package.json");
|
|
5135
|
+
if (existsSync8(marker)) return;
|
|
5087
5136
|
const root = selfPackageRoot();
|
|
5088
5137
|
if (!headless) console.log("Setting up bruine (one time)\u2026");
|
|
5089
5138
|
const dshBase = resolveDshBaseDir();
|
|
@@ -5120,12 +5169,12 @@ function readBruineJson(dshHome) {
|
|
|
5120
5169
|
}
|
|
5121
5170
|
async function printSkills(dshHome) {
|
|
5122
5171
|
const { readInstalledSkills: readInstalledSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
5123
|
-
const skills = await readInstalledSkills2(
|
|
5172
|
+
const skills = await readInstalledSkills2(join8(dshHome, "skills"));
|
|
5124
5173
|
if (skills.length === 0) {
|
|
5125
5174
|
console.log("No skills enabled. Run `bruine setup` to pick skills.");
|
|
5126
5175
|
return;
|
|
5127
5176
|
}
|
|
5128
|
-
console.log(`Skills enabled in ${
|
|
5177
|
+
console.log(`Skills enabled in ${join8(dshHome, "skills")}:`);
|
|
5129
5178
|
for (const s of skills) {
|
|
5130
5179
|
const kind = s.copied === true ? "linked-copy" : s.kind;
|
|
5131
5180
|
console.log(` ${s.name} ${kind}${s.source !== "" ? ` ${s.source}` : ""}`);
|
|
@@ -5169,7 +5218,7 @@ async function runUpdate() {
|
|
|
5169
5218
|
let version = "unknown";
|
|
5170
5219
|
try {
|
|
5171
5220
|
const manifest = JSON.parse(
|
|
5172
|
-
readFileSync7(
|
|
5221
|
+
readFileSync7(join8(dirname5(real), "..", "package.json"), "utf8")
|
|
5173
5222
|
);
|
|
5174
5223
|
version = manifest.version ?? "unknown";
|
|
5175
5224
|
} catch {
|
|
@@ -5303,7 +5352,7 @@ async function main() {
|
|
|
5303
5352
|
console.error("bruine: --continue cannot be combined with -p");
|
|
5304
5353
|
process.exit(2);
|
|
5305
5354
|
}
|
|
5306
|
-
if (!
|
|
5355
|
+
if (!existsSync8(join8(dshHome, "settings.yaml"))) {
|
|
5307
5356
|
if (headless) {
|
|
5308
5357
|
console.error("bruine: run `bruine setup` before using -p");
|
|
5309
5358
|
process.exit(2);
|
|
@@ -5337,7 +5386,22 @@ async function main() {
|
|
|
5337
5386
|
});
|
|
5338
5387
|
const { dir } = await ensureProfile(dshHome);
|
|
5339
5388
|
ensureBundleInstalled(dir, dshEntry, env, headless);
|
|
5340
|
-
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") });
|
|
5341
5405
|
if (migrated.linked.length > 0) {
|
|
5342
5406
|
const n = String(migrated.linked.length);
|
|
5343
5407
|
const kept = `bruine: kept your ${n} skill${migrated.linked.length === 1 ? "" : "s"} from .agents/skills (manage them with bruine setup)`;
|