@shipeasy/openapi 1.5.0 → 1.6.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 (57) hide show
  1. package/dist/index.d.ts +24 -0
  2. package/dist/index.js +1913 -1
  3. package/dist/node-context.d.ts +37 -0
  4. package/dist/node-context.js +56 -0
  5. package/dist/operations/attributes.d.ts +33 -0
  6. package/dist/operations/attributes.js +16 -0
  7. package/dist/operations/cli-adapter.d.ts +35 -0
  8. package/dist/operations/cli-adapter.js +91 -0
  9. package/dist/operations/coerce.d.ts +32 -0
  10. package/dist/operations/coerce.js +53 -0
  11. package/dist/operations/configs.d.ts +28 -0
  12. package/dist/operations/configs.js +119 -0
  13. package/dist/operations/docs.d.ts +37 -0
  14. package/dist/operations/docs.js +39 -0
  15. package/dist/operations/events.d.ts +28 -0
  16. package/dist/operations/events.js +121 -0
  17. package/dist/operations/experiments.d.ts +28 -0
  18. package/dist/operations/experiments.js +280 -0
  19. package/dist/operations/gates.d.ts +28 -0
  20. package/dist/operations/gates.js +132 -0
  21. package/dist/operations/i18n.d.ts +28 -0
  22. package/dist/operations/i18n.js +121 -0
  23. package/dist/operations/index.d.ts +63 -0
  24. package/dist/operations/index.js +1751 -0
  25. package/dist/operations/killswitches.d.ts +28 -0
  26. package/dist/operations/killswitches.js +126 -0
  27. package/dist/operations/mcp-adapter.d.ts +35 -0
  28. package/dist/operations/mcp-adapter.js +94 -0
  29. package/dist/operations/metrics.d.ts +30 -0
  30. package/dist/operations/metrics.js +114 -0
  31. package/dist/operations/ops.d.ts +28 -0
  32. package/dist/operations/ops.js +313 -0
  33. package/dist/operations/projects.d.ts +28 -0
  34. package/dist/operations/projects.js +36 -0
  35. package/dist/operations/sdk-docs.d.ts +28 -0
  36. package/dist/operations/sdk-docs.js +160 -0
  37. package/dist/operations/types.d.ts +138 -0
  38. package/dist/operations/types.js +9 -0
  39. package/dist/operations/universes.d.ts +28 -0
  40. package/dist/operations/universes.js +93 -0
  41. package/dist/operations/util.d.ts +33 -0
  42. package/dist/operations/util.js +9 -0
  43. package/dist/resources/attributes.d.ts +19 -0
  44. package/dist/resources/attributes.js +10 -0
  45. package/dist/resources/events.d.ts +61 -0
  46. package/dist/resources/events.js +42 -0
  47. package/dist/resources/i18n.d.ts +84 -0
  48. package/dist/resources/i18n.js +60 -0
  49. package/dist/resources/index.d.ts +22 -4
  50. package/dist/resources/index.js +173 -1
  51. package/dist/resources/metrics.d.ts +54 -0
  52. package/dist/resources/metrics.js +40 -0
  53. package/dist/resources/ops.d.ts +88 -0
  54. package/dist/resources/ops.js +36 -0
  55. package/dist/resources/projects.d.ts +54 -0
  56. package/dist/resources/projects.js +14 -0
  57. package/package.json +10 -1
