bantamkit-mcp 0.35.7 → 0.35.9

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 (53) hide show
  1. package/README.md +24 -9
  2. package/assets/tools/memory_compact.json +1 -2
  3. package/assets/tools/memory_recall.json +1 -3
  4. package/assets/tools/shiftwork_clock_in.json +1 -1
  5. package/assets/tools/shiftwork_clock_out.json +1 -1
  6. package/assets/tools/validate_json.json +1 -1
  7. package/assets/tools/work_plan.json +14 -8
  8. package/dist/assets.js +28 -4
  9. package/dist/cli.js +83 -24
  10. package/dist/contract.d.ts +0 -9
  11. package/dist/contract.js +51 -12
  12. package/dist/eventlog.d.ts +22 -2
  13. package/dist/eventlog.js +30 -3
  14. package/dist/hookadapter.js +263 -43
  15. package/dist/hostinstall.d.ts +2 -2
  16. package/dist/hostinstall.js +318 -84
  17. package/dist/index.d.ts +2 -2
  18. package/dist/index.js +1 -1
  19. package/dist/mcp/identity.js +27 -1
  20. package/dist/mcp/pyargs.d.ts +22 -6
  21. package/dist/mcp/pyargs.js +113 -39
  22. package/dist/mcp/server.js +177 -41
  23. package/dist/mcp/status.js +11 -4
  24. package/dist/mcp/transport.d.ts +51 -6
  25. package/dist/mcp/transport.js +217 -26
  26. package/dist/mcpreport.d.ts +12 -0
  27. package/dist/mcpreport.js +67 -15
  28. package/dist/memory/cli.js +18 -3
  29. package/dist/memory/component.d.ts +17 -0
  30. package/dist/memory/component.js +51 -7
  31. package/dist/memory/factfile.d.ts +21 -3
  32. package/dist/memory/factfile.js +351 -12
  33. package/dist/memory/layers.d.ts +19 -0
  34. package/dist/memory/layers.js +102 -2
  35. package/dist/memory/pyyaml.d.ts +6 -4
  36. package/dist/memory/pyyaml.js +6 -4
  37. package/dist/memory/store.d.ts +82 -7
  38. package/dist/memory/store.js +277 -29
  39. package/dist/npminstall.d.ts +18 -0
  40. package/dist/npminstall.js +26 -5
  41. package/dist/pyargparse.js +48 -2
  42. package/dist/pyjsonschema.d.ts +85 -4
  43. package/dist/pyjsonschema.js +1812 -181
  44. package/dist/selfupdate.d.ts +112 -32
  45. package/dist/selfupdate.js +221 -79
  46. package/dist/shiftwork.d.ts +46 -7
  47. package/dist/shiftwork.js +246 -42
  48. package/dist/tokenledger.js +20 -4
  49. package/dist/updatecheck.d.ts +15 -3
  50. package/dist/updatecheck.js +23 -8
  51. package/dist/workplan.d.ts +8 -3
  52. package/dist/workplan.js +62 -3
  53. package/package.json +2 -2
@@ -55,7 +55,12 @@ export type PlanResult = PlanOk | PlanError;
55
55
  * with nothing left to do is the answer, the same reasoning `clock_in` applies when an all-terminal
56
56
  * checkpoint reports success rather than escalating on a dangling cursor.
57
57
  *
58
- * **The three refusals are checked in a fixed order** — duplicate id, then unknown dependency, then
59
- * cycle — because a graph can carry two faults at once and both runtimes have to name the same one.
58
+ * **The four refusals are checked in a fixed order** — a node's shape, then duplicate id, then
59
+ * unknown dependency, then cycle — because a graph can carry two faults at once and both runtimes
60
+ * have to name the same one.
61
+ *
62
+ * Takes `unknown[]` rather than `PlanNode[]` on purpose: the wire hands the server whatever the
63
+ * client sent inside each node, and the check that it IS a `PlanNode` lives here, beside the
64
+ * reference's (`workplan.py` checks the same shape in the same function), not in the caller.
60
65
  */
61
- export declare function plan(nodes: readonly PlanNode[]): PlanResult;
66
+ export declare function plan(input: readonly unknown[]): PlanResult;
package/dist/workplan.js CHANGED
@@ -27,6 +27,56 @@
27
27
  * for what it actually dispatches.
28
28
  */
29
29
  const refuse = (reason) => ({ result: 'error', reason });
