argsbarg 5.1.16 → 6.0.1

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 (73) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/README.md +33 -25
  3. package/docs/README.md +2 -1
  4. package/docs/api-server.md +141 -0
  5. package/docs/bundled-docs.md +24 -10
  6. package/docs/cli-program.md +17 -2
  7. package/docs/config-schema.md +18 -8
  8. package/docs/developing.md +1 -1
  9. package/docs/mcp.md +5 -5
  10. package/docs/output-schema.md +78 -47
  11. package/examples/full-example/README.md +15 -6
  12. package/examples/full-example/docs/README.md +27 -0
  13. package/examples/full-example/docs/api.md +511 -0
  14. package/examples/full-example/docs/cli-schema.json +453 -0
  15. package/examples/full-example/docs/http.md +81 -0
  16. package/examples/full-example/docs/mcp.md +159 -0
  17. package/examples/full-example/docs/openapi.json +222 -0
  18. package/examples/full-example/docs/skill.md +46 -0
  19. package/examples/full-example/justfile +6 -2
  20. package/examples/full-example/schemas/generated/app-config.json +1 -1
  21. package/examples/full-example/schemas/generated/status.json +1 -1
  22. package/examples/full-example/scripts/dev-formula.ts +1 -1
  23. package/examples/full-example/scripts/schemagen/discover-schema-roots.test.ts +3 -3
  24. package/examples/full-example/scripts/schemagen/discover-schema-roots.ts +90 -35
  25. package/examples/full-example/scripts/schemagen/naming.ts +17 -0
  26. package/examples/full-example/scripts/schemagen.ts +14 -3
  27. package/examples/full-example/src/commands/echo/command.ts +6 -1
  28. package/examples/full-example/src/commands/status/schema-types.ts +14 -0
  29. package/examples/full-example/src/commands/status/types.ts +1 -11
  30. package/examples/full-example/src/{types.ts → config/schema-types.ts} +3 -2
  31. package/examples/full-example/src/program.ts +3 -0
  32. package/examples/mcp-test.ts +13 -2
  33. package/examples/nested.ts +12 -3
  34. package/examples/servers.ts +72 -0
  35. package/index.d.ts +66 -7
  36. package/package.json +17 -17
  37. package/src/api/openapi.ts +117 -0
  38. package/src/api/result.ts +111 -0
  39. package/src/api/schema-deref.test.ts +99 -0
  40. package/src/api/schema-deref.ts +76 -0
  41. package/src/api/server.ts +120 -0
  42. package/src/api.integration.test.ts +441 -0
  43. package/src/builtins/api.ts +38 -0
  44. package/src/builtins/dispatch.ts +26 -0
  45. package/src/builtins/registry.ts +4 -0
  46. package/src/capabilities.ts +12 -1
  47. package/src/cli-errors.ts +3 -0
  48. package/src/cli-tool/full-example-capabilities.test.ts +3 -0
  49. package/src/cli.ts +60 -8
  50. package/src/config.integration.test.ts +22 -4
  51. package/src/context.ts +29 -1
  52. package/src/docs/api-guide.ts +2 -2
  53. package/src/docs/builtin.ts +11 -1
  54. package/src/docs/docs.test.ts +70 -12
  55. package/src/docs/http-guide.ts +132 -0
  56. package/src/docs/mcp-guide.ts +3 -3
  57. package/src/docs/mcp-resources.ts +5 -2
  58. package/src/docs/resolve.ts +26 -2
  59. package/src/docs/save.ts +5 -2
  60. package/src/headless/tool-call.ts +157 -0
  61. package/src/headless.test.ts +4 -2
  62. package/src/headless.ts +10 -5
  63. package/src/index.ts +5 -0
  64. package/src/mcp/result.ts +39 -34
  65. package/src/mcp/server.ts +18 -36
  66. package/src/mcp/tools.ts +14 -3
  67. package/src/mcp.integration.test.ts +46 -39
  68. package/src/parse.test.ts +16 -6
  69. package/src/respond.ts +48 -0
  70. package/src/schema.ts +1 -1
  71. package/src/skill/generate.ts +1 -1
  72. package/src/types.ts +46 -4
  73. package/src/validate.ts +7 -0
