@opencodehub/cli 0.1.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.
Files changed (191) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +85 -0
  3. package/dist/agent-context.d.ts +54 -0
  4. package/dist/agent-context.d.ts.map +1 -0
  5. package/dist/agent-context.js +122 -0
  6. package/dist/agent-context.js.map +1 -0
  7. package/dist/cobol-proleap-setup.d.ts +77 -0
  8. package/dist/cobol-proleap-setup.d.ts.map +1 -0
  9. package/dist/cobol-proleap-setup.js +289 -0
  10. package/dist/cobol-proleap-setup.js.map +1 -0
  11. package/dist/commands/analyze.d.ts +234 -0
  12. package/dist/commands/analyze.d.ts.map +1 -0
  13. package/dist/commands/analyze.js +1096 -0
  14. package/dist/commands/analyze.js.map +1 -0
  15. package/dist/commands/augment.d.ts +48 -0
  16. package/dist/commands/augment.d.ts.map +1 -0
  17. package/dist/commands/augment.js +249 -0
  18. package/dist/commands/augment.js.map +1 -0
  19. package/dist/commands/baseline.d.ts +68 -0
  20. package/dist/commands/baseline.d.ts.map +1 -0
  21. package/dist/commands/baseline.js +110 -0
  22. package/dist/commands/baseline.js.map +1 -0
  23. package/dist/commands/bench.d.ts +54 -0
  24. package/dist/commands/bench.d.ts.map +1 -0
  25. package/dist/commands/bench.js +283 -0
  26. package/dist/commands/bench.js.map +1 -0
  27. package/dist/commands/ci-init.d.ts +37 -0
  28. package/dist/commands/ci-init.d.ts.map +1 -0
  29. package/dist/commands/ci-init.js +115 -0
  30. package/dist/commands/ci-init.js.map +1 -0
  31. package/dist/commands/clean.d.ts +13 -0
  32. package/dist/commands/clean.d.ts.map +1 -0
  33. package/dist/commands/clean.js +38 -0
  34. package/dist/commands/clean.js.map +1 -0
  35. package/dist/commands/code-pack.d.ts +105 -0
  36. package/dist/commands/code-pack.d.ts.map +1 -0
  37. package/dist/commands/code-pack.js +187 -0
  38. package/dist/commands/code-pack.js.map +1 -0
  39. package/dist/commands/context.d.ts +30 -0
  40. package/dist/commands/context.d.ts.map +1 -0
  41. package/dist/commands/context.js +237 -0
  42. package/dist/commands/context.js.map +1 -0
  43. package/dist/commands/detect-changes.d.ts +26 -0
  44. package/dist/commands/detect-changes.d.ts.map +1 -0
  45. package/dist/commands/detect-changes.js +73 -0
  46. package/dist/commands/detect-changes.js.map +1 -0
  47. package/dist/commands/doctor.d.ts +52 -0
  48. package/dist/commands/doctor.d.ts.map +1 -0
  49. package/dist/commands/doctor.js +472 -0
  50. package/dist/commands/doctor.js.map +1 -0
  51. package/dist/commands/find-enclosing-symbol.d.ts +67 -0
  52. package/dist/commands/find-enclosing-symbol.d.ts.map +1 -0
  53. package/dist/commands/find-enclosing-symbol.js +106 -0
  54. package/dist/commands/find-enclosing-symbol.js.map +1 -0
  55. package/dist/commands/group.d.ts +123 -0
  56. package/dist/commands/group.d.ts.map +1 -0
  57. package/dist/commands/group.js +448 -0
  58. package/dist/commands/group.js.map +1 -0
  59. package/dist/commands/impact.d.ts +23 -0
  60. package/dist/commands/impact.d.ts.map +1 -0
  61. package/dist/commands/impact.js +91 -0
  62. package/dist/commands/impact.js.map +1 -0
  63. package/dist/commands/index-repo.d.ts +39 -0
  64. package/dist/commands/index-repo.d.ts.map +1 -0
  65. package/dist/commands/index-repo.js +148 -0
  66. package/dist/commands/index-repo.js.map +1 -0
  67. package/dist/commands/ingest-sarif.d.ts +64 -0
  68. package/dist/commands/ingest-sarif.d.ts.map +1 -0
  69. package/dist/commands/ingest-sarif.js +381 -0
  70. package/dist/commands/ingest-sarif.js.map +1 -0
  71. package/dist/commands/init.d.ts +75 -0
  72. package/dist/commands/init.d.ts.map +1 -0
  73. package/dist/commands/init.js +315 -0
  74. package/dist/commands/init.js.map +1 -0
  75. package/dist/commands/list.d.ts +17 -0
  76. package/dist/commands/list.d.ts.map +1 -0
  77. package/dist/commands/list.js +79 -0
  78. package/dist/commands/list.js.map +1 -0
  79. package/dist/commands/mcp.d.ts +8 -0
  80. package/dist/commands/mcp.d.ts.map +1 -0
  81. package/dist/commands/mcp.js +28 -0
  82. package/dist/commands/mcp.js.map +1 -0
  83. package/dist/commands/open-store.d.ts +25 -0
  84. package/dist/commands/open-store.d.ts.map +1 -0
  85. package/dist/commands/open-store.js +47 -0
  86. package/dist/commands/open-store.js.map +1 -0
  87. package/dist/commands/pack.d.ts +35 -0
  88. package/dist/commands/pack.d.ts.map +1 -0
  89. package/dist/commands/pack.js +83 -0
  90. package/dist/commands/pack.js.map +1 -0
  91. package/dist/commands/query.d.ts +85 -0
  92. package/dist/commands/query.d.ts.map +1 -0
  93. package/dist/commands/query.js +309 -0
  94. package/dist/commands/query.js.map +1 -0
  95. package/dist/commands/scan.d.ts +81 -0
  96. package/dist/commands/scan.d.ts.map +1 -0
  97. package/dist/commands/scan.js +407 -0
  98. package/dist/commands/scan.js.map +1 -0
  99. package/dist/commands/setup.d.ts +178 -0
  100. package/dist/commands/setup.d.ts.map +1 -0
  101. package/dist/commands/setup.js +370 -0
  102. package/dist/commands/setup.js.map +1 -0
  103. package/dist/commands/sql.d.ts +19 -0
  104. package/dist/commands/sql.d.ts.map +1 -0
  105. package/dist/commands/sql.js +51 -0
  106. package/dist/commands/sql.js.map +1 -0
  107. package/dist/commands/status.d.ts +13 -0
  108. package/dist/commands/status.d.ts.map +1 -0
  109. package/dist/commands/status.js +66 -0
  110. package/dist/commands/status.js.map +1 -0
  111. package/dist/commands/verdict-render.d.ts +33 -0
  112. package/dist/commands/verdict-render.d.ts.map +1 -0
  113. package/dist/commands/verdict-render.js +123 -0
  114. package/dist/commands/verdict-render.js.map +1 -0
  115. package/dist/commands/verdict.d.ts +61 -0
  116. package/dist/commands/verdict.d.ts.map +1 -0
  117. package/dist/commands/verdict.js +146 -0
  118. package/dist/commands/verdict.js.map +1 -0
  119. package/dist/commands/wiki.d.ts +26 -0
  120. package/dist/commands/wiki.d.ts.map +1 -0
  121. package/dist/commands/wiki.js +74 -0
  122. package/dist/commands/wiki.js.map +1 -0
  123. package/dist/editors/claude-code.d.ts +23 -0
  124. package/dist/editors/claude-code.d.ts.map +1 -0
  125. package/dist/editors/claude-code.js +58 -0
  126. package/dist/editors/claude-code.js.map +1 -0
  127. package/dist/editors/codex.d.ts +22 -0
  128. package/dist/editors/codex.d.ts.map +1 -0
  129. package/dist/editors/codex.js +59 -0
  130. package/dist/editors/codex.js.map +1 -0
  131. package/dist/editors/cursor.d.ts +13 -0
  132. package/dist/editors/cursor.d.ts.map +1 -0
  133. package/dist/editors/cursor.js +21 -0
  134. package/dist/editors/cursor.js.map +1 -0
  135. package/dist/editors/index.d.ts +12 -0
  136. package/dist/editors/index.d.ts.map +1 -0
  137. package/dist/editors/index.js +11 -0
  138. package/dist/editors/index.js.map +1 -0
  139. package/dist/editors/opencode.d.ts +23 -0
  140. package/dist/editors/opencode.d.ts.map +1 -0
  141. package/dist/editors/opencode.js +61 -0
  142. package/dist/editors/opencode.js.map +1 -0
  143. package/dist/editors/types.d.ts +33 -0
  144. package/dist/editors/types.d.ts.map +1 -0
  145. package/dist/editors/types.js +19 -0
  146. package/dist/editors/types.js.map +1 -0
  147. package/dist/editors/windows-wrap.d.ts +19 -0
  148. package/dist/editors/windows-wrap.d.ts.map +1 -0
  149. package/dist/editors/windows-wrap.js +28 -0
  150. package/dist/editors/windows-wrap.js.map +1 -0
  151. package/dist/editors/windsurf.d.ts +12 -0
  152. package/dist/editors/windsurf.d.ts.map +1 -0
  153. package/dist/editors/windsurf.js +21 -0
  154. package/dist/editors/windsurf.js.map +1 -0
  155. package/dist/embedder-downloader.d.ts +87 -0
  156. package/dist/embedder-downloader.d.ts.map +1 -0
  157. package/dist/embedder-downloader.js +261 -0
  158. package/dist/embedder-downloader.js.map +1 -0
  159. package/dist/fs-atomic.d.ts +22 -0
  160. package/dist/fs-atomic.d.ts.map +1 -0
  161. package/dist/fs-atomic.js +28 -0
  162. package/dist/fs-atomic.js.map +1 -0
  163. package/dist/groups.d.ts +64 -0
  164. package/dist/groups.d.ts.map +1 -0
  165. package/dist/groups.js +172 -0
  166. package/dist/groups.js.map +1 -0
  167. package/dist/index.d.ts +11 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +703 -0
  170. package/dist/index.js.map +1 -0
  171. package/dist/lib/is-indexed.d.ts +20 -0
  172. package/dist/lib/is-indexed.d.ts.map +1 -0
  173. package/dist/lib/is-indexed.js +35 -0
  174. package/dist/lib/is-indexed.js.map +1 -0
  175. package/dist/registry.d.ts +64 -0
  176. package/dist/registry.d.ts.map +1 -0
  177. package/dist/registry.js +145 -0
  178. package/dist/registry.js.map +1 -0
  179. package/dist/scip-downloader.d.ts +138 -0
  180. package/dist/scip-downloader.d.ts.map +1 -0
  181. package/dist/scip-downloader.js +372 -0
  182. package/dist/scip-downloader.js.map +1 -0
  183. package/dist/scip-pins.d.ts +99 -0
  184. package/dist/scip-pins.d.ts.map +1 -0
  185. package/dist/scip-pins.js +195 -0
  186. package/dist/scip-pins.js.map +1 -0
  187. package/dist/skills-gen.d.ts +47 -0
  188. package/dist/skills-gen.d.ts.map +1 -0
  189. package/dist/skills-gen.js +292 -0
  190. package/dist/skills-gen.js.map +1 -0
  191. package/package.json +81 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Pure render helpers for `codehub verdict`.
