harness-bujang 0.8.0 → 0.8.1
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.
|
@@ -170,6 +170,62 @@ If installed via npm, try reinstalling. If running from source, run "npm run bui
|
|
|
170
170
|
);
|
|
171
171
|
}
|
|
172
172
|
var ALL_ADAPTERS = ["cursor", "cline", "aider", "codex", "gemini"];
|
|
173
|
+
var CODEX_BALANCED = {
|
|
174
|
+
director: "gpt-5",
|
|
175
|
+
cofounder: "gpt-5",
|
|
176
|
+
"architect-team": "gpt-5",
|
|
177
|
+
consultant: "gpt-5",
|
|
178
|
+
"security-team": "o1",
|
|
179
|
+
"db-guard-team": "o1",
|
|
180
|
+
"dev-team": "gpt-5-codex",
|
|
181
|
+
"code-review-team": "gpt-5-codex",
|
|
182
|
+
"qa-team": "gpt-4-turbo",
|
|
183
|
+
"verifier-team": "gpt-4-turbo",
|
|
184
|
+
"doc-sync-team": "gpt-4-turbo",
|
|
185
|
+
"research-team": "gpt-5",
|
|
186
|
+
"analysis-team": "gpt-5",
|
|
187
|
+
"script-team": "gpt-4-turbo",
|
|
188
|
+
"image-team": "o1-mini",
|
|
189
|
+
"voice-team": "o1-mini",
|
|
190
|
+
"edit-team": "o1-mini",
|
|
191
|
+
"content-qa-team": "o1-mini"
|
|
192
|
+
};
|
|
193
|
+
var GEMINI_BALANCED = {
|
|
194
|
+
director: "gemini-2.5-pro",
|
|
195
|
+
cofounder: "gemini-2.5-pro",
|
|
196
|
+
"architect-team": "gemini-2.5-pro",
|
|
197
|
+
consultant: "gemini-2.5-pro",
|
|
198
|
+
"security-team": "gemini-2.5-pro",
|
|
199
|
+
"db-guard-team": "gemini-2.5-pro",
|
|
200
|
+
"dev-team": "gemini-2.5-pro",
|
|
201
|
+
"code-review-team": "gemini-2.5-pro",
|
|
202
|
+
"qa-team": "gemini-2.5-flash",
|
|
203
|
+
"verifier-team": "gemini-2.5-flash",
|
|
204
|
+
"doc-sync-team": "gemini-2.5-flash",
|
|
205
|
+
"research-team": "gemini-2.5-pro",
|
|
206
|
+
"analysis-team": "gemini-2.5-pro",
|
|
207
|
+
"script-team": "gemini-2.5-flash",
|
|
208
|
+
"image-team": "gemini-2.5-flash",
|
|
209
|
+
"voice-team": "gemini-2.5-flash",
|
|
210
|
+
"edit-team": "gemini-2.5-flash",
|
|
211
|
+
"content-qa-team": "gemini-2.5-flash"
|
|
212
|
+
};
|
|
213
|
+
function resolveCodexPreset(preset) {
|
|
214
|
+
if (preset === "keep") return {};
|
|
215
|
+
if (preset === "balanced") return { ...CODEX_BALANCED };
|
|
216
|
+
const tier = preset === "cost" ? "gpt-4-turbo" : "gpt-5";
|
|
217
|
+
const out = {};
|
|
218
|
+
for (const k of Object.keys(CODEX_BALANCED)) out[k] = tier;
|
|
219
|
+
return out;
|
|
220
|
+
}
|
|
221
|
+
function resolveGeminiPreset(preset) {
|
|
222
|
+
if (preset === "keep") return {};
|
|
223
|
+
if (preset === "balanced") return { ...GEMINI_BALANCED };
|
|
224
|
+
const tier = preset === "cost" ? "gemini-2.5-flash" : "gemini-2.5-pro";
|
|
225
|
+
const out = {};
|
|
226
|
+
for (const k of Object.keys(GEMINI_BALANCED)) out[k] = tier;
|
|
227
|
+
return out;
|
|
228
|
+
}
|
|
173
229
|
var BALANCED_MAPPING = {
|
|
174
230
|
director: "opus",
|
|
175
231
|
cofounder: "opus",
|
|
@@ -233,9 +289,9 @@ async function runInit(args) {
|
|
|
233
289
|
console.log(c.dim(` Language: ${opts.lang}`));
|
|
234
290
|
console.log(c.dim(` Chat backend: ${opts.chatBackend}${opts.chatBackend === "sqlite" ? " (local file)" : " (cloud Postgres)"}`));
|
|
235
291
|
console.log(c.dim(` Tools: claude${opts.adapters.length > 0 ? ` + ${opts.adapters.join(", ")}` : " (only)"}`));
|
|
236
|
-
console.log(c.dim(` Claude
|
|
237
|
-
if (opts.
|
|
238
|
-
if (opts.
|
|
292
|
+
console.log(c.dim(` Claude models: ${describeModelMap(opts.modelMap)}`));
|
|
293
|
+
if (opts.codexModelMap) console.log(c.dim(` Codex models: ${describeAnyMap(opts.codexModelMap)}`));
|
|
294
|
+
if (opts.geminiModelMap) console.log(c.dim(` Gemini models: ${describeAnyMap(opts.geminiModelMap)}`));
|
|
239
295
|
if (opts.aiderModel && opts.aiderModel !== "(skip)") console.log(c.dim(` Aider model: ${opts.aiderModel} (.aider.conf.yml)`));
|
|
240
296
|
if (scan.framework.startsWith("Next.js")) {
|
|
241
297
|
console.log(c.dim(` Chat-room UI: ${opts.installTemplate ? "install" : "skip"}`));
|
|
@@ -419,8 +475,8 @@ async function runInit(args) {
|
|
|
419
475
|
`--target=${opts.target}`,
|
|
420
476
|
"--yes"
|
|
421
477
|
]);
|
|
422
|
-
if (opts.
|
|
423
|
-
if (opts.
|
|
478
|
+
if (opts.codexModelMap && Object.keys(opts.codexModelMap).length > 0) await injectCodexModelMemos(opts.target, opts.codexModelMap);
|
|
479
|
+
if (opts.geminiModelMap && Object.keys(opts.geminiModelMap).length > 0) await injectGeminiModelMemos(opts.target, opts.geminiModelMap);
|
|
424
480
|
if (opts.aiderModel && opts.aiderModel !== "(skip)") await setAiderModel(opts.target, opts.aiderModel);
|
|
425
481
|
}
|
|
426
482
|
console.log(c.bold(c.green("\u2705 Done.")));
|
|
@@ -504,34 +560,35 @@ async function promptInteractive(opts, scan) {
|
|
|
504
560
|
});
|
|
505
561
|
modelMap = preset === "custom" ? await promptCustomModelMap() : resolvePreset(preset);
|
|
506
562
|
}
|
|
507
|
-
let
|
|
563
|
+
let codexModelMap;
|
|
508
564
|
if (adapters.includes("codex")) {
|
|
509
|
-
|
|
510
|
-
message: "\u{1F7E2} Codex \
|
|
565
|
+
const preset = await select({
|
|
566
|
+
message: "\u{1F7E2} Codex \uC5D0\uC774\uC804\uD2B8 \uBAA8\uB378 \uB9E4\uD551? [AGENTS.md \uC758 \uAC01 \uC5D0\uC774\uC804\uD2B8 \uC139\uC158\uC5D0 \uBA54\uBAA8\uB85C \uBC15\uD798 \u2014 \uAC00\uC774\uB4DC\uC6A9]",
|
|
511
567
|
choices: [
|
|
512
|
-
{ name: "gpt-5
|
|
513
|
-
{ name: "
|
|
514
|
-
{ name: "gpt-4-turbo", value: "
|
|
515
|
-
{ name: "
|
|
516
|
-
{ name: "
|
|
517
|
-
{ name: "skip (\uBA54\uBAA8 \uC548 \uBC15\uC74C)", value: "skip" }
|
|
568
|
+
{ name: "balanced \u2014 gpt-5 / gpt-5-codex / o1 / gpt-4-turbo \uC5ED\uD560\uBCC4 \uB9E4\uD551 (\uCD94\uCC9C)", value: "balanced" },
|
|
569
|
+
{ name: "keep \u2014 \uBA54\uBAA8 \uC548 \uBC15\uC74C (\uC0AC\uC6A9\uC790\uAC00 \uCF54\uB371\uC2A4 \uC548\uC5D0\uC11C \uD53D)", value: "keep" },
|
|
570
|
+
{ name: "cost \u2014 \uC804\uBD80 gpt-4-turbo (\uAC00\uC7A5 \uC800\uB834)", value: "cost" },
|
|
571
|
+
{ name: "quality \u2014 \uC804\uBD80 gpt-5 (\uAC00\uC7A5 \uB611\uB611)", value: "quality" },
|
|
572
|
+
{ name: "custom \u2014 \uC5D0\uC774\uC804\uD2B8\uBCC4 \uC9C1\uC811 \uC120\uD0DD (18\uAC1C prompt)", value: "custom" }
|
|
518
573
|
],
|
|
519
|
-
default: "
|
|
574
|
+
default: "balanced"
|
|
520
575
|
});
|
|
576
|
+
codexModelMap = preset === "custom" ? await promptCustomCodexMap() : resolveCodexPreset(preset);
|
|
521
577
|
}
|
|
522
|
-
let
|
|
578
|
+
let geminiModelMap;
|
|
523
579
|
if (adapters.includes("gemini")) {
|
|
524
|
-
|
|
525
|
-
message: "\u{1F535} Gemini \
|
|
580
|
+
const preset = await select({
|
|
581
|
+
message: "\u{1F535} Gemini \uC5D0\uC774\uC804\uD2B8 \uBAA8\uB378 \uB9E4\uD551? [GEMINI.md \uC758 \uAC01 \uC5D0\uC774\uC804\uD2B8 \uC139\uC158\uC5D0 \uBA54\uBAA8\uB85C \uBC15\uD798 \u2014 \uAC00\uC774\uB4DC\uC6A9]",
|
|
526
582
|
choices: [
|
|
527
|
-
{ name: "
|
|
528
|
-
{ name: "
|
|
529
|
-
{ name: "gemini-2.
|
|
530
|
-
{ name: "gemini-2.
|
|
531
|
-
{ name: "
|
|
583
|
+
{ name: "balanced \u2014 pro / flash \uC5ED\uD560\uBCC4 \uB9E4\uD551 (\uCD94\uCC9C)", value: "balanced" },
|
|
584
|
+
{ name: "keep \u2014 \uBA54\uBAA8 \uC548 \uBC15\uC74C (Gemini \uB3C4\uAD6C \uC548\uC5D0\uC11C \uD53D)", value: "keep" },
|
|
585
|
+
{ name: "cost \u2014 \uC804\uBD80 gemini-2.5-flash (\uAC00\uC7A5 \uBE60\uB974\uACE0 \uC800\uB834)", value: "cost" },
|
|
586
|
+
{ name: "quality \u2014 \uC804\uBD80 gemini-2.5-pro (\uAC00\uC7A5 \uB611\uB611)", value: "quality" },
|
|
587
|
+
{ name: "custom \u2014 \uC5D0\uC774\uC804\uD2B8\uBCC4 \uC9C1\uC811 \uC120\uD0DD (18\uAC1C prompt)", value: "custom" }
|
|
532
588
|
],
|
|
533
|
-
default: "
|
|
589
|
+
default: "balanced"
|
|
534
590
|
});
|
|
591
|
+
geminiModelMap = preset === "custom" ? await promptCustomGeminiMap() : resolveGeminiPreset(preset);
|
|
535
592
|
}
|
|
536
593
|
let aiderModel;
|
|
537
594
|
if (adapters.includes("aider")) {
|
|
@@ -561,11 +618,52 @@ async function promptInteractive(opts, scan) {
|
|
|
561
618
|
installTemplate,
|
|
562
619
|
adapters,
|
|
563
620
|
modelMap,
|
|
564
|
-
|
|
565
|
-
|
|
621
|
+
codexModelMap,
|
|
622
|
+
geminiModelMap,
|
|
566
623
|
aiderModel
|
|
567
624
|
};
|
|
568
625
|
}
|
|
626
|
+
async function promptCustomCodexMap() {
|
|
627
|
+
const out = {};
|
|
628
|
+
const slugs = Object.keys(CODEX_BALANCED);
|
|
629
|
+
console.log();
|
|
630
|
+
console.log(c.dim(` Codex custom \uB9E4\uD551 \u2014 ${slugs.length}\uAC1C \uC5D0\uC774\uC804\uD2B8\uB9C8\uB2E4 \uBAA8\uB378\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.`));
|
|
631
|
+
for (const slug of slugs) {
|
|
632
|
+
const tier = await select({
|
|
633
|
+
message: `${slug.padEnd(20)}`,
|
|
634
|
+
choices: [
|
|
635
|
+
{ name: "gpt-5 (\uCD5C\uC2E0, \uD070 \uACB0\uC815)", value: "gpt-5" },
|
|
636
|
+
{ name: "gpt-5-codex (\uCF54\uB529 \uD2B9\uD654)", value: "gpt-5-codex" },
|
|
637
|
+
{ name: "gpt-4-turbo (\uADE0\uD615)", value: "gpt-4-turbo" },
|
|
638
|
+
{ name: "o1 (\uCD94\uB860 \uD2B9\uD654)", value: "o1" },
|
|
639
|
+
{ name: "o1-mini (\uAC00\uBCBC\uC6B4, \uBE60\uB984)", value: "o1-mini" }
|
|
640
|
+
],
|
|
641
|
+
default: CODEX_BALANCED[slug] ?? "gpt-4-turbo"
|
|
642
|
+
});
|
|
643
|
+
out[slug] = tier;
|
|
644
|
+
}
|
|
645
|
+
return out;
|
|
646
|
+
}
|
|
647
|
+
async function promptCustomGeminiMap() {
|
|
648
|
+
const out = {};
|
|
649
|
+
const slugs = Object.keys(GEMINI_BALANCED);
|
|
650
|
+
console.log();
|
|
651
|
+
console.log(c.dim(` Gemini custom \uB9E4\uD551 \u2014 ${slugs.length}\uAC1C \uC5D0\uC774\uC804\uD2B8\uB9C8\uB2E4 \uBAA8\uB378\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.`));
|
|
652
|
+
for (const slug of slugs) {
|
|
653
|
+
const tier = await select({
|
|
654
|
+
message: `${slug.padEnd(20)}`,
|
|
655
|
+
choices: [
|
|
656
|
+
{ name: "gemini-2.5-pro (\uCD5C\uC2E0, \uAC00\uC7A5 \uB611\uB611)", value: "gemini-2.5-pro" },
|
|
657
|
+
{ name: "gemini-2.5-flash (\uBE60\uB974\uACE0 \uC800\uB834)", value: "gemini-2.5-flash" },
|
|
658
|
+
{ name: "gemini-2.0-pro", value: "gemini-2.0-pro" },
|
|
659
|
+
{ name: "gemini-2.0-flash", value: "gemini-2.0-flash" }
|
|
660
|
+
],
|
|
661
|
+
default: GEMINI_BALANCED[slug] ?? "gemini-2.5-flash"
|
|
662
|
+
});
|
|
663
|
+
out[slug] = tier;
|
|
664
|
+
}
|
|
665
|
+
return out;
|
|
666
|
+
}
|
|
569
667
|
async function promptCustomModelMap() {
|
|
570
668
|
const out = {};
|
|
571
669
|
const slugs = Object.keys(BALANCED_MAPPING);
|
|
@@ -619,8 +717,22 @@ function parseArgs(args) {
|
|
|
619
717
|
}
|
|
620
718
|
modelMap = resolvePreset(modelsRaw);
|
|
621
719
|
}
|
|
622
|
-
const
|
|
623
|
-
const
|
|
720
|
+
const codexPresetRaw = getFlag(args, "--codex-models");
|
|
721
|
+
const geminiPresetRaw = getFlag(args, "--gemini-models");
|
|
722
|
+
let codexModelMap;
|
|
723
|
+
let geminiModelMap;
|
|
724
|
+
if (codexPresetRaw) {
|
|
725
|
+
if (!["balanced", "cost", "quality", "keep"].includes(codexPresetRaw)) {
|
|
726
|
+
throw new Error(`--codex-models must be one of: balanced, cost, quality, keep (got "${codexPresetRaw}")`);
|
|
727
|
+
}
|
|
728
|
+
codexModelMap = resolveCodexPreset(codexPresetRaw);
|
|
729
|
+
}
|
|
730
|
+
if (geminiPresetRaw) {
|
|
731
|
+
if (!["balanced", "cost", "quality", "keep"].includes(geminiPresetRaw)) {
|
|
732
|
+
throw new Error(`--gemini-models must be one of: balanced, cost, quality, keep (got "${geminiPresetRaw}")`);
|
|
733
|
+
}
|
|
734
|
+
geminiModelMap = resolveGeminiPreset(geminiPresetRaw);
|
|
735
|
+
}
|
|
624
736
|
const aiderModel = getFlag(args, "--aider-model");
|
|
625
737
|
return {
|
|
626
738
|
lang,
|
|
@@ -635,8 +747,8 @@ function parseArgs(args) {
|
|
|
635
747
|
yes: args.includes("--yes") || args.includes("-y"),
|
|
636
748
|
adapters,
|
|
637
749
|
modelMap,
|
|
638
|
-
|
|
639
|
-
|
|
750
|
+
codexModelMap,
|
|
751
|
+
geminiModelMap,
|
|
640
752
|
aiderModel
|
|
641
753
|
};
|
|
642
754
|
}
|
|
@@ -756,41 +868,42 @@ function printBackendInstructions(backend, commitChat) {
|
|
|
756
868
|
}
|
|
757
869
|
console.log();
|
|
758
870
|
}
|
|
759
|
-
async function
|
|
871
|
+
async function injectCodexModelMemos(target, modelMap) {
|
|
760
872
|
const fp = path2.join(target, "AGENTS.md");
|
|
761
873
|
if (!await exists2(fp)) return;
|
|
762
874
|
const raw = await fs2.readFile(fp, "utf8");
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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}`));
|
|
875
|
+
const updated = injectPerAgentMemos(raw, modelMap, "\uCF54\uB371\uC2A4 / Copilot \uC548\uC5D0\uC11C \uC774 \uBAA8\uB378\uB85C \uC791\uC5C5");
|
|
876
|
+
await fs2.writeFile(fp, updated);
|
|
877
|
+
const count = Object.keys(modelMap).length;
|
|
878
|
+
console.log(c.dim(` \u2713 AGENTS.md \u2190 Codex \uAD8C\uC7A5 \uBAA8\uB378 \uBA54\uBAA8 ${count}\uAC74 (\uAC01 \uC5D0\uC774\uC804\uD2B8 \uC139\uC158 \uC704)`));
|
|
776
879
|
}
|
|
777
|
-
async function
|
|
880
|
+
async function injectGeminiModelMemos(target, modelMap) {
|
|
778
881
|
const fp = path2.join(target, "GEMINI.md");
|
|
779
882
|
if (!await exists2(fp)) return;
|
|
780
883
|
const raw = await fs2.readFile(fp, "utf8");
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
884
|
+
const updated = injectPerAgentMemos(raw, modelMap, "Gemini CLI / Antigravity \uC548\uC5D0\uC11C \uC774 \uBAA8\uB378\uB85C \uC791\uC5C5");
|
|
885
|
+
await fs2.writeFile(fp, updated);
|
|
886
|
+
const count = Object.keys(modelMap).length;
|
|
887
|
+
console.log(c.dim(` \u2713 GEMINI.md \u2190 Gemini \uAD8C\uC7A5 \uBAA8\uB378 \uBA54\uBAA8 ${count}\uAC74 (\uAC01 \uC5D0\uC774\uC804\uD2B8 \uC139\uC158 \uC704)`));
|
|
888
|
+
}
|
|
889
|
+
function injectPerAgentMemos(raw, modelMap, hint) {
|
|
785
890
|
const lines = raw.split("\n");
|
|
786
|
-
const
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
891
|
+
const out = [];
|
|
892
|
+
for (let i = 0; i < lines.length; i++) {
|
|
893
|
+
const line = lines[i];
|
|
894
|
+
const m = /^##\s+([a-z][a-z0-9-]*)\s*$/.exec(line);
|
|
895
|
+
if (m) {
|
|
896
|
+
const slug = m[1];
|
|
897
|
+
const model = modelMap[slug];
|
|
898
|
+
const prev = out[out.length - 1] ?? "";
|
|
899
|
+
if (model && !prev.includes("\u{1F4A1} Recommended")) {
|
|
900
|
+
out.push(`> \u{1F4A1} Recommended model: \`${model}\` \u2014 ${hint}`);
|
|
901
|
+
out.push("");
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
out.push(line);
|
|
905
|
+
}
|
|
906
|
+
return out.join("\n");
|
|
794
907
|
}
|
|
795
908
|
async function setAiderModel(target, model) {
|
|
796
909
|
const fp = path2.join(target, ".aider.conf.yml");
|
|
@@ -827,6 +940,13 @@ function describeModelMap(map) {
|
|
|
827
940
|
}
|
|
828
941
|
return parts.join(" \xB7 ");
|
|
829
942
|
}
|
|
943
|
+
function describeAnyMap(map) {
|
|
944
|
+
if (Object.keys(map).length === 0) return "keep (\uBA54\uBAA8 \uC548 \uBC15\uC74C)";
|
|
945
|
+
const counts = {};
|
|
946
|
+
for (const v of Object.values(map)) counts[v] = (counts[v] ?? 0) + 1;
|
|
947
|
+
const parts = Object.entries(counts).sort((a, b) => b[1] - a[1]).map(([model, n]) => `${n} ${model}`);
|
|
948
|
+
return parts.join(" \xB7 ");
|
|
949
|
+
}
|
|
830
950
|
function stackReviewRules(framework) {
|
|
831
951
|
if (framework.startsWith("Next.js")) {
|
|
832
952
|
return `Next.js App Router rules:
|
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-WAVPUHNL.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-HAGOKTNL.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.8.
|
|
3
|
+
"version": "0.8.1",
|
|
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",
|