bantamkit-mcp 0.35.8 → 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.
- package/README.md +13 -2
- package/dist/assets.js +28 -4
- package/dist/cli.js +55 -24
- package/dist/eventlog.d.ts +8 -1
- package/dist/eventlog.js +7 -0
- package/dist/hookadapter.js +16 -2
- package/dist/hostinstall.d.ts +2 -2
- package/dist/hostinstall.js +69 -6
- package/dist/mcp/identity.js +27 -1
- package/dist/mcp/server.js +159 -14
- package/dist/mcp/transport.d.ts +51 -6
- package/dist/mcp/transport.js +217 -26
- package/dist/pyargparse.js +48 -2
- package/dist/tokenledger.js +20 -4
- package/dist/updatecheck.d.ts +15 -3
- package/dist/updatecheck.js +23 -8
- package/package.json +2 -2
package/dist/pyargparse.js
CHANGED
|
@@ -79,9 +79,55 @@ export class ArgumentTypeError extends Error {
|
|
|
79
79
|
* a second hand-written copy of a conversion rule is the defect this module was built from.
|
|
80
80
|
*/
|
|
81
81
|
export function pyIntStrict(text) {
|
|
82
|
-
|
|
82
|
+
// job66/#174: CPython's `int(str)`, measured on 3.12 rather than recalled. It first maps
|
|
83
|
+
// every NON-ASCII character through `_PyUnicode_TransformDecimalAndSpaceToASCII`: a Unicode
|
|
84
|
+
// decimal digit (category Nd, any script, astral included) becomes its ASCII digit and a
|
|
85
|
+
// Unicode space becomes ' '. ASCII passes through untouched, so the only ASCII whitespace
|
|
86
|
+
// the parser then skips is ` \t\n\v\f\r` — `int('3\x1c')` is a ValueError although
|
|
87
|
+
// `'\x1c'.isspace()` is true — and U+FEFF is not a space at all. Single underscores may sit
|
|
88
|
+
// BETWEEN digits only, and more than 4300 digits is a ValueError (`sys.int_info
|
|
89
|
+
// .default_max_str_digits`). WAS: `/^\s*[+-]?\d+(?:_\d+)*\s*$/` without the `u` flag —
|
|
90
|
+
// ASCII digits only, so `--k ٣` was exit 2 here and served on the reference, while JS
|
|
91
|
+
// `\s` admitted U+FEFF and refused U+0085, both the opposite of CPython.
|
|
92
|
+
let ascii = '';
|
|
93
|
+
for (const ch of text) {
|
|
94
|
+
const cp = ch.codePointAt(0);
|
|
95
|
+
if (cp < 0x80)
|
|
96
|
+
ascii += ch;
|
|
97
|
+
else if (PY_UNICODE_SPACE.has(cp))
|
|
98
|
+
ascii += ' ';
|
|
99
|
+
else if (/\p{Nd}/u.test(ch))
|
|
100
|
+
ascii += String(ndValue(cp));
|
|
101
|
+
else
|
|
102
|
+
throw new TypeError('not an int');
|
|
103
|
+
}
|
|
104
|
+
const match = /^[ \t\n\v\f\r]*([+-]?)([0-9]+(?:_[0-9]+)*)[ \t\n\v\f\r]*$/.exec(ascii);
|
|
105
|
+
if (match === null)
|
|
83
106
|
throw new TypeError('not an int');
|
|
84
|
-
|
|
107
|
+
const digits = match[2].replace(/_/g, '');
|
|
108
|
+
if (digits.length > PY_INT_MAX_STR_DIGITS)
|
|
109
|
+
throw new TypeError('not an int');
|
|
110
|
+
const value = Number(`${match[1]}${digits}`);
|
|
111
|
+
return value === 0 ? 0 : value; // `int('-0')` is 0, never JavaScript's -0
|
|
112
|
+
}
|
|
113
|
+
/** `sys.int_info.default_max_str_digits`: CPython refuses a longer decimal string. */
|
|
114
|
+
const PY_INT_MAX_STR_DIGITS = 4300;
|
|
115
|
+
/** The non-ASCII code points `str.isspace()` is true for (CPython 3.12, Unicode 15.0). */
|
|
116
|
+
const PY_UNICODE_SPACE = new Set([
|
|
117
|
+
0x85, 0xa0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008,
|
|
118
|
+
0x2009, 0x200a, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000,
|
|
119
|
+
]);
|
|
120
|
+
/**
|
|
121
|
+
* `unicodedata.decimal(ch)` for a category-Nd code point. Unicode allocates every decimal
|
|
122
|
+
* digit set as ten contiguous code points from 0 to 9, and sets that touch are back to back
|
|
123
|
+
* (the five mathematical sets at U+1D7CE), so the value is the offset from the start of the
|
|
124
|
+
* contiguous Nd run, modulo ten.
|
|
125
|
+
*/
|
|
126
|
+
function ndValue(cp) {
|
|
127
|
+
let start = cp;
|
|
128
|
+
while (start > 0 && /\p{Nd}/u.test(String.fromCodePoint(start - 1)))
|
|
129
|
+
start -= 1;
|
|
130
|
+
return (cp - start) % 10;
|
|
85
131
|
}
|
|
86
132
|
/** `_get_action_name`: the name argparse puts after `argument `. */
|
|
87
133
|
const actionName = (action) => action.optionStrings.length > 0
|
package/dist/tokenledger.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* total`), never as a comparison afterwards: a `number` past 2**53 is already rounded, so the
|
|
32
32
|
* check would be reading a value this side had got wrong.
|
|
33
33
|
*/
|
|
34
|
-
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
34
|
+
import { existsSync, lstatSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
35
35
|
import { join } from 'node:path';
|
|
36
36
|
import { BantamError } from './errors.js';
|
|
37
37
|
import { MAX_SAFE_INT, TOKEN_CLASSES, loadPriceTable, priceTokens, } from './pricing.js';
|
|
@@ -125,8 +125,21 @@ export function walk(base) {
|
|
|
125
125
|
// exactly as it is there.
|
|
126
126
|
isDirectory = false;
|
|
127
127
|
}
|
|
128
|
-
if (isDirectory)
|
|
129
|
-
|
|
128
|
+
if (isDirectory) {
|
|
129
|
+
// #151: a symlinked directory is not a transcript tree. `statSync` follows the link,
|
|
130
|
+
// so a link to a directory lands in this arm and is skipped here: neither walked nor
|
|
131
|
+
// read. Following it walked a link to an ancestor until ELOOP and counted the one
|
|
132
|
+
// transcript beneath it once per level. `skill_audit`'s rule, and the reference's.
|
|
133
|
+
let link = false;
|
|
134
|
+
try {
|
|
135
|
+
link = lstatSync(child).isSymbolicLink();
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
link = false;
|
|
139
|
+
}
|
|
140
|
+
if (!link)
|
|
141
|
+
visit(child, `${rel}/`);
|
|
142
|
+
}
|
|
130
143
|
else if (name.endsWith(TRANSCRIPT_SUFFIX))
|
|
131
144
|
found.push([child, rel]);
|
|
132
145
|
}
|
|
@@ -139,7 +152,10 @@ export function walk(base) {
|
|
|
139
152
|
* raises, which would make an unreadable transcript a counted one on this side alone.
|
|
140
153
|
*/
|
|
141
154
|
function readUtf8Strict(path) {
|
|
142
|
-
|
|
155
|
+
// `ignoreBOM: true` KEEPS a leading U+FEFF (#150). The default strips it from the first line
|
|
156
|
+
// only, where `read_text(encoding="utf-8")` keeps it and `json.loads` refuses it; kept, the
|
|
157
|
+
// line is `unparsed-line` on both sides, as a BOM on any later line already was.
|
|
158
|
+
const decoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
|
|
143
159
|
return decoder.decode(readFileSync(path));
|
|
144
160
|
}
|
|
145
161
|
function usageOf(record) {
|
package/dist/updatecheck.d.ts
CHANGED
|
@@ -30,6 +30,18 @@ export declare const UPDATE_NEVER = "update: never checked.";
|
|
|
30
30
|
* falsify the claim, the same reason `selfupdate.COMPARISON` carries both.
|
|
31
31
|
*/
|
|
32
32
|
export declare const UPDATE_AVAILABLE: string;
|
|
33
|
+
/**
|
|
34
|
+
* The command `UPDATE_AVAILABLE` tells the operator to run: THIS node, absolute (job66/#171).
|
|
35
|
+
*
|
|
36
|
+
* WAS: `` `{program} --update` ``, the bare command, which `--install` puts only in
|
|
37
|
+
* `<prefix>/node_modules/.bin` — on nobody's PATH — so the sentence answered `command not
|
|
38
|
+
* found` from a GUI-launched host's shell. `process.execPath` and this build's own `cli.js`
|
|
39
|
+
* (the sibling of this module in `dist/`), each double-quoted, need no PATH and hold a home
|
|
40
|
+
* directory with a space in it. The reference fills in `sys.executable -m bantamkit.mcpserver`
|
|
41
|
+
* instead; the TEMPLATE stays byte-identical and the filling is the `docs/porting.md` row
|
|
42
|
+
* *the update command names each runtime's own interpreter*.
|
|
43
|
+
*/
|
|
44
|
+
export declare function updateCommand(): string;
|
|
33
45
|
/** Names the date because the record may be months old. */
|
|
34
46
|
export declare const UPDATE_CURRENT = "update: {program} {installed} is current as of {date}.";
|
|
35
47
|
/**
|
|
@@ -111,8 +123,8 @@ export declare function readRecord(path?: string): Record<string, unknown> | nul
|
|
|
111
123
|
* and not only on the `current` path: a record that cannot say when it was written is not a
|
|
112
124
|
* record, and one rule is one thing for the two runtimes to reproduce instead of two.
|
|
113
125
|
*/
|
|
114
|
-
export declare function decide(installed: string, source: Source, record: Record<string, unknown> | null, key?: string): UpdateStatus;
|
|
126
|
+
export declare function decide(installed: string, source: Source, record: Record<string, unknown> | null, key?: string, command?: string): UpdateStatus;
|
|
115
127
|
/** Read the record and decide. The whole reader, in one call, for `bantamkit_status`. */
|
|
116
|
-
export declare function updateStatus(installed: string, key?: string, path?: string): UpdateStatus;
|
|
128
|
+
export declare function updateStatus(installed: string, key?: string, path?: string, command?: string): UpdateStatus;
|
|
117
129
|
/** Exactly one of the five sentences. Always a line: there is no silent state here. */
|
|
118
|
-
export declare function updateLine(installed: string, key?: string, path?: string): string;
|
|
130
|
+
export declare function updateLine(installed: string, key?: string, path?: string, command?: string): string;
|
package/dist/updatecheck.js
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* `0.10.0` is the pair that says so, and `test/updatecheck.test.mjs` both runs it and pins
|
|
36
36
|
* structurally that nothing comparator-shaped is defined here.
|
|
37
37
|
*
|
|
38
|
-
* NO NEW DEPENDENCY: `node:fs`, `node:os` and `node:
|
|
38
|
+
* NO NEW DEPENDENCY: `node:fs`, `node:os`, `node:path` and `node:url`. The `str.format` substitution the
|
|
39
39
|
* reference gets from CPython is the four lines of `fill` below — `selfupdate.ts` has the same
|
|
40
40
|
* four and cannot be imported for them, for the reason two paragraphs up.
|
|
41
41
|
*
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
import { readFileSync } from 'node:fs';
|
|
46
46
|
import { homedir } from 'node:os';
|
|
47
47
|
import { join } from 'node:path';
|
|
48
|
+
import { fileURLToPath } from 'node:url';
|
|
48
49
|
import { compareVersions } from './npminstall.js';
|
|
49
50
|
export { compareVersions };
|
|
50
51
|
/**
|
|
@@ -80,7 +81,21 @@ export const UPDATE_NEVER = 'update: never checked.';
|
|
|
80
81
|
* falsify the claim, the same reason `selfupdate.COMPARISON` carries both.
|
|
81
82
|
*/
|
|
82
83
|
export const UPDATE_AVAILABLE = 'update: {program} {installed} is running; the package index has {latest} — run ' +
|
|
83
|
-
'`{
|
|
84
|
+
'`{command}`, then reconnect the host.';
|
|
85
|
+
/**
|
|
86
|
+
* The command `UPDATE_AVAILABLE` tells the operator to run: THIS node, absolute (job66/#171).
|
|
87
|
+
*
|
|
88
|
+
* WAS: `` `{program} --update` ``, the bare command, which `--install` puts only in
|
|
89
|
+
* `<prefix>/node_modules/.bin` — on nobody's PATH — so the sentence answered `command not
|
|
90
|
+
* found` from a GUI-launched host's shell. `process.execPath` and this build's own `cli.js`
|
|
91
|
+
* (the sibling of this module in `dist/`), each double-quoted, need no PATH and hold a home
|
|
92
|
+
* directory with a space in it. The reference fills in `sys.executable -m bantamkit.mcpserver`
|
|
93
|
+
* instead; the TEMPLATE stays byte-identical and the filling is the `docs/porting.md` row
|
|
94
|
+
* *the update command names each runtime's own interpreter*.
|
|
95
|
+
*/
|
|
96
|
+
export function updateCommand() {
|
|
97
|
+
return `"${process.execPath}" "${fileURLToPath(new URL('./cli.js', import.meta.url))}" --update`;
|
|
98
|
+
}
|
|
84
99
|
/** Names the date because the record may be months old. */
|
|
85
100
|
export const UPDATE_CURRENT = 'update: {program} {installed} is current as of {date}.';
|
|
86
101
|
/**
|
|
@@ -268,7 +283,7 @@ function checkedDate(record, key) {
|
|
|
268
283
|
* and not only on the `current` path: a record that cannot say when it was written is not a
|
|
269
284
|
* record, and one rule is one thing for the two runtimes to reproduce instead of two.
|
|
270
285
|
*/
|
|
271
|
-
export function decide(installed, source, record, key = KEY) {
|
|
286
|
+
export function decide(installed, source, record, key = KEY, command = updateCommand()) {
|
|
272
287
|
if (source === SOURCE_ABSENT)
|
|
273
288
|
return { state: STATE_NEVER, line: UPDATE_NEVER };
|
|
274
289
|
if (source !== SOURCE_RECORD || record === null) {
|
|
@@ -283,7 +298,7 @@ export function decide(installed, source, record, key = KEY) {
|
|
|
283
298
|
if (order < 0) {
|
|
284
299
|
return {
|
|
285
300
|
state: STATE_AVAILABLE,
|
|
286
|
-
line: fill(UPDATE_AVAILABLE, { program: PROGRAM, installed, latest }),
|
|
301
|
+
line: fill(UPDATE_AVAILABLE, { program: PROGRAM, installed, latest, command }),
|
|
287
302
|
};
|
|
288
303
|
}
|
|
289
304
|
if (order === 0) {
|
|
@@ -298,11 +313,11 @@ export function decide(installed, source, record, key = KEY) {
|
|
|
298
313
|
};
|
|
299
314
|
}
|
|
300
315
|
/** Read the record and decide. The whole reader, in one call, for `bantamkit_status`. */
|
|
301
|
-
export function updateStatus(installed, key = KEY, path = recordPath()) {
|
|
316
|
+
export function updateStatus(installed, key = KEY, path = recordPath(), command = updateCommand()) {
|
|
302
317
|
const { source, record } = loadRecord(path);
|
|
303
|
-
return decide(installed, source, record, key);
|
|
318
|
+
return decide(installed, source, record, key, command);
|
|
304
319
|
}
|
|
305
320
|
/** Exactly one of the five sentences. Always a line: there is no silent state here. */
|
|
306
|
-
export function updateLine(installed, key = KEY, path = recordPath()) {
|
|
307
|
-
return updateStatus(installed, key, path).line;
|
|
321
|
+
export function updateLine(installed, key = KEY, path = recordPath(), command = updateCommand()) {
|
|
322
|
+
return updateStatus(installed, key, path, command).line;
|
|
308
323
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bantamkit-mcp",
|
|
3
|
-
"version": "0.35.
|
|
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.
|
|
63
|
+
"@modelcontextprotocol/sdk": "1.31.0"
|
|
64
64
|
}
|
|
65
65
|
}
|