@ai-ecoverse/mcpcat 0.17.0 → 0.17.2

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/README.md CHANGED
@@ -26,7 +26,7 @@ mcpcat runs natively on macOS, Linux and Windows (Node ≥ 24), and inside Slicc
26
26
 
27
27
  ## Releases: certified = latest
28
28
 
29
- Every change that alters what mcpcat ships is certified before it reaches `main`. A pull request that touches `src/`, the build, the dependencies or the release workflows gets mcpcat's cert-review on a pack of its head, and again in the merge queue on the exact tree that lands on `main`; a FAIL blocks the merge. Docs-, test- and CI-only changes skip it as "not behaviour". Each merge to `main` is then released to npm as `latest` in one step by semantic-release, with provenance, so `npm install @ai-ecoverse/mcpcat` and the installer always get certified code. The verdict line is a comment on the pull request and the `cert-review` commit status. It reads `certified …`, `cert-ci: FAIL …` when the reviewer or a check in code found a defect (status `failure`), or `cert-ci: INCOMPLETE …` when the review couldn't decide: the review job didn't succeed or was skipped, no verdict could be read, or the artifact or the runner's own `gh` was missing (status `error`). A fork's change to shipped behaviour also reads INCOMPLETE, since it gets no review. INCOMPLETE never certifies; re-run the failed jobs. A run that ends without `record` posting its status (a crashed plan, record or verdict job) still posts one on the head: `error` with its INCOMPLETE line, `failure` for a FAIL, or `pending` while the coordinator approval is missing. So the required `cert-review` check never waits forever, and a label change reuses only a `success` or `failure` verdict, never an INCOMPLETE one. The reviewer's verdict can add defects but never clear one found in code: `record` re-reads the suites' evidence (`stage.json`, `suites.json`), uploaded before the reviewer runs and bound by the artifact id and digest the review job output. A suite or security row that failed on the host or a pinned kernel, a changed test that fails on the head, an import in the kernel bundle or an unexplained rebuild difference is a FAIL. Missing suites, kernels or rows are INCOMPLETE. The NEGATIVE runs each changed test on the base's code: the subject's tests, helpers and fixtures with the base's `dist`, `scripts/` and `.github/workflows/`, all from the base sha, so a test of the cert tooling runs against main's tooling. The record names both shas. A changed test that also passes on the base is named in the line as `gaps: no-negative <file>`. Every artifact a later job reads (the tarball, the verdict, the suites' evidence) is downloaded by the artifact id its producer output, after `bind.mjs` checks the artifact's name, run and digest against that producer's outputs. Any other artifact from this attempt of the run under `mcpcat-tarball-`, `mcpcat-npm-tarball-` or `cert-review-` makes the line INCOMPLETE. An earlier attempt's leftovers, created before this attempt started, are never read.
29
+ Every change that alters what mcpcat ships is certified before it reaches `main`. A pull request that touches `src/`, the build, the dependencies or the release workflows gets mcpcat's cert-review on a pack of its head, and again in the merge queue on the exact tree that lands on `main`; a FAIL blocks the merge. Docs-, test- and CI-only changes skip it as "not behaviour". A draft pull request is not reviewed: its `cert-review` is red with `draft: not reviewed, mark it ready for review`, and marking it ready starts the review (converted_to_draft cancels a running one). Mark ready = reviewed, and merges on green; a pull request held for anything stays a draft. For a PR that needs the coordinator's security read, the order is: the coordinator reads the draft, it is marked ready, the cert runs, then the queue. Each merge to `main` is then released to npm as `latest` in one step by semantic-release, with provenance, so `npm install @ai-ecoverse/mcpcat` and the installer always get certified code. The verdict line is a comment on the pull request and the `cert-review` commit status. It reads `certified …`, `cert-ci: FAIL …` when the reviewer or a check in code found a defect (status `failure`), or `cert-ci: INCOMPLETE …` when the review couldn't decide: the review job didn't succeed or was skipped, no verdict could be read, or the artifact or the runner's own `gh` was missing (status `error`). A fork's change to shipped behaviour also reads INCOMPLETE, since it gets no review. INCOMPLETE never certifies; re-run the failed jobs. A run that ends without `record` posting its status (a crashed plan, record or verdict job) still posts one on the head: `error` with its INCOMPLETE line, `failure` for a FAIL, or `pending` while the coordinator approval is missing. So the required `cert-review` check never waits forever, and a label change reuses only a `success` or `failure` verdict, never an INCOMPLETE one. The reviewer's verdict can add defects but never clear one found in code: `record` re-reads the suites' evidence (`stage.json`, `suites.json`), uploaded before the reviewer runs and bound by the artifact id and digest the review job output. A suite or security row that failed on the host or a pinned kernel, a changed test that fails on the head, an import in the kernel bundle or an unexplained rebuild difference is a FAIL. Missing suites, kernels or rows are INCOMPLETE. The NEGATIVE runs each changed test on the base's code: the subject's tests, helpers and fixtures with the base's `dist`, `scripts/` and `.github/workflows/`, all from the base sha, so a test of the cert tooling runs against main's tooling. The record names both shas. A changed test that also passes on the base is named in the line as `gaps: no-negative <file>`. Every artifact a later job reads (the tarball, the verdict, the suites' evidence) is downloaded by the artifact id its producer output, after `bind.mjs` checks the artifact's name, run and digest against that producer's outputs. Any other artifact from this attempt of the run under `mcpcat-tarball-`, `mcpcat-npm-tarball-` or `cert-review-` makes the line INCOMPLETE. An earlier attempt's leftovers, created before this attempt started, are never read.
30
30
 
31
31
  After each release, `cert-verify.yml` (on the Release run's success, or dispatched from `main` with a `version`) checks again that npm serves the SLSA subject built by `release.yml` on `main` from the tag, and that every pull request merged since the previous tag carries a green `cert-review` status on its head. Its hosted, write-only `notes` job then puts one line into the GitHub release notes, between `<!-- cert-verify -->` markers: `certified @ai-ecoverse/mcpcat@<version> sha256=<sha> (…; pr-certified since v<prev>: …)`, or `verified …` when some pull request lacks a green cert-review. A re-run with the same bytes leaves the notes as they are. Notes that already name another sha for the version, or npm bytes that don't verify, are a supply-chain alert: nothing is written and an issue is filed. Checks that couldn't run read `cert-ci: INCOMPLETE` and write nothing.
32
32
 
@@ -10192,6 +10192,29 @@ init_lock();
10192
10192
 
10193
10193
  // src/config/edit.ts
10194
10194
  init_lock();
10195
+ var FILE_MODE2 = 384;
10196
+ var DIR_MODE2 = 448;
10197
+ var PI_DIR = /\/\.pi(\/agent)?$/;
10198
+ async function privateDir(fs, dir, made) {
10199
+ try {
10200
+ await fs.mkdir(dir, { mode: DIR_MODE2 });
10201
+ } catch {
10202
+ }
10203
+ if (fs.chmod && (made || PI_DIR.test(dir))) {
10204
+ try {
10205
+ await fs.chmod(dir, DIR_MODE2);
10206
+ } catch {
10207
+ }
10208
+ }
10209
+ }
10210
+ async function privateFile(fs, path, output) {
10211
+ await fs.writeFile(path, output, { mode: FILE_MODE2 });
10212
+ if (!fs.chmod) return;
10213
+ try {
10214
+ await fs.chmod(path, FILE_MODE2);
10215
+ } catch {
10216
+ }
10217
+ }
10195
10218
  function isRecord2(value) {
10196
10219
  return typeof value === "object" && value !== null && !Array.isArray(value);
10197
10220
  }
@@ -10208,6 +10231,8 @@ async function readText(fs, path) {
10208
10231
  }
10209
10232
  }
10210
10233
  async function editMcpServers(fs, path, edit) {
10234
+ const dir = path.slice(0, path.lastIndexOf("/"));
10235
+ const made = dir !== "" && !await fs.exists(dir).catch(() => false);
10211
10236
  const release = await acquireLock(fs, path);
10212
10237
  try {
10213
10238
  const text = await readText(fs, path);
@@ -10219,16 +10244,10 @@ async function editMcpServers(fs, path, edit) {
10219
10244
  const indent = text ? detectIndent(text) : " ";
10220
10245
  const output = `${JSON.stringify(parsed, null, indent)}
10221
10246
  `;
10222
- const dir = path.slice(0, path.lastIndexOf("/"));
10223
- if (dir) {
10224
- try {
10225
- await fs.mkdir(dir);
10226
- } catch {
10227
- }
10228
- }
10247
+ if (dir) await privateDir(fs, dir, made);
10229
10248
  const tmpPath = `${path}.tmp.${Date.now()}`;
10230
- await fs.writeFile(tmpPath, output);
10231
10249
  try {
10250
+ await privateFile(fs, tmpPath, output);
10232
10251
  await fs.rename(tmpPath, path);
10233
10252
  } catch (renameErr) {
10234
10253
  try {
@@ -15432,11 +15451,15 @@ Client verbs:
15432
15451
  tools <target> List tools
15433
15452
  call <target> <tool> Call a tool
15434
15453
  describe <target> [tool] Tool schema and help
15454
+ resources <target> List resources
15455
+ read <target> <uri> Read a resource
15456
+ prompts <target> List prompts
15457
+ prompt <target> <name> Get a prompt
15435
15458
 
15436
15459
  Configuration verbs:
15437
15460
  add <name> <url> Add a server to mcp.json
15438
- add <name> --bridge --
15439
- Bridge a stdio server to HTTP (kernel only,
15461
+ add <name> --bridge -- <command> [args\u2026]
15462
+ Bridge a stdio server to HTTP (kernel only,
15440
15463
  runs in foreground, does not survive reload)
15441
15464
  rm <name> Remove a server
15442
15465
  list List configured servers
@@ -15452,12 +15475,12 @@ Server and code verbs:
15452
15475
  grep <pattern> [target\u2026] Search tools by name or description
15453
15476
  discover <url> Find MCP servers at a URL
15454
15477
  inbox [--json] List discovery candidates
15455
- help [verb] Show help
15478
+ help Show this help
15456
15479
  help --skill Print the agent skill (SKILL.md) for this version
15457
15480
 
15458
15481
  Options:
15459
15482
  --json JSON output
15460
- -H, --header 'N: V' Extra header
15483
+ -H, --header 'N: V' Extra header
15461
15484
  -d <json> Tool arguments as JSON (or @file, @- for stdin)
15462
15485
  -m, --timeout <s> Request timeout (default 60)
15463
15486
  --memory <MiB> Code mode memory limit (default 256, max 1024)
@@ -15471,7 +15494,7 @@ Options:
15471
15494
  -s, --server <name> Server target (code, repeatable)
15472
15495
  --allow-shell Enable shell() global (code)
15473
15496
  -v, --verbose Trace on stderr
15474
- -s, --silent Suppress progress
15497
+ --silent Suppress progress
15475
15498
  -o, --output <path> Write result to file
15476
15499
  -V, --version Print version
15477
15500
  -h, --help Show this help
@@ -16988,5 +17011,5 @@ try {
16988
17011
  });
16989
17012
  } catch {
16990
17013
  }
16991
- var code = await run(platform, "0.17.0", args);
17014
+ var code = await run(platform, "0.17.2", args);
16992
17015
  process.exit(code);
@@ -9813,6 +9813,29 @@ init_lock();
9813
9813
 
9814
9814
  // src/config/edit.ts
9815
9815
  init_lock();
9816
+ var FILE_MODE2 = 384;
9817
+ var DIR_MODE2 = 448;
9818
+ var PI_DIR = /\/\.pi(\/agent)?$/;
9819
+ async function privateDir(fs, dir, made) {
9820
+ try {
9821
+ await fs.mkdir(dir, { mode: DIR_MODE2 });
9822
+ } catch {
9823
+ }
9824
+ if (fs.chmod && (made || PI_DIR.test(dir))) {
9825
+ try {
9826
+ await fs.chmod(dir, DIR_MODE2);
9827
+ } catch {
9828
+ }
9829
+ }
9830
+ }
9831
+ async function privateFile(fs, path, output) {
9832
+ await fs.writeFile(path, output, { mode: FILE_MODE2 });
9833
+ if (!fs.chmod) return;
9834
+ try {
9835
+ await fs.chmod(path, FILE_MODE2);
9836
+ } catch {
9837
+ }
9838
+ }
9816
9839
  function isRecord2(value) {
9817
9840
  return typeof value === "object" && value !== null && !Array.isArray(value);
9818
9841
  }
@@ -9829,6 +9852,8 @@ async function readText(fs, path) {
9829
9852
  }
9830
9853
  }
9831
9854
  async function editMcpServers(fs, path, edit) {
9855
+ const dir = path.slice(0, path.lastIndexOf("/"));
9856
+ const made = dir !== "" && !await fs.exists(dir).catch(() => false);
9832
9857
  const release = await acquireLock(fs, path);
9833
9858
  try {
9834
9859
  const text = await readText(fs, path);
@@ -9840,16 +9865,10 @@ async function editMcpServers(fs, path, edit) {
9840
9865
  const indent = text ? detectIndent(text) : " ";
9841
9866
  const output = `${JSON.stringify(parsed, null, indent)}
9842
9867
  `;
9843
- const dir = path.slice(0, path.lastIndexOf("/"));
9844
- if (dir) {
9845
- try {
9846
- await fs.mkdir(dir);
9847
- } catch {
9848
- }
9849
- }
9868
+ if (dir) await privateDir(fs, dir, made);
9850
9869
  const tmpPath = `${path}.tmp.${Date.now()}`;
9851
- await fs.writeFile(tmpPath, output);
9852
9870
  try {
9871
+ await privateFile(fs, tmpPath, output);
9853
9872
  await fs.rename(tmpPath, path);
9854
9873
  } catch (renameErr) {
9855
9874
  try {
@@ -15053,11 +15072,15 @@ Client verbs:
15053
15072
  tools <target> List tools
15054
15073
  call <target> <tool> Call a tool
15055
15074
  describe <target> [tool] Tool schema and help
15075
+ resources <target> List resources
15076
+ read <target> <uri> Read a resource
15077
+ prompts <target> List prompts
15078
+ prompt <target> <name> Get a prompt
15056
15079
 
15057
15080
  Configuration verbs:
15058
15081
  add <name> <url> Add a server to mcp.json
15059
- add <name> --bridge --
15060
- Bridge a stdio server to HTTP (kernel only,
15082
+ add <name> --bridge -- <command> [args\u2026]
15083
+ Bridge a stdio server to HTTP (kernel only,
15061
15084
  runs in foreground, does not survive reload)
15062
15085
  rm <name> Remove a server
15063
15086
  list List configured servers
@@ -15073,12 +15096,12 @@ Server and code verbs:
15073
15096
  grep <pattern> [target\u2026] Search tools by name or description
15074
15097
  discover <url> Find MCP servers at a URL
15075
15098
  inbox [--json] List discovery candidates
15076
- help [verb] Show help
15099
+ help Show this help
15077
15100
  help --skill Print the agent skill (SKILL.md) for this version
15078
15101
 
15079
15102
  Options:
15080
15103
  --json JSON output
15081
- -H, --header 'N: V' Extra header
15104
+ -H, --header 'N: V' Extra header
15082
15105
  -d <json> Tool arguments as JSON (or @file, @- for stdin)
15083
15106
  -m, --timeout <s> Request timeout (default 60)
15084
15107
  --memory <MiB> Code mode memory limit (default 256, max 1024)
@@ -15092,7 +15115,7 @@ Options:
15092
15115
  -s, --server <name> Server target (code, repeatable)
15093
15116
  --allow-shell Enable shell() global (code)
15094
15117
  -v, --verbose Trace on stderr
15095
- -s, --silent Suppress progress
15118
+ --silent Suppress progress
15096
15119
  -o, --output <path> Write result to file
15097
15120
  -V, --version Print version
15098
15121
  -h, --help Show this help
@@ -16710,7 +16733,7 @@ async function main(ctx) {
16710
16733
  packageDir: "/node_modules/@ai-ecoverse/mcpcat"
16711
16734
  });
16712
16735
  const args = ctx.argv.slice(1);
16713
- return run(platform2, "0.17.0", args);
16736
+ return run(platform2, "0.17.2", args);
16714
16737
  }
16715
16738
  export {
16716
16739
  main as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/mcpcat",
3
- "version": "0.17.0",
3
+ "version": "0.17.2",
4
4
  "description": "A curl for the Model Context Protocol",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -61,15 +61,15 @@
61
61
  "trust:dry": "npx fledgling sync --dry-run -y --skip-publish"
62
62
  },
63
63
  "devDependencies": {
64
- "@ai-ecoverse/slicc-bios": "1.20.0",
65
- "@ai-ecoverse/slicc-kernel": "1.127.1",
64
+ "@ai-ecoverse/slicc-bios": "1.31.5",
65
+ "@ai-ecoverse/slicc-kernel": "1.134.1",
66
66
  "@ai-ecoverse/slicc-shared-web": "1.23.2",
67
67
  "@biomejs/biome": "2.5.15",
68
68
  "@earendil-works/pi-codemode": "1.2.0",
69
69
  "@earendil-works/pi-mcp": "1.2.0",
70
70
  "@types/node": "26.6.5",
71
71
  "esbuild": "0.28.2",
72
- "kernel-cert-new": "npm:@ai-ecoverse/slicc-kernel@1.127.1",
72
+ "kernel-cert-new": "npm:@ai-ecoverse/slicc-kernel@1.134.1",
73
73
  "monocart-coverage-reports": "2.13.2",
74
74
  "proper-lockfile": "4.1.2",
75
75
  "quickjs-wasi": "3.6.2",