@@ -0,0 +1,222 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "full-example",
5
+ "version": "1.0.0",
6
+ "description": "Argsbarg full example reference app"
7
+ },
8
+ "paths": {
9
+ "/tools/echo": {
10
+ "post": {
11
+ "operationId": "echo",
12
+ "summary": "echo — Echo a message (MCP-friendly leaf).",
13
+ "requestBody": {
14
+ "required": false,
15
+ "content": {
16
+ "application/json; charset=utf-8": {
17
+ "schema": {
18
+ "type": "object",
19
+ "properties": {
20
+ "message": {
21
+ "type": "string",
22
+ "description": "Text to print."
23
+ }
24
+ },
25
+ "additionalProperties": false,
26
+ "required": [
27
+ "message"
28
+ ]
29
+ }
30
+ }
31
+ }
32
+ },
33
+ "responses": {
34
+ "200": {
35
+ "description": "Successful tool invocation",
36
+ "content": {
37
+ "application/json": {
38
+ "schema": {
39
+ "type": "object"
40
+ }
41
+ }
42
+ }
43
+ },
44
+ "400": {
45
+ "description": "Invalid arguments or help requested",
46
+ "content": {
47
+ "application/json; charset=utf-8": {
48
+ "schema": {
49
+ "type": "object",
50
+ "properties": {
51
+ "error": {
52
+ "type": "string"
53
+ },
54
+ "exitCode": {
55
+ "type": "integer"
56
+ }
57
+ },
58
+ "required": [
59
+ "error"
60
+ ]
61
+ }
62
+ }
63
+ }
64
+ },
65
+ "404": {
66
+ "description": "Unknown tool",
67
+ "content": {
68
+ "application/json; charset=utf-8": {
69
+ "schema": {
70
+ "type": "object",
71
+ "properties": {
72
+ "error": {
73
+ "type": "string"
74
+ }
75
+ },
76
+ "required": [
77
+ "error"
78
+ ]
79
+ }
80
+ }
81
+ }
82
+ },
83
+ "500": {
84
+ "description": "Handler error",
85
+ "content": {
86
+ "application/json; charset=utf-8": {
87
+ "schema": {
88
+ "type": "object",
89
+ "properties": {
90
+ "error": {
91
+ "type": "string"
92
+ }
93
+ },
94
+ "required": [
95
+ "error"
96
+ ]
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ },
104
+ "/tools/status": {
105
+ "post": {
106
+ "operationId": "status",
107
+ "summary": "status — Show resolved config and app version.",
108
+ "requestBody": {
109
+ "required": false,
110
+ "content": {
111
+ "application/json; charset=utf-8": {
112
+ "schema": {
113
+ "type": "object",
114
+ "properties": {
115
+ "json": {
116
+ "type": "boolean",
117
+ "description": "Emit JSON."
118
+ }
119
+ },
120
+ "additionalProperties": false
121
+ }
122
+ }
123
+ }
124
+ },
125
+ "responses": {
126
+ "200": {
127
+ "description": "Successful tool invocation",
128
+ "content": {
129
+ "application/json": {
130
+ "schema": {
131
+ "$schema": "http://json-schema.org/draft-07/schema#",
132
+ "type": "object",
133
+ "properties": {
134
+ "defaultRegion": {
135
+ "type": "string",
136
+ "description": "Resolved AWS region."
137
+ },
138
+ "maxRetries": {
139
+ "type": "number",
140
+ "description": "Resolved retry count."
141
+ },
142
+ "apiTokenSet": {
143
+ "type": "boolean",
144
+ "description": "Whether apiToken is set (value never included)."
145
+ },
146
+ "version": {
147
+ "type": "string",
148
+ "description": "App version from program root."
149
+ }
150
+ },
151
+ "required": [
152
+ "apiTokenSet",
153
+ "version"
154
+ ],
155
+ "description": "JSON payload for `full-example status --json`.",
156
+ "definitions": {}
157
+ }
158
+ }
159
+ }
160
+ },
161
+ "400": {
162
+ "description": "Invalid arguments or help requested",
163
+ "content": {
164
+ "application/json; charset=utf-8": {
165
+ "schema": {
166
+ "type": "object",
167
+ "properties": {
168
+ "error": {
169
+ "type": "string"
170
+ },
171
+ "exitCode": {
172
+ "type": "integer"
173
+ }
174
+ },
175
+ "required": [
176
+ "error"
177
+ ]
178
+ }
179
+ }
180
+ }
181
+ },
182
+ "404": {
183
+ "description": "Unknown tool",
184
+ "content": {
185
+ "application/json; charset=utf-8": {
186
+ "schema": {
187
+ "type": "object",
188
+ "properties": {
189
+ "error": {
190
+ "type": "string"
191
+ }
192
+ },
193
+ "required": [
194
+ "error"
195
+ ]
196
+ }
197
+ }
198
+ }
199
+ },
200
+ "500": {
201
+ "description": "Handler error",
202
+ "content": {
203
+ "application/json; charset=utf-8": {
204
+ "schema": {
205
+ "type": "object",
206
+ "properties": {
207
+ "error": {
208
+ "type": "string"
209
+ }
210
+ },
211
+ "required": [
212
+ "error"
213
+ ]
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: full_example
3
+ description: Operates the full-example CLI (echo, status). Use when the user mentions full-example, echo, status, or related tasks.
4
+ ---
5
+ <!-- Generated by full-example docs skill --save; do not edit. -->
6
+
7
+
8
+ # full-example
9
+
10
+ Argsbarg full example reference app
11
+
12
+ ## Execution
13
+
14
+ Invoke via shell:
15
+
16
+ ```bash
17
+ full-example <subcommand> [options] [args]
18
+ ```
19
+
20
+ ## Commands
21
+
22
+ - **`full-example echo`** — Echo a message (MCP-friendly leaf).
23
+ - **`full-example status`** — Show resolved config and app version. (flags: --json)
24
+
25
+ ## Configuration
26
+
27
+ - **apiToken** (`apiToken` (env: `FULL_EXAMPLE_API_TOKEN`)) — Create at https://example.com/settings/tokens
28
+ - **defaultRegion** (`defaultRegion`) — AWS region for API calls.
29
+ - **maxRetries** (`maxRetries`) — HTTP retry count (0–10).
30
+ - **prefs** (`prefs`) — Local cache preferences (not exported to env).
31
+
32
+ ## Pitfalls
33
+
34
+ - Pass `--` before arguments that look like flags.
35
+
36
+ ## Reference
37
+
38
+ For full detail, open `reference.md` in this skill directory (same as `full-example docs api`).
39
+
40
+ ## Cursor install location
41
+
42
+ - Project: `.cursor/skills/full_example/`
43
+ - Global: `~/.cursor/skills/full_example/`
44
+
45
+ Do not install under `~/.cursor/skills-cursor/` (reserved for Cursor built-ins).
46
+
@@ -27,10 +27,14 @@ check: schemagen format typecheck
27
27
  dev *ARGS:
28
28
  bun --watch ./src/index.ts {{ARGS}}
29
29
 
30
- # Regenerate docs/schema.json and docs/skill.md
30
+ # Regenerate consumer docs under ./docs/
31
31
  docgen: schemagen
32
- @just run docs schema --save
32
+ @just run docs cli-schema --save
33
+ @just run docs api --save
33
34
  @just run docs skill --save
35
+ @just run docs mcp --save
36
+ @just run docs http --save
37
+ @just run docs openapi --save
34
38
 
35
39
  alias fmt := format
36
40
 
@@ -35,6 +35,6 @@
35
35
  "maxRetries"
36
36
  ],
37
37
  "additionalProperties": false,
38
- "description": "Config schema\n\nApplication settings for `full-example` (`program.appConfig`).",
38
+ "description": "Application settings for `full-example` (`program.appConfig`).",
39
39
  "definitions": {}
40
40
  }
@@ -23,6 +23,6 @@
23
23
  "apiTokenSet",
24
24
  "version"
25
25
  ],
26
- "description": "JSON payload for `full-example status --json`.",
26
+ "description": "JSON stdout for `full-example status --json`.",
27
27
  "definitions": {}
28
28
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  /**
3
3
  * Stage or restore the dev Homebrew formula for `just install-local`.
4
- * `install` — back up release `Formula/{key}.rb` and write a `file://` dev formula.
4
+ * `install` — back up release `Formula/full-example.rb` and write a `file://` dev formula.
5
5
  * `reset` — restore the release formula from backup.
6
6
  */
7
7
 
@@ -5,19 +5,19 @@ import { discoverSchemaRoots } from "./discover-schema-roots.ts";
5
5
  const projectRoot = join(import.meta.dir, "../..");
6
6
 
7
7
  describe("discover-schema-roots", () => {
8
- test("finds AppConfig and StatusJsonOutput in src types.ts files", () => {
8
+ test("finds AppConfig and StatusJsonOutput in schema-types.ts files", () => {
9
9
  const roots = discoverSchemaRoots(projectRoot);
10
10
  const config = roots.find((r) => r.kind === "config");
11
11
  const output = roots.find((r) => r.kind === "output");
12
12
  expect(config).toMatchObject({
13
13
  typeName: "AppConfig",
14
- relFile: "src/types.ts",
14
+ path: "src/config/schema-types.ts",
15
15
  outfile: "app-config.json",
16
16
  exportName: "APP_CONFIG_JSON_SCHEMA",
17
17
  });
18
18
  expect(output).toMatchObject({
19
19
  typeName: "StatusJsonOutput",
20
- relFile: "src/commands/status/types.ts",
20
+ path: "src/commands/status/schema-types.ts",
21
21
  outfile: "status.json",
22
22
  exportName: "STATUS_JSON_OUTPUT_SCHEMA",
23
23
  });
@@ -1,5 +1,5 @@
1
1
  /*
2
- Discovers schema roots in src (recursive) types.ts files by JSDoc markers.
2
+ Discovers schema roots in schema-types.ts files via configType / inputType / outputType exports.
3
3
  Copy per consumer repo — see docs/output-schema.md and docs/config-schema.md.
4
4
  */
5
5
 
@@ -7,87 +7,142 @@ import { readdirSync, readFileSync, statSync } from "node:fs";
7
7
  import { join, relative } from "node:path";
8
8
  import {
9
9
  configSchemaExportName,
10
+ inputSchemaExportName,
10
11
  outfileForConfigType,
12
+ outfileForInputType,
11
13
  outfileForOutputType,
12
14
  outputSchemaExportName,
13
15
  } from "./naming.ts";
14
16
 
15
- export type SchemaRootKind = "config" | "output";
17
+ export type SchemaRootKind = "config" | "input" | "output";
18
+
19
+ export type SchemaRole = "configType" | "inputType" | "outputType";
16
20
 
17
21
  export interface SchemaRoot {
18
22
  kind: SchemaRootKind;
19
23
  typeName: string;
20
- /** Path relative to project root (e.g. src/types.ts). */
21
- relFile: string;
24
+ /** Path relative to project root (e.g. src/config/schema-types.ts). */
25
+ path: string;
22
26
  outfile: string;
23
27
  exportName: string;
24
28
  }
25
29
 
26
- const CONFIG_MARKER = "Config schema";
27
- const OUTPUT_MARKER = "JSON payload";
30
+ const SCHEMA_TYPES_FILE = "schema-types.ts";
31
+
32
+ const ROLE_EXPORT_RE = /export\s+type\s+(configType|inputType|outputType)\s*=\s*(\w+)/g;
28
33
 
29
- const INTERFACE_RE = /\/\*\*([\s\S]*?)\*\/\s*export\s+interface\s+(\w+)/g;
34
+ const ROLE_TO_KIND: Record<SchemaRole, SchemaRootKind> = {
35
+ configType: "config",
36
+ inputType: "input",
37
+ outputType: "output",
38
+ };
30
39
 
31
- function listTypesTsFiles(srcDir: string, baseDir: string, out: string[]): void {
40
+ function listSchemaTypesFiles(srcDir: string, baseDir: string, out: string[]): void {
32
41
  for (const ent of readdirSync(srcDir)) {
33
42
  const full = join(srcDir, ent);
34
43
  const st = statSync(full);
35
44
  if (st.isDirectory()) {
36
- listTypesTsFiles(full, baseDir, out);
45
+ listSchemaTypesFiles(full, baseDir, out);
37
46
  continue;
38
47
  }
39
- if (ent === "types.ts") {
48
+ if (ent === SCHEMA_TYPES_FILE) {
40
49
  out.push(relative(baseDir, full));
41
50
  }
42
51
  }
43
52
  }
44
53
 
45
- function classifyRoot(jsDoc: string, typeName: string, relFile: string): SchemaRoot | undefined {
46
- const hasConfig = jsDoc.includes(CONFIG_MARKER);
47
- const hasOutput = jsDoc.includes(OUTPUT_MARKER);
48
- if (hasConfig && hasOutput) {
49
- throw new Error(`${relFile}: ${typeName} has both Config schema and JSON payload markers`);
54
+ /** True when `typeName` is declared in this file (not a re-export alias to another module). */
55
+ function isTypeDefinedInFile(text: string, typeName: string): boolean {
56
+ if (new RegExp(`export\\s+interface\\s+${typeName}\\b`).test(text)) {
57
+ return true;
50
58
  }
51
- if (!hasConfig && !hasOutput) {
52
- return undefined;
59
+ if (new RegExp(`export\\s+type\\s+${typeName}\\s*=`).test(text)) {
60
+ return !["configType", "inputType", "outputType"].includes(typeName);
53
61
  }
54
- if (hasConfig) {
62
+ return false;
63
+ }
64
+
65
+ function rootForRole(role: SchemaRole, typeName: string, path: string): SchemaRoot {
66
+ const kind = ROLE_TO_KIND[role];
67
+ if (kind === "config") {
55
68
  return {
56
- kind: "config",
69
+ kind,
57
70
  typeName,
58
- relFile,
71
+ path,
59
72
  outfile: outfileForConfigType(typeName),
60
73
  exportName: configSchemaExportName(typeName),
61
74
  };
62
75
  }
76
+ if (kind === "input") {
77
+ return {
78
+ kind,
79
+ typeName,
80
+ path,
81
+ outfile: outfileForInputType(typeName),
82
+ exportName: inputSchemaExportName(typeName),
83
+ };
84
+ }
63
85
  return {
64
- kind: "output",
86
+ kind,
65
87
  typeName,
66
- relFile,
88
+ path,
67
89
  outfile: outfileForOutputType(typeName),
68
90
  exportName: outputSchemaExportName(typeName),
69
91
  };
70
92
  }
71
93
 
72
- /** Find all schema roots under `src/` in files named types.ts. */
94
+ function discoverFromFile(path: string, text: string): SchemaRoot[] {
95
+ const rolesSeen = new Set<SchemaRole>();
96
+ const roots: SchemaRoot[] = [];
97
+
98
+ for (const match of text.matchAll(ROLE_EXPORT_RE)) {
99
+ const role = match[1] as SchemaRole | undefined;
100
+ const typeName = match[2];
101
+ if (!role || !typeName) {
102
+ continue;
103
+ }
104
+ if (rolesSeen.has(role)) {
105
+ throw new Error(`${path}: duplicate export type ${role}`);
106
+ }
107
+ rolesSeen.add(role);
108
+ if (!isTypeDefinedInFile(text, typeName)) {
109
+ continue;
110
+ }
111
+ roots.push(rootForRole(role, typeName, path));
112
+ }
113
+
114
+ return roots;
115
+ }
116
+
117
+ /** Find all schema roots under `src/` in files named schema-types.ts. */
73
118
  export function discoverSchemaRoots(projectRoot: string): SchemaRoot[] {
74
119
  const srcDir = join(projectRoot, "src");
75
120
  const files: string[] = [];
76
- listTypesTsFiles(srcDir, projectRoot, files);
121
+ listSchemaTypesFiles(srcDir, projectRoot, files);
122
+
77
123
  const roots: SchemaRoot[] = [];
78
- for (const relFile of files.sort()) {
79
- const text = readFileSync(join(projectRoot, relFile), "utf8");
80
- for (const match of text.matchAll(INTERFACE_RE)) {
81
- const jsDoc = match[1] ?? "";
82
- const typeName = match[2];
83
- if (!typeName) {
84
- continue;
85
- }
86
- const root = classifyRoot(jsDoc, typeName, relFile);
87
- if (root) {
88
- roots.push(root);
124
+ const typeOwners = new Map<string, string>();
125
+
126
+ for (const relPath of files.sort()) {
127
+ const text = readFileSync(join(projectRoot, relPath), "utf8");
128
+ for (const root of discoverFromFile(relPath, text)) {
129
+ const prev = typeOwners.get(root.typeName);
130
+ if (prev) {
131
+ throw new Error(
132
+ `${relPath}: duplicate schema root type ${root.typeName} (already declared in ${prev})`,
133
+ );
89
134
  }
135
+ typeOwners.set(root.typeName, relPath);
136
+ roots.push(root);
90
137
  }
91
138
  }
139
+
140
+ const configRoots = roots.filter((r) => r.kind === "config");
141
+ if (configRoots.length > 1) {
142
+ throw new Error(
143
+ `multiple config schema roots: ${configRoots.map((r) => `${r.typeName} (${r.path})`).join(", ")}`,
144
+ );
145
+ }
146
+
92
147
  return roots;
93
148
  }
@@ -16,6 +16,23 @@ export function camelToScreamingSnake(name: string): string {
16
16
  return camelToKebab(name).replace(/-/g, "_").toUpperCase();
17
17
  }
18
18
 
19
+ /** Generated JSON filename for a tool-input schema root. */
20
+ export function outfileForInputType(typeName: string): string {
21
+ if (typeName.endsWith("ToolInput")) {
22
+ return `${camelToKebab(typeName.slice(0, -"ToolInput".length))}-tool-input.json`;
23
+ }
24
+ return `${camelToKebab(typeName)}-tool-input.json`;
25
+ }
26
+
27
+ /** Bridge export constant for a tool-input schema root. */
28
+ export function inputSchemaExportName(typeName: string): string {
29
+ if (typeName.endsWith("ToolInput")) {
30
+ const base = typeName.slice(0, -"ToolInput".length);
31
+ return `${camelToScreamingSnake(base)}_TOOL_INPUT_SCHEMA`;
32
+ }
33
+ return `${camelToScreamingSnake(typeName)}_TOOL_INPUT_SCHEMA`;
34
+ }
35
+
19
36
  /** Generated JSON filename for an output-schema root type. */
20
37
  export function outfileForOutputType(typeName: string): string {
21
38
  if (typeName.endsWith("JsonOutput")) {
@@ -1,5 +1,5 @@
1
1
  /*
2
- Generate JSON Schema artifacts and bridge modules from discovered types.ts roots.
2
+ Generate JSON Schema artifacts and bridge modules from discovered schema-types.ts roots.
3
3
  */
4
4
 
5
5
  import { mkdirSync, writeFileSync } from "node:fs";
@@ -13,7 +13,7 @@ const generatedDir = join(projectRoot, "schemas", "generated");
13
13
 
14
14
  function generateJson(root: SchemaRoot): Record<string, unknown> {
15
15
  const generator = createGenerator({
16
- path: join(projectRoot, root.relFile),
16
+ path: join(projectRoot, root.path),
17
17
  type: root.typeName,
18
18
  tsconfig: join(projectRoot, "tsconfig.json"),
19
19
  topRef: false,
@@ -52,6 +52,7 @@ function writeBridge(path: string, scriptName: string, roots: SchemaRoot[], bann
52
52
 
53
53
  const roots = discoverSchemaRoots(projectRoot);
54
54
  const configRoots = roots.filter((r) => r.kind === "config");
55
+ const inputRoots = roots.filter((r) => r.kind === "input");
55
56
  const outputRoots = roots.filter((r) => r.kind === "output");
56
57
 
57
58
  mkdirSync(generatedDir, { recursive: true });
@@ -70,6 +71,14 @@ writeBridge(
70
71
  configRoots,
71
72
  "JSON Schema for program.appConfig.jsonSchema from",
72
73
  );
74
+ if (inputRoots.length > 0) {
75
+ writeBridge(
76
+ join(projectRoot, "schemas", "inputSchemas.ts"),
77
+ "schemagen.ts",
78
+ inputRoots,
79
+ "JSON Schema for leaf inputSchema from",
80
+ );
81
+ }
73
82
  writeBridge(
74
83
  join(projectRoot, "schemas", "outputSchemas.ts"),
75
84
  "schemagen.ts",
@@ -77,4 +86,6 @@ writeBridge(
77
86
  "JSON Schema for leaf outputSchema from",
78
87
  );
79
88
 
80
- console.log(`config roots: ${configRoots.length}, output roots: ${outputRoots.length}`);
89
+ console.log(
90
+ `config roots: ${configRoots.length}, input roots: ${inputRoots.length}, output roots: ${outputRoots.length}`,
91
+ );
@@ -16,6 +16,11 @@ export const echoCommand = {
16
16
  },
17
17
  ],
18
18
  handler: (ctx) => {
19
- console.log(ctx.stringOpt("message") ?? "");
19
+ const message = ctx.stringOpt("message") ?? "";
20
+ if (ctx.invocation === "cli") {
21
+ console.log(message);
22
+ return;
23
+ }
24
+ return message;
20
25
  },
21
26
  } satisfies CliLeaf;
@@ -0,0 +1,14 @@
1
+ /** JSON stdout for `full-example status --json`. */
2
+ export interface StatusJsonOutput {
3
+ /** Resolved AWS region. */
4
+ defaultRegion?: string;
5
+ /** Resolved retry count. */
6
+ maxRetries?: number;
7
+ /** Whether apiToken is set (value never included). */
8
+ apiTokenSet: boolean;
9
+ /** App version from program root. */
10
+ version: string;
11
+ }
12
+
13
+ /** Schemagen root for leaf outputSchema. */
14
+ export type outputType = StatusJsonOutput;
@@ -1,11 +1 @@
1
- /** JSON payload for `full-example status --json`. */
2
- export interface StatusJsonOutput {
3
- /** Resolved AWS region. */
4
- defaultRegion?: string;
5
- /** Resolved retry count. */
6
- maxRetries?: number;
7
- /** Whether apiToken is set (value never included). */
8
- apiTokenSet: boolean;
9
- /** App version from program root. */
10
- version: string;
11
- }
1
+ export type { StatusJsonOutput } from "./schema-types.ts";
@@ -1,6 +1,4 @@
1
1
  /**
2
- * Config schema
3
- *
4
2
  * Application settings for `full-example` (`program.appConfig`).
5
3
  */
6
4
  export interface AppConfig {
@@ -21,3 +19,6 @@ export interface AppConfig {
21
19
  ttl: number;
22
20
  };
23
21
  }
22
+
23
+ /** Schemagen root for program.appConfig.jsonSchema. */
24
+ export type configType = AppConfig;
@@ -50,5 +50,8 @@ export const program = {
50
50
  mcpd: true,
51
51
  claudePlugin: true,
52
52
  },
53
+ apiServer: {
54
+ enabled: true,
55
+ },
53
56
  commands: [echoCommand, statusCommand],
54
57
  } satisfies CliProgram;