@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/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 readFile4, writeFile as writeFile3 } from "node:fs/promises";
184639
- import { join as join2 } from "node:path";
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 = join2(options.cwd, "kyoso.config.ts");
184642
- const skillPath = join2(options.cwd, ".agents/skills/kyoso-review/SKILL.md");
184643
- const gitignorePath = join2(options.cwd, ".gitignore");
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 readFile4(path, "utf8");
185098
+ content = await readFile5(path, "utf8");
184658
185099
  } catch (error51) {
184659
- if (!isMissingPathError2(error51))
185100
+ if (!isMissingPathError3(error51))
184660
185101
  throw error51;
184661
- await writeFile3(path, `${entry}
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 writeFile3(path, `${content}${separator}${entry}
185112
+ await writeFile4(path, `${content}${separator}${entry}
184672
185113
  `, "utf8");
184673
185114
  return "updated";
184674
185115
  }
184675
- function isMissingPathError2(error51) {
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((resolve3, reject) => {
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
- resolve3(parseResult.data);
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 = resolve3.call(this, root, ref);
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 resolve3(root, ref) {
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 resolve3(baseURI, relativeURI, options) {
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: resolve3,
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((resolve3, reject) => {
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
- resolve3();
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
- resolve3();
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 resolve4 } from "node:path";
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 readFile5, realpath } from "node:fs/promises";
194128
- import { isAbsolute, relative, resolve as resolve3 } from "node:path";
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 isRecord4(value) {
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 (!isRecord4(params) || !isJsonRpcId(params["requestId"])) {
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((resolve3, reject) => {
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
- resolve3(value);
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((resolve3) => {
196304
- this.abortController.signal.addEventListener("abort", () => resolve3());
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((resolve3, reject) => {
196875
- this.waiters.push({ resolve: resolve3, reject });
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 (!isRecord5(value))
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 (!isRecord5(item) || typeof item.path !== "string" || item.path.trim().length === 0) {
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 isRecord5(value) {
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 readFile5(readablePath, "utf8").catch(() => {
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 (isMissingPathError3(error51))
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 = resolve3(workspaceRoot, requestedPath);
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 = resolve3(workspaceRoot, "repo", relativePath);
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 isMissingPathError3(error51) {
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 mkdir3, appendFile } from "node:fs/promises";
198386
- import { dirname as dirname4, isAbsolute as isAbsolute2, join as join3 } from "node:path";
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 = join3(options.cwd, directory, date5, `${options.traceId}.jsonl`);
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 mkdir3(dirname4(tracePath), { recursive: true });
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 mkdir4, mkdtemp, writeFile as writeFile4 } from "node:fs/promises";
198870
- import { dirname as dirname5, join as join4 } from "node:path";
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(join4(tmpdir(), `kyoso-${traceId}-`));
198874
- const repoDir = join4(root, "repo");
198875
- const contextDir = join4(root, "context");
198876
- await mkdir4(repoDir, { recursive: true });
198877
- await mkdir4(contextDir, { recursive: true });
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 = join4(repoDir, relative2);
198886
- await mkdir4(dirname5(dest), { recursive: true });
198887
- await writeFile4(dest, file2.content, "utf8");
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 writeFile4(join4(contextDir, "request.json"), JSON.stringify(stripContents(request), null, 2), "utf8");
198894
- await writeFile4(join4(contextDir, "selected_files_manifest.json"), JSON.stringify(buildSelectedFilesManifest(request), null, 2), "utf8");
198895
- await writeFile4(join4(contextDir, "instructions.codex.md"), buildAgentPrompt(tool, request, "codex"), "utf8");
198896
- await writeFile4(join4(contextDir, "instructions.claude.md"), buildAgentPrompt(tool, request, "claude"), "utf8");
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 writeFile4(join4(contextDir, "repo_summary.md"), request.repoSummary, "utf8");
199339
+ await writeFile5(join5(contextDir, "repo_summary.md"), request.repoSummary, "utf8");
198899
199340
  if (request.currentPlan)
198900
- await writeFile4(join4(contextDir, "current_plan.md"), request.currentPlan, "utf8");
199341
+ await writeFile5(join5(contextDir, "current_plan.md"), request.currentPlan, "utf8");
198901
199342
  if (request.diff?.unifiedDiff)
198902
- await writeFile4(join4(contextDir, "diff.patch"), request.diff.unifiedDiff, "utf8");
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 (resolve4(cwd, requestRoot) !== resolve4(cwd, configRoot)) {
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 = spawnSync("git", ["diff", base, head], { encoding: "utf8" });
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]