@kyo-so/cli 0.1.0 → 0.3.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.
@@ -1,5 +1,6 @@
1
1
  export type ParsedArgs = {
2
2
  command: string;
3
+ positionals: string[];
3
4
  flags: Record<string, string | boolean | string[]>;
4
5
  };
5
6
  export declare function parseArgs(argv: string[]): ParsedArgs;
@@ -0,0 +1,29 @@
1
+ export type SetupClient = "codex" | "claude-code";
2
+ export type SetupRunner = "npx" | "bunx";
3
+ export type SetupScope = "project" | "global";
4
+ export type SetupOptions = {
5
+ cwd: string;
6
+ client?: string;
7
+ write: boolean;
8
+ global: boolean;
9
+ runner?: string;
10
+ command?: string;
11
+ env?: NodeJS.ProcessEnv;
12
+ };
13
+ type McpCommand = {
14
+ command: string;
15
+ args: string[];
16
+ };
17
+ export declare function runSetup(options: SetupOptions): Promise<string>;
18
+ export declare function commandForRunner(runner: SetupRunner): McpCommand;
19
+ export declare function buildCodexMcpToml(command: McpCommand): string;
20
+ export declare function buildClaudeMcpEntry(command: McpCommand): Record<string, unknown>;
21
+ export declare function skillDestination(client: SetupClient, scope: SetupScope, cwd: string, home: string): string;
22
+ export declare function detectSetup(options: {
23
+ cwd: string;
24
+ home?: string;
25
+ }): Record<SetupClient, {
26
+ mcp: boolean;
27
+ skill: boolean;
28
+ }>;
29
+ export {};
@@ -23,6 +23,7 @@ export declare const kyosoConfigSchema: z.ZodObject<{
23
23
  role: z.ZodEnum<{
24
24
  implementation_reviewer: "implementation_reviewer";
25
25
  architecture_security_reviewer: "architecture_security_reviewer";
26
+ combined_reviewer: "combined_reviewer";
26
27
  }>;
27
28
  timeoutMs: z.ZodDefault<z.ZodNumber>;
28
29
  env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -43,6 +44,7 @@ export declare const kyosoConfigSchema: z.ZodObject<{
43
44
  role: z.ZodEnum<{
44
45
  implementation_reviewer: "implementation_reviewer";
45
46
  architecture_security_reviewer: "architecture_security_reviewer";
47
+ combined_reviewer: "combined_reviewer";
46
48
  }>;
47
49
  timeoutMs: z.ZodDefault<z.ZodNumber>;
48
50
  env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -4,4 +4,4 @@ export declare const DEFAULT_MAX_DIFF_BYTES = 300000;
4
4
  export declare const RAW_OUTPUT_MAX_CHARS = 16384;
5
5
  export declare const TRACE_DIR = ".kyoso/traces";
6
6
  export declare const KYOSO_CHILD_AGENT = "KYOSO_CHILD_AGENT";
7
- export declare const KYOSO_VERSION = "0.1.0";
7
+ export declare const KYOSO_VERSION = "0.3.0";
@@ -59,7 +59,8 @@ export type CisaSecureByDesignResult = {
59
59
  notes: string[];
60
60
  };
61
61
  export type AgentName = "codex" | "claude";
62
- export type AgentRole = "implementation_reviewer" | "architecture_security_reviewer";
62
+ export type AgentRole = "implementation_reviewer" | "architecture_security_reviewer" | "combined_reviewer";
63
+ export type ReviewMode = "multi_agent" | "single_agent";
63
64
  export type NormalizedAgentOpinion = {
64
65
  agent: AgentName;
65
66
  role: string;
@@ -110,6 +111,8 @@ export type AgentRunResult = {
110
111
  export type KyosoResult = {
111
112
  decision: KyosoDecision;
112
113
  degraded: boolean;
114
+ agentsUsed: AgentName[];
115
+ reviewMode: ReviewMode;
113
116
  summaryMarkdown: string;
114
117
  findings: KyosoFinding[];
115
118
  cisaSecureByDesign?: CisaSecureByDesignResult;
package/dist/index.js CHANGED
@@ -183783,7 +183783,11 @@ var agentSchema = exports_external.object({
183783
183783
  command: exports_external.string(),
183784
183784
  args: exports_external.array(exports_external.string()).default([]),
183785
183785
  model: exports_external.string().optional(),
183786
- role: exports_external.enum(["implementation_reviewer", "architecture_security_reviewer"]),
183786
+ role: exports_external.enum([
183787
+ "implementation_reviewer",
183788
+ "architecture_security_reviewer",
183789
+ "combined_reviewer"
183790
+ ]),
183787
183791
  timeoutMs: exports_external.number().int().positive().default(120000),
183788
183792
  env: exports_external.record(exports_external.string(), exports_external.string()).default({}),
183789
183793
  auth: exports_external.object({
@@ -188100,7 +188104,7 @@ function buildOpinion(agent, role, tool) {
188100
188104
  }
188101
188105
 
188102
188106
  // src/acp/prompts.ts
188103
- function buildAgentPrompt(tool, request, agent) {
188107
+ function buildAgentPrompt(tool, request, agent, role) {
188104
188108
  const shared = [
188105
188109
  "You are running as a Kyoso child reviewer.",
188106
188110
  "Do not edit files.",
@@ -188113,15 +188117,26 @@ function buildAgentPrompt(tool, request, agent) {
188113
188117
  "Use empty arrays when no finding, test, risk, or question exists; do not copy the example finding."
188114
188118
  ].join(`
188115
188119
  `);
188116
- const role = agent === "codex" ? [
188117
- "You are the Codex implementation reviewer in Kyoso.",
188118
- "Focus on feasibility, minimal change, existing code consistency, regression risk, tests, migration risk, and maintainability."
188119
- ].join(`
188120
- `) : [
188121
- "You are the Claude architecture and security reviewer in Kyoso.",
188122
- "Focus on architecture, threat modeling, authn/authz, secrets, privacy, secure defaults, CISA Secure by Design, and edge cases."
188123
- ].join(`
188124
- `);
188120
+ const roleInstructions = {
188121
+ implementation_reviewer: [
188122
+ "You are the implementation reviewer role in Kyoso.",
188123
+ "Focus on feasibility, minimal change, existing code consistency, regression risk, tests, migration risk, and maintainability."
188124
+ ].join(`
188125
+ `),
188126
+ architecture_security_reviewer: [
188127
+ "You are the architecture and security reviewer role in Kyoso.",
188128
+ "Focus on architecture, threat modeling, authn/authz, secrets, privacy, secure defaults, CISA Secure by Design, and edge cases."
188129
+ ].join(`
188130
+ `),
188131
+ combined_reviewer: [
188132
+ "You are the combined reviewer role in Kyoso.",
188133
+ "Cover both implementation review and architecture/security review in one pass.",
188134
+ "First assess feasibility, minimal change, existing code consistency, regression risk, tests, migration risk, and maintainability.",
188135
+ "Then assess architecture, threat modeling, authn/authz, secrets, privacy, secure defaults, CISA Secure by Design, and edge cases.",
188136
+ "Use finding category values so readers can distinguish implementation, architecture, and security concerns."
188137
+ ].join(`
188138
+ `)
188139
+ };
188125
188140
  const cisaInstruction = tool === "security_review" ? [
188126
188141
  "For security_review, include cisaMapping on each security-relevant finding when applicable.",
188127
188142
  "Also include cisaSecureByDesign with all four gate dimensions."
@@ -188129,7 +188144,9 @@ function buildAgentPrompt(tool, request, agent) {
188129
188144
  `) : "For plan_review and diff_review, include cisaMapping and cisaSecureByDesign only when relevant.";
188130
188145
  return `${shared}
188131
188146
 
188132
- ${role}
188147
+ Agent: ${agent}
188148
+ Role: ${role}
188149
+ ${roleInstructions[role]}
188133
188150
 
188134
188151
  Tool: ${tool}
188135
188152
  ${cisaInstruction}
@@ -188716,6 +188733,7 @@ function renderMarkdownResult(tool, result, options = {}) {
188716
188733
  `**Decision:** ${result.decision}`,
188717
188734
  `**Mode:** ${tool}`,
188718
188735
  `**Agents:** ${result.agentOpinions.map((opinion) => `${title(opinion.agent)} ${opinion.status}`).join(", ")}`,
188736
+ `**Review mode:** ${formatReviewMode(result)}`,
188719
188737
  `**Degraded:** ${String(result.degraded)}`,
188720
188738
  "",
188721
188739
  "## Summary",
@@ -188742,7 +188760,11 @@ function renderMarkdownResult(tool, result, options = {}) {
188742
188760
  lines.push(`### ${title(opinion.agent)}`, "", `${opinion.summary} (${opinion.status})`, "");
188743
188761
  }
188744
188762
  lines.push("", "## Disagreements", "");
188745
- lines.push(...result.disagreements.length > 0 ? result.disagreements.map((item) => `- ${item.topic}: ${item.judgeComment}`) : ["- None."]);
188763
+ if (result.reviewMode === "single_agent") {
188764
+ lines.push("- N/A - single-agent review.");
188765
+ } else {
188766
+ lines.push(...result.disagreements.length > 0 ? result.disagreements.map((item) => `- ${item.topic}: ${item.judgeComment}`) : ["- None."]);
188767
+ }
188746
188768
  lines.push("", "## Notes", "", "Kyoso did not modify files. Review was performed on a temporary snapshot.");
188747
188769
  if (result.audit.networkMode === "unrestricted") {
188748
188770
  lines.push("Network mode was unrestricted. File modification policy remained denied.");
@@ -188756,6 +188778,14 @@ function defaultSummaryText(result) {
188756
188778
  function title(value) {
188757
188779
  return value.slice(0, 1).toUpperCase() + value.slice(1);
188758
188780
  }
188781
+ function formatReviewMode(result) {
188782
+ if (result.reviewMode !== "single_agent")
188783
+ return "multi-agent";
188784
+ const opinion = result.agentOpinions[0];
188785
+ const agent = opinion ? title(opinion.agent) : "single agent";
188786
+ const role = opinion?.role === "combined_reviewer" ? "combined role" : "configured role";
188787
+ return `single-agent (${agent}, ${role}; cross-model verification was not performed)`;
188788
+ }
188759
188789
  function notes(items) {
188760
188790
  return (items[0] ?? "No notes.").replaceAll("|", "\\|");
188761
188791
  }
@@ -189209,8 +189239,8 @@ async function createSnapshot(traceId, tool, request, options = {}) {
189209
189239
  }
189210
189240
  await writeFile2(join3(contextDir, "request.json"), JSON.stringify(stripContents(request), null, 2), "utf8");
189211
189241
  await writeFile2(join3(contextDir, "selected_files_manifest.json"), JSON.stringify(buildSelectedFilesManifest(request), null, 2), "utf8");
189212
- await writeFile2(join3(contextDir, "instructions.codex.md"), buildAgentPrompt(tool, request, "codex"), "utf8");
189213
- await writeFile2(join3(contextDir, "instructions.claude.md"), buildAgentPrompt(tool, request, "claude"), "utf8");
189242
+ await writeFile2(join3(contextDir, "instructions.codex.md"), buildAgentPrompt(tool, request, "codex", options.agentRoles?.codex ?? "implementation_reviewer"), "utf8");
189243
+ await writeFile2(join3(contextDir, "instructions.claude.md"), buildAgentPrompt(tool, request, "claude", options.agentRoles?.claude ?? "architecture_security_reviewer"), "utf8");
189214
189244
  if (request.repoSummary)
189215
189245
  await writeFile2(join3(contextDir, "repo_summary.md"), request.repoSummary, "utf8");
189216
189246
  if (request.currentPlan)
@@ -189372,9 +189402,11 @@ async function runReview(tool, request, options = {}) {
189372
189402
  allowPatterns
189373
189403
  });
189374
189404
  warnings.push(...built.warnings);
189405
+ const agentRoles = resolveAgentRoles(loaded.config);
189375
189406
  snapshot = await createSnapshot(traceId, tool, built.request, {
189376
189407
  denyPatterns,
189377
- allowPatterns
189408
+ allowPatterns,
189409
+ agentRoles
189378
189410
  });
189379
189411
  await trace.write({
189380
189412
  type: "snapshot_created",
@@ -189394,6 +189426,8 @@ async function runReview(tool, request, options = {}) {
189394
189426
  trace
189395
189427
  });
189396
189428
  const normalizedAgentResults = agentResults.map(normalizeAgentRunResult);
189429
+ const agentsUsed = normalizedAgentResults.map((result2) => result2.agent);
189430
+ const reviewMode = agentsUsed.length === 1 ? "single_agent" : "multi_agent";
189397
189431
  const completed = normalizedAgentResults.filter((result2) => result2.status === "completed");
189398
189432
  const degraded = completed.length !== agentResults.length;
189399
189433
  let aggregate = aggregateAgentResults(normalizedAgentResults);
@@ -189445,6 +189479,8 @@ async function runReview(tool, request, options = {}) {
189445
189479
  const resultWithoutMarkdown = {
189446
189480
  decision,
189447
189481
  degraded,
189482
+ agentsUsed,
189483
+ reviewMode,
189448
189484
  findings: aggregate.findings,
189449
189485
  cisaSecureByDesign: cisa,
189450
189486
  disagreements: aggregate.disagreements,
@@ -189457,7 +189493,7 @@ async function runReview(tool, request, options = {}) {
189457
189493
  traceId,
189458
189494
  startedAt,
189459
189495
  completedAt,
189460
- agentsUsed: normalizedAgentResults.map((result2) => result2.agent),
189496
+ agentsUsed,
189461
189497
  redactionsApplied: secretScan.redactions,
189462
189498
  networkMode,
189463
189499
  workspaceMode: "temp_snapshot",
@@ -189516,12 +189552,13 @@ async function runReview(tool, request, options = {}) {
189516
189552
  }
189517
189553
  }
189518
189554
  async function runAgents(input) {
189555
+ const agentRoles = resolveAgentRoles(input.config);
189519
189556
  const agentInputs = ["codex", "claude"].filter((agent) => input.config.agents[agent].enabled).map((agent) => ({
189520
189557
  traceId: input.traceId,
189521
189558
  agent,
189522
- role: input.config.agents[agent].role,
189559
+ role: agentRoles[agent] ?? input.config.agents[agent].role,
189523
189560
  tool: input.tool,
189524
- prompt: buildAgentPrompt(input.tool, input.request, agent),
189561
+ prompt: buildAgentPrompt(input.tool, input.request, agent, agentRoles[agent] ?? input.config.agents[agent].role),
189525
189562
  workspaceDir: input.workspaceDir,
189526
189563
  timeoutMs: input.request.options?.maxAgentTimeoutMs ?? input.config.agents[agent].timeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS,
189527
189564
  networkMode: input.networkMode
@@ -189530,6 +189567,7 @@ async function runAgents(input) {
189530
189567
  type: "agent_started",
189531
189568
  traceId: input.traceId,
189532
189569
  agent: agentInput.agent,
189570
+ role: agentInput.role,
189533
189571
  timestamp: new Date().toISOString()
189534
189572
  })));
189535
189573
  const results = await input.manager.runAll(agentInputs);
@@ -189538,6 +189576,7 @@ async function runAgents(input) {
189538
189576
  type: "agent_completed",
189539
189577
  traceId: input.traceId,
189540
189578
  agent: result.agent,
189579
+ role: result.role,
189541
189580
  status: result.status,
189542
189581
  startedAt: result.startedAt,
189543
189582
  completedAt: result.completedAt,
@@ -189554,6 +189593,15 @@ async function runAgents(input) {
189554
189593
  }));
189555
189594
  return results;
189556
189595
  }
189596
+ function resolveAgentRoles(config2) {
189597
+ const enabledAgents = ["codex", "claude"].filter((agent) => config2.agents[agent].enabled);
189598
+ const singleAgentMode = enabledAgents.length === 1;
189599
+ const roles = {};
189600
+ for (const agent of enabledAgents) {
189601
+ roles[agent] = singleAgentMode ? "combined_reviewer" : config2.agents[agent].role;
189602
+ }
189603
+ return roles;
189604
+ }
189557
189605
  function defaultAgentManager(config2) {
189558
189606
  if (process.env.KYOSO_TEST_FAKE_AGENTS === "1")
189559
189607
  return new FakeAgentManager;
@@ -189591,6 +189639,8 @@ async function buildSecretBlockResult(input) {
189591
189639
  const resultWithoutMarkdown = {
189592
189640
  decision: "block",
189593
189641
  degraded: false,
189642
+ agentsUsed: [],
189643
+ reviewMode: "multi_agent",
189594
189644
  findings: [finding],
189595
189645
  cisaSecureByDesign: cisa,
189596
189646
  disagreements: [],
@@ -189671,6 +189721,8 @@ async function buildPolicyBlockResult(input) {
189671
189721
  const resultWithoutMarkdown = {
189672
189722
  decision: "block",
189673
189723
  degraded: false,
189724
+ agentsUsed: [],
189725
+ reviewMode: "multi_agent",
189674
189726
  findings: [input.finding],
189675
189727
  cisaSecureByDesign: input.tool === "security_review" ? computeCisaGate([input.finding], []) : undefined,
189676
189728
  disagreements: [],
@@ -1,4 +1,4 @@
1
- import type { KyosoReviewRequest, ReviewTool } from "../core/types.js";
1
+ import type { AgentName, AgentRole, KyosoReviewRequest, ReviewTool } from "../core/types.js";
2
2
  export type Snapshot = {
3
3
  root: string;
4
4
  repoDir: string;
@@ -8,4 +8,5 @@ export type Snapshot = {
8
8
  export declare function createSnapshot(traceId: string, tool: ReviewTool, request: KyosoReviewRequest, options?: {
9
9
  denyPatterns?: string[];
10
10
  allowPatterns?: string[];
11
+ agentRoles?: Partial<Record<AgentName, AgentRole>>;
11
12
  }): Promise<Snapshot>;
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "@kyo-so/cli";
2
+
3
+ export default defineConfig({
4
+ agents: {
5
+ codex: {
6
+ enabled: false,
7
+ },
8
+ },
9
+ });
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "@kyo-so/cli";
2
+
3
+ export default defineConfig({
4
+ agents: {
5
+ claude: {
6
+ enabled: false,
7
+ },
8
+ },
9
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kyo-so/cli",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Kyo-so: MCP-native, ACP-powered multi-agent review gates for AI coding workflows.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",