kryptheon 0.1.5 → 0.1.6

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/README.md CHANGED
@@ -123,9 +123,11 @@ Worth adding to `.gitignore`: `.env`, `kryptheon-baselines.json`,
123
123
 
124
124
  ## Requirements
125
125
 
126
- Node 20.6 or later. Recording needs a real terminal window — it opens a browser,
127
- so it cannot run inside an AI coding assistant. The first run downloads a browser
128
- (about 200MB, once).
126
+ Node 20.6 or later. The first run downloads a browser (about 200MB, once).
127
+
128
+ Recording opens a browser window, so it needs a machine with a screen. It will
129
+ always try — if no window appears within 30 seconds it stops and says so,
130
+ rather than refusing up front.
129
131
 
130
132
  ## Licence
131
133
 
package/bin/kryptheon.js CHANGED
@@ -479,23 +479,51 @@ async function nameRecording(relativeFile) {
479
479
  // Recording needs a real browser window on someone's screen. Inside an AI
480
480
  // coding assistant there is no desktop to draw it on, so codegen would sit
481
481
  // there forever and the run would be killed before anything was tidied up.
482
- function looksLikeNoDesktop() {
483
- if (process.env.KRYPTHEON_FORCE_RECORD) return false;
484
- return !process.stdout.isTTY;
482
+ // There is deliberately no up-front refusal here.
483
+ //
484
+ // This used to check process.stdout.isTTY and refuse before launching. That
485
+ // was wrong: isTTY is falsy in plenty of perfectly good terminals depending on
486
+ // how the process was started, and a real user in Command Prompt was told to
487
+ // go and run the command in Command Prompt. Refusing on a guess is far worse
488
+ // than trying and waiting - so we always launch, and the watchdog below
489
+ // reports only when a window genuinely never appears.
490
+
491
+ // Only ever shown after actually trying: the browser was launched and no
492
+ // window arrived. It must never tell someone to go and run the command they
493
+ // have plainly just run.
494
+ function noWindowLines(seconds) {
495
+ return [
496
+ '',
497
+ ' No browser window appeared.',
498
+ '',
499
+ ' The browser was started, but nothing showed up on screen within ' + seconds,
500
+ ' seconds, so there was nowhere to record.',
501
+ '',
502
+ ' The usual reasons:',
503
+ ' - there is no desktop to draw on - a remote or SSH session, a',
504
+ ' container, or an AI coding assistant running the command for you',
505
+ ' - security software stopped the browser from opening',
506
+ ' - the machine is slow and the browser had not finished starting',
507
+ '',
508
+ ' If you are sitting at the screen, run the same command again - a slow',
509
+ ' first start is the most common cause, and the second attempt usually',
510
+ ' works.',
511
+ '',
512
+ ' If you are connected to a different machine, run it on the machine',
513
+ ' that has the screen.',
514
+ '',
515
+ ' If the window really is open and this keeps happening, set',
516
+ ' KRYPTHEON_FORCE_RECORD=1 to skip this check.',
517
+ '',
518
+ ' Nothing was recorded.',
519
+ '',
520
+ ];
485
521
  }
486
522
 
487
- function explainNoWindow(url) {
488
- console.error('');
489
- console.error(' Recording needs a real browser window on your screen.');
490
- console.error('');
491
- console.error(' This terminal cannot show one - that is what happens inside an');
492
- console.error(' AI coding assistant, or any window-less session.');
493
- console.error('');
494
- console.error(' Open Command Prompt (or PowerShell) yourself and run:');
495
- console.error(' npx kryptheon record ' + url);
496
- console.error('');
497
- console.error(' Nothing was recorded.');
498
- console.error('');
523
+ function explainNoWindow() {
524
+ for (const line of noWindowLines(Math.round(WINDOW_TIMEOUT_MS / 1000))) {
525
+ console.error(line);
526
+ }
499
527
  }
500
528
 
501
529
  // Is a Playwright-controlled browser actually showing a window?
@@ -693,7 +721,7 @@ async function finaliseRecording(outFile, context) {
693
721
  }
694
722
 
695
723
  if (ctx.reason === 'no-window') {
696
- explainNoWindow(ctx.target);
724
+ explainNoWindow();
697
725
  } else if (ctx.reason === 'signal') {
698
726
  console.log('');
699
727
  console.log(' Recording stopped before anything was saved.');
@@ -726,13 +754,6 @@ async function record(url) {
726
754
 
727
755
  const target = normaliseRecordUrl(url);
728
756
 
729
- // No desktop means no window means nothing to record. Say so now rather
730
- // than hanging until something kills us.
731
- if (looksLikeNoDesktop()) {
732
- explainNoWindow(target);
733
- return 1;
734
- }
735
-
736
757
  // Fail early and kindly rather than letting codegen throw a stack trace.
737
758
  const reach = await reachability(target);
738
759
  if (!reach.ok) {
@@ -793,8 +814,14 @@ async function record(url) {
793
814
 
794
815
  return await new Promise((resolve) => {
795
816
  // If no window ever appears, stop instead of waiting for someone to kill us.
817
+ // Someone whose window is real but undetectable can turn this off.
818
+ const watchdogOff = !!process.env.KRYPTHEON_FORCE_RECORD;
796
819
  let waited = 0;
797
820
  const watchdog = setInterval(() => {
821
+ if (watchdogOff) {
822
+ clearInterval(watchdog);
823
+ return;
824
+ }
798
825
  waited += WINDOW_POLL_MS;
799
826
  if (browserWindowIsUp()) {
800
827
  clearInterval(watchdog);
@@ -1299,7 +1326,7 @@ module.exports = {
1299
1326
  takeOutSecrets: takeOutSecrets,
1300
1327
  reportReplayRisks: reportReplayRisks,
1301
1328
  offerToDropLogout: offerToDropLogout,
1302
- looksLikeNoDesktop: looksLikeNoDesktop,
1329
+ noWindowLines: noWindowLines,
1303
1330
  classifyFetchError: classifyFetchError,
1304
1331
  normaliseRecordUrl: normaliseRecordUrl,
1305
1332
  isLocalAddress: isLocalAddress,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kryptheon",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Record what you do in your app and get plain-language reports when it breaks.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",