backstep 0.1.24 → 0.1.25
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/dist/cli.js +9 -2
- package/dist/setup.js +23 -4
- package/mod/.claude-plugin/plugin.json +1 -1
- package/mod/hooks/register.test.tsx +18 -4
- package/mod/hooks/register.tsx +13 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ import { snapshotRest } from "./adapters/rest.js";
|
|
|
17
17
|
const PUSH = /\bgit\b[^;&|]*\bpush\b/;
|
|
18
18
|
import { classifyShell, commandDir, supabaseTarget, touchesDatabase, touchesFirebase, touchesSqlite, touchesSupabase } from "./shell.js";
|
|
19
19
|
import { watchEnd, watchStart } from "./watch.js";
|
|
20
|
-
import { sendActive } from "./telemetry.js";
|
|
20
|
+
import { sendActive, version } from "./telemetry.js";
|
|
21
21
|
import { readFileSync, rmSync } from "node:fs";
|
|
22
22
|
import { loadRules } from "./rules.js";
|
|
23
23
|
import { setup } from "./setup.js";
|
|
@@ -315,8 +315,15 @@ async function main() {
|
|
|
315
315
|
const target = values.version ?? (await checkUpdate()).latest;
|
|
316
316
|
if (!target)
|
|
317
317
|
throw new Error("couldn't reach npm to find the newest version");
|
|
318
|
+
const was = version();
|
|
319
|
+
if (!values.json)
|
|
320
|
+
console.log(`Updating Backstep from ${was} to ${target}… Don't close this terminal until it says it's done (about a minute).`);
|
|
318
321
|
const out = runUpdate(target);
|
|
319
|
-
console.log(values.json
|
|
322
|
+
console.log(values.json
|
|
323
|
+
? JSON.stringify(out)
|
|
324
|
+
: out.ok
|
|
325
|
+
? `Backstep is updated to ${target} (you had ${was}). It's safe to close the terminal now. Restart Claude Code to start using ${target}.`
|
|
326
|
+
: `Backstep couldn't update to ${target}: ${out.detail}. You're still on ${was}, which keeps working.`);
|
|
320
327
|
if (!out.ok)
|
|
321
328
|
process.exitCode = 1;
|
|
322
329
|
return;
|
package/dist/setup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from "./spawn.js";
|
|
2
|
-
import { cpSync, readFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { cpSync, existsSync, readFileSync, renameSync, rmSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { homeDir } from "./store.js";
|
|
@@ -24,9 +24,28 @@ function keepCopy() {
|
|
|
24
24
|
if (run("npm", ["install", "-g", `backstep@${version}`]).ok) {
|
|
25
25
|
return { root: join(run("npm", ["root", "-g"]).out, "backstep"), onPath: true };
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
// The new copy is made beside the old one, then swapped in: closing the
|
|
28
|
+
// terminal partway through leaves the old copy whole and working.
|
|
29
|
+
const app = join(homeDir(), "app");
|
|
30
|
+
const modules = join(app, "node_modules");
|
|
31
|
+
const fresh = join(app, "node_modules.new");
|
|
32
|
+
const old = join(app, "node_modules.old");
|
|
33
|
+
rmSync(fresh, { recursive: true, force: true });
|
|
34
|
+
cpSync(dirname(ROOT), fresh, { recursive: true });
|
|
35
|
+
rmSync(old, { recursive: true, force: true });
|
|
36
|
+
try {
|
|
37
|
+
if (existsSync(modules))
|
|
38
|
+
renameSync(modules, old);
|
|
39
|
+
renameSync(fresh, modules);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// A file still open (Windows won't move it): copy over the old copy where it is instead.
|
|
43
|
+
if (!existsSync(modules) && existsSync(old))
|
|
44
|
+
renameSync(old, modules);
|
|
45
|
+
cpSync(fresh, modules, { recursive: true, force: true });
|
|
46
|
+
}
|
|
47
|
+
rmSync(fresh, { recursive: true, force: true });
|
|
48
|
+
rmSync(old, { recursive: true, force: true });
|
|
30
49
|
return { root: join(modules, "backstep"), onPath: false };
|
|
31
50
|
}
|
|
32
51
|
const WHERE = `In Supabase, open your project, press Connect at the top, and copy the URI under
|
|
@@ -589,7 +589,16 @@ function updates(on: On, answer: string) {
|
|
|
589
589
|
toasts.push(e.text)
|
|
590
590
|
return { value: undefined }
|
|
591
591
|
})
|
|
592
|
-
|
|
592
|
+
const logs: string[] = []
|
|
593
|
+
const statuses: (string | undefined)[] = []
|
|
594
|
+
on('ui.log', (_, e) => {
|
|
595
|
+
logs.push(e.text)
|
|
596
|
+
return { value: undefined }
|
|
597
|
+
})
|
|
598
|
+
on('ui.status', (_, e) => {
|
|
599
|
+
statuses.push(e.text)
|
|
600
|
+
return { value: undefined }
|
|
601
|
+
})
|
|
593
602
|
on('tool.register', (_, e) => ({ value: { tool: `mcp__backstep__${e.name}` } }))
|
|
594
603
|
on('tool.call', { tool: 'AskUserQuestion' }, (_, e) => {
|
|
595
604
|
const questions = (e as unknown as { questions: { question: string }[] }).questions
|
|
@@ -600,7 +609,7 @@ function updates(on: On, answer: string) {
|
|
|
600
609
|
on('session.cwd', () => ({ value: '/repo' }))
|
|
601
610
|
on('session.id', () => ({ value: 's1' }))
|
|
602
611
|
on('tool.call', () => ({ result: {} }))
|
|
603
|
-
return { runs, toasts, asked }
|
|
612
|
+
return { runs, toasts, asked, logs, statuses }
|
|
604
613
|
}
|
|
605
614
|
|
|
606
615
|
// Claude is about to change the database: the moment Backstep asks.
|
|
@@ -614,12 +623,17 @@ async function changeDatabase($: Parameters<Parameters<typeof test>[2]>[0], on:
|
|
|
614
623
|
}
|
|
615
624
|
|
|
616
625
|
test('a newer version is offered as a session starts, and Update installs it', { options: { cli: CLI } }, async ($, on) => {
|
|
617
|
-
const { runs, toasts, asked } = updates(on, 'Update')
|
|
626
|
+
const { runs, toasts, asked, logs, statuses } = updates(on, 'Update')
|
|
618
627
|
await $.session.start({ cwd: '/repo', surface: 'terminal', hasPerson: true } as never)
|
|
619
628
|
await settle()
|
|
620
629
|
expect(asked).toEqual(['Backstep 0.2.0 is out (you have 0.1.2). Update now?'])
|
|
621
630
|
expect(runs.some((r) => r.slice(3).join(' ') === 'update --version 0.2.0 --json')).toBe(true)
|
|
622
|
-
expect(toasts.at(-1)).toBe('Backstep updated to 0.2.0. Restart Claude Code to use it.')
|
|
631
|
+
expect(toasts.at(-1)).toBe('Backstep is updated to 0.2.0. Restart Claude Code to use it.')
|
|
632
|
+
// While it runs it says not to close the terminal; once done, which version it updated to.
|
|
633
|
+
expect(logs.find((l) => l.includes('Updating Backstep from 0.1.2 to 0.2.0'))).toContain("Don't close this terminal")
|
|
634
|
+
expect(statuses[0]).toContain("don't close this terminal")
|
|
635
|
+
expect(statuses.at(-1)).toBeUndefined()
|
|
636
|
+
expect(logs.at(-1)).toContain('Backstep is updated to 0.2.0 (you had 0.1.2)')
|
|
623
637
|
})
|
|
624
638
|
|
|
625
639
|
test('Skip this version stops asking about it, and Not now changes nothing', { options: { cli: CLI } }, async ($, on) => {
|
package/mod/hooks/register.tsx
CHANGED
|
@@ -661,7 +661,11 @@ async function offerUpdate($: EngineInterface) {
|
|
|
661
661
|
return
|
|
662
662
|
}
|
|
663
663
|
if (answer !== UPDATE.yes) return
|
|
664
|
-
|
|
664
|
+
// Said where it stays (the conversation) and where it's seen while it runs (the status line).
|
|
665
|
+
const from = u.current ? ` from ${u.current}` : ''
|
|
666
|
+
$.ui.log(`${MARK_TEXT} Updating Backstep${from} to ${u.latest}… Don't close this terminal until it says it's done (about a minute).`)
|
|
667
|
+
$.ui.toast(`Updating Backstep to ${u.latest}. Don't close this terminal until it's done.`, { timeoutMs: 15_000 })
|
|
668
|
+
$.ui.status(`◀◀ Updating Backstep to ${u.latest}… don't close this terminal`)
|
|
665
669
|
const done = await $.process
|
|
666
670
|
.run(backstep(['update', '--version', u.latest, '--json']), { timeoutMs: 600_000 })
|
|
667
671
|
.catch((err: unknown) => ({ exitCode: 1, stdout: '', stderr: err instanceof Error ? err.message : String(err) }))
|
|
@@ -671,7 +675,14 @@ async function offerUpdate($: EngineInterface) {
|
|
|
671
675
|
} catch {
|
|
672
676
|
// keep the error above
|
|
673
677
|
}
|
|
674
|
-
$.ui.
|
|
678
|
+
$.ui.status(undefined)
|
|
679
|
+
if (r.ok) {
|
|
680
|
+
$.ui.log(`${MARK_TEXT} Backstep is updated to ${u.latest}${u.current ? ` (you had ${u.current})` : ''}. It's safe to close the terminal now. Restart Claude Code to start using ${u.latest}.`)
|
|
681
|
+
$.ui.toast(`Backstep is updated to ${u.latest}. Restart Claude Code to use it.`)
|
|
682
|
+
} else {
|
|
683
|
+
$.ui.log(`${MARK_TEXT} Backstep couldn't update to ${u.latest}: ${r.detail}. You're still on ${u.current ?? 'the version you had'}, which keeps working. To try again, run: npx backstep@latest setup`)
|
|
684
|
+
$.ui.toast(`Backstep couldn't update: ${r.detail}. Try: npx backstep@latest setup`)
|
|
685
|
+
}
|
|
675
686
|
}
|
|
676
687
|
|
|
677
688
|
const KEY = 'mcp__backstep__undo_key'
|