harness-bujang 0.7.2 → 0.8.0
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.
|
@@ -233,7 +233,10 @@ async function runInit(args) {
|
|
|
233
233
|
console.log(c.dim(` Language: ${opts.lang}`));
|
|
234
234
|
console.log(c.dim(` Chat backend: ${opts.chatBackend}${opts.chatBackend === "sqlite" ? " (local file)" : " (cloud Postgres)"}`));
|
|
235
235
|
console.log(c.dim(` Tools: claude${opts.adapters.length > 0 ? ` + ${opts.adapters.join(", ")}` : " (only)"}`));
|
|
236
|
-
console.log(c.dim(`
|
|
236
|
+
console.log(c.dim(` Claude model: ${describeModelMap(opts.modelMap)}`));
|
|
237
|
+
if (opts.codexModel && opts.codexModel !== "skip") console.log(c.dim(` Codex model: ${opts.codexModel} (memo)`));
|
|
238
|
+
if (opts.geminiModel && opts.geminiModel !== "skip") console.log(c.dim(` Gemini model: ${opts.geminiModel} (memo)`));
|
|
239
|
+
if (opts.aiderModel && opts.aiderModel !== "(skip)") console.log(c.dim(` Aider model: ${opts.aiderModel} (.aider.conf.yml)`));
|
|
237
240
|
if (scan.framework.startsWith("Next.js")) {
|
|
238
241
|
console.log(c.dim(` Chat-room UI: ${opts.installTemplate ? "install" : "skip"}`));
|
|
239
242
|
}
|
|
@@ -416,6 +419,9 @@ async function runInit(args) {
|
|
|
416
419
|
`--target=${opts.target}`,
|
|
417
420
|
"--yes"
|
|
418
421
|
]);
|
|
422
|
+
if (opts.codexModel && opts.codexModel !== "skip") await injectCodexModelMemo(opts.target, opts.codexModel);
|
|
423
|
+
if (opts.geminiModel && opts.geminiModel !== "skip") await injectGeminiModelMemo(opts.target, opts.geminiModel);
|
|
424
|
+
if (opts.aiderModel && opts.aiderModel !== "(skip)") await setAiderModel(opts.target, opts.aiderModel);
|
|
419
425
|
}
|
|
420
426
|
console.log(c.bold(c.green("\u2705 Done.")));
|
|
421
427
|
console.log();
|
|
@@ -470,9 +476,9 @@ async function promptInteractive(opts, scan) {
|
|
|
470
476
|
});
|
|
471
477
|
const isPreset = (t) => opts.adapters.includes(t);
|
|
472
478
|
const adaptersRaw = await checkbox({
|
|
473
|
-
message: "\uB3C4\uAD6C \uC120\uD0DD \u2014
|
|
479
|
+
message: "\uB3C4\uAD6C \uC120\uD0DD \u2014 \uCCB4\uD06C\uB41C \uB3C4\uAD6C\uB9CC \uC14B\uC5C5\uB429\uB2C8\uB2E4. (.claude/agents/ \uB294 \uC5B4\uB311\uD130 SoT \uB77C \uD56D\uC0C1 \uAE54\uB9BD\uB2C8\uB2E4)",
|
|
474
480
|
choices: [
|
|
475
|
-
{ name: "Claude Code (.claude/agents/)
|
|
481
|
+
{ name: "Claude Code (.claude/agents/)", value: "claude", checked: true },
|
|
476
482
|
{ name: "Cursor (.cursor/rules/bujang-*.mdc)", value: "cursor", checked: isPreset("cursor") },
|
|
477
483
|
{ name: "Codex / Copilot (AGENTS.md)", value: "codex", checked: isPreset("codex") },
|
|
478
484
|
{ name: "Cline (.clinerules/bujang-*.md)", value: "cline", checked: isPreset("cline") },
|
|
@@ -481,23 +487,65 @@ async function promptInteractive(opts, scan) {
|
|
|
481
487
|
],
|
|
482
488
|
required: false
|
|
483
489
|
});
|
|
490
|
+
const claudeChecked = adaptersRaw.includes("claude");
|
|
484
491
|
const adapters = adaptersRaw.filter((t) => t !== "claude");
|
|
485
|
-
const preset = await select({
|
|
486
|
-
message: "\uC5D0\uC774\uC804\uD2B8\uBCC4 Claude \uBAA8\uB378? (.claude/agents/ \uC5D0\uB9CC \uC801\uC6A9 \u2014 \uB2E4\uB978 \uB3C4\uAD6C\uB294 \uC790\uCCB4 \uBAA8\uB378 \uAD00\uB9AC)",
|
|
487
|
-
choices: [
|
|
488
|
-
{ name: "balanced \u2014 opus / sonnet / haiku \uADE0\uD615 \uB9E4\uD551 (\uCD94\uCC9C, \uBE44\uC6A9 ~60% \uC808\uAC10)", value: "balanced" },
|
|
489
|
-
{ name: "keep \u2014 \uAC01 \uC5D0\uC774\uC804\uD2B8 \uAE30\uBCF8 \uBAA8\uB378 \uADF8\uB300\uB85C", value: "keep" },
|
|
490
|
-
{ name: "cost \u2014 \uC804\uBD80 haiku (\uAC00\uC7A5 \uC800\uB834, \uBE60\uB984)", value: "cost" },
|
|
491
|
-
{ name: "quality \u2014 \uC804\uBD80 opus (\uAC00\uC7A5 \uBE44\uC2F8\uACE0, \uD488\uC9C8 \uCD5C\uC0C1)", value: "quality" },
|
|
492
|
-
{ name: "custom \u2014 \uC5D0\uC774\uC804\uD2B8\uBCC4 \uC9C1\uC811 \uC120\uD0DD (18\uAC1C prompt)", value: "custom" }
|
|
493
|
-
],
|
|
494
|
-
default: "balanced"
|
|
495
|
-
});
|
|
496
492
|
let modelMap = {};
|
|
497
|
-
if (
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
493
|
+
if (claudeChecked) {
|
|
494
|
+
const preset = await select({
|
|
495
|
+
message: "\u{1F7E3} Claude \uC5D0\uC774\uC804\uD2B8 \uBAA8\uB378 \uB9E4\uD551? [.claude/agents/ frontmatter \uC5D0 \uBC15\uD798 \u2014 Claude Code \uAC00 \uC9C4\uC9DC \uC801\uC6A9]",
|
|
496
|
+
choices: [
|
|
497
|
+
{ name: "balanced \u2014 opus / sonnet / haiku \uADE0\uD615 \uB9E4\uD551 (\uCD94\uCC9C, \uBE44\uC6A9 ~60% \uC808\uAC10)", value: "balanced" },
|
|
498
|
+
{ name: "keep \u2014 \uAC01 \uC5D0\uC774\uC804\uD2B8 \uAE30\uBCF8 \uBAA8\uB378 \uADF8\uB300\uB85C", value: "keep" },
|
|
499
|
+
{ name: "cost \u2014 \uC804\uBD80 haiku (\uAC00\uC7A5 \uC800\uB834, \uBE60\uB984)", value: "cost" },
|
|
500
|
+
{ name: "quality \u2014 \uC804\uBD80 opus (\uAC00\uC7A5 \uBE44\uC2F8\uACE0, \uD488\uC9C8 \uCD5C\uC0C1)", value: "quality" },
|
|
501
|
+
{ name: "custom \u2014 \uC5D0\uC774\uC804\uD2B8\uBCC4 \uC9C1\uC811 \uC120\uD0DD (18\uAC1C prompt)", value: "custom" }
|
|
502
|
+
],
|
|
503
|
+
default: "balanced"
|
|
504
|
+
});
|
|
505
|
+
modelMap = preset === "custom" ? await promptCustomModelMap() : resolvePreset(preset);
|
|
506
|
+
}
|
|
507
|
+
let codexModel;
|
|
508
|
+
if (adapters.includes("codex")) {
|
|
509
|
+
codexModel = await select({
|
|
510
|
+
message: "\u{1F7E2} Codex \uAD8C\uC7A5 \uBAA8\uB378? [AGENTS.md \uC0C1\uB2E8 \uBA54\uBAA8\uB85C \uBC15\uD798 \u2014 \uC2E4\uC81C \uBAA8\uB378\uC740 \uCF54\uB371\uC2A4 \uC548\uC5D0\uC11C \uC0AC\uC6A9\uC790\uAC00 \uD53D]",
|
|
511
|
+
choices: [
|
|
512
|
+
{ name: "gpt-5 (\uCD5C\uC2E0)", value: "gpt-5" },
|
|
513
|
+
{ name: "gpt-5-codex (\uCF54\uB529 \uD2B9\uD654)", value: "gpt-5-codex" },
|
|
514
|
+
{ name: "gpt-4-turbo", value: "gpt-4-turbo" },
|
|
515
|
+
{ name: "o1 (\uCD94\uB860 \uD2B9\uD654)", value: "o1" },
|
|
516
|
+
{ name: "o1-mini (\uAC00\uBCBC\uC6B4 \uCD94\uB860)", value: "o1-mini" },
|
|
517
|
+
{ name: "skip (\uBA54\uBAA8 \uC548 \uBC15\uC74C)", value: "skip" }
|
|
518
|
+
],
|
|
519
|
+
default: "gpt-5-codex"
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
let geminiModel;
|
|
523
|
+
if (adapters.includes("gemini")) {
|
|
524
|
+
geminiModel = await select({
|
|
525
|
+
message: "\u{1F535} Gemini \uAD8C\uC7A5 \uBAA8\uB378? [GEMINI.md \uC0C1\uB2E8 \uBA54\uBAA8\uB85C \uBC15\uD798 \u2014 \uC2E4\uC81C \uBAA8\uB378\uC740 Gemini \uB3C4\uAD6C \uC548\uC5D0\uC11C \uC0AC\uC6A9\uC790\uAC00 \uD53D]",
|
|
526
|
+
choices: [
|
|
527
|
+
{ name: "gemini-2.5-pro (\uCD5C\uC2E0, \uAC00\uC7A5 \uB611\uB611)", value: "gemini-2.5-pro" },
|
|
528
|
+
{ name: "gemini-2.5-flash (\uBE60\uB974\uACE0 \uC800\uB834)", value: "gemini-2.5-flash" },
|
|
529
|
+
{ name: "gemini-2.0-pro", value: "gemini-2.0-pro" },
|
|
530
|
+
{ name: "gemini-2.0-flash", value: "gemini-2.0-flash" },
|
|
531
|
+
{ name: "skip (\uBA54\uBAA8 \uC548 \uBC15\uC74C)", value: "skip" }
|
|
532
|
+
],
|
|
533
|
+
default: "gemini-2.5-pro"
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
let aiderModel;
|
|
537
|
+
if (adapters.includes("aider")) {
|
|
538
|
+
aiderModel = await select({
|
|
539
|
+
message: "\u{1F7E1} Aider \uBAA8\uB378? [.aider.conf.yml \uC758 model \uD544\uB4DC\uC5D0 \uBC15\uD798 \u2014 Aider \uAC00 \uC2DC\uC791 \uC2DC \uC9C4\uC9DC \uC801\uC6A9]",
|
|
540
|
+
choices: [
|
|
541
|
+
{ name: "claude-opus-4-7 (\uCD5C\uACE0 \uD488\uC9C8)", value: "claude-opus-4-7" },
|
|
542
|
+
{ name: "claude-sonnet-4-6 (\uADE0\uD615)", value: "claude-sonnet-4-6" },
|
|
543
|
+
{ name: "gpt-5 (OpenAI \uCD5C\uC2E0)", value: "gpt-5" },
|
|
544
|
+
{ name: "gemini-2.5-pro (Google \uCD5C\uC2E0)", value: "gemini-2.5-pro" },
|
|
545
|
+
{ name: "(skip) (model \uD544\uB4DC \uC548 \uBC15\uC74C)", value: "(skip)" }
|
|
546
|
+
],
|
|
547
|
+
default: "claude-sonnet-4-6"
|
|
548
|
+
});
|
|
501
549
|
}
|
|
502
550
|
let installTemplate = opts.installTemplate;
|
|
503
551
|
if (scan.framework.startsWith("Next.js") && opts.installTemplate) {
|
|
@@ -506,7 +554,17 @@ async function promptInteractive(opts, scan) {
|
|
|
506
554
|
default: true
|
|
507
555
|
});
|
|
508
556
|
}
|
|
509
|
-
return {
|
|
557
|
+
return {
|
|
558
|
+
...opts,
|
|
559
|
+
lang,
|
|
560
|
+
chatBackend,
|
|
561
|
+
installTemplate,
|
|
562
|
+
adapters,
|
|
563
|
+
modelMap,
|
|
564
|
+
codexModel,
|
|
565
|
+
geminiModel,
|
|
566
|
+
aiderModel
|
|
567
|
+
};
|
|
510
568
|
}
|
|
511
569
|
async function promptCustomModelMap() {
|
|
512
570
|
const out = {};
|
|
@@ -561,6 +619,9 @@ function parseArgs(args) {
|
|
|
561
619
|
}
|
|
562
620
|
modelMap = resolvePreset(modelsRaw);
|
|
563
621
|
}
|
|
622
|
+
const codexModel = getFlag(args, "--codex-model");
|
|
623
|
+
const geminiModel = getFlag(args, "--gemini-model");
|
|
624
|
+
const aiderModel = getFlag(args, "--aider-model");
|
|
564
625
|
return {
|
|
565
626
|
lang,
|
|
566
627
|
target: path2.resolve(targetRaw),
|
|
@@ -573,7 +634,10 @@ function parseArgs(args) {
|
|
|
573
634
|
seedLearningLog: !args.includes("--no-learning-log"),
|
|
574
635
|
yes: args.includes("--yes") || args.includes("-y"),
|
|
575
636
|
adapters,
|
|
576
|
-
modelMap
|
|
637
|
+
modelMap,
|
|
638
|
+
codexModel,
|
|
639
|
+
geminiModel,
|
|
640
|
+
aiderModel
|
|
577
641
|
};
|
|
578
642
|
}
|
|
579
643
|
function resolvePreset(preset) {
|
|
@@ -692,6 +756,57 @@ function printBackendInstructions(backend, commitChat) {
|
|
|
692
756
|
}
|
|
693
757
|
console.log();
|
|
694
758
|
}
|
|
759
|
+
async function injectCodexModelMemo(target, model) {
|
|
760
|
+
const fp = path2.join(target, "AGENTS.md");
|
|
761
|
+
if (!await exists2(fp)) return;
|
|
762
|
+
const raw = await fs2.readFile(fp, "utf8");
|
|
763
|
+
const memo = `
|
|
764
|
+
> \u{1F4A1} **Recommended model**: \`${model}\` \u2014 pick this in your Codex / Copilot settings for best results with this harness.
|
|
765
|
+
`;
|
|
766
|
+
if (raw.includes("Recommended model")) return;
|
|
767
|
+
const lines = raw.split("\n");
|
|
768
|
+
const h1Idx = lines.findIndex((l) => l.startsWith("# "));
|
|
769
|
+
if (h1Idx < 0) {
|
|
770
|
+
await fs2.writeFile(fp, memo + raw);
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
lines.splice(h1Idx + 1, 0, memo);
|
|
774
|
+
await fs2.writeFile(fp, lines.join("\n"));
|
|
775
|
+
console.log(c.dim(` \u2713 AGENTS.md \u2190 Codex \uAD8C\uC7A5 \uBAA8\uB378 \uBA54\uBAA8: ${model}`));
|
|
776
|
+
}
|
|
777
|
+
async function injectGeminiModelMemo(target, model) {
|
|
778
|
+
const fp = path2.join(target, "GEMINI.md");
|
|
779
|
+
if (!await exists2(fp)) return;
|
|
780
|
+
const raw = await fs2.readFile(fp, "utf8");
|
|
781
|
+
const memo = `
|
|
782
|
+
> \u{1F4A1} **Recommended model**: \`${model}\` \u2014 pick this in Gemini CLI / Antigravity / Code Assist settings.
|
|
783
|
+
`;
|
|
784
|
+
if (raw.includes("Recommended model")) return;
|
|
785
|
+
const lines = raw.split("\n");
|
|
786
|
+
const h1Idx = lines.findIndex((l) => l.startsWith("# "));
|
|
787
|
+
if (h1Idx < 0) {
|
|
788
|
+
await fs2.writeFile(fp, memo + raw);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
lines.splice(h1Idx + 1, 0, memo);
|
|
792
|
+
await fs2.writeFile(fp, lines.join("\n"));
|
|
793
|
+
console.log(c.dim(` \u2713 GEMINI.md \u2190 Gemini \uAD8C\uC7A5 \uBAA8\uB378 \uBA54\uBAA8: ${model}`));
|
|
794
|
+
}
|
|
795
|
+
async function setAiderModel(target, model) {
|
|
796
|
+
const fp = path2.join(target, ".aider.conf.yml");
|
|
797
|
+
if (!await exists2(fp)) return;
|
|
798
|
+
let raw = await fs2.readFile(fp, "utf8");
|
|
799
|
+
if (/^model:\s*\S+/m.test(raw)) {
|
|
800
|
+
raw = raw.replace(/^model:\s*\S+/m, `model: ${model}`);
|
|
801
|
+
} else {
|
|
802
|
+
raw = raw.trimEnd() + `
|
|
803
|
+
# Added by harness-bujang init
|
|
804
|
+
model: ${model}
|
|
805
|
+
`;
|
|
806
|
+
}
|
|
807
|
+
await fs2.writeFile(fp, raw);
|
|
808
|
+
console.log(c.dim(` \u2713 .aider.conf.yml \u2190 model: ${model}`));
|
|
809
|
+
}
|
|
695
810
|
function overrideModelFrontmatter(content, model) {
|
|
696
811
|
if (!content.startsWith("---\n")) return content;
|
|
697
812
|
const end = content.indexOf("\n---\n", 4);
|
package/dist/index.js
CHANGED
|
@@ -189,7 +189,7 @@ async function main() {
|
|
|
189
189
|
const command = args[0];
|
|
190
190
|
switch (command) {
|
|
191
191
|
case "init":
|
|
192
|
-
await (await import("./init-
|
|
192
|
+
await (await import("./init-HUQA2RDS.js")).runInit(args.slice(1));
|
|
193
193
|
break;
|
|
194
194
|
case "status":
|
|
195
195
|
await (await import("./status-UE2TQQPU.js")).runStatus(args.slice(1));
|
|
@@ -201,7 +201,7 @@ async function main() {
|
|
|
201
201
|
await (await import("./adapt-VPWOYF6W.js")).runAdapt(args.slice(1));
|
|
202
202
|
break;
|
|
203
203
|
case "update":
|
|
204
|
-
await (await import("./update-
|
|
204
|
+
await (await import("./update-35E4M6TJ.js")).runUpdate(args.slice(1));
|
|
205
205
|
break;
|
|
206
206
|
case "migrate":
|
|
207
207
|
await (await import("./migrate-PISZFX6C.js")).runMigrate(args.slice(1));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harness-bujang",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Install the Harness-Bujang multi-agent harness into any project — Director, 7 specialist teams, real-time chat-room UI. Korean and English personas. Works with Claude Code, Cursor, Cline, Aider, or any tool that reads .claude/agents/.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|