memgineering 0.7.0 → 0.7.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/CHANGELOG.md +68 -1
- package/assets/MEMGINEERING.md +1 -1
- package/assets/memgineering-setup/SKILL.md +18 -0
- package/dist/index.js +107 -6
- package/package.json +2 -2
- package/scripts/postinstall.mjs +11 -9
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,73 @@ language the reader wants. The bilingual rule the monorepo applies to
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.7.2] — 2026-08-18
|
|
15
|
+
|
|
16
|
+
Everyone who runs this CLI is an agent, and an agent can only act on what a
|
|
17
|
+
command actually prints. Three places were telling the user's agent nothing.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Any command run before setup finishes now says so, in markdown, on stderr**
|
|
22
|
+
— what is missing, the two questions to ask, and the command to run, addressed
|
|
23
|
+
to the agent rather than to the person. The same text has been in the install
|
|
24
|
+
script all along and reached nobody: npm swallows lifecycle-script output on
|
|
25
|
+
`npm i -g`, which is the exact command the README gives. Measured — npm 11.13
|
|
26
|
+
showed it 0 times without `--foreground-scripts` and once with; npm 12 never.
|
|
27
|
+
So the CLI says it itself, where nothing can suppress it, and stops saying it
|
|
28
|
+
the moment the step is done.
|
|
29
|
+
|
|
30
|
+
It goes to stderr because stdout under `--json` is one parseable document, and
|
|
31
|
+
a preamble there would break every caller that parses it.
|
|
32
|
+
|
|
33
|
+
- **When setup has run and no brain is connected**, the same channel says that
|
|
34
|
+
instead, with `link` and `init` side by side and a note that an existing folder
|
|
35
|
+
needs no index and no frontmatter of its own — plain markdown is a brain.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- **`setup` now signs in by default**, on both the flag path and the interactive
|
|
40
|
+
one. It opens no browser: a pairing code is printed for the agent to show its
|
|
41
|
+
user, and nothing exists on the server until they approve it. `--no-login` is
|
|
42
|
+
the one flag that says "this machine only", and setup still reports which way
|
|
43
|
+
it went.
|
|
44
|
+
|
|
45
|
+
The old default skipped the account unless asked, to avoid sending anyone to a
|
|
46
|
+
consent screen they had not chosen. Separating the account from the browser
|
|
47
|
+
keeps that, and drops what it cost: an install that never mentioned accounts,
|
|
48
|
+
and a user who discovered weeks later that their memory did not follow them.
|
|
49
|
+
|
|
50
|
+
### Agent guidance
|
|
51
|
+
|
|
52
|
+
- `memgineering-setup` now covers the sign-in default, what the pairing code
|
|
53
|
+
means, and the two ways to hand setup to someone who would rather do it
|
|
54
|
+
themselves (`--human` in your terminal, `--web` in their browser). **Restart
|
|
55
|
+
your agent session after upgrading** so the updated guidance loads.
|
|
56
|
+
|
|
57
|
+
## [0.7.1] — 2026-08-17
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- **The semantic-search figures 0.7.0 quoted were measured on the set it was
|
|
62
|
+
tuned against.** An independent set of 70 questions — written by someone
|
|
63
|
+
reading only the notes and never a search result, with the expected note fixed
|
|
64
|
+
from what they had just read — scores lower on the same brain and the same
|
|
65
|
+
server: the right note is in the top five for **72.9%** of them and ranked
|
|
66
|
+
first for **45.7%**, and for a question asked across a language, **61.1%** and
|
|
67
|
+
**33.3%**. Text search alone scores 47.1% / 35.7% overall and 5.6% / 0% across
|
|
68
|
+
a language on that set, so meaning still moves every category it touches, and
|
|
69
|
+
cross-language remains the largest move either set shows. Both sets are real
|
|
70
|
+
measurements; only the tuned one had been reported. Expect the lower pair from
|
|
71
|
+
a question nobody tuned for.
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- `recall --help` no longer offers `--detail summary`, `chunks`, and `full` as
|
|
76
|
+
though a hosted brain could answer them. It now says which two levels a hosted
|
|
77
|
+
brain does answer, and points at a brain in a folder or `open <handle>` for the
|
|
78
|
+
deeper ones. The refusal was already correct; the help text described a
|
|
79
|
+
different product.
|
|
80
|
+
|
|
14
81
|
## [0.7.0] — 2026-08-16
|
|
15
82
|
|
|
16
83
|
Recall reads what a note says, not only what it is called. And the pile of
|
|
@@ -181,6 +248,7 @@ that goes one approved change at a time.
|
|
|
181
248
|
the shape of its answers without changing its name.
|
|
182
249
|
|
|
183
250
|
### Fixed
|
|
251
|
+
|
|
184
252
|
- **`push` now reports the notes it never sent.** A note held back by the name
|
|
185
253
|
deny list or by an ignore rule was dropped before the upload and appeared in
|
|
186
254
|
no summary — a 277-note brain reported `276 note(s) uploaded` and said nothing
|
|
@@ -205,7 +273,6 @@ that goes one approved change at a time.
|
|
|
205
273
|
held each note, instead of pointing at `memgineering reindex` — which reports
|
|
206
274
|
the name and content screens and says nothing about an ignore rule.
|
|
207
275
|
|
|
208
|
-
|
|
209
276
|
- **A `supersedes:` written as a single value is no longer ignored.**
|
|
210
277
|
`supersedes: mem-abc` is what somebody writes when one memory replaces one
|
|
211
278
|
other, and it parsed to nothing at all — no relation, no complaint, no way to
|
package/assets/MEMGINEERING.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: memgineering
|
|
3
3
|
description: Use whenever the user refers to something they told you before, asks what was decided, tells you something worth keeping, or settles something that should hold next time. The memory lives in their own folder and outlives this session; check it before answering from guesswork, and write to it when you learn something durable.
|
|
4
4
|
type: skill
|
|
5
|
-
version: 0.7.
|
|
5
|
+
version: 0.7.2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# memgineering
|
|
@@ -38,6 +38,24 @@ memgineering setup --agent \
|
|
|
38
38
|
|
|
39
39
|
`--dry-run` reports what would change without changing it.
|
|
40
40
|
|
|
41
|
+
**The account is the default, and the browser is not.** `setup --agent` starts a
|
|
42
|
+
sign-in on its own: it prints a short pairing code and returns immediately,
|
|
43
|
+
opening nothing. Show the user the code — they approve it in their browser while
|
|
44
|
+
you keep working, and the next command picks the token up. Nothing exists on the
|
|
45
|
+
server until they approve.
|
|
46
|
+
|
|
47
|
+
`--no-login` is how someone says "this machine only". Offer it, do not assume it:
|
|
48
|
+
a brain that lives in a folder here cannot follow them to their phone or their
|
|
49
|
+
next laptop, and that is discovered weeks later, by which time the notes are in
|
|
50
|
+
the wrong place. Ask which they want in one sentence before you run anything.
|
|
51
|
+
|
|
52
|
+
**If they would rather set it up themselves**, hand them a screen instead of
|
|
53
|
+
doing it: `setup --human` draws a checkbox list in your terminal, and
|
|
54
|
+
`setup --web` opens a page in their own browser (`--web --print-url` when you
|
|
55
|
+
cannot open one for them). Both ask the same questions `--agent` takes from
|
|
56
|
+
flags, and `--web` is the one to reach for when the user is not reading your
|
|
57
|
+
terminal at all.
|
|
58
|
+
|
|
41
59
|
**Ask before setting policy for them.** Auto-update means the tool updates
|
|
42
60
|
itself; `--hook on` means note summaries and their standing rules reach an agent
|
|
43
61
|
unasked. Recommend both, but they are theirs to decide.
|
package/dist/index.js
CHANGED
|
@@ -4962,17 +4962,35 @@ async function runSignInStep(opts) {
|
|
|
4962
4962
|
if (summary.pendingUserCode) return { status: "pending", userCode: summary.pendingUserCode };
|
|
4963
4963
|
if (opts.login === false) return { status: "skipped" };
|
|
4964
4964
|
if (opts.dryRun) {
|
|
4965
|
-
|
|
4966
|
-
|
|
4965
|
+
return { status: "would-start" };
|
|
4966
|
+
}
|
|
4967
|
+
if (!opts.interactive && opts.login === void 0) {
|
|
4968
|
+
try {
|
|
4969
|
+
const { pending, opened } = await beginSignIn({ browser: false });
|
|
4970
|
+
return {
|
|
4971
|
+
status: "started",
|
|
4972
|
+
userCode: pending.user_code,
|
|
4973
|
+
verificationUrl: pending.verification_url,
|
|
4974
|
+
opened
|
|
4975
|
+
};
|
|
4976
|
+
} catch (err) {
|
|
4977
|
+
return {
|
|
4978
|
+
status: "unavailable",
|
|
4979
|
+
because: err instanceof MemgError ? err.message : String(err)
|
|
4980
|
+
};
|
|
4981
|
+
}
|
|
4967
4982
|
}
|
|
4968
|
-
if (!opts.interactive && opts.login !== true) return { status: "skipped" };
|
|
4969
4983
|
if (opts.interactive) {
|
|
4970
4984
|
printHuman(c.bold("\nmemgineering \u2014 setup\n"));
|
|
4971
4985
|
const { wants } = await prompts2({
|
|
4972
4986
|
type: "toggle",
|
|
4973
4987
|
name: "wants",
|
|
4974
4988
|
message: "Sign in to a memgineering account first?",
|
|
4975
|
-
|
|
4989
|
+
// Default yes, to match the non-interactive path. Someone at a prompt can
|
|
4990
|
+
// see both answers and press either; the default is which one costs them
|
|
4991
|
+
// nothing to accept, and syncing is the one they cannot add retroactively
|
|
4992
|
+
// to notes they have already written somewhere else.
|
|
4993
|
+
initial: true,
|
|
4976
4994
|
active: "sign in",
|
|
4977
4995
|
inactive: "later"
|
|
4978
4996
|
});
|
|
@@ -12424,7 +12442,10 @@ init_errors();
|
|
|
12424
12442
|
init_vault();
|
|
12425
12443
|
init_ui();
|
|
12426
12444
|
function recallCommand() {
|
|
12427
|
-
return new Command18("recall").description("recall memory cards for a question").argument("<query>", "what you want to remember").option("--vault <path>", "which brain to search").option("--local", "search the brain on this machine, even when signed in to a hosted one").option("--scope <scope>", "restrict to one scope").option("--limit <n>", "max cards", (v) => parseInt(v, 10), 8).option(
|
|
12445
|
+
return new Command18("recall").description("recall memory cards for a question").argument("<query>", "what you want to remember").option("--vault <path>", "which brain to search").option("--local", "search the brain on this machine, even when signed in to a hosted one").option("--scope <scope>", "restrict to one scope").option("--limit <n>", "max cards", (v) => parseInt(v, 10), 8).option(
|
|
12446
|
+
"--detail <level>",
|
|
12447
|
+
"title | card | summary | chunks | full (default: card) \u2014 a hosted brain answers title and card only; deeper needs a brain in a folder, or `open <handle>`"
|
|
12448
|
+
).option("--depth <depth>", "exact | standard (default: standard, which also searches bodies)").option("--budget <tokens>", "max estimated size of the answer", (v) => parseInt(v, 10)).action(
|
|
12428
12449
|
async (query, opts) => {
|
|
12429
12450
|
const detail = parseDetail(opts.detail, "card");
|
|
12430
12451
|
const depth = parseDepth(opts.depth);
|
|
@@ -14083,13 +14104,83 @@ function whoamiCommand() {
|
|
|
14083
14104
|
});
|
|
14084
14105
|
}
|
|
14085
14106
|
|
|
14107
|
+
// src/lib/next-step.ts
|
|
14108
|
+
init_config();
|
|
14109
|
+
function isSetUp(cfg) {
|
|
14110
|
+
return Object.keys(cfg.system.installed).length > 0;
|
|
14111
|
+
}
|
|
14112
|
+
var FINISH_SETUP = `## memgineering is installed. It is NOT set up yet.
|
|
14113
|
+
|
|
14114
|
+
**TO THE AGENT READING THIS** \u2014 finish it now, in this same turn. Do not print
|
|
14115
|
+
these commands for your user and stop: they are yours to run.
|
|
14116
|
+
|
|
14117
|
+
Ask them TWO short questions, in their language, then run setup yourself.
|
|
14118
|
+
|
|
14119
|
+
1. **Where should the memory live?**
|
|
14120
|
+
"Just on this machine, or synced to an account so every device and every
|
|
14121
|
+
tool you use sees the same brain?"
|
|
14122
|
+
|
|
14123
|
+
- this machine \u2192 add \`--no-login\`
|
|
14124
|
+
- synced (default) \u2192 no extra flag
|
|
14125
|
+
|
|
14126
|
+
2. **Who picks the rest of the settings?**
|
|
14127
|
+
"Shall I set it up, or would you rather choose on a screen?"
|
|
14128
|
+
|
|
14129
|
+
- you do it \u2192 \`memgineering setup --agent\`
|
|
14130
|
+
- they choose \u2192 \`memgineering setup --web\`
|
|
14131
|
+
|
|
14132
|
+
\`\`\`bash
|
|
14133
|
+
memgineering setup --agent # synced, you answer the rest
|
|
14134
|
+
memgineering setup --agent --no-login # this machine only
|
|
14135
|
+
memgineering setup --web # they answer on a screen
|
|
14136
|
+
\`\`\`
|
|
14137
|
+
|
|
14138
|
+
Signing in prints a short code \u2014 show it to them and they approve it in the
|
|
14139
|
+
browser. Setup does not wait, and the next command collects the token, so you
|
|
14140
|
+
keep going in the same turn.
|
|
14141
|
+
|
|
14142
|
+
Then read \`memgineering-setup\` for what to do with the brain it points at.`;
|
|
14143
|
+
var CONNECT_A_BRAIN = `## memgineering is set up, and no brain is connected.
|
|
14144
|
+
|
|
14145
|
+
**TO THE AGENT READING THIS** \u2014 a brain is a folder of markdown notes. Until one
|
|
14146
|
+
is connected there is nothing to recall and nowhere to remember. Pick with your
|
|
14147
|
+
user, then run it yourself:
|
|
14148
|
+
|
|
14149
|
+
\`\`\`bash
|
|
14150
|
+
memgineering link <their-notes-folder> # they already keep notes
|
|
14151
|
+
memgineering init <path> # they do not \u2014 creates one, laid out
|
|
14152
|
+
\`\`\`
|
|
14153
|
+
|
|
14154
|
+
\`link\` reports what would be stored before anything is indexed. An existing
|
|
14155
|
+
folder needs no index and no frontmatter of its own \u2014 plain markdown is a brain.
|
|
14156
|
+
|
|
14157
|
+
Then run \`memgineering onboard\`: it prints what to ask so the brain knows whose
|
|
14158
|
+
it is. A brain whose \`01_BASE/\` is still template text answers almost nothing.
|
|
14159
|
+
|
|
14160
|
+
Read \`memgineering-setup\` for accounts and which of their tools this reaches.`;
|
|
14161
|
+
function nextStepFor(cfg) {
|
|
14162
|
+
if (!isSetUp(cfg)) return { id: "finish_setup", markdown: FINISH_SETUP };
|
|
14163
|
+
if (cfg.brain.brains.length === 0 && cfg.brain.cloud === void 0) {
|
|
14164
|
+
return { id: "connect_a_brain", markdown: CONNECT_A_BRAIN };
|
|
14165
|
+
}
|
|
14166
|
+
return null;
|
|
14167
|
+
}
|
|
14168
|
+
async function currentNextStep() {
|
|
14169
|
+
try {
|
|
14170
|
+
return nextStepFor(await loadConfig());
|
|
14171
|
+
} catch {
|
|
14172
|
+
return null;
|
|
14173
|
+
}
|
|
14174
|
+
}
|
|
14175
|
+
|
|
14086
14176
|
// src/program.ts
|
|
14087
14177
|
init_ui();
|
|
14088
14178
|
init_brand();
|
|
14089
14179
|
function buildProgram() {
|
|
14090
|
-
const program = new Command27("memgineering").version(VERSION).description("memgineering \u2014 one memory for the AI you connect").option("--json", "emit JSON to stdout instead of markdown", false).hook("preAction", (thisCommand) => {
|
|
14180
|
+
const program = new Command27("memgineering").version(VERSION).description("memgineering \u2014 one memory for the AI you connect").option("--json", "emit JSON to stdout instead of markdown", false).hook("preAction", async (thisCommand, actionCommand) => {
|
|
14091
14181
|
const opts = thisCommand.optsWithGlobals();
|
|
14092
14182
|
if (opts.json || process.env[BRAND.jsonEnvVar] === "1") setJsonMode(true);
|
|
14183
|
+
await announceNextStep(actionCommand.name());
|
|
14093
14184
|
});
|
|
14094
14185
|
configureGroupedHelp(program);
|
|
14095
14186
|
program.addCommand(recallCommand());
|
|
@@ -14126,6 +14217,16 @@ function buildProgram() {
|
|
|
14126
14217
|
makeParseErrorsActionable(program);
|
|
14127
14218
|
return program;
|
|
14128
14219
|
}
|
|
14220
|
+
var WITHOUT_NEXT_STEP = /* @__PURE__ */ new Set(["setup", "login", "logout", "whoami", "update", "guard"]);
|
|
14221
|
+
async function announceNextStep(commandName) {
|
|
14222
|
+
if (WITHOUT_NEXT_STEP.has(commandName)) return;
|
|
14223
|
+
const step = await currentNextStep();
|
|
14224
|
+
if (step === null) return;
|
|
14225
|
+
process.stderr.write(`
|
|
14226
|
+
${step.markdown}
|
|
14227
|
+
|
|
14228
|
+
`);
|
|
14229
|
+
}
|
|
14129
14230
|
function makeParseErrorsActionable(program) {
|
|
14130
14231
|
const decorate = (cmd) => {
|
|
14131
14232
|
cmd.showSuggestionAfterError(true);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memgineering",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "One memory for the AI you connect. Recall, remember, and revise a brain your agents share
|
|
5
|
+
"description": "One memory for the AI you connect. Recall, remember, and revise a brain your agents share — stored in your own folder.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"homepage": "https://memgineering.com",
|
|
8
8
|
"repository": {
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -42,8 +42,8 @@ if (process.env['npm_config_global'] === 'true') {
|
|
|
42
42
|
' "Just on this machine, or synced to an account so every device',
|
|
43
43
|
' and every tool you use sees the same brain?"',
|
|
44
44
|
'',
|
|
45
|
-
' this machine -> no
|
|
46
|
-
' synced ->
|
|
45
|
+
' this machine -> add --no-login',
|
|
46
|
+
' synced -> no extra flag, this is the default',
|
|
47
47
|
'',
|
|
48
48
|
' 2. Who picks the rest of the settings?',
|
|
49
49
|
' "Shall I set it up, or would you rather choose on a screen?"',
|
|
@@ -51,14 +51,16 @@ if (process.env['npm_config_global'] === 'true') {
|
|
|
51
51
|
' you do it -> memgineering setup --agent',
|
|
52
52
|
' they choose -> memgineering setup --web',
|
|
53
53
|
'',
|
|
54
|
-
'So: `memgineering setup --agent
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
54
|
+
'So: `memgineering setup --agent`, or `--agent --no-login`, or `--web`.',
|
|
55
|
+
'Question 1 matters most — WITH `--no-login`, setup makes a folder on this',
|
|
56
|
+
'machine and never mentions accounts again, and the user finds out later',
|
|
57
|
+
'that their memory does not follow them.',
|
|
58
58
|
'',
|
|
59
|
-
'
|
|
60
|
-
'the browser. Setup does not wait, and the next
|
|
61
|
-
'token, so you keep going in the same turn.',
|
|
59
|
+
'The default prints a short code and opens nothing: show the code to them',
|
|
60
|
+
'and they approve it in the browser. Setup does not wait, and the next',
|
|
61
|
+
'command collects the token, so you keep going in the same turn.',
|
|
62
|
+
'',
|
|
63
|
+
'Then read the `memgineering-setup` skill for what to do with the brain.',
|
|
62
64
|
'',
|
|
63
65
|
].join('\n'),
|
|
64
66
|
);
|