30
+ /**
31
+ * `integer` as JSON Schema reads it: a number with no fractional part. `3.0` IS one under
32
+ * draft 2020-12, and by the time a wire value is a JS number `3.0` and `3` are the same
33
+ * value anyway, so the reference accepts it too (`workplan.py`, `_is_integer`) and the two
34
+ * runtimes agree. A `bigint` never reaches here from the wire (`toJs` narrows to `number`).
35
+ */
36
+ const isInteger = (value) => typeof value === 'number' && Number.isInteger(value);
37
+ /**
38
+ * The first node that contradicts `assets/tools/work_plan.json`'s item schema, by position.
39
+ *
40
+ * #127 (job65). Until this check the port's `planNodes` COERCED: a string `depends_on`
41
+ * became `[]` — so `a` was planned beside the `b` it depended on — a string `priority`
42
+ * became 0, and a numeric id was stringified until `5` and `"5"` collided. The reference
43
+ * did none of those things and none of the right ones either; see `workplan.py`. Now both
44
+ * sides check the shape BEFORE the graph is read, in input order and field order (`id`,
45
+ * `depends_on`, `priority`), and refuse the first contradiction in the `{result, reason}`
46
+ * shape the graph refusals use. The node is named by its index in `nodes`, the one name
47
+ * every node has whatever its `id` is. The four sentences are pinned per side in
48
+ * `test/workplan.test.mjs`, because a sentence both runtimes copied is invisible to the
49
+ * differential.
50
+ *
51
+ * NOT a contradiction, because the surface pinned these before the check existed: an absent
52
+ * or `null` `depends_on` is no dependencies and an absent or `null` `priority` is 0. A node
53
+ * with no `id` at all is refused here as a non-string id; on the wire it never gets this
54
+ * far, because `planNodes` reproduces the reference's `KeyError` first.
55
+ */
56
+ function readNodes(nodes) {
57
+ const read = [];
58
+ for (const [index, raw] of nodes.entries()) {
59
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
60
+ return refuse(`nodes[${index}] must be an object`);
61
+ const node = raw;
62
+ const id = node['id'];
63
+ if (typeof id !== 'string')
64
+ return refuse(`nodes[${index}].id must be a string`);
65
+ const dependsOn = node['depends_on'];
66
+ if (dependsOn != null && !(Array.isArray(dependsOn) && dependsOn.every((dep) => typeof dep === 'string'))) {
67
+ return refuse(`nodes[${index}].depends_on must be a list of strings`);
68
+ }
69
+ const priority = node['priority'];
70
+ if (priority != null && !isInteger(priority))
71
+ return refuse(`nodes[${index}].priority must be an integer`);
72
+ read.push({
73
+ id,
74
+ depends_on: dependsOn == null ? [] : dependsOn,
75
+ priority: priority == null ? 0 : priority,
76
+ });
77
+ }
78
+ return read;
79
+ }
30
80
  /**
31
81
  * Name the cycle that stopped Kahn, deterministically.
32
82
  *
@@ -68,10 +118,19 @@ function cyclePath(nodes, emitted) {
68
118
  * with nothing left to do is the answer, the same reasoning `clock_in` applies when an all-terminal
69
119
  * checkpoint reports success rather than escalating on a dangling cursor.
70
120
  *
71
- * **The three refusals are checked in a fixed order** — duplicate id, then unknown dependency, then
72
- * cycle — because a graph can carry two faults at once and both runtimes have to name the same one.
121
+ * **The four refusals are checked in a fixed order** — a node's shape, then duplicate id, then
122
+ * unknown dependency, then cycle — because a graph can carry two faults at once and both runtimes
123
+ * have to name the same one.
124
+ *
125
+ * Takes `unknown[]` rather than `PlanNode[]` on purpose: the wire hands the server whatever the
126
+ * client sent inside each node, and the check that it IS a `PlanNode` lives here, beside the
127
+ * reference's (`workplan.py` checks the same shape in the same function), not in the caller.
73
128
  */
74
- export function plan(nodes) {
129
+ export function plan(input) {
130
+ // 0 — the shape of every node, before any of it is read as a graph.
131
+ const nodes = readNodes(input);
132
+ if (!Array.isArray(nodes))
133
+ return nodes;
75
134
  // 1 — duplicate id. First in input order wins.
76
135
  const declared = new Set();
77
136
  for (const node of nodes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bantamkit-mcp",
3
- "version": "0.35.7",
3
+ "version": "0.35.9",
4
4
  "description": "Memory MCP server for Claude Code, Cursor, VS Code Copilot and Claude Desktop: per-person memory, JSON Schema validation, shift-work tools. Pure Node; install once with npx, run offline.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -60,6 +60,6 @@
60
60
  "typescript": "^5.7.2"
61
61
  },
62
62
  "dependencies": {
63
- "@modelcontextprotocol/sdk": "1.30.0"
63
+ "@modelcontextprotocol/sdk": "1.31.0"
64
64
  }
65
65
  }