@kyo-so/cli 0.1.0 → 0.2.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.
- package/README.ja.md +289 -0
- package/README.md +90 -5
- package/README.zh-CN.md +289 -0
- package/dist/bin/kyoso.js +517 -64
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/setup.d.ts +29 -0
- package/package.json +1 -1
package/dist/bin/kyoso.js
CHANGED
|
@@ -169495,18 +169495,21 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
|
|
|
169495
169495
|
});
|
|
169496
169496
|
|
|
169497
169497
|
// src/cli/main.ts
|
|
169498
|
-
import { spawnSync } from "node:child_process";
|
|
169498
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
169499
169499
|
|
|
169500
169500
|
// src/cli/args.ts
|
|
169501
169501
|
function parseArgs(argv) {
|
|
169502
169502
|
const [command = "help", ...rest] = argv;
|
|
169503
|
+
const positionals = [];
|
|
169503
169504
|
const flags = {};
|
|
169504
169505
|
for (let index = 0;index < rest.length; index += 1) {
|
|
169505
169506
|
const item = rest[index];
|
|
169506
169507
|
if (!item)
|
|
169507
169508
|
continue;
|
|
169508
|
-
if (!item.startsWith("--"))
|
|
169509
|
+
if (!item.startsWith("--")) {
|
|
169510
|
+
positionals.push(item);
|
|
169509
169511
|
continue;
|
|
169512
|
+
}
|
|
169510
169513
|
const key = item.slice(2);
|
|
169511
169514
|
const next = rest[index + 1];
|
|
169512
169515
|
const value = next && !next.startsWith("--") ? next : true;
|
|
@@ -169521,7 +169524,7 @@ function parseArgs(argv) {
|
|
|
169521
169524
|
flags[key] = [String(existing), String(value)];
|
|
169522
169525
|
}
|
|
169523
169526
|
}
|
|
169524
|
-
return { command, flags };
|
|
169527
|
+
return { command, positionals, flags };
|
|
169525
169528
|
}
|
|
169526
169529
|
function stringFlag(flags, key) {
|
|
169527
169530
|
const value = flags[key];
|
|
@@ -184547,6 +184550,426 @@ function hasEnv(env, key) {
|
|
|
184547
184550
|
return typeof env[key] === "string" && env[key].trim().length > 0;
|
|
184548
184551
|
}
|
|
184549
184552
|
|
|
184553
|
+
// src/cli/setup.ts
|
|
184554
|
+
import { spawnSync } from "node:child_process";
|
|
184555
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
184556
|
+
import { cp, mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
184557
|
+
import { homedir as homedir2 } from "node:os";
|
|
184558
|
+
import { dirname as dirname4, join as join2 } from "node:path";
|
|
184559
|
+
import { fileURLToPath } from "node:url";
|
|
184560
|
+
async function runSetup(options) {
|
|
184561
|
+
const client = parseClient(options.client);
|
|
184562
|
+
const runner = parseRunner(options.runner);
|
|
184563
|
+
const command = options.command ? parseCommandSpec(options.command) : commandForRunner(runner);
|
|
184564
|
+
const context = {
|
|
184565
|
+
cwd: options.cwd,
|
|
184566
|
+
home: options.env?.HOME ?? homedir2(),
|
|
184567
|
+
write: options.write,
|
|
184568
|
+
scope: options.global ? "global" : "project",
|
|
184569
|
+
mcpCommand: command,
|
|
184570
|
+
sourceSkillDir: resolveBundledSkillDir()
|
|
184571
|
+
};
|
|
184572
|
+
if (!client)
|
|
184573
|
+
return renderSetupOverview(context);
|
|
184574
|
+
if (client === "codex")
|
|
184575
|
+
return renderResults(await setupCodex(context));
|
|
184576
|
+
return renderResults(await setupClaudeCode(context));
|
|
184577
|
+
}
|
|
184578
|
+
function commandForRunner(runner) {
|
|
184579
|
+
if (runner === "bunx") {
|
|
184580
|
+
return { command: "bunx", args: ["@kyo-so/cli", "mcp"] };
|
|
184581
|
+
}
|
|
184582
|
+
return { command: "npx", args: ["-y", "@kyo-so/cli", "mcp"] };
|
|
184583
|
+
}
|
|
184584
|
+
function buildCodexMcpToml(command) {
|
|
184585
|
+
return [
|
|
184586
|
+
"[mcp_servers.kyoso]",
|
|
184587
|
+
`command = ${JSON.stringify(command.command)}`,
|
|
184588
|
+
`args = ${JSON.stringify(command.args)}`,
|
|
184589
|
+
'env_vars = ["OPENAI_API_KEY", "CODEX_API_KEY", "ANTHROPIC_API_KEY", "CLAUDE_CODE_OAUTH_TOKEN"]',
|
|
184590
|
+
"startup_timeout_sec = 20",
|
|
184591
|
+
"tool_timeout_sec = 360",
|
|
184592
|
+
"enabled = true",
|
|
184593
|
+
""
|
|
184594
|
+
].join(`
|
|
184595
|
+
`);
|
|
184596
|
+
}
|
|
184597
|
+
function buildClaudeMcpEntry(command) {
|
|
184598
|
+
return {
|
|
184599
|
+
command: command.command,
|
|
184600
|
+
args: command.args,
|
|
184601
|
+
env: {
|
|
184602
|
+
OPENAI_API_KEY: "${OPENAI_API_KEY}",
|
|
184603
|
+
ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY}",
|
|
184604
|
+
CLAUDE_CODE_OAUTH_TOKEN: "${CLAUDE_CODE_OAUTH_TOKEN}"
|
|
184605
|
+
}
|
|
184606
|
+
};
|
|
184607
|
+
}
|
|
184608
|
+
function skillDestination(client, scope, cwd, home) {
|
|
184609
|
+
if (client === "codex") {
|
|
184610
|
+
const root2 = scope === "global" ? home : cwd;
|
|
184611
|
+
return join2(root2, ".agents", "skills", "kyoso-review");
|
|
184612
|
+
}
|
|
184613
|
+
const root = scope === "global" ? home : cwd;
|
|
184614
|
+
return join2(root, ".claude", "skills", "kyoso-review");
|
|
184615
|
+
}
|
|
184616
|
+
function detectSetup(options) {
|
|
184617
|
+
const home = options.home ?? homedir2();
|
|
184618
|
+
return {
|
|
184619
|
+
codex: {
|
|
184620
|
+
mcp: hasCodexMcp(join2(home, ".codex", "config.toml")),
|
|
184621
|
+
skill: existsSync(join2(options.cwd, ".agents", "skills", "kyoso-review", "SKILL.md")) || existsSync(join2(home, ".agents", "skills", "kyoso-review", "SKILL.md"))
|
|
184622
|
+
},
|
|
184623
|
+
"claude-code": {
|
|
184624
|
+
mcp: hasClaudeMcp(join2(options.cwd, ".mcp.json")) || hasClaudeMcp(join2(home, ".claude.json")),
|
|
184625
|
+
skill: existsSync(join2(options.cwd, ".claude", "skills", "kyoso-review", "SKILL.md")) || existsSync(join2(home, ".claude", "skills", "kyoso-review", "SKILL.md"))
|
|
184626
|
+
}
|
|
184627
|
+
};
|
|
184628
|
+
}
|
|
184629
|
+
async function setupCodex(context) {
|
|
184630
|
+
return [
|
|
184631
|
+
await ensureCodexMcp(context),
|
|
184632
|
+
await ensureSkill({
|
|
184633
|
+
title: "Codex skill",
|
|
184634
|
+
sourceDir: context.sourceSkillDir,
|
|
184635
|
+
destinationDir: skillDestination("codex", context.scope, context.cwd, context.home),
|
|
184636
|
+
write: context.write
|
|
184637
|
+
})
|
|
184638
|
+
];
|
|
184639
|
+
}
|
|
184640
|
+
async function setupClaudeCode(context) {
|
|
184641
|
+
return [
|
|
184642
|
+
await ensureClaudeMcp(context),
|
|
184643
|
+
await ensureSkill({
|
|
184644
|
+
title: "Claude Code skill",
|
|
184645
|
+
sourceDir: context.sourceSkillDir,
|
|
184646
|
+
destinationDir: skillDestination("claude-code", context.scope, context.cwd, context.home),
|
|
184647
|
+
write: context.write
|
|
184648
|
+
})
|
|
184649
|
+
];
|
|
184650
|
+
}
|
|
184651
|
+
async function ensureCodexMcp(context) {
|
|
184652
|
+
const configPath = join2(context.home, ".codex", "config.toml");
|
|
184653
|
+
const snippet = buildCodexMcpToml(context.mcpCommand);
|
|
184654
|
+
const current = await readOptionalFile(configPath);
|
|
184655
|
+
if (hasCodexMcpContent(current)) {
|
|
184656
|
+
return {
|
|
184657
|
+
title: "Codex MCP",
|
|
184658
|
+
status: "skipped",
|
|
184659
|
+
path: configPath,
|
|
184660
|
+
detail: "existing [mcp_servers.kyoso] kept"
|
|
184661
|
+
};
|
|
184662
|
+
}
|
|
184663
|
+
const detail = diffForAppend(configPath, snippet);
|
|
184664
|
+
if (!context.write) {
|
|
184665
|
+
return { title: "Codex MCP", status: "dry-run", path: configPath, detail };
|
|
184666
|
+
}
|
|
184667
|
+
const separator = current.length > 0 && !current.endsWith(`
|
|
184668
|
+
`) ? `
|
|
184669
|
+
|
|
184670
|
+
` : "";
|
|
184671
|
+
await mkdir3(dirname4(configPath), { recursive: true });
|
|
184672
|
+
await writeFile3(configPath, `${current}${separator}${snippet}`, "utf8");
|
|
184673
|
+
return {
|
|
184674
|
+
title: "Codex MCP",
|
|
184675
|
+
status: current.length > 0 ? "updated" : "created",
|
|
184676
|
+
path: configPath,
|
|
184677
|
+
detail
|
|
184678
|
+
};
|
|
184679
|
+
}
|
|
184680
|
+
async function ensureClaudeMcp(context) {
|
|
184681
|
+
if (context.scope === "global") {
|
|
184682
|
+
return ensureClaudeGlobalMcp(context);
|
|
184683
|
+
}
|
|
184684
|
+
const configPath = join2(context.cwd, ".mcp.json");
|
|
184685
|
+
const current = await readJsonObject(configPath);
|
|
184686
|
+
const mcpServers = recordValue(current.mcpServers);
|
|
184687
|
+
if (isRecord4(mcpServers.kyoso)) {
|
|
184688
|
+
return {
|
|
184689
|
+
title: "Claude Code MCP",
|
|
184690
|
+
status: "skipped",
|
|
184691
|
+
path: configPath,
|
|
184692
|
+
detail: "existing mcpServers.kyoso kept"
|
|
184693
|
+
};
|
|
184694
|
+
}
|
|
184695
|
+
const next = {
|
|
184696
|
+
...current,
|
|
184697
|
+
mcpServers: {
|
|
184698
|
+
...mcpServers,
|
|
184699
|
+
kyoso: buildClaudeMcpEntry(context.mcpCommand)
|
|
184700
|
+
}
|
|
184701
|
+
};
|
|
184702
|
+
const detail = diffForJson(configPath, current, next);
|
|
184703
|
+
if (!context.write) {
|
|
184704
|
+
return {
|
|
184705
|
+
title: "Claude Code MCP",
|
|
184706
|
+
status: "dry-run",
|
|
184707
|
+
path: configPath,
|
|
184708
|
+
detail
|
|
184709
|
+
};
|
|
184710
|
+
}
|
|
184711
|
+
await writeFile3(configPath, `${JSON.stringify(next, null, 2)}
|
|
184712
|
+
`, "utf8");
|
|
184713
|
+
return {
|
|
184714
|
+
title: "Claude Code MCP",
|
|
184715
|
+
status: Object.keys(current).length > 0 ? "updated" : "created",
|
|
184716
|
+
path: configPath,
|
|
184717
|
+
detail
|
|
184718
|
+
};
|
|
184719
|
+
}
|
|
184720
|
+
function ensureClaudeGlobalMcp(context) {
|
|
184721
|
+
const configPath = join2(context.home, ".claude.json");
|
|
184722
|
+
if (hasClaudeMcp(configPath)) {
|
|
184723
|
+
return {
|
|
184724
|
+
title: "Claude Code MCP",
|
|
184725
|
+
status: "skipped",
|
|
184726
|
+
path: configPath,
|
|
184727
|
+
detail: "existing mcpServers.kyoso kept"
|
|
184728
|
+
};
|
|
184729
|
+
}
|
|
184730
|
+
const json2 = JSON.stringify(buildClaudeMcpEntry(context.mcpCommand));
|
|
184731
|
+
const args = ["mcp", "add-json", "kyoso", json2, "--scope", "user"];
|
|
184732
|
+
const commandLine = ["claude", ...args.map(shellQuote)].join(" ");
|
|
184733
|
+
if (!context.write) {
|
|
184734
|
+
return {
|
|
184735
|
+
title: "Claude Code MCP",
|
|
184736
|
+
status: "dry-run",
|
|
184737
|
+
path: configPath,
|
|
184738
|
+
detail: commandLine
|
|
184739
|
+
};
|
|
184740
|
+
}
|
|
184741
|
+
const result = spawnSync("claude", args, { encoding: "utf8" });
|
|
184742
|
+
if (result.status !== 0) {
|
|
184743
|
+
throw new Error(result.stderr || result.stdout || "claude mcp add-json failed");
|
|
184744
|
+
}
|
|
184745
|
+
return {
|
|
184746
|
+
title: "Claude Code MCP",
|
|
184747
|
+
status: "updated",
|
|
184748
|
+
path: configPath,
|
|
184749
|
+
detail: commandLine
|
|
184750
|
+
};
|
|
184751
|
+
}
|
|
184752
|
+
async function ensureSkill(options) {
|
|
184753
|
+
const destinationSkill = join2(options.destinationDir, "SKILL.md");
|
|
184754
|
+
if (existsSync(destinationSkill)) {
|
|
184755
|
+
return {
|
|
184756
|
+
title: options.title,
|
|
184757
|
+
status: "skipped",
|
|
184758
|
+
path: options.destinationDir,
|
|
184759
|
+
detail: "existing kyoso-review skill kept"
|
|
184760
|
+
};
|
|
184761
|
+
}
|
|
184762
|
+
const detail = [
|
|
184763
|
+
`copy ${options.sourceDir}`,
|
|
184764
|
+
`to ${options.destinationDir}`
|
|
184765
|
+
].join(`
|
|
184766
|
+
`);
|
|
184767
|
+
if (!options.write) {
|
|
184768
|
+
return {
|
|
184769
|
+
title: options.title,
|
|
184770
|
+
status: "dry-run",
|
|
184771
|
+
path: options.destinationDir,
|
|
184772
|
+
detail
|
|
184773
|
+
};
|
|
184774
|
+
}
|
|
184775
|
+
await mkdir3(dirname4(options.destinationDir), { recursive: true });
|
|
184776
|
+
await cp(options.sourceDir, options.destinationDir, {
|
|
184777
|
+
recursive: true,
|
|
184778
|
+
force: false
|
|
184779
|
+
});
|
|
184780
|
+
return {
|
|
184781
|
+
title: options.title,
|
|
184782
|
+
status: "created",
|
|
184783
|
+
path: options.destinationDir,
|
|
184784
|
+
detail
|
|
184785
|
+
};
|
|
184786
|
+
}
|
|
184787
|
+
function renderSetupOverview(context) {
|
|
184788
|
+
const detected = detectSetup({ cwd: context.cwd, home: context.home });
|
|
184789
|
+
return [
|
|
184790
|
+
"Kyoso setup",
|
|
184791
|
+
"",
|
|
184792
|
+
"Clients",
|
|
184793
|
+
` codex: MCP ${statusWord(detected.codex.mcp)}, skill ${statusWord(detected.codex.skill)}`,
|
|
184794
|
+
` claude-code: MCP ${statusWord(detected["claude-code"].mcp)}, skill ${statusWord(detected["claude-code"].skill)}`,
|
|
184795
|
+
"",
|
|
184796
|
+
"Commands",
|
|
184797
|
+
" kyoso setup codex [--write] [--runner npx|bunx] [--global]",
|
|
184798
|
+
" kyoso setup claude-code [--write] [--runner npx|bunx] [--global]",
|
|
184799
|
+
"",
|
|
184800
|
+
`Default MCP command: ${context.mcpCommand.command} ${context.mcpCommand.args.join(" ")}`,
|
|
184801
|
+
"Dry-run is the default. Add --write to modify files."
|
|
184802
|
+
].join(`
|
|
184803
|
+
`);
|
|
184804
|
+
}
|
|
184805
|
+
function renderResults(results) {
|
|
184806
|
+
return [
|
|
184807
|
+
"Kyoso setup",
|
|
184808
|
+
"",
|
|
184809
|
+
...results.flatMap((result) => [
|
|
184810
|
+
`${result.title}: ${result.status}${result.path ? ` (${result.path})` : ""}`,
|
|
184811
|
+
...result.detail ? indent(result.detail).split(`
|
|
184812
|
+
`) : []
|
|
184813
|
+
])
|
|
184814
|
+
].join(`
|
|
184815
|
+
`);
|
|
184816
|
+
}
|
|
184817
|
+
function parseClient(client) {
|
|
184818
|
+
if (client === undefined)
|
|
184819
|
+
return;
|
|
184820
|
+
if (client === "codex" || client === "claude-code")
|
|
184821
|
+
return client;
|
|
184822
|
+
throw new Error(`Invalid setup client "${client}". Expected codex or claude-code.`);
|
|
184823
|
+
}
|
|
184824
|
+
function parseRunner(runner) {
|
|
184825
|
+
if (runner === undefined || runner === "npx")
|
|
184826
|
+
return "npx";
|
|
184827
|
+
if (runner === "bunx")
|
|
184828
|
+
return "bunx";
|
|
184829
|
+
throw new Error(`Invalid --runner value "${runner}". Expected npx or bunx.`);
|
|
184830
|
+
}
|
|
184831
|
+
function parseCommandSpec(value) {
|
|
184832
|
+
const parts = splitCommand(value);
|
|
184833
|
+
const [command, ...args] = parts;
|
|
184834
|
+
if (!command)
|
|
184835
|
+
throw new Error("--command must not be empty");
|
|
184836
|
+
return { command, args };
|
|
184837
|
+
}
|
|
184838
|
+
function splitCommand(value) {
|
|
184839
|
+
const parts = [];
|
|
184840
|
+
let current = "";
|
|
184841
|
+
let quote;
|
|
184842
|
+
for (const char of value.trim()) {
|
|
184843
|
+
if (quote) {
|
|
184844
|
+
if (char === quote) {
|
|
184845
|
+
quote = undefined;
|
|
184846
|
+
} else {
|
|
184847
|
+
current += char;
|
|
184848
|
+
}
|
|
184849
|
+
continue;
|
|
184850
|
+
}
|
|
184851
|
+
if (char === '"' || char === "'") {
|
|
184852
|
+
quote = char;
|
|
184853
|
+
continue;
|
|
184854
|
+
}
|
|
184855
|
+
if (/\s/.test(char)) {
|
|
184856
|
+
if (current.length > 0) {
|
|
184857
|
+
parts.push(current);
|
|
184858
|
+
current = "";
|
|
184859
|
+
}
|
|
184860
|
+
continue;
|
|
184861
|
+
}
|
|
184862
|
+
current += char;
|
|
184863
|
+
}
|
|
184864
|
+
if (quote)
|
|
184865
|
+
throw new Error("--command has an unterminated quote");
|
|
184866
|
+
if (current.length > 0)
|
|
184867
|
+
parts.push(current);
|
|
184868
|
+
return parts;
|
|
184869
|
+
}
|
|
184870
|
+
function resolveBundledSkillDir() {
|
|
184871
|
+
const start = dirname4(fileURLToPath(import.meta.url));
|
|
184872
|
+
let current = start;
|
|
184873
|
+
for (let depth = 0;depth < 5; depth += 1) {
|
|
184874
|
+
const candidate = join2(current, ".agents", "skills", "kyoso-review");
|
|
184875
|
+
if (existsSync(join2(candidate, "SKILL.md")))
|
|
184876
|
+
return candidate;
|
|
184877
|
+
current = dirname4(current);
|
|
184878
|
+
}
|
|
184879
|
+
throw new Error("Bundled kyoso-review skill was not found in this package.");
|
|
184880
|
+
}
|
|
184881
|
+
async function readOptionalFile(path) {
|
|
184882
|
+
try {
|
|
184883
|
+
return await readFile4(path, "utf8");
|
|
184884
|
+
} catch (error51) {
|
|
184885
|
+
if (isMissingPathError2(error51))
|
|
184886
|
+
return "";
|
|
184887
|
+
throw error51;
|
|
184888
|
+
}
|
|
184889
|
+
}
|
|
184890
|
+
async function readJsonObject(path) {
|
|
184891
|
+
const content = await readOptionalFile(path);
|
|
184892
|
+
if (content.trim().length === 0)
|
|
184893
|
+
return {};
|
|
184894
|
+
const parsed = JSON.parse(content);
|
|
184895
|
+
if (!isRecord4(parsed))
|
|
184896
|
+
throw new Error(`${path} must contain a JSON object`);
|
|
184897
|
+
return parsed;
|
|
184898
|
+
}
|
|
184899
|
+
function hasCodexMcp(path) {
|
|
184900
|
+
return existsSync(path) && hasCodexMcpContent(readTextSync(path));
|
|
184901
|
+
}
|
|
184902
|
+
function hasCodexMcpContent(content) {
|
|
184903
|
+
return /^\s*\[mcp_servers\.(?:"kyoso"|kyoso)]\s*$/m.test(content);
|
|
184904
|
+
}
|
|
184905
|
+
function hasClaudeMcp(path) {
|
|
184906
|
+
if (!existsSync(path))
|
|
184907
|
+
return false;
|
|
184908
|
+
try {
|
|
184909
|
+
const parsed = JSON.parse(readTextSync(path));
|
|
184910
|
+
return jsonHasKyosoMcp(parsed);
|
|
184911
|
+
} catch {
|
|
184912
|
+
return false;
|
|
184913
|
+
}
|
|
184914
|
+
}
|
|
184915
|
+
function jsonHasKyosoMcp(value) {
|
|
184916
|
+
if (!isRecord4(value))
|
|
184917
|
+
return false;
|
|
184918
|
+
if (isRecord4(value.mcpServers) && isRecord4(value.mcpServers.kyoso)) {
|
|
184919
|
+
return true;
|
|
184920
|
+
}
|
|
184921
|
+
return Object.values(value).some((child) => jsonHasKyosoMcp(child));
|
|
184922
|
+
}
|
|
184923
|
+
function readTextSync(path) {
|
|
184924
|
+
return readFileSync(path, "utf8");
|
|
184925
|
+
}
|
|
184926
|
+
function recordValue(value) {
|
|
184927
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
184928
|
+
}
|
|
184929
|
+
function isRecord4(value) {
|
|
184930
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
184931
|
+
}
|
|
184932
|
+
function diffForAppend(path, snippet) {
|
|
184933
|
+
return [
|
|
184934
|
+
`--- ${path}`,
|
|
184935
|
+
`+++ ${path}`,
|
|
184936
|
+
"@@",
|
|
184937
|
+
...snippet.split(`
|
|
184938
|
+
`).map((line) => `+${line}`)
|
|
184939
|
+
].join(`
|
|
184940
|
+
`);
|
|
184941
|
+
}
|
|
184942
|
+
function diffForJson(path, before, after) {
|
|
184943
|
+
const beforeText = JSON.stringify(before, null, 2).split(`
|
|
184944
|
+
`);
|
|
184945
|
+
const afterText = JSON.stringify(after, null, 2).split(`
|
|
184946
|
+
`);
|
|
184947
|
+
return [
|
|
184948
|
+
`--- ${path}`,
|
|
184949
|
+
`+++ ${path}`,
|
|
184950
|
+
"@@",
|
|
184951
|
+
...beforeText.map((line) => `-${line}`),
|
|
184952
|
+
...afterText.map((line) => `+${line}`)
|
|
184953
|
+
].join(`
|
|
184954
|
+
`);
|
|
184955
|
+
}
|
|
184956
|
+
function statusWord(value) {
|
|
184957
|
+
return value ? "ok" : "missing";
|
|
184958
|
+
}
|
|
184959
|
+
function indent(value) {
|
|
184960
|
+
return value.split(`
|
|
184961
|
+
`).map((line) => ` ${line}`).join(`
|
|
184962
|
+
`);
|
|
184963
|
+
}
|
|
184964
|
+
function shellQuote(value) {
|
|
184965
|
+
if (/^[A-Za-z0-9_./:=@{}$,-]+$/.test(value))
|
|
184966
|
+
return value;
|
|
184967
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
184968
|
+
}
|
|
184969
|
+
function isMissingPathError2(error51) {
|
|
184970
|
+
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
|
|
184971
|
+
}
|
|
184972
|
+
|
|
184550
184973
|
// src/cli/doctor.ts
|
|
184551
184974
|
async function runDoctor(options) {
|
|
184552
184975
|
const env = options.env ?? process.env;
|
|
@@ -184561,7 +184984,25 @@ async function runDoctor(options) {
|
|
|
184561
184984
|
lines.push(` config hash: ${loaded.configHash}`);
|
|
184562
184985
|
for (const warning of loaded.warnings)
|
|
184563
184986
|
lines.push(` warning: ${warning}`);
|
|
184987
|
+
const setup = detectSetup({ cwd: options.cwd, home: env.HOME });
|
|
184564
184988
|
lines.push("", "MCP", " stdio server: ok");
|
|
184989
|
+
lines.push(` Codex registration: ${setup.codex.mcp ? "ok" : "missing"}`);
|
|
184990
|
+
lines.push(` Claude Code registration: ${setup["claude-code"].mcp ? "ok" : "missing"}`);
|
|
184991
|
+
if (!setup.codex.mcp) {
|
|
184992
|
+
lines.push(" next: run `npx @kyo-so/cli setup codex --write`");
|
|
184993
|
+
}
|
|
184994
|
+
if (!setup["claude-code"].mcp) {
|
|
184995
|
+
lines.push(" next: run `npx @kyo-so/cli setup claude-code --write`");
|
|
184996
|
+
}
|
|
184997
|
+
lines.push("", "Skills");
|
|
184998
|
+
lines.push(` Codex kyoso-review: ${setup.codex.skill ? "ok" : "missing"}`);
|
|
184999
|
+
lines.push(` Claude Code kyoso-review: ${setup["claude-code"].skill ? "ok" : "missing"}`);
|
|
185000
|
+
if (!setup.codex.skill) {
|
|
185001
|
+
lines.push(" next: run `npx @kyo-so/cli setup codex --write`");
|
|
185002
|
+
}
|
|
185003
|
+
if (!setup["claude-code"].skill) {
|
|
185004
|
+
lines.push(" next: run `npx @kyo-so/cli setup claude-code --write`");
|
|
185005
|
+
}
|
|
184565
185006
|
lines.push("", "ACP agents");
|
|
184566
185007
|
for (const agent of ["codex", "claude"]) {
|
|
184567
185008
|
const config2 = loaded.config.agents[agent];
|
|
@@ -184635,12 +185076,12 @@ function commandExists(command, env) {
|
|
|
184635
185076
|
}
|
|
184636
185077
|
|
|
184637
185078
|
// src/cli/init.ts
|
|
184638
|
-
import { readFile as
|
|
184639
|
-
import { join as
|
|
185079
|
+
import { readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
|
|
185080
|
+
import { join as join3 } from "node:path";
|
|
184640
185081
|
async function runInit(options) {
|
|
184641
|
-
const configPath =
|
|
184642
|
-
const skillPath =
|
|
184643
|
-
const gitignorePath =
|
|
185082
|
+
const configPath = join3(options.cwd, "kyoso.config.ts");
|
|
185083
|
+
const skillPath = join3(options.cwd, ".agents/skills/kyoso-review/SKILL.md");
|
|
185084
|
+
const gitignorePath = join3(options.cwd, ".gitignore");
|
|
184644
185085
|
const configResult = await writeFileWithOverwritePrompt(configPath, CONFIG_TEMPLATE, options.force);
|
|
184645
185086
|
const skillResult = await writeFileWithOverwritePrompt(skillPath, SKILL_TEMPLATE, options.force);
|
|
184646
185087
|
const gitignoreResult = await ensureGitignoreEntry(gitignorePath, ".kyoso/");
|
|
@@ -184654,11 +185095,11 @@ async function runInit(options) {
|
|
|
184654
185095
|
async function ensureGitignoreEntry(path, entry) {
|
|
184655
185096
|
let content = "";
|
|
184656
185097
|
try {
|
|
184657
|
-
content = await
|
|
185098
|
+
content = await readFile5(path, "utf8");
|
|
184658
185099
|
} catch (error51) {
|
|
184659
|
-
if (!
|
|
185100
|
+
if (!isMissingPathError3(error51))
|
|
184660
185101
|
throw error51;
|
|
184661
|
-
await
|
|
185102
|
+
await writeFile4(path, `${entry}
|
|
184662
185103
|
`, "utf8");
|
|
184663
185104
|
return "created";
|
|
184664
185105
|
}
|
|
@@ -184668,11 +185109,11 @@ async function ensureGitignoreEntry(path, entry) {
|
|
|
184668
185109
|
const separator = content.length > 0 && !content.endsWith(`
|
|
184669
185110
|
`) ? `
|
|
184670
185111
|
` : "";
|
|
184671
|
-
await
|
|
185112
|
+
await writeFile4(path, `${content}${separator}${entry}
|
|
184672
185113
|
`, "utf8");
|
|
184673
185114
|
return "updated";
|
|
184674
185115
|
}
|
|
184675
|
-
function
|
|
185116
|
+
function isMissingPathError3(error51) {
|
|
184676
185117
|
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
|
|
184677
185118
|
}
|
|
184678
185119
|
var CONFIG_TEMPLATE = `import { defineConfig } from "@kyo-so/cli";
|
|
@@ -186479,7 +186920,7 @@ var Protocol = class {
|
|
|
186479
186920
|
const { relatedRequestId, resumptionToken, onresumptiontoken } = options ?? {};
|
|
186480
186921
|
let onAbort;
|
|
186481
186922
|
let cleanupMessageId;
|
|
186482
|
-
return new Promise((
|
|
186923
|
+
return new Promise((resolve4, reject) => {
|
|
186483
186924
|
const earlyReject = (error51) => {
|
|
186484
186925
|
reject(error51);
|
|
186485
186926
|
};
|
|
@@ -186539,7 +186980,7 @@ var Protocol = class {
|
|
|
186539
186980
|
return reject(response);
|
|
186540
186981
|
validateStandardSchema(resultSchema, response.result).then((parseResult) => {
|
|
186541
186982
|
if (parseResult.success)
|
|
186542
|
-
|
|
186983
|
+
resolve4(parseResult.data);
|
|
186543
186984
|
else
|
|
186544
186985
|
reject(new SdkError(SdkErrorCode.InvalidResult, `Invalid result for ${request.method}: ${parseResult.error}`));
|
|
186545
186986
|
}, reject);
|
|
@@ -189617,7 +190058,7 @@ var require_compile = /* @__PURE__ */ __commonJSMin((exports) => {
|
|
|
189617
190058
|
const schOrFunc = root.refs[ref];
|
|
189618
190059
|
if (schOrFunc)
|
|
189619
190060
|
return schOrFunc;
|
|
189620
|
-
let _sch =
|
|
190061
|
+
let _sch = resolve4.call(this, root, ref);
|
|
189621
190062
|
if (_sch === undefined) {
|
|
189622
190063
|
const schema = (_a3 = root.localRefs) === null || _a3 === undefined ? undefined : _a3[ref];
|
|
189623
190064
|
const { schemaId } = this.opts;
|
|
@@ -189648,7 +190089,7 @@ var require_compile = /* @__PURE__ */ __commonJSMin((exports) => {
|
|
|
189648
190089
|
function sameSchemaEnv(s1, s2) {
|
|
189649
190090
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
189650
190091
|
}
|
|
189651
|
-
function
|
|
190092
|
+
function resolve4(root, ref) {
|
|
189652
190093
|
let sch;
|
|
189653
190094
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
189654
190095
|
ref = sch;
|
|
@@ -190154,7 +190595,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin((exports, module) => {
|
|
|
190154
190595
|
uri = parse5(serialize(uri, options), options);
|
|
190155
190596
|
return uri;
|
|
190156
190597
|
}
|
|
190157
|
-
function
|
|
190598
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
190158
190599
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
190159
190600
|
const resolved = resolveComponent(parse5(baseURI, schemelessOptions), parse5(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
190160
190601
|
schemelessOptions.skipEscape = true;
|
|
@@ -190365,7 +190806,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin((exports, module) => {
|
|
|
190365
190806
|
const fastUri = {
|
|
190366
190807
|
SCHEMES,
|
|
190367
190808
|
normalize,
|
|
190368
|
-
resolve:
|
|
190809
|
+
resolve: resolve4,
|
|
190369
190810
|
resolveComponent,
|
|
190370
190811
|
equal,
|
|
190371
190812
|
serialize,
|
|
@@ -194087,7 +194528,7 @@ var StdioServerTransport = class {
|
|
|
194087
194528
|
send(message) {
|
|
194088
194529
|
if (this._closed)
|
|
194089
194530
|
return Promise.reject(/* @__PURE__ */ new Error("StdioServerTransport is closed"));
|
|
194090
|
-
return new Promise((
|
|
194531
|
+
return new Promise((resolve4, reject) => {
|
|
194091
194532
|
const json2 = serializeMessage(message);
|
|
194092
194533
|
let settled = false;
|
|
194093
194534
|
const onError = (error51) => {
|
|
@@ -194104,7 +194545,7 @@ var StdioServerTransport = class {
|
|
|
194104
194545
|
settled = true;
|
|
194105
194546
|
this._stdout.off("error", onError);
|
|
194106
194547
|
this._stdout.off("drain", onDrain);
|
|
194107
|
-
|
|
194548
|
+
resolve4();
|
|
194108
194549
|
};
|
|
194109
194550
|
this._stdout.once("error", onError);
|
|
194110
194551
|
if (this._stdout.write(json2)) {
|
|
@@ -194112,7 +194553,7 @@ var StdioServerTransport = class {
|
|
|
194112
194553
|
return;
|
|
194113
194554
|
settled = true;
|
|
194114
194555
|
this._stdout.off("error", onError);
|
|
194115
|
-
|
|
194556
|
+
resolve4();
|
|
194116
194557
|
} else if (!settled)
|
|
194117
194558
|
this._stdout.once("drain", onDrain);
|
|
194118
194559
|
});
|
|
@@ -194120,12 +194561,12 @@ var StdioServerTransport = class {
|
|
|
194120
194561
|
};
|
|
194121
194562
|
|
|
194122
194563
|
// src/core/runReview.ts
|
|
194123
|
-
import { resolve as
|
|
194564
|
+
import { resolve as resolve5 } from "node:path";
|
|
194124
194565
|
|
|
194125
194566
|
// src/acp/AcpAgentProcess.ts
|
|
194126
194567
|
import { spawn } from "node:child_process";
|
|
194127
|
-
import { readFile as
|
|
194128
|
-
import { isAbsolute, relative, resolve as
|
|
194568
|
+
import { readFile as readFile6, realpath } from "node:fs/promises";
|
|
194569
|
+
import { isAbsolute, relative, resolve as resolve4 } from "node:path";
|
|
194129
194570
|
import { Readable, Writable } from "node:stream";
|
|
194130
194571
|
|
|
194131
194572
|
// node_modules/@agentclientprotocol/sdk/dist/schema/index.js
|
|
@@ -195999,14 +196440,14 @@ function ndJsonStream(output2, input2) {
|
|
|
195999
196440
|
}
|
|
196000
196441
|
// node_modules/@agentclientprotocol/sdk/dist/jsonrpc.js
|
|
196001
196442
|
var CANCEL_REQUEST_METHOD = "$/cancel_request";
|
|
196002
|
-
function
|
|
196443
|
+
function isRecord5(value) {
|
|
196003
196444
|
return typeof value === "object" && value !== null;
|
|
196004
196445
|
}
|
|
196005
196446
|
function isJsonRpcId(value) {
|
|
196006
196447
|
return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
|
|
196007
196448
|
}
|
|
196008
196449
|
function cancelRequestId(params) {
|
|
196009
|
-
if (!
|
|
196450
|
+
if (!isRecord5(params) || !isJsonRpcId(params["requestId"])) {
|
|
196010
196451
|
return;
|
|
196011
196452
|
}
|
|
196012
196453
|
return params["requestId"];
|
|
@@ -196230,12 +196671,12 @@ class Connection {
|
|
|
196230
196671
|
}
|
|
196231
196672
|
const id = this.nextRequestId++;
|
|
196232
196673
|
let cancel = () => {};
|
|
196233
|
-
const responsePromise = new Promise((
|
|
196674
|
+
const responsePromise = new Promise((resolve4, reject) => {
|
|
196234
196675
|
const pendingResponse = {
|
|
196235
196676
|
resolve: (response) => {
|
|
196236
196677
|
try {
|
|
196237
196678
|
const value = mapResponse ? mapResponse(response) : response;
|
|
196238
|
-
|
|
196679
|
+
resolve4(value);
|
|
196239
196680
|
} catch (error51) {
|
|
196240
196681
|
reject(error51);
|
|
196241
196682
|
}
|
|
@@ -196300,8 +196741,8 @@ class Connection {
|
|
|
196300
196741
|
initialize(stream, handlers) {
|
|
196301
196742
|
this.stream = stream;
|
|
196302
196743
|
this.staticHandlers = handlers;
|
|
196303
|
-
this.closedPromise = new Promise((
|
|
196304
|
-
this.abortController.signal.addEventListener("abort", () =>
|
|
196744
|
+
this.closedPromise = new Promise((resolve4) => {
|
|
196745
|
+
this.abortController.signal.addEventListener("abort", () => resolve4());
|
|
196305
196746
|
});
|
|
196306
196747
|
this.receive();
|
|
196307
196748
|
}
|
|
@@ -196871,8 +197312,8 @@ class AsyncQueue {
|
|
|
196871
197312
|
if (this.failed) {
|
|
196872
197313
|
return Promise.reject(this.failure);
|
|
196873
197314
|
}
|
|
196874
|
-
return new Promise((
|
|
196875
|
-
this.waiters.push({ resolve:
|
|
197315
|
+
return new Promise((resolve4, reject) => {
|
|
197316
|
+
this.waiters.push({ resolve: resolve4, reject });
|
|
196876
197317
|
});
|
|
196877
197318
|
}
|
|
196878
197319
|
}
|
|
@@ -197558,7 +197999,7 @@ function isSeverity(value) {
|
|
|
197558
197999
|
return typeof value === "string" && severities.includes(value);
|
|
197559
198000
|
}
|
|
197560
198001
|
function normalizeCisaSecureByDesign(value) {
|
|
197561
|
-
if (!
|
|
198002
|
+
if (!isRecord6(value))
|
|
197562
198003
|
return;
|
|
197563
198004
|
const normalized = {};
|
|
197564
198005
|
const customerSecurityOutcomes = normalizeGateStatus(value.customerSecurityOutcomes);
|
|
@@ -197599,7 +198040,7 @@ function normalizeFindingFiles(value) {
|
|
|
197599
198040
|
if (!Array.isArray(value))
|
|
197600
198041
|
return;
|
|
197601
198042
|
const files = value.flatMap((item) => {
|
|
197602
|
-
if (!
|
|
198043
|
+
if (!isRecord6(item) || typeof item.path !== "string" || item.path.trim().length === 0) {
|
|
197603
198044
|
return [];
|
|
197604
198045
|
}
|
|
197605
198046
|
const file2 = {
|
|
@@ -197618,7 +198059,7 @@ function normalizeFindingFiles(value) {
|
|
|
197618
198059
|
function normalizeLineNumber(value) {
|
|
197619
198060
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
197620
198061
|
}
|
|
197621
|
-
function
|
|
198062
|
+
function isRecord6(value) {
|
|
197622
198063
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
197623
198064
|
}
|
|
197624
198065
|
|
|
@@ -197806,7 +198247,7 @@ async function readWorkspaceFile(workspaceDir, requestedPath, line, limit) {
|
|
|
197806
198247
|
const readablePath = await resolveReadableFile(workspaceRoot, absolute);
|
|
197807
198248
|
if (!readablePath)
|
|
197808
198249
|
continue;
|
|
197809
|
-
content = await
|
|
198250
|
+
content = await readFile6(readablePath, "utf8").catch(() => {
|
|
197810
198251
|
return;
|
|
197811
198252
|
});
|
|
197812
198253
|
if (content !== undefined)
|
|
@@ -197823,7 +198264,7 @@ async function readWorkspaceFile(workspaceDir, requestedPath, line, limit) {
|
|
|
197823
198264
|
}
|
|
197824
198265
|
async function resolveReadableFile(workspaceRoot, absolute) {
|
|
197825
198266
|
const realPath = await realpath(absolute).catch((error51) => {
|
|
197826
|
-
if (
|
|
198267
|
+
if (isMissingPathError4(error51))
|
|
197827
198268
|
return;
|
|
197828
198269
|
throw error51;
|
|
197829
198270
|
});
|
|
@@ -197833,13 +198274,13 @@ async function resolveReadableFile(workspaceRoot, absolute) {
|
|
|
197833
198274
|
return realPath;
|
|
197834
198275
|
}
|
|
197835
198276
|
function resolveReadablePaths(workspaceRoot, requestedPath) {
|
|
197836
|
-
const primary =
|
|
198277
|
+
const primary = resolve4(workspaceRoot, requestedPath);
|
|
197837
198278
|
assertWithinWorkspace(workspaceRoot, primary);
|
|
197838
198279
|
const relativePath = relative(workspaceRoot, primary).replaceAll("\\", "/");
|
|
197839
198280
|
if (relativePath.startsWith("context/") || relativePath.startsWith("repo/")) {
|
|
197840
198281
|
return [primary];
|
|
197841
198282
|
}
|
|
197842
|
-
const repoPath =
|
|
198283
|
+
const repoPath = resolve4(workspaceRoot, "repo", relativePath);
|
|
197843
198284
|
assertWithinWorkspace(workspaceRoot, repoPath);
|
|
197844
198285
|
return isAbsolute(requestedPath) ? [primary, repoPath] : [repoPath, primary];
|
|
197845
198286
|
}
|
|
@@ -197861,7 +198302,7 @@ function terminateChild(child) {
|
|
|
197861
198302
|
}, 2000);
|
|
197862
198303
|
killTimer.unref();
|
|
197863
198304
|
}
|
|
197864
|
-
function
|
|
198305
|
+
function isMissingPathError4(error51) {
|
|
197865
198306
|
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
|
|
197866
198307
|
}
|
|
197867
198308
|
function buildAgentFailure(rawDetail, fallbackMessage) {
|
|
@@ -198382,8 +198823,8 @@ function normalizeTitle(value) {
|
|
|
198382
198823
|
}
|
|
198383
198824
|
|
|
198384
198825
|
// src/audit/trace.ts
|
|
198385
|
-
import { mkdir as
|
|
198386
|
-
import { dirname as
|
|
198826
|
+
import { mkdir as mkdir4, appendFile } from "node:fs/promises";
|
|
198827
|
+
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join4 } from "node:path";
|
|
198387
198828
|
|
|
198388
198829
|
// src/context/pathPolicy.ts
|
|
198389
198830
|
import { normalize, sep } from "node:path";
|
|
@@ -198477,13 +198918,13 @@ function createTraceWriter(options) {
|
|
|
198477
198918
|
}
|
|
198478
198919
|
const date5 = new Date().toISOString().slice(0, 10);
|
|
198479
198920
|
const directory = validateAuditDirectory(options.directory, warnings);
|
|
198480
|
-
const tracePath =
|
|
198921
|
+
const tracePath = join4(options.cwd, directory, date5, `${options.traceId}.jsonl`);
|
|
198481
198922
|
return {
|
|
198482
198923
|
tracePath,
|
|
198483
198924
|
warnings,
|
|
198484
198925
|
async write(event) {
|
|
198485
198926
|
try {
|
|
198486
|
-
await
|
|
198927
|
+
await mkdir4(dirname5(tracePath), { recursive: true });
|
|
198487
198928
|
await appendFile(tracePath, `${JSON.stringify(sanitizeForAudit(event, {
|
|
198488
198929
|
includeRawAgentOutput: options.includeRawAgentOutput
|
|
198489
198930
|
}))}
|
|
@@ -198866,15 +199307,15 @@ function decide(input2) {
|
|
|
198866
199307
|
}
|
|
198867
199308
|
|
|
198868
199309
|
// src/workspace/createSnapshot.ts
|
|
198869
|
-
import { chmod, mkdir as
|
|
198870
|
-
import { dirname as
|
|
199310
|
+
import { chmod, mkdir as mkdir5, mkdtemp, writeFile as writeFile5 } from "node:fs/promises";
|
|
199311
|
+
import { dirname as dirname6, join as join5 } from "node:path";
|
|
198871
199312
|
import { tmpdir } from "node:os";
|
|
198872
199313
|
async function createSnapshot(traceId, tool, request, options = {}) {
|
|
198873
|
-
const root = await mkdtemp(
|
|
198874
|
-
const repoDir =
|
|
198875
|
-
const contextDir =
|
|
198876
|
-
await
|
|
198877
|
-
await
|
|
199314
|
+
const root = await mkdtemp(join5(tmpdir(), `kyoso-${traceId}-`));
|
|
199315
|
+
const repoDir = join5(root, "repo");
|
|
199316
|
+
const contextDir = join5(root, "context");
|
|
199317
|
+
await mkdir5(repoDir, { recursive: true });
|
|
199318
|
+
await mkdir5(contextDir, { recursive: true });
|
|
198878
199319
|
let fileCount = 0;
|
|
198879
199320
|
for (const file2 of request.selectedFiles ?? []) {
|
|
198880
199321
|
const relative2 = normalizeRelativePath(file2.path);
|
|
@@ -198882,24 +199323,24 @@ async function createSnapshot(traceId, tool, request, options = {}) {
|
|
|
198882
199323
|
continue;
|
|
198883
199324
|
if (!isAllowedPath(relative2, options.allowPatterns ?? []))
|
|
198884
199325
|
continue;
|
|
198885
|
-
const dest =
|
|
198886
|
-
await
|
|
198887
|
-
await
|
|
199326
|
+
const dest = join5(repoDir, relative2);
|
|
199327
|
+
await mkdir5(dirname6(dest), { recursive: true });
|
|
199328
|
+
await writeFile5(dest, file2.content, "utf8");
|
|
198888
199329
|
await chmod(dest, 292).catch(() => {
|
|
198889
199330
|
return;
|
|
198890
199331
|
});
|
|
198891
199332
|
fileCount += 1;
|
|
198892
199333
|
}
|
|
198893
|
-
await
|
|
198894
|
-
await
|
|
198895
|
-
await
|
|
198896
|
-
await
|
|
199334
|
+
await writeFile5(join5(contextDir, "request.json"), JSON.stringify(stripContents(request), null, 2), "utf8");
|
|
199335
|
+
await writeFile5(join5(contextDir, "selected_files_manifest.json"), JSON.stringify(buildSelectedFilesManifest(request), null, 2), "utf8");
|
|
199336
|
+
await writeFile5(join5(contextDir, "instructions.codex.md"), buildAgentPrompt(tool, request, "codex"), "utf8");
|
|
199337
|
+
await writeFile5(join5(contextDir, "instructions.claude.md"), buildAgentPrompt(tool, request, "claude"), "utf8");
|
|
198897
199338
|
if (request.repoSummary)
|
|
198898
|
-
await
|
|
199339
|
+
await writeFile5(join5(contextDir, "repo_summary.md"), request.repoSummary, "utf8");
|
|
198899
199340
|
if (request.currentPlan)
|
|
198900
|
-
await
|
|
199341
|
+
await writeFile5(join5(contextDir, "current_plan.md"), request.currentPlan, "utf8");
|
|
198901
199342
|
if (request.diff?.unifiedDiff)
|
|
198902
|
-
await
|
|
199343
|
+
await writeFile5(join5(contextDir, "diff.patch"), request.diff.unifiedDiff, "utf8");
|
|
198903
199344
|
return { root, repoDir, contextDir, fileCount };
|
|
198904
199345
|
}
|
|
198905
199346
|
function stripContents(request) {
|
|
@@ -199395,7 +199836,7 @@ function mergeDenyPatterns(configDeny, requestDeny) {
|
|
|
199395
199836
|
function assertTrustedWorkspaceRoot(requestRoot, configRoot, cwd) {
|
|
199396
199837
|
if (!requestRoot)
|
|
199397
199838
|
return;
|
|
199398
|
-
if (
|
|
199839
|
+
if (resolve5(cwd, requestRoot) !== resolve5(cwd, configRoot)) {
|
|
199399
199840
|
throw new KyosoRequestError("workspace.root is not trusted by config", "UNTRUSTED_WORKSPACE_ROOT");
|
|
199400
199841
|
}
|
|
199401
199842
|
}
|
|
@@ -199503,6 +199944,17 @@ async function main() {
|
|
|
199503
199944
|
console.log(await runInit({ cwd, force: booleanFlag(parsed.flags, "force") }));
|
|
199504
199945
|
return;
|
|
199505
199946
|
}
|
|
199947
|
+
if (parsed.command === "setup") {
|
|
199948
|
+
console.log(await runSetup({
|
|
199949
|
+
cwd,
|
|
199950
|
+
client: parsed.positionals[0],
|
|
199951
|
+
write: booleanFlag(parsed.flags, "write"),
|
|
199952
|
+
global: booleanFlag(parsed.flags, "global"),
|
|
199953
|
+
runner: stringFlag(parsed.flags, "runner"),
|
|
199954
|
+
command: stringFlag(parsed.flags, "command")
|
|
199955
|
+
}));
|
|
199956
|
+
return;
|
|
199957
|
+
}
|
|
199506
199958
|
if (parsed.command === "plan" || parsed.command === "security" || parsed.command === "diff") {
|
|
199507
199959
|
const tool = commandToTool(parsed.command);
|
|
199508
199960
|
const request = await buildReviewRequest(tool, parsed.flags);
|
|
@@ -199554,7 +200006,7 @@ async function buildDiff(tool, flags) {
|
|
|
199554
200006
|
return;
|
|
199555
200007
|
const base = stringFlag(flags, "base") ?? "main";
|
|
199556
200008
|
const head = stringFlag(flags, "head") ?? "HEAD";
|
|
199557
|
-
const result =
|
|
200009
|
+
const result = spawnSync2("git", ["diff", base, head], { encoding: "utf8" });
|
|
199558
200010
|
if (result.status !== 0) {
|
|
199559
200011
|
throw new Error(result.stderr || `git diff failed for ${base}..${head}`);
|
|
199560
200012
|
}
|
|
@@ -199594,6 +200046,7 @@ var HELP = `Kyoso
|
|
|
199594
200046
|
|
|
199595
200047
|
Usage:
|
|
199596
200048
|
kyoso mcp [--config kyoso.config.ts] [--ignore-config] [--trust-config] [--network model_only|unrestricted]
|
|
200049
|
+
kyoso setup [codex|claude-code] [--write] [--runner npx|bunx] [--command <command>] [--global]
|
|
199597
200050
|
kyoso plan --goal <text> [--plan <path-or-text>] [--file <path>] [--json] [--trust-config]
|
|
199598
200051
|
kyoso security --goal <text> [--diff <path>] [--file <path>] [--allow-secret-redaction] [--trust-config]
|
|
199599
200052
|
kyoso diff --base main --head HEAD [--json] [--trust-config]
|