@thenavidm/slipway 0.1.13 → 0.1.14

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 CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  What changed in Slipway, newest first.
4
4
 
5
+ ## 0.1.14, 2026-10-05: what Buffer needed
6
+
7
+ - **`which` and the search surface read what a tool takes.** Argument names count for a little less than the title and more than the description, and camelCase is split, so `channelId` reads as "channel" and `createPost` as "create post". Buffer's "schedule a post to a channel" never listed `create-post`, whose description says neither word but whose `channelId` and `schedulingType` say both; a Codex run that asked `which` then read the whole command list as well.
8
+
5
9
  ## 0.1.13, 2026-10-05: what Beehiiv needed
6
10
 
7
11
  - **`jsonSchema(schema, { shareRepeats: true })` writes each repeated part of a contract schema once.** A schema generated from an API contract often spells one definition out everywhere it is used. Beehiiv's post body repeats its block styling in each of 33 block types and carries the body twice, as its own fields and as `payload`, so its create-post tool advertised 387 KB. With each repeated part under `$defs` and referred to with `$ref`, it is 40 KB, and Beehiiv's 117 tools together go from 1,684 KB to 308 KB. Nothing is lost: each part reads the same once the references are followed, Claude Code and Codex both read fields that appear only under `$defs`, and validation accepts and refuses the same arguments. Definitions take the name of the property or block type they came from, such as `paragraph` or `visual_settings`, and parts under 200 bytes stay inline. The work is linear in the schema's size and happens when the tool is first listed. `shareRepeats()` is exported for a schema built some other way.
package/dist/search.js CHANGED
@@ -12,6 +12,8 @@ const STOP_WORDS = new Set([
12
12
  ]);
13
13
  function words(text) {
14
14
  return text
15
+ // camelCase splits, so `channelId` reads as "channel id" and `createPost` as "create post".
16
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
15
17
  .toLowerCase()
16
18
  .split(/[^a-z0-9]+/)
17
19
  .filter((word) => word.length > 1)
@@ -91,11 +93,13 @@ export function searchTools(tools, query, limit = 10, synonyms = {}) {
91
93
  const title = words(tool.title);
92
94
  const tags = tool.tags.flatMap(words);
93
95
  const description = words(tool.description);
96
+ // What a tool takes says what it is for: `channelId` and `schedulingType` find the post tool for "schedule a post to a channel".
97
+ const args = Object.keys(tool.jsonSchema.properties ?? {}).filter((key) => key !== "confirm").flatMap(words);
94
98
  let score = 0;
95
99
  let matched = 0;
96
100
  for (const term of terms) {
97
101
  // A term that is the tool's name is not a hint, it is the answer.
98
- const got = (named(tool, term) ? 20 : 0) + hits(term, name, extra) * 5 + hits(term, title, extra) * 4 + hits(term, tags, extra) * 3 + hits(term, description, extra);
102
+ const got = (named(tool, term) ? 20 : 0) + hits(term, name, extra) * 5 + hits(term, title, extra) * 4 + hits(term, tags, extra) * 3 + hits(term, args, extra) * 2 + hits(term, description, extra);
99
103
  if (got > 0)
100
104
  matched++;
101
105
  score += got;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thenavidm/slipway",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Slipway, the TypeScript framework for MCP servers and agent-native CLIs. One tool definition ships an MCP server and a CLI, with write safety, typed results and release checks built in.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",