argsbarg 7.0.11 → 7.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 (89) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README.md +3 -2
  3. package/docs/ai-skills.md +2 -2
  4. package/docs/cli-program.md +3 -5
  5. package/docs/developing.md +3 -3
  6. package/docs/mcp.md +20 -7
  7. package/docs/output-schema.md +1 -1
  8. package/examples/full-example/AGENTS.md +20 -12
  9. package/examples/full-example/README.md +57 -12
  10. package/examples/full-example/biome.json +5 -4
  11. package/examples/full-example/bunfig.toml +3 -0
  12. package/examples/full-example/justfile +22 -27
  13. package/examples/full-example-json/AGENTS.md +14 -12
  14. package/examples/full-example-json/README.md +63 -15
  15. package/examples/full-example-json/biome.json +1 -3
  16. package/examples/full-example-json/bunfig.toml +3 -0
  17. package/examples/full-example-json/justfile +22 -27
  18. package/examples/mcp-plugin/.claude-plugin/plugin.json +11 -0
  19. package/examples/mcp-plugin/.cursor/hooks/run-tests-on-stop.ts +56 -0
  20. package/examples/mcp-plugin/.cursor/hooks.json +12 -0
  21. package/examples/mcp-plugin/.cursor-plugin/plugin.json +12 -0
  22. package/examples/mcp-plugin/.mcp.json +6 -0
  23. package/examples/mcp-plugin/AGENTS.md +90 -0
  24. package/examples/mcp-plugin/CLAUDE.md +1 -0
  25. package/examples/mcp-plugin/README.md +70 -0
  26. package/examples/mcp-plugin/biome.json +20 -0
  27. package/examples/mcp-plugin/bun.lock +48 -0
  28. package/examples/mcp-plugin/bunfig.toml +3 -0
  29. package/examples/mcp-plugin/docs/README.md +27 -0
  30. package/examples/mcp-plugin/docs/cli-schema.json +2085 -0
  31. package/examples/mcp-plugin/docs/cli.md +2026 -0
  32. package/examples/mcp-plugin/docs/http.md +92 -0
  33. package/examples/mcp-plugin/docs/mcp.md +116 -0
  34. package/examples/mcp-plugin/docs/openapi.json +1243 -0
  35. package/examples/mcp-plugin/justfile +89 -0
  36. package/examples/mcp-plugin/mcp.json +8 -0
  37. package/examples/mcp-plugin/package.json +23 -0
  38. package/examples/mcp-plugin/scripts/create-identity.ts +12 -0
  39. package/examples/mcp-plugin/scripts/mcp.mjs +11106 -0
  40. package/examples/mcp-plugin/scripts/release.ts +225 -0
  41. package/examples/mcp-plugin/skills/mcp-plugin/SKILL.md +59 -0
  42. package/examples/mcp-plugin/src/commands/echo/command.ts +26 -0
  43. package/examples/mcp-plugin/src/commands/render-json/__generated__/RenderJsonInputSchema.json +15 -0
  44. package/examples/mcp-plugin/src/commands/render-json/__generated__/index.ts +5 -0
  45. package/examples/mcp-plugin/src/commands/render-json/command.test.ts +46 -0
  46. package/examples/mcp-plugin/src/commands/render-json/command.ts +30 -0
  47. package/examples/mcp-plugin/src/commands/render-json/types.ts +9 -0
  48. package/examples/mcp-plugin/src/commands/status/__generated__/StatusJsonOutputSchema.json +15 -0
  49. package/examples/mcp-plugin/src/commands/status/__generated__/index.ts +5 -0
  50. package/examples/mcp-plugin/src/commands/status/command.test.ts +10 -0
  51. package/examples/mcp-plugin/src/commands/status/command.ts +28 -0
  52. package/examples/mcp-plugin/src/commands/status/types.ts +6 -0
  53. package/examples/mcp-plugin/src/commands/workspaces/__generated__/WorkspaceNameInputSchema.json +15 -0
  54. package/examples/mcp-plugin/src/commands/workspaces/__generated__/index.ts +5 -0
  55. package/examples/mcp-plugin/src/commands/workspaces/command.test.ts +58 -0
  56. package/examples/mcp-plugin/src/commands/workspaces/command.ts +94 -0
  57. package/examples/mcp-plugin/src/commands/workspaces/types.ts +6 -0
  58. package/examples/mcp-plugin/src/db/index.test.ts +86 -0
  59. package/examples/mcp-plugin/src/db/index.ts +77 -0
  60. package/examples/mcp-plugin/src/db/tables/workspaces.ts +58 -0
  61. package/examples/mcp-plugin/src/index.ts +10 -0
  62. package/examples/mcp-plugin/src/program.ts +32 -0
  63. package/examples/mcp-plugin/src/types/argsbarg.d.ts +11 -0
  64. package/examples/mcp-plugin/src/types/md.d.ts +4 -0
  65. package/examples/mcp-plugin/tsconfig.json +17 -0
  66. package/index.d.ts +12 -0
  67. package/package.json +1 -1
  68. package/src/builtins/mcp.ts +1 -1
  69. package/src/cli-tool/create.test.ts +5 -0
  70. package/src/cli-tool/create.ts +9 -1
  71. package/src/config/manifest.ts +56 -0
  72. package/src/config/resolve.test.ts +12 -12
  73. package/src/configure/configure.test.ts +5 -3
  74. package/src/core/parse.test.ts +6 -5
  75. package/src/core/types.ts +12 -0
  76. package/src/exports/mcp.ts +12 -0
  77. package/src/mcp/bundle.ts +12 -3
  78. package/src/mcp/claude.test.ts +2 -7
  79. package/src/mcp/claude.ts +49 -67
  80. package/src/mcp/cursor.test.ts +151 -0
  81. package/src/mcp/cursor.ts +155 -0
  82. package/src/mcp/hidden-mcpb.test.ts +34 -1
  83. package/src/mcp/plugin-shared.ts +107 -0
  84. package/src/mcp/result.ts +5 -1
  85. package/src/mcp/server.ts +3 -2
  86. package/src/test/fixtures.ts +13 -0
  87. package/src/test/integration/mcp.test.ts +8 -7
  88. package/examples/full-example/scripts/print-identity.ts +0 -28
  89. package/examples/full-example-json/scripts/print-identity.ts +0 -28
