kryptheon 0.1.39 → 0.1.41

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/LICENSE CHANGED
@@ -5,7 +5,7 @@ Copyright (c) 2026 Kryptheon (https://kryptheon.tech). All rights reserved.
5
5
  This software is proprietary. It is not open source.
6
6
 
7
7
  1. Use. You may install and run this software, as published by Kryptheon,
8
- free of charge, to check software and databases that you own or are
8
+ at no charge, to check software and databases that you own or are
9
9
  authorised to test. Features that kryptheon.tech offers on a paid plan
10
10
  are provided only under that plan and the Terms at
11
11
  https://kryptheon.tech/terms.
package/README.md CHANGED
@@ -1,261 +1,261 @@
1
- # kryptheon
2
-
3
- Record a flow in your app once, replay it after every AI change, and get told in
4
- plain English what broke.
5
-
6
- Runs entirely on your machine. No account, no API key, nothing leaves your
7
- computer. It is a wrapper around [Playwright](https://playwright.dev).
8
-
9
- ## The one command
10
-
11
- ```
12
- npx kryptheon@latest dashboard
13
- ```
14
-
15
- Run it in your project's folder. It opens a page in your browser, and
16
- everything else is a button on that page:
17
-
18
- | | how often |
19
- | --- | --- |
20
- | Read my code | after every change |
21
- | Record a flow | one time - again only when that flow changes |
22
- | Replay | after every change |
23
- | Connect your database | one time |
24
- | Check my database | after every change |
25
- | Set up the nightly check | one time |
26
- | Re-check a finding | after every change |
27
-
28
- Every button shows the terminal command that does the same thing, in small
29
- print, for when the page cannot be used. The database connection string is
30
- pasted into the page, used for one run, and never saved, logged or shown
31
- again; reload the page and it is gone.
32
-
33
- ## Only have a web address?
34
-
35
- Built your app in Lovable, Bolt or v0, and there is no project folder on your
36
- computer? Open a terminal and run:
37
-
38
- ```
39
- npx kryptheon record https://your-app.lovable.app
40
- ```
41
-
42
- Before it opens anything, it looks at the folder you are in. If that folder is
43
- not set up for recordings it says so and asks first, then adds a `package.json`
44
- and kryptheon itself (about 20MB) — nothing else. A new terminal opens in your
45
- home folder, so from there it keeps your recordings in a `kryptheon-tests`
46
- folder of their own and tells you where that is.
47
-
48
- After every change to your app, from that same folder:
49
-
50
- ```
51
- npx kryptheon check
52
- ```
53
-
54
- ## Install
55
-
56
- ```
57
- npm i -D kryptheon
58
- ```
59
-
60
- Install it into your project, not globally — every recording imports
61
- `kryptheon/kryptheon-fixture`, and your tests can only find that if kryptheon is
62
- in your project's `node_modules`.
63
-
64
- ## Record
65
-
66
- ```
67
- npx kryptheon record https://your-app.example.com
68
- ```
69
-
70
- A browser opens. Use your app the way a customer would. Close the browser when
71
- you are done, and the recording is saved as a test.
72
-
73
- Add `--phone` to record in a phone-sized window (390 x 844) - for a menu or a
74
- layout that only changes on a phone. The recording keeps that size, so every
75
- replay uses it too. On the dashboard it is the "Phone size" box under Record.
76
-
77
- On its own, a recording knows that every button and field is still there and
78
- that the last page looks the same. To say what must be true — "Reservation
79
- received" appears after booking — use the toolbar at the top of the page while
80
- recording:
81
-
82
- | Button | Click it, then click… | Kryptheon then checks |
83
- | --- | --- | --- |
84
- | Eye | any element | it is on the page |
85
- | `ab` | some text | that text is there |
86
- | Box | a filled-in field | the field still holds that value |
87
- | `{ }` | a part of the page | that part is laid out the same |
88
-
89
- The round red button pauses and resumes recording. The arrow only shows how an
90
- element would be found; it adds nothing to the test. One check at the end of a
91
- flow — on the success message — is usually all a recording needs.
92
-
93
- ## Check
94
-
95
- ```
96
- npx kryptheon check
97
- ```
98
-
99
- Runs everything you have recorded:
100
-
101
- ```
102
- OK Sign in (4.1s)
103
-
104
- X Checkout
105
- Could not find the button "Place order" on the page.
106
- This was working on 12 Mar at 9:14 AM.
107
- What to check: your last change may have renamed, hidden, or removed it.
108
- Where to look:
109
- - Browser was on: https://your-app.example.com/cart
110
- - POST /api/orders returned 500
111
- the server crashed or is unavailable - the error is in backend code, not the page
112
- ```
113
-
114
- Every failure ends with a short summary you can paste straight into an AI coding
115
- tool.
116
-
117
- ## Recording something that replays
118
-
119
- A recording is only useful if it still works the second time. So:
120
-
121
- - **Record one simple flow.** Sign in and look at a page. Open a thing and check
122
- it loaded. Short beats thorough.
123
- - **Sign in with an account that already exists.** Do not sign up during a
124
- recording — the account exists next time, and the signup step fails.
125
- - **Avoid steps that cannot repeat.** Adding data piles up a row on every run.
126
- Logging out at the end means the next run does not start where this one did.
127
-
128
- Kryptheon warns you about these after a recording, and names the exact step.
129
-
130
- ## Make your AI assistant check its own work
131
-
132
- An assistant will happily call a change done after only reading the code. This
133
- writes a rule into the files assistants already read, so it has to run the check
134
- first:
135
-
136
- ```
137
- npx kryptheon setup-ai
138
- ```
139
-
140
- It writes `CLAUDE.md`, `AGENTS.md` and `.cursorrules`. If a file already exists,
141
- it adds a marked section at the end rather than overwriting anything, and
142
- running it again replaces that section instead of adding a second copy.
143
-
144
- The rule: after any change, run `npx kryptheon check`, show the output, and do
145
- not report the work as done until it passes.
146
-
147
- For an assistant running the check after every change, `--quiet` keeps the
148
- conversation readable — one line when everything passes, the full explanation
149
- only when something breaks:
150
-
151
- ```
152
- npx kryptheon check --quiet
153
- ```
154
-
155
- ```
156
- OK 3 recordings still working.
157
- ```
158
-
159
- ## Automatic checks
160
-
161
- The first time a test passes, kryptheon remembers where the browser ended up and
162
- what the page was called. If either changes later, the test fails and says what
163
- changed — so a recording catches regressions without you writing a single
164
- assertion.
165
-
166
- When a change is intentional, accept it for that one test:
167
-
168
- ```
169
- npx kryptheon accept "Checkout"
170
- ```
171
-
172
- `npx kryptheon accept` on its own lists what has been saved.
173
-
174
- ## Renamed buttons
175
-
176
- A button that only changed its words has not broken anything. When a step
177
- cannot find "Reserve a table" and the page shows exactly one new button in its
178
- place — "Reserve here" — kryptheon clicks that one, carries on through the rest
179
- of the flow, and says so:
180
-
181
- ```
182
- OK Reserve a table (16.0s)
183
- Renamed: The button "Reserve a table" is now called "Reserve here" - I used "Reserve here" and carried on.
184
- Nothing is broken. To stop seeing this, record the flow again.
185
- ```
186
-
187
- It only does this when the page proves it: one name gone, the one the step
188
- wanted, and one new name of the same kind. A button that is gone with nothing
189
- in its place, or a rename next to other new buttons, fails as it always did.
190
- Checks you added with the toolbar are never redirected.
191
-
192
- ## Dashboard
193
-
194
- ```
195
- npx kryptheon
196
- ```
197
-
198
- In a terminal, with no command, this opens a page on your own machine
199
- (`http://127.0.0.1:4789/`) for this project, in your browser by itself (the
200
- address is printed too): what is broken, what needs a look, every run, recent
201
- changes, and switches for each check. Every check runs from a button, one at a
202
- time, with its progress shown on the page as it goes. It is only reachable
203
- from this machine; press Ctrl+C to stop it. From a script, use
204
- `npx kryptheon dashboard`; set `KRYPTHEON_NO_OPEN=1` to keep the browser shut.
205
-
206
- It opens on the one thing to do next, and under it "Start here": read your
207
- code, record your main flows, replay them, connect and check your database,
208
- and set up the nightly check - each marked done only once it has actually run,
209
- and each labelled "one time" or "after every change".
210
-
211
- Checks that are not built yet are listed as "not available" - never as
212
- passed.
213
-
214
- ## Reading your code
215
-
216
- ```
217
- npx kryptheon code
218
- ```
219
-
220
- Reads your frontend code for values put into the page as HTML - `innerHTML`,
221
- `insertAdjacentHTML`, `document.write`, React's `dangerouslySetInnerHTML`,
222
- Vue's `v-html`. If such a value can hold text someone typed, a `<` in it can
223
- run script with the signed-in person's session. Nothing is run; every result
224
- is "verification required", ranked HIGH when the value comes from a server
225
- response or an error message, MEDIUM when the code alone cannot say. The fix
226
- prompt for each one names the file, line and value.
227
-
228
- ## What goes where
229
-
230
- Only your recordings go in your project, in `tests/`. Everything Kryptheon
231
- remembers about the project is kept outside it, so it can never end up in your
232
- repo:
233
-
234
- ~/.kryptheon/projects/<folder-name>-<id>/
235
- baselines.json the remembered result for each test
236
- history.jsonl one line per run, used for "this was working on …"
237
- test-results/ the screenshot of the last failure
238
-
239
- Set `KRYPTHEON_HOME` to keep them somewhere else. Each project folder gets its
240
- own store, so two projects are never mixed. A project folder that is moved or
241
- renamed starts a new store.
242
-
243
- Older versions kept `kryptheon-baselines.json`, `kryptheon-history.jsonl` and
244
- `test-results/` in the project. The first run of this version moves them out,
245
- once, and says so.
246
-
247
- A `.env` in the same folder is loaded automatically, and anything you type into a
248
- password box is replaced with an environment variable rather than written into
249
- the test. When there is a password, `.env` is added to an existing `.gitignore`.
250
-
251
- ## Requirements
252
-
253
- Node 20.6 or later. The first run downloads a browser (about 200MB, once).
254
-
255
- Recording opens a browser window, so it needs a machine with a screen. It will
256
- always try — if no window appears within 30 seconds it stops and says so,
257
- rather than refusing up front.
258
-
259
- ## Licence
260
-
261
- Free to use, not open source: see LICENSE. Paid features are on kryptheon.tech.
1
+ # kryptheon
2
+
3
+ Record a flow in your app once, replay it after every AI change, and get told in
4
+ plain English what broke.
5
+
6
+ Runs entirely on your machine. No account, no API key, nothing leaves your
7
+ computer. It is a wrapper around [Playwright](https://playwright.dev).
8
+
9
+ ## The one command
10
+
11
+ ```
12
+ npx kryptheon@latest dashboard
13
+ ```
14
+
15
+ Run it in your project's folder. It opens a page in your browser, and
16
+ everything else is a button on that page:
17
+
18
+ | | how often |
19
+ | --- | --- |
20
+ | Read my code | after every change |
21
+ | Record a flow | one time - again only when that flow changes |
22
+ | Replay | after every change |
23
+ | Connect your database | one time |
24
+ | Check my database | after every change |
25
+ | Set up the nightly check | one time |
26
+ | Re-check a finding | after every change |
27
+
28
+ Every button shows the terminal command that does the same thing, in small
29
+ print, for when the page cannot be used. The database connection string is
30
+ pasted into the page, used for one run, and never saved, logged or shown
31
+ again; reload the page and it is gone.
32
+
33
+ ## Only have a web address?
34
+
35
+ Built your app in Lovable, Bolt or v0, and there is no project folder on your
36
+ computer? Open a terminal and run:
37
+
38
+ ```
39
+ npx kryptheon record https://your-app.lovable.app
40
+ ```
41
+
42
+ Before it opens anything, it looks at the folder you are in. If that folder is
43
+ not set up for recordings it says so and asks first, then adds a `package.json`
44
+ and kryptheon itself (about 20MB) — nothing else. A new terminal opens in your
45
+ home folder, so from there it keeps your recordings in a `kryptheon-tests`
46
+ folder of their own and tells you where that is.
47
+
48
+ After every change to your app, from that same folder:
49
+
50
+ ```
51
+ npx kryptheon check
52
+ ```
53
+
54
+ ## Install
55
+
56
+ ```
57
+ npm i -D kryptheon
58
+ ```
59
+
60
+ Install it into your project, not globally — every recording imports
61
+ `kryptheon/kryptheon-fixture`, and your tests can only find that if kryptheon is
62
+ in your project's `node_modules`.
63
+
64
+ ## Record
65
+
66
+ ```
67
+ npx kryptheon record https://your-app.example.com
68
+ ```
69
+
70
+ A browser opens. Use your app the way a customer would. Close the browser when
71
+ you are done, and the recording is saved as a test.
72
+
73
+ Add `--phone` to record in a phone-sized window (390 x 844) - for a menu or a
74
+ layout that only changes on a phone. The recording keeps that size, so every
75
+ replay uses it too. On the dashboard it is the "Phone size" box under Record.
76
+
77
+ On its own, a recording knows that every button and field is still there and
78
+ that the last page looks the same. To say what must be true — "Reservation
79
+ received" appears after booking — use the toolbar at the top of the page while
80
+ recording:
81
+
82
+ | Button | Click it, then click… | Kryptheon then checks |
83
+ | --- | --- | --- |
84
+ | Eye | any element | it is on the page |
85
+ | `ab` | some text | that text is there |
86
+ | Box | a filled-in field | the field still holds that value |
87
+ | `{ }` | a part of the page | that part is laid out the same |
88
+
89
+ The round red button pauses and resumes recording. The arrow only shows how an
90
+ element would be found; it adds nothing to the test. One check at the end of a
91
+ flow — on the success message — is usually all a recording needs.
92
+
93
+ ## Check
94
+
95
+ ```
96
+ npx kryptheon check
97
+ ```
98
+
99
+ Runs everything you have recorded:
100
+
101
+ ```
102
+ OK Sign in (4.1s)
103
+
104
+ X Checkout
105
+ Could not find the button "Place order" on the page.
106
+ This was working on 12 Mar at 9:14 AM.
107
+ What to check: your last change may have renamed, hidden, or removed it.
108
+ Where to look:
109
+ - Browser was on: https://your-app.example.com/cart
110
+ - POST /api/orders returned 500
111
+ the server crashed or is unavailable - the error is in backend code, not the page
112
+ ```
113
+
114
+ Every failure ends with a short summary you can paste straight into an AI coding
115
+ tool.
116
+
117
+ ## Recording something that replays
118
+
119
+ A recording is only useful if it still works the second time. So:
120
+
121
+ - **Record one simple flow.** Sign in and look at a page. Open a thing and check
122
+ it loaded. Short beats thorough.
123
+ - **Sign in with an account that already exists.** Do not sign up during a
124
+ recording — the account exists next time, and the signup step fails.
125
+ - **Avoid steps that cannot repeat.** Adding data piles up a row on every run.
126
+ Logging out at the end means the next run does not start where this one did.
127
+
128
+ Kryptheon warns you about these after a recording, and names the exact step.
129
+
130
+ ## Make your AI assistant check its own work
131
+
132
+ An assistant will happily call a change done after only reading the code. This
133
+ writes a rule into the files assistants already read, so it has to run the check
134
+ first:
135
+
136
+ ```
137
+ npx kryptheon setup-ai
138
+ ```
139
+
140
+ It writes `CLAUDE.md`, `AGENTS.md` and `.cursorrules`. If a file already exists,
141
+ it adds a marked section at the end rather than overwriting anything, and
142
+ running it again replaces that section instead of adding a second copy.
143
+
144
+ The rule: after any change, run `npx kryptheon check`, show the output, and do
145
+ not report the work as done until it passes.
146
+
147
+ For an assistant running the check after every change, `--quiet` keeps the
148
+ conversation readable — one line when everything passes, the full explanation
149
+ only when something breaks:
150
+
151
+ ```
152
+ npx kryptheon check --quiet
153
+ ```
154
+
155
+ ```
156
+ OK 3 recordings still working.
157
+ ```
158
+
159
+ ## Automatic checks
160
+
161
+ The first time a test passes, kryptheon remembers where the browser ended up and
162
+ what the page was called. If either changes later, the test fails and says what
163
+ changed — so a recording catches regressions without you writing a single
164
+ assertion.
165
+
166
+ When a change is intentional, accept it for that one test:
167
+
168
+ ```
169
+ npx kryptheon accept "Checkout"
170
+ ```
171
+
172
+ `npx kryptheon accept` on its own lists what has been saved.
173
+
174
+ ## Renamed buttons
175
+
176
+ A button that only changed its words has not broken anything. When a step
177
+ cannot find "Reserve a table" and the page shows exactly one new button in its
178
+ place — "Reserve here" — kryptheon clicks that one, carries on through the rest
179
+ of the flow, and says so:
180
+
181
+ ```
182
+ OK Reserve a table (16.0s)
183
+ Renamed: The button "Reserve a table" is now called "Reserve here" - I used "Reserve here" and carried on.
184
+ Nothing is broken. To stop seeing this, record the flow again.
185
+ ```
186
+
187
+ It only does this when the page proves it: one name gone, the one the step
188
+ wanted, and one new name of the same kind. A button that is gone with nothing
189
+ in its place, or a rename next to other new buttons, fails as it always did.
190
+ Checks you added with the toolbar are never redirected.
191
+
192
+ ## Dashboard
193
+
194
+ ```
195
+ npx kryptheon
196
+ ```
197
+
198
+ In a terminal, with no command, this opens a page on your own machine
199
+ (`http://127.0.0.1:4789/`) for this project, in your browser by itself (the
200
+ address is printed too): what is broken, what needs a look, every run, recent
201
+ changes, and switches for each check. Every check runs from a button, one at a
202
+ time, with its progress shown on the page as it goes. It is only reachable
203
+ from this machine; press Ctrl+C to stop it. From a script, use
204
+ `npx kryptheon dashboard`; set `KRYPTHEON_NO_OPEN=1` to keep the browser shut.
205
+
206
+ It opens on the one thing to do next, and under it "Start here": read your
207
+ code, record your main flows, replay them, connect and check your database,
208
+ and set up the nightly check - each marked done only once it has actually run,
209
+ and each labelled "one time" or "after every change".
210
+
211
+ Checks that are not built yet are listed as "not available" - never as
212
+ passed.
213
+
214
+ ## Reading your code
215
+
216
+ ```
217
+ npx kryptheon code
218
+ ```
219
+
220
+ Reads your frontend code for values put into the page as HTML - `innerHTML`,
221
+ `insertAdjacentHTML`, `document.write`, React's `dangerouslySetInnerHTML`,
222
+ Vue's `v-html`. If such a value can hold text someone typed, a `<` in it can
223
+ run script with the signed-in person's session. Nothing is run; every result
224
+ is "verification required", ranked HIGH when the value comes from a server
225
+ response or an error message, MEDIUM when the code alone cannot say. The fix
226
+ prompt for each one names the file, line and value.
227
+
228
+ ## What goes where
229
+
230
+ Only your recordings go in your project, in `tests/`. Everything Kryptheon
231
+ remembers about the project is kept outside it, so it can never end up in your
232
+ repo:
233
+
234
+ ~/.kryptheon/projects/<folder-name>-<id>/
235
+ baselines.json the remembered result for each test
236
+ history.jsonl one line per run, used for "this was working on …"
237
+ test-results/ the screenshot of the last failure
238
+
239
+ Set `KRYPTHEON_HOME` to keep them somewhere else. Each project folder gets its
240
+ own store, so two projects are never mixed. A project folder that is moved or
241
+ renamed starts a new store.
242
+
243
+ Older versions kept `kryptheon-baselines.json`, `kryptheon-history.jsonl` and
244
+ `test-results/` in the project. The first run of this version moves them out,
245
+ once, and says so.
246
+
247
+ A `.env` in the same folder is loaded automatically, and anything you type into a
248
+ password box is replaced with an environment variable rather than written into
249
+ the test. When there is a password, `.env` is added to an existing `.gitignore`.
250
+
251
+ ## Requirements
252
+
253
+ Node 20.6 or later. The first run downloads a browser (about 200MB, once).
254
+
255
+ Recording opens a browser window, so it needs a machine with a screen. It will
256
+ always try — if no window appears within 30 seconds it stops and says so,
257
+ rather than refusing up front.
258
+
259
+ ## Licence
260
+
261
+ Proprietary software, not open source - see LICENSE. It runs on your own machine, with no account and no card. The nightly check, with its morning report, alerts and history, is part of the Pro and Studio plans on kryptheon.tech.
package/bin/kryptheon.js CHANGED
@@ -2632,9 +2632,12 @@ function dashboardAlreadyRunning(port) {
2632
2632
  res.on('data', (chunk) => { if (body.length < 5000000) body += chunk; });
2633
2633
  res.on('end', () => {
2634
2634
  try {
2635
- const root = JSON.parse(body).project.root;
2635
+ const state = JSON.parse(body);
2636
+ const root = state.project.root;
2636
2637
  const same = (a) => (process.platform === 'win32' ? path.resolve(a).toLowerCase() : path.resolve(a));
2637
- resolve(res.statusCode === 200 && typeof root === 'string' && same(root) === same(USER_DIR));
2638
+ if (res.statusCode !== 200 || typeof root !== 'string' || same(root) !== same(USER_DIR)) return resolve(false);
2639
+ // Before 0.1.41 a dashboard did not say which it was: an old one.
2640
+ resolve({ version: typeof state.kryptheon === 'string' ? state.kryptheon : null });
2638
2641
  } catch (err) {
2639
2642
  resolve(false);
2640
2643
  }
@@ -2645,6 +2648,49 @@ function dashboardAlreadyRunning(port) {
2645
2648
  });
2646
2649
  }
2647
2650
 
2651
+ /** The process listening on 127.0.0.1:port, or null. */
2652
+ function listenerOn(port) {
2653
+ try {
2654
+ if (process.platform === 'win32') {
2655
+ const out = spawnSync('netstat', ['-ano', '-p', 'TCP'], { encoding: 'utf8', windowsHide: true, timeout: 10000 }).stdout || '';
2656
+ for (const line of out.split(/\r?\n/)) {
2657
+ const m = line.trim().split(/\s+/);
2658
+ if (m.length >= 5 && m[1] === '127.0.0.1:' + port && m[3] === 'LISTENING' && /^\d+$/.test(m[4])) return Number(m[4]);
2659
+ }
2660
+ return null;
2661
+ }
2662
+ const out = spawnSync('lsof', ['-nP', '-iTCP@127.0.0.1:' + port, '-sTCP:LISTEN', '-t'], { encoding: 'utf8', timeout: 10000 }).stdout || '';
2663
+ const pid = Number(out.trim().split(/\s+/)[0]);
2664
+ return pid > 0 ? pid : null;
2665
+ } catch (err) {
2666
+ return null;
2667
+ }
2668
+ }
2669
+
2670
+ /**
2671
+ * An older dashboard for this same folder, still running - from yesterday's
2672
+ * Win+R, or started at sign-in - is stopped so this version takes its place.
2673
+ * Found when the first paying user ran the new version and kept getting the
2674
+ * old page: npx fetched the new one, which then only opened the old one.
2675
+ * Only the process that answered as this folder's Kryptheon dashboard is
2676
+ * stopped. Whether the port came free is the answer.
2677
+ */
2678
+ async function replaceOldDashboard(port) {
2679
+ const pid = listenerOn(port);
2680
+ if (!pid || pid === process.pid) return false;
2681
+ try {
2682
+ if (process.platform === 'win32') spawnSync('taskkill', ['/PID', String(pid), '/F'], { windowsHide: true, timeout: 10000 });
2683
+ else process.kill(pid, 'SIGTERM');
2684
+ } catch (err) {
2685
+ return false;
2686
+ }
2687
+ for (let i = 0; i < 50; i++) {
2688
+ if (listenerOn(port) === null) return true;
2689
+ await new Promise((r) => setTimeout(r, 100));
2690
+ }
2691
+ return false;
2692
+ }
2693
+
2648
2694
  /**
2649
2695
  * The dashboard, started from the home folder: kept in a kryptheon-tests
2650
2696
  * folder there, the one record already uses - set up the first time, asked
@@ -2732,7 +2778,16 @@ async function dashboardCommand() {
2732
2778
  }
2733
2779
  // Running already: open that one rather than a second, which would watch
2734
2780
  // the same project twice. Exit code 0 is how the launcher knows.
2735
- if (await dashboardAlreadyRunning(DASHBOARD_PORT)) {
2781
+ const running = await dashboardAlreadyRunning(DASHBOARD_PORT);
2782
+ const mine = require(path.join(PACKAGE_DIR, 'package.json')).version;
2783
+ if (running && running.version !== mine) {
2784
+ const was = running.version || 'from before 0.1.41';
2785
+ console.log('');
2786
+ console.log(await replaceOldDashboard(DASHBOARD_PORT)
2787
+ ? ' An older Kryptheon dashboard (' + was + ') was running for this folder.\n It was closed, and ' + mine + ' starts in its place.'
2788
+ : ' An older Kryptheon dashboard (' + was + ') is still running and could not be\n closed. This one starts at another address; close the old window when you can.');
2789
+ }
2790
+ if (running && running.version === mine) {
2736
2791
  const address = 'http://127.0.0.1:' + DASHBOARD_PORT + '/';
2737
2792
  const shown = openInBrowser(address);
2738
2793
  console.log('');
@@ -25,6 +25,7 @@ const { spawnSync } = require('child_process');
25
25
  const store = require('./kryptheon-store.js');
26
26
  const changes = require('./kryptheon-changes.js');
27
27
  const autostart = require('./kryptheon-autostart.js');
28
+ const VERSION = require('./package.json').version;
28
29
 
29
30
  /**
30
31
  * Every check the dashboard knows the name of, in the order the person asked
@@ -543,6 +544,9 @@ function buildState(root, env) {
543
544
 
544
545
  return {
545
546
  project: { name: path.basename(root), root: root, storeDir: paths.dir },
547
+ // Which kryptheon this dashboard is: a newer `dashboard` asks, and takes
548
+ // the place of an older one still running, instead of opening it.
549
+ kryptheon: VERSION,
546
550
  looks: looks,
547
551
  proven: proven,
548
552
  checks: checks,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kryptheon",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "description": "Record what you do in your app and get plain-language reports when it breaks.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "commonjs",