3
+ *
4
+ * The CLI supports three output formats:
5
+ * - `summary` — chalk-free ANSI pretty-print for human eyes in a TTY.
6
+ * Honors `NO_COLOR` and falls back to plain text when
7
+ * stdout is not a TTY (piped or redirected).
8
+ * - `markdown` — the PR-comment markdown string already synthesized by
9
+ * the analysis module. Safe to pipe directly into
10
+ * `gh pr comment`.
11
+ * - `json` — pretty-printed JSON document of the entire response.
12
+ *
13
+ * Renderers are pure: they take a {@link VerdictResponse} and return a
14
+ * string. Side-effect output (stdout, exit code) is the caller's concern.
15
+ *
16
+ * The CLI also defines its own exit-code ladder (0/1/2/3) for the
17
+ * `--exit-code` flag. That ladder is stricter than
18
+ * `VerdictResponse.exitCode` (which maxes out at 2 per the analysis
19
+ * module's original PRD contract) so CI pipes get distinct signals for
20
+ * `single_review` vs `dual_review` vs `block`.
21
+ */
22
+ /** CLI exit-code ladder distinct from `VerdictResponse.exitCode`. */
23
+ const CLI_TIER_EXIT_CODES = {
24
+ auto_merge: 0,
25
+ single_review: 1,
26
+ dual_review: 1,
27
+ expert_review: 2,
28
+ block: 3,
29
+ };
30
+ export function cliExitCodeForTier(tier) {
31
+ return CLI_TIER_EXIT_CODES[tier];
32
+ }
33
+ export function renderJson(verdict) {
34
+ return JSON.stringify(verdict, null, 2);
35
+ }
36
+ export function renderMarkdown(verdict) {
37
+ if (verdict.reviewCommentMarkdown.length > 0) {
38
+ return verdict.reviewCommentMarkdown;
39
+ }
40
+ // Defensive fallback — should not normally trigger because
41
+ // computeVerdict always populates reviewCommentMarkdown.
42
+ return [
43
+ `## OpenCodeHub Verdict: \`${verdict.verdict}\``,
44
+ "",
45
+ `**Confidence:** ${(verdict.confidence * 100).toFixed(0)}% | **Exit code:** ${verdict.exitCode}`,
46
+ `**Blast radius:** ${verdict.blastRadius} across ${verdict.communitiesTouched.length} communities`,
47
+ ].join("\n");
48
+ }
49
+ /** ANSI SGR codes. */
50
+ const RESET = "\x1b[0m";
51
+ const BOLD = "\x1b[1m";
52
+ const DIM = "\x1b[2m";
53
+ const RED = "\x1b[31m";
54
+ const GREEN = "\x1b[32m";
55
+ const YELLOW = "\x1b[33m";
56
+ const CYAN = "\x1b[36m";
57
+ const TIER_COLORS = {
58
+ auto_merge: GREEN,
59
+ single_review: CYAN,
60
+ dual_review: YELLOW,
61
+ expert_review: RED,
62
+ block: RED,
63
+ };
64
+ function paintFactory(env) {
65
+ if (env.noColor || !env.isTty) {
66
+ return (_color, text) => text;
67
+ }
68
+ return (color, text) => `${color}${text}${RESET}`;
69
+ }
70
+ export function renderSummary(verdict, opts = {}) {
71
+ const env = {
72
+ isTty: opts.isTty ?? process.stdout.isTTY === true,
73
+ noColor: opts.noColor ??
74
+ (typeof process.env["NO_COLOR"] === "string" && process.env["NO_COLOR"].length > 0),
75
+ };
76
+ const paint = paintFactory(env);
77
+ const tierColor = TIER_COLORS[verdict.verdict];
78
+ const out = [];
79
+ const confidencePct = (verdict.confidence * 100).toFixed(0);
80
+ out.push(`${paint(BOLD, "Verdict:")} ${paint(tierColor + BOLD, verdict.verdict)} ` +
81
+ `${paint(DIM, `(confidence ${confidencePct}%)`)}`);
82
+ out.push(`${paint(BOLD, "Blast radius:")} ${verdict.blastRadius} symbols across ` +
83
+ `${verdict.communitiesTouched.length} communities`);
84
+ out.push(`${paint(BOLD, "Files changed:")} ${verdict.changedFileCount} | ` +
85
+ `${paint(BOLD, "Symbols affected:")} ${verdict.affectedSymbolCount}`);
86
+ const boundary = verdict.decisionBoundary;
87
+ if (boundary.nextTier !== null) {
88
+ out.push(`${paint(BOLD, "Boundary:")} ${boundary.distancePercent}% away from ` +
89
+ `${paint(TIER_COLORS[boundary.nextTier], boundary.nextTier)}`);
90
+ }
91
+ else {
92
+ out.push(`${paint(BOLD, "Boundary:")} terminal tier (no escalation above)`);
93
+ }
94
+ out.push("");
95
+ out.push(paint(BOLD, "Reasoning:"));
96
+ if (verdict.reasoningChain.length === 0) {
97
+ out.push(" (no signals)");
98
+ }
99
+ else {
100
+ for (const sig of verdict.reasoningChain) {
101
+ const sevPaint = sig.severity === "error" ? RED : sig.severity === "warn" ? YELLOW : DIM;
102
+ const marker = sig.severity === "error" ? "[!!]" : sig.severity === "warn" ? "(!)" : "(i)";
103
+ out.push(` ${paint(sevPaint, marker)} ${sig.label}: ${String(sig.value)}`);
104
+ }
105
+ }
106
+ out.push("");
107
+ out.push(paint(BOLD, "Suggested reviewers:"));
108
+ if (verdict.recommendedReviewers.length === 0) {
109
+ out.push(" (none)");
110
+ }
111
+ else {
112
+ for (const rev of verdict.recommendedReviewers) {
113
+ const label = rev.name.length > 0 ? `${rev.name} <${rev.email}>` : rev.email;
114
+ out.push(` - ${label} ${paint(DIM, `(${rev.weight.toFixed(2)})`)}`);
115
+ }
116
+ }
117
+ if (verdict.githubLabels.length > 0) {
118
+ out.push("");
119
+ out.push(`${paint(BOLD, "Labels:")} ${verdict.githubLabels.join(", ")}`);
120
+ }
121
+ return out.join("\n");
122
+ }
123
+ //# sourceMappingURL=verdict-render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict-render.js","sourceRoot":"","sources":["../../src/commands/verdict-render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * `codehub verdict` — 5-tier PR verdict CLI.
3
+ */
4
+ import { type VerdictConfig, type VerdictQuery, type VerdictResponse, type VerdictTier } from "@opencodehub/analysis";
5
+ import { type Policy, PolicyValidationError } from "@opencodehub/policy";
6
+ import type { IGraphStore, Store } from "@opencodehub/storage";
7
+ export type VerdictOutputFormat = "markdown" | "json" | "summary";
8
+ /**
9
+ * Policy tier mapping: VerdictTier -> numeric blast-radius tier used by
10
+ * policy.blast_radius_max rules. `max_tier: 2` therefore means "block
11
+ * any diff whose verdict is dual_review or higher".
12
+ *
13
+ * Kept inline + exported so tests and downstream callers can assert on it.
14
+ */
15
+ export declare const POLICY_TIER_FOR_VERDICT: Record<VerdictTier, number>;
16
+ export interface VerdictCliOptions {
17
+ readonly base?: string;
18
+ readonly head?: string;
19
+ readonly repo?: string;
20
+ readonly home?: string;
21
+ readonly outputFormat?: VerdictOutputFormat;
22
+ readonly prComment?: boolean;
23
+ readonly exitCode?: boolean;
24
+ readonly json?: boolean;
25
+ readonly configOverrides?: Partial<VerdictConfig>;
26
+ /**
27
+ * Test seam — inject a custom store factory. Production callers leave
28
+ * this unset; the runtime calls {@link openStoreForCommand}. Either an
29
+ * `IGraphStore`-shaped fake (legacy tests) or the composed `Store`
30
+ * envelope is acceptable; the runVerdict body normalises both into an
31
+ * `IGraphStore` for the analysis call.
32
+ */
33
+ readonly storeFactory?: () => Promise<{
34
+ store: IGraphStore | Store;
35
+ repoPath: string;
36
+ }>;
37
+ readonly computeVerdictFn?: (store: IGraphStore, query: VerdictQuery) => Promise<VerdictResponse>;
38
+ /**
39
+ * Test hook: override the policy loader. Defaults to loadPolicy against
40
+ * `<repoPath>/opencodehub.policy.yaml`.
41
+ */
42
+ readonly loadPolicyFn?: (filePath: string) => Promise<Policy | undefined>;
43
+ /**
44
+ * Test hook: override the approvals list (e.g. coming from the PR's
45
+ * review state). v1 does not fetch approvals from anywhere — CI callers
46
+ * that want ownership_required rules to pass must inject them.
47
+ */
48
+ readonly approvals?: readonly string[];
49
+ }
50
+ export interface ResolvedVerdictMode {
51
+ readonly format: VerdictOutputFormat;
52
+ readonly exitCode: boolean;
53
+ }
54
+ /**
55
+ * Resolve raw CLI flags to effective mode. `--pr-comment` implies markdown +
56
+ * exit-code. `--json` is a backward-compat alias for `--output-format json`.
57
+ */
58
+ export declare function resolveVerdictMode(opts: VerdictCliOptions): ResolvedVerdictMode;
59
+ export declare function runVerdict(opts?: VerdictCliOptions): Promise<void>;
60
+ export { PolicyValidationError };
61
+ //# sourceMappingURL=verdict.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict.d.ts","sourceRoot":"","sources":["../../src/commands/verdict.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,WAAW,EACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,KAAK,MAAM,EAGX,qBAAqB,EACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAI/D,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAElE;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAM9D,CAAC;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAClD;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,GAAG,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAClG;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC1E;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,CAY/E;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqD5E;AA2DD,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * `codehub verdict` — 5-tier PR verdict CLI.
3
+ */
4
+ import { join } from "node:path";
5
+ import { computeVerdict, } from "@opencodehub/analysis";
6
+ import { evaluatePolicy, loadPolicy, PolicyValidationError, } from "@opencodehub/policy";
7
+ import { openStoreForCommand } from "./open-store.js";
8
+ import { cliExitCodeForTier, renderJson, renderMarkdown, renderSummary } from "./verdict-render.js";
9
+ /**
10
+ * Policy tier mapping: VerdictTier -> numeric blast-radius tier used by
11
+ * policy.blast_radius_max rules. `max_tier: 2` therefore means "block
12
+ * any diff whose verdict is dual_review or higher".
13
+ *
14
+ * Kept inline + exported so tests and downstream callers can assert on it.
15
+ */
16
+ export const POLICY_TIER_FOR_VERDICT = Object.freeze({
17
+ auto_merge: 1,
18
+ single_review: 2,
19
+ dual_review: 3,
20
+ expert_review: 4,
21
+ block: 5,
22
+ });
23
+ /**
24
+ * Resolve raw CLI flags to effective mode. `--pr-comment` implies markdown +
25
+ * exit-code. `--json` is a backward-compat alias for `--output-format json`.
26
+ */
27
+ export function resolveVerdictMode(opts) {
28
+ if (opts.prComment === true) {
29
+ return { format: "markdown", exitCode: true };
30
+ }
31
+ const explicit = opts.outputFormat;
32
+ const format = explicit ?? (opts.json === true ? "json" : "summary");
33
+ // Default exit-code policy: on for summary (interactive + CI ergonomic),
34
+ // off for json and explicit markdown (backward compat for scripts that
35
+ // parse the output and manage their own exit).
36
+ const defaultExit = format === "summary";
37
+ const exitCode = opts.exitCode === true ? true : opts.exitCode === false ? false : defaultExit;
38
+ return { format, exitCode };
39
+ }
40
+ export async function runVerdict(opts = {}) {
41
+ const mode = resolveVerdictMode(opts);
42
+ const factory = opts.storeFactory ?? (() => openStoreForCommand(opts));
43
+ const { store, repoPath } = await factory();
44
+ const compute = opts.computeVerdictFn ?? computeVerdict;
45
+ try {
46
+ const query = {
47
+ repoPath,
48
+ ...(opts.base !== undefined ? { base: opts.base } : {}),
49
+ ...(opts.head !== undefined ? { head: opts.head } : {}),
50
+ ...(opts.configOverrides !== undefined ? { config: opts.configOverrides } : {}),
51
+ };
52
+ // Normalise — production passes the composed `Store` envelope; legacy
53
+ // test fakes pass an `IGraphStore`. The analysis layer only needs the
54
+ // graph view either way.
55
+ const graph = "graph" in store ? store.graph : store;
56
+ const verdict = await compute(graph, query);
57
+ // Fold opencodehub.policy.yaml into the decision. `loadPolicy` returns
58
+ // undefined for the starter (all-comment) state so the default repo
59
+ // gets unchanged behavior. A malformed policy file throws — we let the
60
+ // error propagate so the CLI exits non-zero rather than silently pass.
61
+ const load = opts.loadPolicyFn ?? loadPolicy;
62
+ const policyPath = join(repoPath, "opencodehub.policy.yaml");
63
+ const policy = await load(policyPath);
64
+ const policyDecision = policy !== undefined
65
+ ? evaluatePolicy(policy, buildPolicyContext(verdict, opts.approvals ?? []))
66
+ : undefined;
67
+ const baseOutput = mode.format === "json"
68
+ ? renderJson(verdict)
69
+ : mode.format === "markdown"
70
+ ? renderMarkdown(verdict)
71
+ : renderSummary(verdict);
72
+ const output = mode.format === "json"
73
+ ? renderJsonWithPolicy(baseOutput, policyDecision)
74
+ : policyDecision !== undefined
75
+ ? `${baseOutput}\n${renderPolicyBlock(policyDecision, mode.format)}`
76
+ : baseOutput;
77
+ process.stdout.write(`${output}\n`);
78
+ if (mode.exitCode) {
79
+ const tierExit = cliExitCodeForTier(verdict.verdict);
80
+ // Policy block is strictly at least as severe as the verdict's own
81
+ // exit code: max(tierExit, 3 when policyDecision.status === "block").
82
+ const policyExit = policyDecision?.status === "block" ? 3 : 0;
83
+ process.exitCode = Math.max(tierExit, policyExit);
84
+ }
85
+ }
86
+ finally {
87
+ await store.close();
88
+ }
89
+ }
90
+ function buildPolicyContext(verdict, approvals) {
91
+ return {
92
+ // v1 wiring: verdict does not yet compute a license audit, so we
93
+ // surface an empty set. license_allowlist rules therefore pass until a
94
+ // follow-up task wires SBOM license data in.
95
+ licenseViolations: [],
96
+ blastRadiusTier: POLICY_TIER_FOR_VERDICT[verdict.verdict],
97
+ // v1 wiring: ownership_required rules inspect touched paths. We don't
98
+ // have the raw changed-file list on VerdictResponse yet — the closest
99
+ // structured data is communitiesTouched. Leave touchedPaths empty for
100
+ // now; this means ownership_required is a no-op until the verdict
101
+ // pipeline surfaces changed paths explicitly.
102
+ touchedPaths: [],
103
+ ownersByPath: new Map(),
104
+ approvals,
105
+ };
106
+ }
107
+ /**
108
+ * Merge the policy decision into the JSON output. Parsing the rendered JSON
109
+ * is marginally slower than re-stringifying `verdict`, but it keeps a single
110
+ * source of truth for the baseline shape (`renderJson`) and survives future
111
+ * additions to VerdictResponse without touching this file.
112
+ */
113
+ function renderJsonWithPolicy(baseJson, policy) {
114
+ if (policy === undefined)
115
+ return baseJson;
116
+ const parsed = JSON.parse(baseJson);
117
+ parsed["policy"] = policy;
118
+ return JSON.stringify(parsed, null, 2);
119
+ }
120
+ function renderPolicyBlock(decision, format) {
121
+ if (format === "markdown")
122
+ return renderPolicyMarkdown(decision);
123
+ return renderPolicySummary(decision);
124
+ }
125
+ function renderPolicyMarkdown(decision) {
126
+ if (decision.status === "pass") {
127
+ return "### Policy\n\nPolicy: `pass`";
128
+ }
129
+ const lines = ["### Policy", "", `Policy: \`${decision.status}\``, "", "Violations:"];
130
+ for (const v of decision.violations) {
131
+ lines.push(`- \`${v.ruleId}\`: ${v.reason}`);
132
+ }
133
+ return lines.join("\n");
134
+ }
135
+ function renderPolicySummary(decision) {
136
+ const header = `Policy: ${decision.status}`;
137
+ if (decision.status === "pass")
138
+ return header;
139
+ const lines = [header];
140
+ for (const v of decision.violations) {
141
+ lines.push(` [!!] ${v.ruleId}: ${v.reason}`);
142
+ }
143
+ return lines.join("\n");
144
+ }
145
+ export { PolicyValidationError };
146
+ //# sourceMappingURL=verdict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict.js","sourceRoot":"","sources":["../../src/commands/verdict.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `codehub wiki` — emit a graph-only Markdown wiki (default) or, with `--llm`,
3
+ * route the top-ranked modules through `@opencodehub/summarizer`'s Bedrock
4
+ * Converse client to generate narrative prose.
5
+ *
6
+ * Gating rules (mirrored in `@opencodehub/analysis`):
7
+ * - `--llm` absent: exact existing behavior (deterministic, no network).
8
+ * - `--llm` + `--offline`: hard error. The summarizer requires network.
9
+ * - `--llm --max-llm-calls 0`: dry-run — enumerate candidate modules but
10
+ * never contact Bedrock.
11
+ * - `--llm --max-llm-calls <n>`: call the summarizer for the top N modules
12
+ * by symbolCount. Per-module failures fall back to a deterministic
13
+ * substitute for that module without aborting the run.
14
+ */
15
+ export interface WikiCommandOptions {
16
+ readonly output: string;
17
+ readonly repo?: string;
18
+ readonly home?: string;
19
+ readonly json?: boolean;
20
+ readonly offline?: boolean;
21
+ readonly llm?: boolean;
22
+ readonly maxLlmCalls?: number;
23
+ readonly llmModel?: string;
24
+ }
25
+ export declare function runWiki(opts: WikiCommandOptions): Promise<void>;
26
+ //# sourceMappingURL=wiki.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki.d.ts","sourceRoot":"","sources":["../../src/commands/wiki.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmErE"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * `codehub wiki` — emit a graph-only Markdown wiki (default) or, with `--llm`,
3
+ * route the top-ranked modules through `@opencodehub/summarizer`'s Bedrock
4
+ * Converse client to generate narrative prose.
5
+ *
6
+ * Gating rules (mirrored in `@opencodehub/analysis`):
7
+ * - `--llm` absent: exact existing behavior (deterministic, no network).
8
+ * - `--llm` + `--offline`: hard error. The summarizer requires network.
9
+ * - `--llm --max-llm-calls 0`: dry-run — enumerate candidate modules but
10
+ * never contact Bedrock.
11
+ * - `--llm --max-llm-calls <n>`: call the summarizer for the top N modules
12
+ * by symbolCount. Per-module failures fall back to a deterministic
13
+ * substitute for that module without aborting the run.
14
+ */
15
+ import { computeRiskTrends, loadSnapshots } from "@opencodehub/analysis";
16
+ import { generateWiki } from "@opencodehub/wiki";
17
+ import { openStoreForCommand } from "./open-store.js";
18
+ export async function runWiki(opts) {
19
+ const llmRequested = opts.llm === true;
20
+ if (llmRequested && opts.offline === true) {
21
+ throw new Error("codehub wiki: --llm requires network access; remove --offline or drop --llm");
22
+ }
23
+ const { store, repoPath } = await openStoreForCommand({
24
+ ...(opts.repo !== undefined ? { repo: opts.repo } : {}),
25
+ ...(opts.home !== undefined ? { home: opts.home } : {}),
26
+ });
27
+ try {
28
+ const maxLlmCalls = Math.max(0, typeof opts.maxLlmCalls === "number" && Number.isFinite(opts.maxLlmCalls)
29
+ ? Math.floor(opts.maxLlmCalls)
30
+ : 0);
31
+ const llm = llmRequested
32
+ ? {
33
+ enabled: true,
34
+ maxCalls: maxLlmCalls,
35
+ ...(opts.llmModel !== undefined ? { modelId: opts.llmModel } : {}),
36
+ }
37
+ : undefined;
38
+ const result = await generateWiki(store.graph, {
39
+ outputDir: opts.output,
40
+ repoPath,
41
+ loadTrends: async (p) => computeRiskTrends(await loadSnapshots(p)),
42
+ ...(llm !== undefined ? { llm } : {}),
43
+ });
44
+ if (opts.json === true) {
45
+ console.log(JSON.stringify({
46
+ outputDir: opts.output,
47
+ fileCount: result.filesWritten.length,
48
+ totalBytes: result.totalBytes,
49
+ files: result.filesWritten,
50
+ llm: llm === undefined
51
+ ? { enabled: false }
52
+ : {
53
+ enabled: true,
54
+ maxCalls: llm.maxCalls,
55
+ ...(llm.modelId !== undefined ? { modelId: llm.modelId } : {}),
56
+ dryRun: llm.maxCalls === 0,
57
+ },
58
+ }, null, 2));
59
+ return;
60
+ }
61
+ console.warn(`wiki: wrote ${result.filesWritten.length} files (${result.totalBytes} bytes) to ${opts.output}`);
62
+ if (llm !== undefined) {
63
+ const mode = llm.maxCalls === 0 ? "dry-run (0 calls)" : `cap ${llm.maxCalls}`;
64
+ console.warn(`wiki: llm mode active — ${mode}`);
65
+ }
66
+ for (const f of result.filesWritten) {
67
+ console.log(f);
68
+ }
69
+ }
70
+ finally {
71
+ await store.close();
72
+ }
73
+ }
74
+ //# sourceMappingURL=wiki.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki.js","sourceRoot":"","sources":["../../src/commands/wiki.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Claude Code MCP config writer.
3
+ *
4
+ * Targets `<project>/.mcp.json` by default, which is the `project` scope that
5
+ * gets checked into VCS. Shape:
6
+ * { "mcpServers": { "<name>": { "command": ..., "args": [...], "env": {...} } } }
7
+ *
8
+ * The writer preserves every top-level key on the file AND every sibling entry
9
+ * under `mcpServers`. Only the `codehub` key is upserted.
10
+ */
11
+ import type { EditorWriter, McpInvocation } from "./types.js";
12
+ export interface ClaudeCodeWriterOptions {
13
+ /** Absolute project root. The writer targets `<root>/.mcp.json`. */
14
+ readonly projectRoot: string;
15
+ }
16
+ export declare function createClaudeCodeWriter(opts: ClaudeCodeWriterOptions): EditorWriter;
17
+ /**
18
+ * Shared JSON merge for the "mcpServers" shape — used by Claude Code, Cursor,
19
+ * and Windsurf. Exposed so each editor's writer stays a one-liner.
20
+ */
21
+ export declare function mergeMcpServers(existing: string | undefined, invocation: McpInvocation): string;
22
+ export declare function buildMcpServersEntry(invocation: McpInvocation): Record<string, unknown>;
23
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/editors/claude-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,uBAAuB,GAAG,YAAY,CASlF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,aAAa,GAAG,MAAM,CAM/F;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASvF"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Claude Code MCP config writer.
3
+ *
4
+ * Targets `<project>/.mcp.json` by default, which is the `project` scope that
5
+ * gets checked into VCS. Shape:
6
+ * { "mcpServers": { "<name>": { "command": ..., "args": [...], "env": {...} } } }
7
+ *
8
+ * The writer preserves every top-level key on the file AND every sibling entry
9
+ * under `mcpServers`. Only the `codehub` key is upserted.
10
+ */
11
+ import { resolve } from "node:path";
12
+ export function createClaudeCodeWriter(opts) {
13
+ const configPath = resolve(opts.projectRoot, ".mcp.json");
14
+ return {
15
+ id: "claude-code",
16
+ configPath,
17
+ merge(existing, invocation) {
18
+ return mergeMcpServers(existing, invocation);
19
+ },
20
+ };
21
+ }
22
+ /**
23
+ * Shared JSON merge for the "mcpServers" shape — used by Claude Code, Cursor,
24
+ * and Windsurf. Exposed so each editor's writer stays a one-liner.
25
+ */
26
+ export function mergeMcpServers(existing, invocation) {
27
+ const doc = parseJsonObject(existing);
28
+ const servers = isObject(doc["mcpServers"]) ? { ...doc["mcpServers"] } : {};
29
+ servers["codehub"] = buildMcpServersEntry(invocation);
30
+ doc["mcpServers"] = servers;
31
+ return `${JSON.stringify(doc, null, 2)}\n`;
32
+ }
33
+ export function buildMcpServersEntry(invocation) {
34
+ const entry = {
35
+ command: invocation.command,
36
+ args: [...invocation.args],
37
+ };
38
+ if (Object.keys(invocation.env).length > 0) {
39
+ entry["env"] = { ...invocation.env };
40
+ }
41
+ return entry;
42
+ }
43
+ function parseJsonObject(input) {
44
+ if (input === undefined || input.trim().length === 0)
45
+ return {};
46
+ const parsed = JSON.parse(stripBom(input));
47
+ if (!isObject(parsed)) {
48
+ throw new Error("Expected config file to contain a top-level JSON object");
49
+ }
50
+ return { ...parsed };
51
+ }
52
+ function stripBom(s) {
53
+ return s.charCodeAt(0) === 0xfeff ? s.slice(1) : s;
54
+ }
55
+ function isObject(v) {
56
+ return typeof v === "object" && v !== null && !Array.isArray(v);
57
+ }
58
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/editors/claude-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,MAAM,UAAU,sBAAsB,CAAC,IAA6B;IAClE,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC1D,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,UAAU;QACV,KAAK,CAAC,QAAQ,EAAE,UAAU;YACxB,OAAO,eAAe,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAA4B,EAAE,UAAyB;IACrF,MAAM,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,OAAO,CAAC,SAAS,CAAC,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;IACtD,GAAG,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC;IAC5B,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,UAAyB;IAC5D,MAAM,KAAK,GAA4B;QACrC,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,IAAI,EAAE,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC;KAC3B,CAAC;IACF,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;IACvC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,KAAyB;IAChD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAChE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAY,CAAC;IACtD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;AACvB,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * OpenAI Codex CLI MCP config writer.
3
+ *
4
+ * Targets `~/.codex/config.toml` — the only TOML config of the five. Shape:
5
+ *
6
+ * [mcp_servers.codehub]
7
+ * command = "codehub"
8
+ * args = ["mcp"]
9
+ * env = { ... }
10
+ *
11
+ * We round-trip the file via `@iarna/toml`. The library preserves string
12
+ * values and key ordering for tables we don't touch; we only rewrite the
13
+ * `[mcp_servers.codehub]` table. Other `[mcp_servers.*]` tables and unrelated
14
+ * top-level tables are preserved verbatim.
15
+ */
16
+ import type { EditorWriter, McpInvocation } from "./types.js";
17
+ export interface CodexWriterOptions {
18
+ readonly home?: string;
19
+ }
20
+ export declare function createCodexWriter(opts?: CodexWriterOptions): EditorWriter;
21
+ export declare function mergeCodexConfig(existing: string | undefined, invocation: McpInvocation): string;
22
+ //# sourceMappingURL=codex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/editors/codex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,kBAAuB,GAAG,YAAY,CAU7E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,aAAa,GAAG,MAAM,CAMhG"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * OpenAI Codex CLI MCP config writer.
3
+ *
4
+ * Targets `~/.codex/config.toml` — the only TOML config of the five. Shape:
5
+ *
6
+ * [mcp_servers.codehub]
7
+ * command = "codehub"
8
+ * args = ["mcp"]
9
+ * env = { ... }
10
+ *
11
+ * We round-trip the file via `@iarna/toml`. The library preserves string
12
+ * values and key ordering for tables we don't touch; we only rewrite the
13
+ * `[mcp_servers.codehub]` table. Other `[mcp_servers.*]` tables and unrelated
14
+ * top-level tables are preserved verbatim.
15
+ */
16
+ import { homedir } from "node:os";
17
+ import { resolve } from "node:path";
18
+ import * as TOML from "@iarna/toml";
19
+ export function createCodexWriter(opts = {}) {
20
+ const home = opts.home ?? homedir();
21
+ const configPath = resolve(home, ".codex", "config.toml");
22
+ return {
23
+ id: "codex",
24
+ configPath,
25
+ merge(existing, invocation) {
26
+ return mergeCodexConfig(existing, invocation);
27
+ },
28
+ };
29
+ }
30
+ export function mergeCodexConfig(existing, invocation) {
31
+ const doc = parseTomlObject(existing);
32
+ const servers = isObject(doc["mcp_servers"]) ? { ...doc["mcp_servers"] } : {};
33
+ servers["codehub"] = buildCodexEntry(invocation);
34
+ doc["mcp_servers"] = servers;
35
+ return TOML.stringify(doc);
36
+ }
37
+ function buildCodexEntry(invocation) {
38
+ const entry = {
39
+ command: invocation.command,
40
+ args: [...invocation.args],
41
+ };
42
+ if (Object.keys(invocation.env).length > 0) {
43
+ entry["env"] = { ...invocation.env };
44
+ }
45
+ return entry;
46
+ }
47
+ function parseTomlObject(input) {
48
+ if (input === undefined || input.trim().length === 0)
49
+ return {};
50
+ const parsed = TOML.parse(input);
51
+ if (!isObject(parsed)) {
52
+ throw new Error("Expected Codex config to parse as a TOML table");
53
+ }
54
+ return { ...parsed };
55
+ }
56
+ function isObject(v) {
57
+ return typeof v === "object" && v !== null && !Array.isArray(v);
58
+ }
59
+ //# sourceMappingURL=codex.js.map