backstep 0.1.32 → 0.1.33
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/CHANGES.json +41 -0
- package/README.md +1 -1
- package/dist/cli.js +16 -1
- package/dist/update.js +11 -1
- package/mod/.claude-plugin/plugin.json +1 -1
- package/mod/hooks/register.test.tsx +4 -0
- package/mod/hooks/register.tsx +20 -3
- package/package.json +3 -2
package/CHANGES.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.1.33",
|
|
4
|
+
"notes": [
|
|
5
|
+
"After an update, Backstep shows what's new, like this."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.1.32",
|
|
10
|
+
"notes": [
|
|
11
|
+
"Undoing a Notion change in auto mode now finishes properly when Claude makes the last step.",
|
|
12
|
+
"Opening a page, file or app is no longer listed as something that couldn't be undone.",
|
|
13
|
+
"When something can't be undone, Backstep says why in plain words."
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"version": "0.1.31",
|
|
18
|
+
"notes": [
|
|
19
|
+
"In auto mode, Notion undos are finished by Claude straight away, with no extra question and no red error."
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"version": "0.1.30",
|
|
24
|
+
"notes": [
|
|
25
|
+
"Updates now say when they're done and it's safe to close the terminal.",
|
|
26
|
+
"Notion undos work in auto mode."
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"version": "0.1.29",
|
|
31
|
+
"notes": [
|
|
32
|
+
"If you edited a file after Claude's turn, undo asks before taking your changes along. Keep my changes undoes only Claude's."
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"version": "0.1.28",
|
|
37
|
+
"notes": [
|
|
38
|
+
"Updates install the new version even when Claude Code is open in a project named backstep."
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
]
|
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ The undo key is ctrl+u (not ctrl+z: Claude Code suspends itself on ctrl+z in a t
|
|
|
70
70
|
|
|
71
71
|
In the Claude Code desktop app, keys don't reach Backstep, so the line above the message box has an **Undo last turn** button to click instead (it asks once, then undoes). Typing `/backstep-undo` works everywhere and undoes straight away.
|
|
72
72
|
|
|
73
|
-
Backstep checks npm for a newer version as each Claude Code session starts and asks before updating (Update, Not now, or Skip this version; `backstep update` does it by hand, `BACKSTEP_UPDATE_CHECK=0` turns the check off).
|
|
73
|
+
Backstep checks npm for a newer version as each Claude Code session starts and asks before updating (Update, Not now, or Skip this version; `backstep update` does it by hand, `BACKSTEP_UPDATE_CHECK=0` turns the check off). Once an update is in place, Backstep says what's new, from `CHANGES.json`.
|
|
74
74
|
|
|
75
75
|
Other commands: `backstep ui`, `backstep log`, `backstep undo <action-id>`, `backstep undo --run <run-id>`, `backstep connect [supabase|firebase]` (connects what the project uses, the same as asking Claude), `backstep disconnect supabase <ref>`.
|
|
76
76
|
|
package/dist/cli.js
CHANGED
|
@@ -57,7 +57,7 @@ import { connect } from "./connect.js";
|
|
|
57
57
|
import { check, printCheck } from "./check.js";
|
|
58
58
|
import { logo } from "./look.js";
|
|
59
59
|
import { keyLabel, setUndoKey, undoKeys } from "./keys.js";
|
|
60
|
-
import { checkUpdate, runUpdate, skipVersion } from "./update.js";
|
|
60
|
+
import { changesSince, checkUpdate, runUpdate, skipVersion } from "./update.js";
|
|
61
61
|
import { askConnectionString } from "./setup.js";
|
|
62
62
|
// Header values can name env vars, so tokens don't have to sit in agent config files.
|
|
63
63
|
function parseHeaders(list) {
|
|
@@ -124,6 +124,8 @@ const HELP = `backstep: undo for everything your agents touch
|
|
|
124
124
|
backstep undo --since <ms> [--until <ms>] [--json] [--via-claude-code] [--manual ask|undo|keep]
|
|
125
125
|
undo everything any agent did in that window; files changed since
|
|
126
126
|
(often by hand) are undone too, kept, or named first with ask
|
|
127
|
+
backstep changes --since <version> [--json]
|
|
128
|
+
what's new since that version
|
|
127
129
|
backstep after <action-id> note how a tool left the files, once it ran (used by the Claude Code mod)
|
|
128
130
|
backstep snap --session <id> --tool <name> [--cwd <dir>] -- <paths...>
|
|
129
131
|
save paths before Claude Code's own tools change them (used by the Claude Code mod)
|
|
@@ -340,6 +342,19 @@ async function main() {
|
|
|
340
342
|
return;
|
|
341
343
|
}
|
|
342
344
|
// `backstep update` installs the newest version; --skip <v> stops asking about that one.
|
|
345
|
+
// What's new since a version, for the mod to show once an update is in place.
|
|
346
|
+
if (cmd === "changes") {
|
|
347
|
+
const { values } = parseArgs({ args: rest, options: { since: { type: "string" }, json: { type: "boolean", default: false } } });
|
|
348
|
+
if (!values.since)
|
|
349
|
+
throw new Error("usage: backstep changes --since <version> [--json]");
|
|
350
|
+
const list = changesSince(values.since);
|
|
351
|
+
if (values.json)
|
|
352
|
+
console.log(JSON.stringify(list));
|
|
353
|
+
else
|
|
354
|
+
for (const c of list)
|
|
355
|
+
console.log(`${c.version}\n${c.notes.map((n) => ` - ${n}`).join("\n")}`);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
343
358
|
if (cmd === "update") {
|
|
344
359
|
const { values } = parseArgs({ args: rest, options: { skip: { type: "string" }, version: { type: "string" }, json: { type: "boolean", default: false } } });
|
|
345
360
|
if (values.skip) {
|
package/dist/update.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// Off with BACKSTEP_UPDATE_CHECK=0.
|
|
5
5
|
import { spawnSync } from "./spawn.js";
|
|
6
6
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { join } from "node:path";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
8
9
|
import { tmpdir } from "node:os";
|
|
9
10
|
import { homeDir } from "./store.js";
|
|
10
11
|
import { version } from "./telemetry.js";
|
|
@@ -48,6 +49,15 @@ export async function checkUpdate() {
|
|
|
48
49
|
const available = latest !== null && newer(latest, current) && settings().skipVersion !== latest;
|
|
49
50
|
return { current, latest, available };
|
|
50
51
|
}
|
|
52
|
+
export function changesSince(from, upTo = version()) {
|
|
53
|
+
try {
|
|
54
|
+
const all = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), "..", "CHANGES.json"), "utf8"));
|
|
55
|
+
return all.filter((c) => newer(c.version, from) && !newer(c.version, upTo)).sort((a, b) => (newer(a.version, b.version) ? -1 : 1));
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
51
61
|
export function skipVersion(v) {
|
|
52
62
|
mkdirSync(homeDir(), { recursive: true });
|
|
53
63
|
writeFileSync(file(), JSON.stringify({ ...settings(), skipVersion: v }, null, 2) + "\n");
|
|
@@ -1277,6 +1277,8 @@ test('an update that reloads the mod partway is finished by the reloaded mod: it
|
|
|
1277
1277
|
}
|
|
1278
1278
|
const stdout = argv.includes('update-check')
|
|
1279
1279
|
? JSON.stringify({ current: started ? '0.2.0' : '0.1.2', latest: '0.2.0', available: !started })
|
|
1280
|
+
: argv.includes('changes')
|
|
1281
|
+
? JSON.stringify(argv.includes('0.1.2') ? [{ version: '0.2.0', notes: ['Undo is faster.', 'Notion undos finish in auto mode.'] }] : [])
|
|
1280
1282
|
: argv.includes('status')
|
|
1281
1283
|
? JSON.stringify({ items: [], suggest: [] })
|
|
1282
1284
|
: '[]'
|
|
@@ -1320,6 +1322,8 @@ test('an update that reloads the mod partway is finished by the reloaded mod: it
|
|
|
1320
1322
|
}
|
|
1321
1323
|
expect(statuses.at(-1)).toBeUndefined()
|
|
1322
1324
|
expect(logs.join('\n')).toContain('Backstep is updated to 0.2.0 (you had 0.1.2). It\'s safe to close this terminal now.')
|
|
1325
|
+
// Then what changed, from the new version's own notes.
|
|
1326
|
+
expect(logs.join('\n')).toContain("What's new in 0.2.0:\n • Undo is faster.\n • Notion undos finish in auto mode.")
|
|
1323
1327
|
await ui.unmount()
|
|
1324
1328
|
})
|
|
1325
1329
|
|
package/mod/hooks/register.tsx
CHANGED
|
@@ -905,9 +905,26 @@ async function offerUpdate($: EngineInterface) {
|
|
|
905
905
|
await installUpdate($, u.current, u.latest)
|
|
906
906
|
}
|
|
907
907
|
|
|
908
|
-
function updated($: EngineInterface, u: Updating) {
|
|
908
|
+
async function updated($: EngineInterface, u: Updating) {
|
|
909
909
|
$.ui.log(`${MARK_TEXT} Backstep is updated to ${u.to}${u.from ? ` (you had ${u.from})` : ''}. It's safe to close ${u.win} now. Restart Claude Code to start using ${u.to}.`)
|
|
910
910
|
$.ui.toast(`Backstep is updated to ${u.to}. Restart Claude Code to use it.`)
|
|
911
|
+
if (u.from) await whatsNew($, u.from)
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// What changed since the version before, from the new version's own notes.
|
|
915
|
+
async function whatsNew($: EngineInterface, from: string) {
|
|
916
|
+
const ran = await $.process.run(backstep(['changes', '--since', from, '--json']), { timeoutMs: 15_000 }).catch(() => null)
|
|
917
|
+
let list: { version: string; notes: string[] }[] = []
|
|
918
|
+
try {
|
|
919
|
+
list = JSON.parse(ran?.stdout || '[]') as typeof list
|
|
920
|
+
} catch {
|
|
921
|
+
return
|
|
922
|
+
}
|
|
923
|
+
list = list.filter((c) => c.notes?.length)
|
|
924
|
+
if (!list.length) return
|
|
925
|
+
const one = list.length === 1
|
|
926
|
+
const lines = one ? list[0].notes.map((n) => ` • ${n}`) : list.flatMap((c) => [` ${c.version}`, ...c.notes.map((n) => ` • ${n}`)])
|
|
927
|
+
$.ui.log([`${MARK_TEXT} What's new${one ? ` in ${list[0].version}` : ` since ${from}`}:`, ...lines].join('\n'))
|
|
911
928
|
}
|
|
912
929
|
|
|
913
930
|
// After a reload in the middle of an update: once the new version is in place,
|
|
@@ -929,7 +946,7 @@ async function finishUpdate($: EngineInterface) {
|
|
|
929
946
|
await $.clock.sleep(5000)
|
|
930
947
|
$.ui.status(undefined)
|
|
931
948
|
await update($, updating, () => null)
|
|
932
|
-
updated($, u)
|
|
949
|
+
await updated($, u)
|
|
933
950
|
return
|
|
934
951
|
}
|
|
935
952
|
await $.clock.sleep(5000)
|
|
@@ -961,7 +978,7 @@ async function installUpdate($: EngineInterface, current: string | undefined, la
|
|
|
961
978
|
$.ui.status(undefined)
|
|
962
979
|
await update($, updating, () => null)
|
|
963
980
|
if (r.ok) {
|
|
964
|
-
updated($, { ...(u.current ? { from: u.current } : {}), to: latest, win })
|
|
981
|
+
await updated($, { ...(u.current ? { from: u.current } : {}), to: latest, win })
|
|
965
982
|
return true
|
|
966
983
|
} else {
|
|
967
984
|
$.ui.log(`${MARK_TEXT} Backstep couldn't update to ${u.latest}: ${r.detail}. You're still on ${u.current ?? 'the version you had'}${forced ? '' : ', which keeps working'}. To try again, run: npx backstep@latest setup`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backstep",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33",
|
|
4
4
|
"description": "Undo for everything your agents touch: an MCP proxy that makes agent actions reversible.",
|
|
5
5
|
"homepage": "https://getbackstep.com",
|
|
6
6
|
"scripts": {
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"files": [
|
|
38
38
|
"dist",
|
|
39
39
|
"mod",
|
|
40
|
-
"README.md"
|
|
40
|
+
"README.md",
|
|
41
|
+
"CHANGES.json"
|
|
41
42
|
],
|
|
42
43
|
"keywords": [
|
|
43
44
|
"mcp",
|