package/src/mcp/result.ts CHANGED
@@ -38,6 +38,7 @@ export interface McpBinaryRespondContent {
38
38
  export function buildToolCallSuccessFromResponse(response: CliRespondOptions): McpToolCallSuccess {
39
39
  const { body, contentType = "application/json; charset=utf-8" } = response;
40
40
  let structuredContent: unknown;
41
+ let text = "";
41
42
 
42
43
  if (body instanceof Uint8Array) {
43
44
  structuredContent = {
@@ -45,17 +46,20 @@ export function buildToolCallSuccessFromResponse(response: CliRespondOptions): M
45
46
  contentType,
46
47
  encoding: "base64",
47
48
  } satisfies McpBinaryRespondContent;
49
+ text = `[Binary data: ${contentType}, ${body.length} bytes]`;
48
50
  } else if (typeof body === "string") {
49
51
  structuredContent = {
50
52
  content: body,
51
53
  contentType,
52
54
  } satisfies McpStringRespondContent;
55
+ text = body;
53
56
  } else {
54
57
  structuredContent = body;
58
+ text = typeof body === "object" && body !== null ? JSON.stringify(body, null, 2) : String(body ?? "");
55
59
  }
56
60
 
57
61
  return {
58
- content: [{ type: "text", text: "" }],
62
+ content: [{ type: "text", text }],
59
63
  structuredContent,
60
64
  isError: false,
61
65
  };
package/src/mcp/server.ts CHANGED
@@ -253,8 +253,9 @@ async function handleRequestLine(cli: Cli, line: string): Promise<void> {
253
253
  /** Runs the MCP NDJSON read loop on stdin until EOF. */
254
254
  export async function mcpServeStdioLoop(cli: Cli): Promise<void> {
255
255
  let buffer = "";
256
- for await (const chunk of Bun.stdin.stream()) {
257
- buffer += new TextDecoder().decode(chunk);
256
+ const decoder = new TextDecoder();
257
+ for await (const chunk of process.stdin) {
258
+ buffer += typeof chunk === "string" ? chunk : decoder.decode(chunk);
258
259
  let nl = buffer.indexOf("\n");
259
260
  while (nl !== -1) {
260
261
  const line = buffer.slice(0, nl).trim();
@@ -1,10 +1,23 @@
1
1
  import type { CliProgram } from "../core/types.ts";
2
2
  import { CliFallbackMode, CliOptionKind } from "../core/types.ts";
3
+ import type { McpToolDef } from "../mcp/tools.ts";
3
4
 
4
5
  export function testProgram(prog: Record<string, unknown> & { key: string; description: string }): CliProgram {
5
6
  return { version: "0.0.0", ...prog } as CliProgram;
6
7
  }
7
8
 
9
+ /** MCP tool with `name` from `collectMcpTools`, or throw. */
10
+ export function requireMcpTool(
11
+ /** Tools from `collectMcpTools`. */
12
+ tools: McpToolDef[],
13
+ /** MCP tool name to find. */
14
+ name: string,
15
+ ): McpToolDef {
16
+ const tool = tools.find((t) => t.name === name);
17
+ if (!tool) throw new Error(`expected MCP tool ${name}`);
18
+ return tool;
19
+ }
20
+
8
21
  export const nestedMcpFixture = testProgram({
9
22
  key: "nested.ts",
10
23
  description: "Nested groups demo.",
@@ -16,7 +16,7 @@ import {
16
16
  mcpToolName,
17
17
  sanitizeToolSegment,
18
18
  } from "../../mcp/tools.ts";
19
- import { mcpRequest, nestedMcpFixture, testProgram } from "../fixtures.ts";
19
+ import { mcpRequest, nestedMcpFixture, requireMcpTool, testProgram } from "../fixtures.ts";
20
20
 
21
21
  test("sanitizeToolSegment normalizes dotted app keys", () => {
22
22
  expect(sanitizeToolSegment("minimal.ts")).toBe("minimal_ts");
@@ -39,7 +39,7 @@ test("collectMcpTools lists user leaf commands only", () => {
39
39
  const tools = collectMcpTools(nestedMcpFixture);
40
40
  const names = tools.map((t) => t.name);
41
41
  expect(names).toContain("stat_owner_lookup");
42
- const lookup = tools.find((t) => t.name === "stat_owner_lookup")!;
42
+ const lookup = requireMcpTool(tools, "stat_owner_lookup");
43
43
  expect(lookup.description).toBe("stat owner lookup — Resolve owner info.");
44
44
  expect(names).toContain("read");
45
45
  expect(names).not.toContain("hidden");
@@ -155,7 +155,7 @@ test("outputSchema must be a JSON Schema object", () => {
155
155
 
156
156
  test("collectMcpTools uses leaf-local options in inputSchema", () => {
157
157
  const tools = collectMcpTools(nestedMcpFixture);
158
- const lookup = tools.find((t) => t.name === "stat_owner_lookup")!;
158
+ const lookup = requireMcpTool(tools, "stat_owner_lookup");
159
159
  const schema = lookup.inputSchema as { properties: Record<string, unknown>; required?: string[] };
160
160
  expect(schema.properties.json).toBeUndefined();
161
161
  expect(schema.properties["user-name"]).toBeDefined();
@@ -193,13 +193,13 @@ test("collectMcpTools includes outputSchema when set on leaf", () => {
193
193
 
194
194
  test("collectMcpTools omits outputSchema when leaf has none", () => {
195
195
  const tools = collectMcpTools(nestedMcpFixture);
196
- const lookup = tools.find((t) => t.name === "stat_owner_lookup")!;
196
+ const lookup = requireMcpTool(tools, "stat_owner_lookup");
197
197
  expect(lookup.outputSchema).toBeUndefined();
198
198
  });
199
199
 
200
200
  test("mcpToolCallToArgv builds nested lookup argv", () => {
201
201
  const tools = collectMcpTools(nestedMcpFixture);
202
- const lookup = tools.find((t) => t.name === "stat_owner_lookup")!;
202
+ const lookup = requireMcpTool(tools, "stat_owner_lookup");
203
203
  const argv = mcpToolCallToArgv(nestedMcpFixture, lookup, {
204
204
  "user-name": "alice",
205
205
  path: "./x",
@@ -209,7 +209,7 @@ test("mcpToolCallToArgv builds nested lookup argv", () => {
209
209
 
210
210
  test("mcpToolCallToArgv expands varargs positionals", () => {
211
211
  const tools = collectMcpTools(nestedMcpFixture);
212
- const read = tools.find((t) => t.name === "read")!;
212
+ const read = requireMcpTool(tools, "read");
213
213
  const argv = mcpToolCallToArgv(nestedMcpFixture, read, { files: ["a", "b"] });
214
214
  expect(argv).toEqual(["read", "a", "b"]);
215
215
  });
@@ -318,7 +318,7 @@ test("buildToolCallSuccessFromResponse maps JSON object", () => {
318
318
  const result = buildToolCallSuccessFromResponse({ body: { a: 1 } });
319
319
  expect(result.isError).toBe(false);
320
320
  expect(result.structuredContent).toEqual({ a: 1 });
321
- expect(result.content[0]?.text).toBe("");
321
+ expect(result.content[0]?.text).toBe(JSON.stringify({ a: 1 }, null, 2));
322
322
  });
323
323
 
324
324
  test("buildToolCallSuccessFromResponse maps string body", () => {
@@ -330,6 +330,7 @@ test("buildToolCallSuccessFromResponse maps string body", () => {
330
330
  content: "lookup user=x",
331
331
  contentType: "text/plain; charset=utf-8",
332
332
  });
333
+ expect(result.content[0]?.text).toBe("lookup user=x");
333
334
  });
334
335
 
335
336
  test("buildToolCallSuccessFromResponse maps binary body as base64", () => {
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env bun
2
- /** Print a field from scripts/create-identity.ts for justfile backticks. */
3
-
4
- import { createIdentity } from "./create-identity.ts";
5
-
6
- const field = process.argv[2];
7
- if (!field) {
8
- console.error("Usage: bun scripts/print-identity.ts <key|className|tap|tapOrg|tapRepo|releaseRepo|envPrefix>");
9
- process.exit(1);
10
- }
11
-
12
- const [tapOrg, tapRepo] = createIdentity.tap.split("/");
13
- const values: Record<string, string> = {
14
- key: createIdentity.key,
15
- className: createIdentity.className,
16
- tap: createIdentity.tap,
17
- tapOrg: tapOrg ?? "",
18
- tapRepo: tapRepo ?? "",
19
- envPrefix: createIdentity.envPrefix,
20
- releaseRepo: createIdentity.releaseRepo,
21
- };
22
-
23
- const value = values[field];
24
- if (value === undefined) {
25
- console.error(`Unknown field: ${field}`);
26
- process.exit(1);
27
- }
28
- process.stdout.write(value);
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env bun
2
- /** Print a field from scripts/create-identity.ts for justfile backticks. */
3
-
4
- import { createIdentity } from "./create-identity.ts";
5
-
6
- const field = process.argv[2];
7
- if (!field) {
8
- console.error("Usage: bun scripts/print-identity.ts <key|className|tap|tapOrg|tapRepo|releaseRepo|envPrefix>");
9
- process.exit(1);
10
- }
11
-
12
- const [tapOrg, tapRepo] = createIdentity.tap.split("/");
13
- const values: Record<string, string> = {
14
- key: createIdentity.key,
15
- className: createIdentity.className,
16
- tap: createIdentity.tap,
17
- tapOrg: tapOrg ?? "",
18
- tapRepo: tapRepo ?? "",
19
- envPrefix: createIdentity.envPrefix,
20
- releaseRepo: createIdentity.releaseRepo,
21
- };
22
-
23
- const value = values[field];
24
- if (value === undefined) {
25
- console.error(`Unknown field: ${field}`);
26
- process.exit(1);
27
- }
28
- process.stdout.write(value);