@@ -0,0 +1,37 @@
1
+ interface ConsumerContext {
2
+ /** SDK token used as `X-SDK-Key`. */
3
+ token: string;
4
+ /** Resolved project id used as `X-Project-Id`. */
5
+ projectId: string;
6
+ /** Directory that held the `.shipeasy` binding, if any. */
7
+ boundDir: string | null;
8
+ /** Path to the XDG config file that supplied the session, if read. */
9
+ configPath: string;
10
+ /** Owner email from the session config, if present. */
11
+ userEmail: string | null;
12
+ /** True when a `.shipeasy` binding (or `--project`/env override) supplied the project id. */
13
+ bound: boolean;
14
+ }
15
+ /** XDG config path for the CLI/MCP session (`~/.config/shipeasy/config.json`). */
16
+ declare function configPath(): string;
17
+ /** Walk up from `dir` (like `.git`) to find the nearest `.shipeasy` file. */
18
+ declare function findBoundDir(dir: string): string | null;
19
+ /** The bound project id from the nearest `.shipeasy`, or undefined. */
20
+ declare function getBoundProjectId(dir?: string): string | undefined;
21
+ interface ResolveOptions {
22
+ /** Explicit `--project` override (highest precedence). */
23
+ projectOverride?: string;
24
+ /** Directory to resolve the binding from (defaults to cwd). */
25
+ cwd?: string;
26
+ }
27
+ /**
28
+ * Resolve the consumer context once: env overrides → `.shipeasy` binding →
29
+ * session config. Returns null if there is no usable session token.
30
+ *
31
+ * Precedence for the project id: `projectOverride` → `SHIPEASY_PROJECT_ID` →
32
+ * `.shipeasy` → session default. The token comes from `SHIPEASY_CLI_TOKEN` or
33
+ * the session config.
34
+ */
35
+ declare function resolveConsumerContext(opts?: ResolveOptions): ConsumerContext | null;
36
+
37
+ export { type ConsumerContext, type ResolveOptions, configPath, findBoundDir, getBoundProjectId, resolveConsumerContext };
@@ -0,0 +1,56 @@
1
+ // src/node-context.ts
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { homedir } from "os";
4
+ import { dirname, join, resolve } from "path";
5
+ function configPath() {
6
+ const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
7
+ return join(base, "shipeasy", "config.json");
8
+ }
9
+ function readJson(path) {
10
+ if (!existsSync(path)) return null;
11
+ try {
12
+ return JSON.parse(readFileSync(path, "utf8"));
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ function findBoundDir(dir) {
18
+ let cur = resolve(dir);
19
+ for (; ; ) {
20
+ if (existsSync(join(cur, ".shipeasy"))) return cur;
21
+ const parent = dirname(cur);
22
+ if (parent === cur) return null;
23
+ cur = parent;
24
+ }
25
+ }
26
+ function getBoundProjectId(dir = process.cwd()) {
27
+ const boundDir = findBoundDir(dir);
28
+ if (!boundDir) return void 0;
29
+ return readJson(join(boundDir, ".shipeasy"))?.project_id;
30
+ }
31
+ function resolveConsumerContext(opts = {}) {
32
+ const cwd = opts.cwd ?? process.cwd();
33
+ const cfgPath = configPath();
34
+ const cfg = readJson(cfgPath) ?? {};
35
+ const token = process.env.SHIPEASY_CLI_TOKEN || cfg.cli_token;
36
+ if (!token) return null;
37
+ const boundDir = findBoundDir(cwd);
38
+ const boundId = boundDir ? readJson(join(boundDir, ".shipeasy"))?.project_id : void 0;
39
+ const envProject = process.env.SHIPEASY_PROJECT_ID;
40
+ const projectId = opts.projectOverride || envProject || boundId || cfg.project_id;
41
+ if (!projectId) return null;
42
+ return {
43
+ token,
44
+ projectId,
45
+ boundDir: boundId ? boundDir : null,
46
+ configPath: cfgPath,
47
+ userEmail: cfg.user_email ?? null,
48
+ bound: Boolean(opts.projectOverride || envProject || boundId)
49
+ };
50
+ }
51
+ export {
52
+ configPath,
53
+ findBoundDir,
54
+ getBoundProjectId,
55
+ resolveConsumerContext
56
+ };
@@ -0,0 +1,33 @@
1
+ import { Operation } from './types.js';
2
+ import '../resources/index.js';
3
+ import 'zod/v4/core';
4
+ import 'zod';
5
+ import '../resources/attributes.js';
6
+ import '../transport.js';
7
+ import '../resources/i18n.js';
8
+ import '../resources/projects.js';
9
+ import '../resources/ops.js';
10
+ import '../resources/events.js';
11
+ import '../resources/metrics.js';
12
+ import '../resources/alert-rules.js';
13
+ import '../schemas/alert-rules.js';
14
+ import '../resources/killswitches.js';
15
+ import '../schemas/killswitches.js';
16
+ import '../schemas/pagination.js';
17
+ import '../resources/universes.js';
18
+ import '../schemas/universes.js';
19
+ import '../resources/configs.js';
20
+ import '../schemas/configs.js';
21
+ import '../resources/experiments.js';
22
+ import '../schemas/experiments.js';
23
+ import '../resources/gates.js';
24
+ import '../schemas/gates.js';
25
+
26
+ /**
27
+ * Attribute operations — `attributes …`. One read-only op so the typed
28
+ * `attributes_list` MCP tool replaces the `attributes` kind of the deleted
29
+ * generic-read path (doc 21 §A4.3).
30
+ */
31
+ declare const attributeOperations: Operation[];
32
+
33
+ export { attributeOperations };
@@ -0,0 +1,16 @@
1
+ // src/operations/attributes.ts
2
+ var attributeOperations = [
3
+ {
4
+ group: ["attributes"],
5
+ name: "list",
6
+ mutates: false,
7
+ summary: "List targeting attributes",
8
+ description: "List the auto-inferred user-attribute schema available for gate/experiment targeting.",
9
+ params: [],
10
+ examples: [{ run: "shipeasy attributes list" }],
11
+ run: (client) => client.attributes.list()
12
+ }
13
+ ];
14
+ export {
15
+ attributeOperations
16
+ };
@@ -0,0 +1,35 @@
1
+ import { CommandLike, Operation, CliContext } from './types.js';
2
+ import '../resources/index.js';
3
+ import 'zod/v4/core';
4
+ import 'zod';
5
+ import '../resources/attributes.js';
6
+ import '../transport.js';
7
+ import '../resources/i18n.js';
8
+ import '../resources/projects.js';
9
+ import '../resources/ops.js';
10
+ import '../resources/events.js';
11
+ import '../resources/metrics.js';
12
+ import '../resources/alert-rules.js';
13
+ import '../schemas/alert-rules.js';
14
+ import '../resources/killswitches.js';
15
+ import '../schemas/killswitches.js';
16
+ import '../schemas/pagination.js';
17
+ import '../resources/universes.js';
18
+ import '../schemas/universes.js';
19
+ import '../resources/configs.js';
20
+ import '../schemas/configs.js';
21
+ import '../resources/experiments.js';
22
+ import '../schemas/experiments.js';
23
+ import '../resources/gates.js';
24
+ import '../schemas/gates.js';
25
+
26
+ /**
27
+ * Mount every operation as a commander subcommand under `group`. The CLI passes
28
+ * its own commander `Command` (which satisfies `CommandLike`) and a `CliContext`
29
+ * carrying the bits `@shipeasy/openapi` must not own (client resolution, table
30
+ * formatting, process.exit). Replaces the per-command hand-wiring in
31
+ * `packages/cli/src/commands/*`.
32
+ */
33
+ declare function mountOperations(group: CommandLike, ops: Operation[], ctx: CliContext): void;
34
+
35
+ export { mountOperations };
@@ -0,0 +1,91 @@
1
+ // src/transport.ts
2
+ var ApiError = class extends Error {
3
+ constructor(message, status) {
4
+ super(message);
5
+ this.status = status;
6
+ this.name = "ApiError";
7
+ }
8
+ status;
9
+ };
10
+
11
+ // src/operations/coerce.ts
12
+ function coerceValue(param, raw) {
13
+ if (raw === void 0 || raw === null) return void 0;
14
+ switch (param.type) {
15
+ case "number": {
16
+ const n = typeof raw === "number" ? raw : Number(raw);
17
+ if (!Number.isFinite(n)) throw new ApiError(`--${param.name} must be a number`, 400);
18
+ return n;
19
+ }
20
+ case "boolean":
21
+ return raw === true || raw === "true" || raw === "1";
22
+ case "json":
23
+ if (typeof raw !== "string") return raw;
24
+ try {
25
+ return JSON.parse(raw);
26
+ } catch {
27
+ throw new ApiError(`--${param.name} must be valid JSON`, 400);
28
+ }
29
+ case "string":
30
+ default: {
31
+ const s = String(raw);
32
+ if (param.enum && !param.enum.includes(s)) {
33
+ throw new ApiError(`--${param.name} must be one of: ${param.enum.join(", ")}`, 400);
34
+ }
35
+ return s;
36
+ }
37
+ }
38
+ }
39
+ function coerceInput(op, raw) {
40
+ const out = {};
41
+ for (const param of op.params) {
42
+ const value = coerceValue(param, raw[param.name]);
43
+ if (value === void 0) {
44
+ if (param.required) throw new ApiError(`${param.name} is required`, 400);
45
+ continue;
46
+ }
47
+ out[param.name] = value;
48
+ }
49
+ return out;
50
+ }
51
+
52
+ // src/operations/cli-adapter.ts
53
+ var toKebab = (s) => s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
54
+ function commandSignature(op) {
55
+ const positionals = op.params.filter((p) => p.positional).map((p) => p.required === false ? `[${p.name}]` : `<${p.name}>`);
56
+ return [op.name, ...positionals].join(" ");
57
+ }
58
+ function mountOperations(group, ops, ctx) {
59
+ for (const op of ops) {
60
+ const positionals = op.params.filter((p) => p.positional);
61
+ const flags = op.params.filter((p) => !p.positional);
62
+ const cmd = group.command(commandSignature(op)).description(op.summary);
63
+ for (const p of flags) {
64
+ cmd.option(`--${toKebab(p.name)} <value>`, p.description);
65
+ }
66
+ cmd.option("--json", "Output as JSON");
67
+ cmd.option("--project <id>", "Project ID override");
68
+ cmd.action(async (...argv) => {
69
+ try {
70
+ const opts = argv.find((a) => a && typeof a === "object" && !Array.isArray(a)) ?? {};
71
+ const raw = { ...opts };
72
+ positionals.forEach((p, i) => {
73
+ raw[p.name] = argv[i];
74
+ });
75
+ const input = coerceInput(op, raw);
76
+ const client = ctx.getClient({
77
+ mutates: op.mutates,
78
+ projectOverride: opts.project
79
+ });
80
+ const data = await op.run(client, input);
81
+ if (opts.json) ctx.printJson(data);
82
+ else ctx.printResult(op, data, input);
83
+ } catch (e) {
84
+ ctx.onError(e);
85
+ }
86
+ });
87
+ }
88
+ }
89
+ export {
90
+ mountOperations
91
+ };
@@ -0,0 +1,32 @@
1
+ import { Operation, OpInput } from './types.js';
2
+ import '../resources/index.js';
3
+ import 'zod/v4/core';
4
+ import 'zod';
5
+ import '../resources/attributes.js';
6
+ import '../transport.js';
7
+ import '../resources/i18n.js';
8
+ import '../resources/projects.js';
9
+ import '../resources/ops.js';
10
+ import '../resources/events.js';
11
+ import '../resources/metrics.js';
12
+ import '../resources/alert-rules.js';
13
+ import '../schemas/alert-rules.js';
14
+ import '../resources/killswitches.js';
15
+ import '../schemas/killswitches.js';
16
+ import '../schemas/pagination.js';
17
+ import '../resources/universes.js';
18
+ import '../schemas/universes.js';
19
+ import '../resources/configs.js';
20
+ import '../schemas/configs.js';
21
+ import '../resources/experiments.js';
22
+ import '../schemas/experiments.js';
23
+ import '../resources/gates.js';
24
+ import '../schemas/gates.js';
25
+
26
+ /**
27
+ * Build the coerced facade input `run` expects from a raw key→value bag
28
+ * (commander's merged args+opts, or MCP's `arguments`). Enforces `required`.
29
+ */
30
+ declare function coerceInput(op: Operation, raw: Record<string, unknown>): OpInput;
31
+
32
+ export { coerceInput };
@@ -0,0 +1,53 @@
1
+ // src/transport.ts
2
+ var ApiError = class extends Error {
3
+ constructor(message, status) {
4
+ super(message);
5
+ this.status = status;
6
+ this.name = "ApiError";
7
+ }
8
+ status;
9
+ };
10
+
11
+ // src/operations/coerce.ts
12
+ function coerceValue(param, raw) {
13
+ if (raw === void 0 || raw === null) return void 0;
14
+ switch (param.type) {
15
+ case "number": {
16
+ const n = typeof raw === "number" ? raw : Number(raw);
17
+ if (!Number.isFinite(n)) throw new ApiError(`--${param.name} must be a number`, 400);
18
+ return n;
19
+ }
20
+ case "boolean":
21
+ return raw === true || raw === "true" || raw === "1";
22
+ case "json":
23
+ if (typeof raw !== "string") return raw;
24
+ try {
25
+ return JSON.parse(raw);
26
+ } catch {
27
+ throw new ApiError(`--${param.name} must be valid JSON`, 400);
28
+ }
29
+ case "string":
30
+ default: {
31
+ const s = String(raw);
32
+ if (param.enum && !param.enum.includes(s)) {
33
+ throw new ApiError(`--${param.name} must be one of: ${param.enum.join(", ")}`, 400);
34
+ }
35
+ return s;
36
+ }
37
+ }
38
+ }
39
+ function coerceInput(op, raw) {
40
+ const out = {};
41
+ for (const param of op.params) {
42
+ const value = coerceValue(param, raw[param.name]);
43
+ if (value === void 0) {
44
+ if (param.required) throw new ApiError(`${param.name} is required`, 400);
45
+ continue;
46
+ }
47
+ out[param.name] = value;
48
+ }
49
+ return out;
50
+ }
51
+ export {
52
+ coerceInput
53
+ };
@@ -0,0 +1,28 @@
1
+ import { Operation } from './types.js';
2
+ import '../resources/index.js';
3
+ import 'zod/v4/core';
4
+ import 'zod';
5
+ import '../resources/attributes.js';
6
+ import '../transport.js';
7
+ import '../resources/i18n.js';
8
+ import '../resources/projects.js';
9
+ import '../resources/ops.js';
10
+ import '../resources/events.js';
11
+ import '../resources/metrics.js';
12
+ import '../resources/alert-rules.js';
13
+ import '../schemas/alert-rules.js';
14
+ import '../resources/killswitches.js';
15
+ import '../schemas/killswitches.js';
16
+ import '../schemas/pagination.js';
17
+ import '../resources/universes.js';
18
+ import '../schemas/universes.js';
19
+ import '../resources/configs.js';
20
+ import '../schemas/configs.js';
21
+ import '../resources/experiments.js';
22
+ import '../schemas/experiments.js';
23
+ import '../resources/gates.js';
24
+ import '../schemas/gates.js';
25
+
26
+ declare const configOperations: Operation[];
27
+
28
+ export { configOperations };
@@ -0,0 +1,119 @@
1
+ // src/operations/util.ts
2
+ var str = (i, k) => i[k] === void 0 ? void 0 : i[k];
3
+
4
+ // src/operations/configs.ts
5
+ var GROUP = ["release", "configs"];
6
+ var configOperations = [
7
+ {
8
+ group: GROUP,
9
+ name: "list",
10
+ mutates: false,
11
+ summary: "List all configs",
12
+ description: "Return every dynamic config (name, schema, last updated).",
13
+ params: [],
14
+ examples: [{ run: "shipeasy release configs list" }],
15
+ run: (client) => client.configs.listAll()
16
+ },
17
+ {
18
+ group: GROUP,
19
+ name: "get",
20
+ mutates: false,
21
+ summary: "Show a config by name",
22
+ description: "Resolve a config by name and return its full detail (schema + per-env values + drafts).",
23
+ params: [{ name: "name", type: "string", description: "Config name.", required: true, positional: true }],
24
+ examples: [{ run: "shipeasy release configs get pricing" }],
25
+ run: async (client, i) => {
26
+ const c = await client.configs.resolve(i.name);
27
+ return client.configs.get(c.id);
28
+ }
29
+ },
30
+ {
31
+ group: GROUP,
32
+ name: "create",
33
+ mutates: true,
34
+ summary: "Create a config",
35
+ description: "Create a dynamic config. Configs are JSON objects validated against a JSON Schema (object-only).",
36
+ params: [
37
+ { name: "name", type: "string", description: "Config name.", required: true, positional: true },
38
+ { name: "schema", type: "json", description: "JSON Schema (top-level type=object). Defaults to a permissive object schema." },
39
+ { name: "value", type: "json", description: "Initial value as a JSON object. Defaults to {}." },
40
+ { name: "description", type: "string", description: "Human-readable description." }
41
+ ],
42
+ examples: [
43
+ { note: "Permissive schema, empty value", run: "shipeasy release configs create pricing" },
44
+ { note: "Seed an initial value", run: `shipeasy release configs create pricing --value '{"free_trial_days":14}'` }
45
+ ],
46
+ run: (client, i) => client.configs.create({
47
+ name: i.name,
48
+ schema: i.schema ?? { type: "object", properties: {}, additionalProperties: true },
49
+ value: i.value ?? {},
50
+ ...i.description ? { description: i.description } : {}
51
+ })
52
+ },
53
+ {
54
+ group: GROUP,
55
+ name: "update",
56
+ mutates: true,
57
+ summary: "Update a config's value (flat, all envs)",
58
+ description: "Legacy flat value update across all envs. Use draft + publish for per-env staging.",
59
+ params: [
60
+ { name: "name", type: "string", description: "Config name.", required: true, positional: true },
61
+ { name: "value", type: "json", description: "New value (JSON object).", required: true }
62
+ ],
63
+ examples: [{ note: "Overwrite the value (all envs)", run: `shipeasy release configs update pricing --value '{"free_trial_days":30}'` }],
64
+ run: async (client, i) => {
65
+ const c = await client.configs.resolve(i.name);
66
+ return client.configs.update(c.id, { value: i.value });
67
+ }
68
+ },
69
+ {
70
+ group: GROUP,
71
+ name: "draft",
72
+ mutates: true,
73
+ summary: "Save a draft value for one env",
74
+ description: "Stage a draft value for the given env, to publish later.",
75
+ params: [
76
+ { name: "name", type: "string", description: "Config name.", required: true, positional: true },
77
+ { name: "env", type: "string", description: "Target env (e.g. prod, staging, dev).", required: true },
78
+ { name: "value", type: "json", description: "Draft value (JSON object).", required: true }
79
+ ],
80
+ examples: [{ note: "Stage a prod value", run: `shipeasy release configs draft pricing --env prod --value '{"free_trial_days":30}'` }],
81
+ run: async (client, i) => {
82
+ const c = await client.configs.resolve(i.name);
83
+ return client.configs.saveDraft(c.id, { env: i.env, value: i.value });
84
+ }
85
+ },
86
+ {
87
+ group: GROUP,
88
+ name: "publish",
89
+ mutates: true,
90
+ summary: "Publish the saved draft for one env",
91
+ description: "Promote the staged draft for the given env to live.",
92
+ params: [
93
+ { name: "name", type: "string", description: "Config name.", required: true, positional: true },
94
+ { name: "env", type: "string", description: "Target env to publish.", required: true }
95
+ ],
96
+ examples: [{ note: "Promote staged draft to prod", run: "shipeasy release configs publish pricing --env prod" }],
97
+ run: async (client, i) => {
98
+ const c = await client.configs.resolve(i.name);
99
+ return client.configs.publish(c.id, { env: str(i, "env") });
100
+ }
101
+ },
102
+ {
103
+ group: GROUP,
104
+ name: "archive",
105
+ mutates: true,
106
+ summary: "Archive a config",
107
+ description: "Archive (soft-delete) a config by name.",
108
+ params: [{ name: "name", type: "string", description: "Config name.", required: true, positional: true }],
109
+ examples: [{ run: "shipeasy release configs archive pricing" }],
110
+ run: async (client, i) => {
111
+ const c = await client.configs.resolve(i.name);
112
+ await client.configs.delete(c.id);
113
+ return { ok: true, archived: i.name };
114
+ }
115
+ }
116
+ ];
117
+ export {
118
+ configOperations
119
+ };
@@ -0,0 +1,37 @@
1
+ import { Operation } from './types.js';
2
+ import '../resources/index.js';
3
+ import 'zod/v4/core';
4
+ import 'zod';
5
+ import '../resources/attributes.js';
6
+ import '../transport.js';
7
+ import '../resources/i18n.js';
8
+ import '../resources/projects.js';
9
+ import '../resources/ops.js';
10
+ import '../resources/events.js';
11
+ import '../resources/metrics.js';
12
+ import '../resources/alert-rules.js';
13
+ import '../schemas/alert-rules.js';
14
+ import '../resources/killswitches.js';
15
+ import '../schemas/killswitches.js';
16
+ import '../schemas/pagination.js';
17
+ import '../resources/universes.js';
18
+ import '../schemas/universes.js';
19
+ import '../resources/configs.js';
20
+ import '../schemas/configs.js';
21
+ import '../resources/experiments.js';
22
+ import '../schemas/experiments.js';
23
+ import '../resources/gates.js';
24
+ import '../schemas/gates.js';
25
+
26
+ /**
27
+ * Render the registry to Markdown — the "documentation comes along for free"
28
+ * half of the proposal. Both `cli/scripts/gen-cli-docs.ts` and
29
+ * `mcp/scripts/gen-mcp-docs.ts` can call this instead of re-describing every
30
+ * command/tool by hand, so help text, tool descriptions, and the docs site all
31
+ * derive from the same `summary`/`description`/`params`/`examples`.
32
+ */
33
+ declare function renderOperationsMarkdown(ops: Operation[], opts?: {
34
+ title?: string;
35
+ }): string;
36
+
37
+ export { renderOperationsMarkdown };
@@ -0,0 +1,39 @@
1
+ // src/operations/types.ts
2
+ var opId = (op) => [...op.group, op.name].join(".");
3
+ var opMcpName = (op) => [...op.group, op.name].join("_");
4
+ var opCli = (op) => [...op.group, op.name].join(" ");
5
+
6
+ // src/operations/docs.ts
7
+ function renderOperationsMarkdown(ops, opts = {}) {
8
+ const lines = [];
9
+ if (opts.title) lines.push(`# ${opts.title}`, "");
10
+ for (const op of ops) {
11
+ lines.push(`## \`${opId(op)}\``, "");
12
+ lines.push(op.summary, "");
13
+ if (op.description && op.description !== op.summary) lines.push(op.description, "");
14
+ lines.push(
15
+ `- **CLI:** \`shipeasy ${opCli(op)}\` \xB7 **MCP tool:** \`${opMcpName(op)}\` \xB7 ${op.mutates ? "write (needs project binding)" : "read"}`,
16
+ ""
17
+ );
18
+ if (op.params.length) {
19
+ lines.push("| Param | Type | Required | Description |", "| --- | --- | --- | --- |");
20
+ for (const p of op.params) {
21
+ const kind = p.positional ? `${p.type} (positional)` : p.type;
22
+ lines.push(`| \`${p.name}\` | ${kind} | ${p.required ? "yes" : "no"} | ${p.description} |`);
23
+ }
24
+ lines.push("");
25
+ }
26
+ if (op.examples?.length) {
27
+ lines.push("**Examples**", "");
28
+ for (const ex of op.examples) {
29
+ if (ex.note) lines.push(`- ${ex.note}:`);
30
+ lines.push("```sh", ex.run, "```");
31
+ }
32
+ lines.push("");
33
+ }
34
+ }
35
+ return lines.join("\n");
36
+ }
37
+ export {
38
+ renderOperationsMarkdown
39
+ };
@@ -0,0 +1,28 @@
1
+ import { Operation } from './types.js';
2
+ import '../resources/index.js';
3
+ import 'zod/v4/core';
4
+ import 'zod';
5
+ import '../resources/attributes.js';
6
+ import '../transport.js';
7
+ import '../resources/i18n.js';
8
+ import '../resources/projects.js';
9
+ import '../resources/ops.js';
10
+ import '../resources/events.js';
11
+ import '../resources/metrics.js';
12
+ import '../resources/alert-rules.js';
13
+ import '../schemas/alert-rules.js';
14
+ import '../resources/killswitches.js';
15
+ import '../schemas/killswitches.js';
16
+ import '../schemas/pagination.js';
17
+ import '../resources/universes.js';
18
+ import '../schemas/universes.js';
19
+ import '../resources/configs.js';
20
+ import '../schemas/configs.js';
21
+ import '../resources/experiments.js';
22
+ import '../schemas/experiments.js';
23
+ import '../resources/gates.js';
24
+ import '../schemas/gates.js';
25
+
26
+ declare const eventOperations: Operation[];
27
+
28
+ export { eventOperations };