memhouse 0.15.0 → 0.16.0
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/bin/memhouse.js
CHANGED
|
@@ -30,6 +30,7 @@ const {
|
|
|
30
30
|
const envfile = require(path.join(REPO_ROOT, 'memhouse', 'envfile'));
|
|
31
31
|
const { consumeSecretChunk } = require(path.join(REPO_ROOT, 'memhouse', 'secret-input'));
|
|
32
32
|
const { capabilitiesFrom } = require(path.join(REPO_ROOT, 'memhouse', 'capabilities'));
|
|
33
|
+
const { unknownFlags, allowedFlags, suggestFlag } = require(path.join(REPO_ROOT, 'memhouse', 'flags'));
|
|
33
34
|
|
|
34
35
|
const HOME_DIR = process.env.MEMHOUSE_HOME || path.join(os.homedir(), '.memhouse');
|
|
35
36
|
const ENV_FILE = path.join(HOME_DIR, 'env');
|
|
@@ -53,6 +54,22 @@ for (let i = 0; i < rest.length; i++) {
|
|
|
53
54
|
}
|
|
54
55
|
const JSON_OUT = flags.json === true;
|
|
55
56
|
|
|
57
|
+
// Unknown flags stop the run — see memhouse/flags.js for why a shrug is not enough.
|
|
58
|
+
(() => {
|
|
59
|
+
const bad = unknownFlags(cmd, flags);
|
|
60
|
+
if (!bad.length) return;
|
|
61
|
+
const allowed = allowedFlags(cmd);
|
|
62
|
+
for (const f of bad) {
|
|
63
|
+
const hint = suggestFlag(f, allowed);
|
|
64
|
+
console.error(`memhouse: unknown option --${f}${hint ? ` (did you mean --${hint}?)` : ''}`);
|
|
65
|
+
}
|
|
66
|
+
const list = [...allowed].sort().map((f) => `--${f}`).join(' ');
|
|
67
|
+
console.error(` ${cmd || 'memhouse'} takes: ${list || '(no options)'}`);
|
|
68
|
+
console.error(' Nothing ran. A flag that is ignored rather than refused is how a --dry-run typo');
|
|
69
|
+
console.error(' becomes a real migration.');
|
|
70
|
+
process.exit(2);
|
|
71
|
+
})();
|
|
72
|
+
|
|
56
73
|
let ONBOARDING = false;
|
|
57
74
|
let _inviteFileToShred = null;
|
|
58
75
|
let _inviteWantsRotate = false;
|
|
@@ -2957,6 +2974,9 @@ async function cmdWhoami() {
|
|
|
2957
2974
|
const au = process.env.MEMHOUSE_ADMIN_USER;
|
|
2958
2975
|
const ap = process.env.MEMHOUSE_ADMIN_PASSWORD;
|
|
2959
2976
|
const usingAdminEnv = wantAdmin && au;
|
|
2977
|
+
// `--admin` with nothing to resolve is worth saying out loud. Silently falling back to
|
|
2978
|
+
// the member credential makes `whoami --admin` and `whoami` print the same thing, and
|
|
2979
|
+
// the reader is left thinking they asked a question the program never heard.
|
|
2960
2980
|
const who = usingAdminEnv ? { ...cfg, user: au, password: ap || '' } : cfg;
|
|
2961
2981
|
|
|
2962
2982
|
if (!who.url || !who.user) {
|
|
@@ -2990,10 +3010,16 @@ async function cmdWhoami() {
|
|
|
2990
3010
|
console.log(JSON.stringify({
|
|
2991
3011
|
ok: true, url: who.url, user: server, db: who.db, source, role, ...caps,
|
|
2992
3012
|
grants_readable: grants.length > 0,
|
|
3013
|
+
admin_env_present: Boolean(au),
|
|
3014
|
+
admin_requested: wantAdmin,
|
|
2993
3015
|
}, null, 2));
|
|
2994
3016
|
return 0;
|
|
2995
3017
|
}
|
|
2996
3018
|
console.log(ok(`${server} at ${who.url} — ${role}`));
|
|
3019
|
+
if (wantAdmin && !usingAdminEnv) {
|
|
3020
|
+
console.log(warn('--admin asked for MEMHOUSE_ADMIN_USER / MEMHOUSE_ADMIN_PASSWORD; neither is set,'));
|
|
3021
|
+
console.log(' so this is the ordinary configured credential.');
|
|
3022
|
+
}
|
|
2997
3023
|
console.log(` credential from: ${source}`);
|
|
2998
3024
|
console.log(` house: ${who.db || '(none set)'}`);
|
|
2999
3025
|
console.log(` may create users: ${caps.canMintUsers ? 'yes' : 'no'}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mem",
|
|
3
3
|
"description": "Conversation memory for AI agents over the memhouse typed ClickHouse store: ask, search, browse, analyze, check, share, and invite across all 17 supported editors and machines, plus administration of the ClickHouse behind it. Skills install as /mem:hello, /mem:ask, /mem:search, /mem:sessions, /mem:share, /mem:invite, /mem:sql, /mem:status, /mem:users, and /mem:admin.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.16.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ramazan Polat"
|
|
7
7
|
},
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Which options each command takes, and what to say when one is not among them.
|
|
2
|
+
//
|
|
3
|
+
// Anything `--like-this` used to be accepted and ignored. That is quiet in the good case
|
|
4
|
+
// and dangerous in the bad one: `--dryrun` for `--dry-run` does not warn, it RUNS the
|
|
5
|
+
// migration; `--adopt` on a build that predates the guard is swallowed and the invite
|
|
6
|
+
// proceeds into somebody else's house. A flag the program does not know is a sentence
|
|
7
|
+
// the user believes they said and the program never heard.
|
|
8
|
+
//
|
|
9
|
+
// The tables live here rather than beside the parser so a test can hold them against the
|
|
10
|
+
// flags the CLI actually reads — a flag added to one and not the other fails the suite
|
|
11
|
+
// instead of being discovered by whoever typed it.
|
|
12
|
+
|
|
13
|
+
const GLOBAL_FLAGS = ['json', 'yes', 'help', 'version'];
|
|
14
|
+
|
|
15
|
+
const COMMAND_FLAGS = {
|
|
16
|
+
null: [], help: [], version: [],
|
|
17
|
+
whoami: ['admin'],
|
|
18
|
+
discover: [], stats: [], stop: [], doctor: [], 'sessions-query': [],
|
|
19
|
+
status: [], start: [],
|
|
20
|
+
onboard: ['url', 'user', 'password', 'db', 'port', 'no-ship', 'target', 'house-port', 'tag', 'local'],
|
|
21
|
+
install: ['url', 'user', 'password', 'db', 'port', 'no-ship', 'env', 'print-sql', 'member',
|
|
22
|
+
'member-password', 'admin-user', 'admin-password', 'ensure-schema', 'rotate-password', 'force'],
|
|
23
|
+
setup: ['url', 'user', 'password', 'db', 'port'],
|
|
24
|
+
ship: ['full', 'loop', 'ensure-schema'],
|
|
25
|
+
search: ['limit'],
|
|
26
|
+
resume: [],
|
|
27
|
+
update: ['check', 'migrate', 'no-install'],
|
|
28
|
+
reset: ['all-origins'],
|
|
29
|
+
invite: ['url', 'db', 'out', 'admin-user', 'admin-password', 'adopt', 'print-sql',
|
|
30
|
+
'allow-local', 'member-password'],
|
|
31
|
+
passwd: ['password', 'admin-user', 'admin-password', 'print-sql', 'member'],
|
|
32
|
+
nightly: ['out'],
|
|
33
|
+
migrate: ['dry-run'], 'migrate-rooms': ['dry-run'],
|
|
34
|
+
relocate: ['to', 'to-user', 'to-password', 'to-db', 'from-native-host', 'from-native-port',
|
|
35
|
+
'insecure-native', 'keep-shipper', 'dry-run'],
|
|
36
|
+
deploy: ['local', 'down', 'house-port', 'port', 'tag'],
|
|
37
|
+
service: ['interval'],
|
|
38
|
+
uninstall: ['credentials', 'full-removal'],
|
|
39
|
+
plugins: ['target'],
|
|
40
|
+
prompt: ['install'],
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Levenshtein, small and local — this is the only caller. */
|
|
44
|
+
function editDistance(a, b) {
|
|
45
|
+
const m = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)]);
|
|
46
|
+
for (let j = 0; j <= b.length; j++) m[0][j] = j;
|
|
47
|
+
for (let i = 1; i <= a.length; i++) {
|
|
48
|
+
for (let j = 1; j <= b.length; j++) {
|
|
49
|
+
m[i][j] = Math.min(m[i - 1][j] + 1, m[i][j - 1] + 1, m[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return m[a.length][b.length];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The flag a typo most likely meant, or null when nothing is close enough to guess. */
|
|
56
|
+
function suggestFlag(bad, allowed) {
|
|
57
|
+
let best = null; let bd = Infinity;
|
|
58
|
+
for (const c of allowed) { const d = editDistance(bad, c); if (d < bd) { bd = d; best = c; } }
|
|
59
|
+
return bd <= Math.max(2, Math.floor(bad.length / 3)) ? best : null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Every option this command does not take. Unknown COMMANDS return [] — dispatch owns that. */
|
|
63
|
+
function unknownFlags(cmd, flags) {
|
|
64
|
+
const known = COMMAND_FLAGS[cmd === null || cmd === undefined ? 'null' : cmd];
|
|
65
|
+
if (known === undefined) return [];
|
|
66
|
+
const allowed = allowedFlags(cmd);
|
|
67
|
+
return Object.keys(flags).filter((f) => !allowed.has(f));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The full accepted set for a command, globals included. */
|
|
71
|
+
function allowedFlags(cmd) {
|
|
72
|
+
const known = COMMAND_FLAGS[cmd === null || cmd === undefined ? 'null' : cmd] || [];
|
|
73
|
+
return new Set([...GLOBAL_FLAGS, ...known]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = { GLOBAL_FLAGS, COMMAND_FLAGS, unknownFlags, allowedFlags, suggestFlag, editDistance };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memhouse",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "memhouse \u2014 agent conversation memory across 17 editors: parse-on-client shippers, a typed ClickHouse store with one set of rooms per member, kernel-agency install, and the agentlytics dashboard",
|
|
5
5
|
"main": "bin/memhouse.js",
|
|
6
6
|
"bin": {
|