argsbarg 7.1.0 → 7.1.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.
- package/CHANGELOG.md +17 -1
- package/docs/mcp.md +1 -1
- package/examples/mcp-plugin/.claude-plugin/marketplace.json +13 -0
- package/examples/mcp-plugin/.claude-plugin/plugin.json +1 -2
- package/examples/mcp-plugin/.cursor-plugin/plugin.json +1 -2
- package/examples/mcp-plugin/README.md +25 -23
- package/package.json +1 -1
- package/src/cli-tool/program.ts +1 -1
- package/src/headless/tool-call.test.ts +32 -0
- package/src/headless/tool-call.ts +19 -8
- package/src/mcp/bundle.ts +3 -2
- package/src/mcp/claude.ts +4 -2
- package/src/mcp/cursor.ts +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [7.1.1] - 2026-09-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`argsbarg create --template plugin`** — support `"plugin"` choice for scaffolding agent MCP plugins with in-repo Cursor and Claude manifests.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **AGENTS.md** — updated Memory section to use `thread-memory` MCP plugin (`recall`/`feedback`) backed by centralized SQLite store.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Headless tool failures (MCP `tools/call` and HTTP JSON `{ "error" }`) now return the full error message (ANSI stripped, newlines preserved) instead of collapsing to the first line.
|
|
23
|
+
- `packClaudePlugin`, `packCursorPlugin`, and `packMcpBundle` staged the compiled binary via `cpSync(src, dest, { mode: 0o755 })` — but `cpSync`'s `mode` option is a bitmask of copy-behavior flags (`COPYFILE_EXCL`/`FICLONE`/`FICLONE_FORCE`, valid range 0–7), not a POSIX file permission mode. `0o755` (493) was always out of range; a stricter Bun `fs.cpSync` validation now throws on it instead of silently ignoring it. Fixed by dropping the bogus `mode` option and calling `chmodSync(dest, 0o755)` after the copy, which is what the code actually intended.
|
|
24
|
+
|
|
10
25
|
## [7.1.0] - 2026-09-18
|
|
11
26
|
|
|
12
27
|
### Changed
|
|
@@ -1033,7 +1048,8 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
|
|
|
1033
1048
|
- Migrate schemas: rename every `children` property to **`commands`**; move positional definitions to **`CliPositional`** objects on `positionals` and strip `positional` / `argMin` / `argMax` from flag definitions under `options` (flags only carry `name`, `description`, `kind`, and optional `shortName`).
|
|
1034
1049
|
- Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
|
|
1035
1050
|
|
|
1036
|
-
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v7.1.
|
|
1051
|
+
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v7.1.1...HEAD
|
|
1052
|
+
[7.1.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v7.1.1
|
|
1037
1053
|
[7.1.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v7.1.0
|
|
1038
1054
|
[7.0.11]: https://github.com/bdombro/bun-argsbarg/releases/tag/v7.0.11
|
|
1039
1055
|
[7.0.10]: https://github.com/bdombro/bun-argsbarg/releases/tag/v7.0.10
|
package/docs/mcp.md
CHANGED
|
@@ -196,7 +196,7 @@ On success (`isError: false`):
|
|
|
196
196
|
- **stderr** — when non-empty, a second `content` text block with trimmed stderr (no prefix). The block’s position signals stderr; hosts may label it themselves.
|
|
197
197
|
- **structuredContent** — when trimmed stdout is valid JSON, the parsed value is also returned per the [MCP tools spec](https://modelcontextprotocol.io/specification/draft/server/tools). Objects and arrays from flags like `--json` are the common case. JSON **primitives** (`true`, `42`, `"hello"`) are parsed too — a handler that prints the literal string `true` as human text would get `structuredContent: true`. Prefer objects for machine-readable output.
|
|
198
198
|
|
|
199
|
-
On failure (parse error, validation error, non-zero exit, thrown error), the message is returned as text content with `isError: true
|
|
199
|
+
On failure (parse error, validation error, non-zero exit, thrown error), the **full** error message is returned as text content with `isError: true` (ANSI stripped, newlines preserved). HTTP JSON `{ "error": "…" }` uses the same full text. Do not collapse headless errors to the first line.
|
|
200
200
|
|
|
201
201
|
Help and `docs cli-schema` are not available through tool calls; use the schema resource or run the CLI directly for those.
|
|
202
202
|
|
|
@@ -11,22 +11,23 @@ Argsbarg MCP plugin template for Cursor and Claude Code marketplaces (@sg schema
|
|
|
11
11
|
- **In-repo skills**: `skills/mcp-plugin/SKILL.md` discovered and loaded by agent platforms.
|
|
12
12
|
- **Standalone runner**: `bun build --target=node src/index.ts --outfile scripts/mcp.mjs` creates an inlined, zero-npm-install script.
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Installation
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
# Install dependencies and generate schemas
|
|
18
|
-
just setup
|
|
16
|
+
### Cursor
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
just build
|
|
18
|
+
Recommended: import directly from GitHub — Cursor Dashboard → **Settings → Plugins → Team Marketplaces → Import**, then enter `https://github.com/bdombro/bun-argsbarg` (subdirectory `examples/mcp-plugin` once copied to its own repo). Once published to the [official marketplace](https://cursor.com/marketplace/publish), install via `/add-plugin mcp-plugin` or the Customize sidebar.
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
node ./scripts/mcp.mjs mcp
|
|
20
|
+
### Claude Code
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
Recommended: add the GitHub repo as a marketplace, then install:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
/plugin marketplace add <owner>/<repo>
|
|
26
|
+
/plugin install mcp-plugin@<repo>
|
|
28
27
|
```
|
|
29
28
|
|
|
29
|
+
Once merged into [anthropics/claude-plugins-official](https://github.com/anthropics/claude-plugins-official), install via `/plugin install mcp-plugin@claude-plugins-official`.
|
|
30
|
+
|
|
30
31
|
## Commands
|
|
31
32
|
|
|
32
33
|
- `mcp-plugin echo` — Echo text back to stdout or inspect flags.
|
|
@@ -42,23 +43,24 @@ just install-plugin-cursor
|
|
|
42
43
|
- `mcp-plugin mcp` — Start the Model Context Protocol (stdio) server for AI coding agents.
|
|
43
44
|
- `mcp-plugin version` — Display version information.
|
|
44
45
|
|
|
45
|
-
##
|
|
46
|
+
## Contributing / Local Development
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/bdombro/bun-argsbarg.git
|
|
50
|
+
cd bun-argsbarg/examples/mcp-plugin
|
|
48
51
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- **Official Cursor Marketplace**: Submit your repository URL at [cursor.com/marketplace/publish](https://cursor.com/marketplace/publish). Once approved, users can install directly via `/add-plugin mcp-plugin` or from the Customize sidebar.
|
|
52
|
+
# Install dependencies and generate schemas
|
|
53
|
+
just setup
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
# Build standalone MCP bundle
|
|
56
|
+
just build
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- **Official Directory**: Submit a pull request to [anthropics/claude-plugins-official](https://github.com/anthropics/claude-plugins-official) under `external_plugins/`. Once merged, users can install directly via `/plugin install mcp-plugin@claude-plugins-official`.
|
|
58
|
+
# Test MCP server directly with node
|
|
59
|
+
node ./scripts/mcp.mjs mcp
|
|
60
|
+
|
|
61
|
+
# Link into local Cursor plugins for live testing
|
|
62
|
+
just install-plugin-cursor
|
|
63
|
+
```
|
|
62
64
|
|
|
63
65
|
## Documentation
|
|
64
66
|
|
package/package.json
CHANGED
package/src/cli-tool/program.ts
CHANGED
|
@@ -18,7 +18,7 @@ export const program = {
|
|
|
18
18
|
name: "template",
|
|
19
19
|
description: "Template: cli (default) or json (schema-first).",
|
|
20
20
|
kind: CliOptionKind.Enum,
|
|
21
|
-
choices: ["cli", "json"],
|
|
21
|
+
choices: ["cli", "json", "plugin"],
|
|
22
22
|
},
|
|
23
23
|
{ name: "key", description: "CLI binary name.", kind: CliOptionKind.String },
|
|
24
24
|
{
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* Unit tests for shared headless error text (MCP and HTTP). */
|
|
2
|
+
|
|
3
|
+
import { describe, expect, test } from "bun:test";
|
|
4
|
+
import { type HeadlessToolCallFailure, headlessFailureMcpMessage, headlessFailureToHttpResponse } from "./tool-call.ts";
|
|
5
|
+
|
|
6
|
+
/** Builds a failed headless result with the given error message. */
|
|
7
|
+
function invokeFailure(
|
|
8
|
+
/** Full error text from the leaf. */
|
|
9
|
+
message: string,
|
|
10
|
+
): HeadlessToolCallFailure {
|
|
11
|
+
return {
|
|
12
|
+
exitCode: 1,
|
|
13
|
+
kind: "invoke",
|
|
14
|
+
message,
|
|
15
|
+
ok: false,
|
|
16
|
+
stderr: "",
|
|
17
|
+
stdout: "",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("headless error text", () => {
|
|
22
|
+
const multiline =
|
|
23
|
+
'cannot copy tab "Spec" losslessly (1 smart chip(s): "Ada"). Use force: true.\n' +
|
|
24
|
+
' • node h.x: contains 1 smart chip(s) ("Ada")\n\n' +
|
|
25
|
+
"Google Docs REST API has no native tab duplication endpoint.";
|
|
26
|
+
|
|
27
|
+
test("MCP and HTTP both keep the full multi-line error", async () => {
|
|
28
|
+
expect(headlessFailureMcpMessage(invokeFailure(multiline))).toBe(multiline);
|
|
29
|
+
const body = (await headlessFailureToHttpResponse(invokeFailure(multiline)).json()) as { error: string };
|
|
30
|
+
expect(body.error).toBe(multiline);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -6,7 +6,7 @@ import { bootstrapAppConfig } from "../config/bootstrap.ts";
|
|
|
6
6
|
import { formatMcpMissingConfigMessage, missingRequiredConfig } from "../config/resolve.ts";
|
|
7
7
|
import type { CliInvocation, CliProgram, InvokeFailureKind } from "../core/types.ts";
|
|
8
8
|
import { failureKindHttpStatus } from "../hooks/run.ts";
|
|
9
|
-
import { apiErrorResponse, apiSuccessResponse,
|
|
9
|
+
import { apiErrorResponse, apiSuccessResponse, stripAnsi } from "../http/result.ts";
|
|
10
10
|
import { type HttpRouteDef, httpRequestToArgv } from "../http/routes.ts";
|
|
11
11
|
import { obscureUnexpectedClientMessage } from "../log/emitter.ts";
|
|
12
12
|
import { buildToolCallSuccessFromResponse } from "../mcp/result.ts";
|
|
@@ -188,11 +188,7 @@ export function headlessSuccessToHttpResponse(
|
|
|
188
188
|
/** Maps a headless failure result to a JSON HTTP error Response. */
|
|
189
189
|
export function headlessFailureToHttpResponse(result: HeadlessToolCallFailure, obscureUnexpected = false): Response {
|
|
190
190
|
const status = resolveHttpErrorStatus(result);
|
|
191
|
-
|
|
192
|
-
if (obscureUnexpected && result.failureKind === "unexpected") {
|
|
193
|
-
message = obscureUnexpectedClientMessage();
|
|
194
|
-
}
|
|
195
|
-
return apiErrorResponse(status, { error: message });
|
|
191
|
+
return apiErrorResponse(status, { error: formatHeadlessError(result, obscureUnexpected) });
|
|
196
192
|
}
|
|
197
193
|
|
|
198
194
|
function resolveHttpErrorStatus(result: HeadlessToolCallFailure): number {
|
|
@@ -212,11 +208,26 @@ function resolveHttpErrorStatus(result: HeadlessToolCallFailure): number {
|
|
|
212
208
|
}
|
|
213
209
|
|
|
214
210
|
/** Maps invoke failure kind to MCP tools/call error text (respects obscureUnexpected). */
|
|
215
|
-
export function headlessFailureMcpMessage(
|
|
211
|
+
export function headlessFailureMcpMessage(
|
|
212
|
+
/** Failed headless tool invocation. */
|
|
213
|
+
result: HeadlessToolCallFailure,
|
|
214
|
+
/** When true, unexpected failures return a generic client message. */
|
|
215
|
+
obscureUnexpected = false,
|
|
216
|
+
): string {
|
|
217
|
+
return formatHeadlessError(result, obscureUnexpected);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Formats a headless failure for MCP text content and HTTP JSON `error` (full message, ANSI stripped). */
|
|
221
|
+
function formatHeadlessError(
|
|
222
|
+
/** Failed headless tool invocation. */
|
|
223
|
+
result: HeadlessToolCallFailure,
|
|
224
|
+
/** When true, unexpected failures return a generic client message. */
|
|
225
|
+
obscureUnexpected: boolean,
|
|
226
|
+
): string {
|
|
216
227
|
if (obscureUnexpected && result.failureKind === "unexpected") {
|
|
217
228
|
return obscureUnexpectedClientMessage();
|
|
218
229
|
}
|
|
219
|
-
return
|
|
230
|
+
return stripAnsi(result.message).trim();
|
|
220
231
|
}
|
|
221
232
|
|
|
222
233
|
/** Missing-config lookup failures as MCP/HTTP pre-invoke errors. */
|
package/src/mcp/bundle.ts
CHANGED
|
@@ -3,7 +3,7 @@ Packs a CLI program into an MCP Bundle (`.mcpb`) for Claude Desktop.
|
|
|
3
3
|
Expects `dist/<program.key>` as the compiled binary input.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { chmodSync, cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { basename, join, resolve } from "node:path";
|
|
9
9
|
import { buildProgramUserConfig } from "../config/manifest.ts";
|
|
@@ -119,7 +119,8 @@ export function packMcpBundle(program: CliProgram, opts: PackMcpBundleOpts = {})
|
|
|
119
119
|
const staging = mkdtempSync(join(tmpdir(), "mcpb-"));
|
|
120
120
|
try {
|
|
121
121
|
const stagedBinary = join(staging, binaryName);
|
|
122
|
-
cpSync(binaryPath, stagedBinary
|
|
122
|
+
cpSync(binaryPath, stagedBinary);
|
|
123
|
+
chmodSync(stagedBinary, 0o755);
|
|
123
124
|
|
|
124
125
|
const manifest = generateMcpManifest(program, binaryName);
|
|
125
126
|
const files: { name: string; data: Buffer }[] = [
|
package/src/mcp/claude.ts
CHANGED
|
@@ -3,7 +3,7 @@ Packs a Claude Code plugin zip from a compiled CLI binary.
|
|
|
3
3
|
Internal module — not exported from index.ts.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { cpSync, existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { chmodSync, cpSync, existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { basename, join, resolve } from "node:path";
|
|
9
9
|
import { buildPluginMcpEnvMapping, buildProgramUserConfig } from "../config/manifest.ts";
|
|
@@ -104,7 +104,9 @@ function writePluginTree(
|
|
|
104
104
|
join(pluginRoot, ".mcp.json"),
|
|
105
105
|
`${JSON.stringify(generatePluginMcpJson(program, binaryName), null, 2)}\n`,
|
|
106
106
|
);
|
|
107
|
-
|
|
107
|
+
const stagedBinary = join(pluginRoot, "bin", binaryName);
|
|
108
|
+
cpSync(binaryPath, stagedBinary);
|
|
109
|
+
chmodSync(stagedBinary, 0o755);
|
|
108
110
|
stagePluginSkills(pluginRoot, program, cwd);
|
|
109
111
|
}
|
|
110
112
|
|
package/src/mcp/cursor.ts
CHANGED
|
@@ -3,7 +3,7 @@ Packs a Cursor plugin zip from a compiled CLI binary.
|
|
|
3
3
|
Internal module — not exported from index.ts.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { cpSync, existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { chmodSync, cpSync, existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { basename, join, resolve } from "node:path";
|
|
9
9
|
import { buildCursorPluginMcpEnvMapping, buildCursorPluginVariables } from "../config/manifest.ts";
|
|
@@ -117,7 +117,9 @@ function writePluginTree(
|
|
|
117
117
|
join(pluginRoot, "mcp.json"),
|
|
118
118
|
`${JSON.stringify(generateCursorPluginMcpJson(program, binaryName), null, 2)}\n`,
|
|
119
119
|
);
|
|
120
|
-
|
|
120
|
+
const stagedBinary = join(pluginRoot, "bin", binaryName);
|
|
121
|
+
cpSync(binaryPath, stagedBinary);
|
|
122
|
+
chmodSync(stagedBinary, 0o755);
|
|
121
123
|
stagePluginSkills(pluginRoot, program, cwd);
|
|
122
124
|
}
|
|
123
125
|
|