@illuminis/comprism 0.1.4 → 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.
Files changed (116) hide show
  1. package/out/agent/command.js +5 -5
  2. package/out/agent/render.d.ts +39 -6
  3. package/out/agent/render.js +287 -28
  4. package/out/agent/session.d.ts +21 -1
  5. package/out/agent/session.js +81 -17
  6. package/out/commands/agents.js +3 -3
  7. package/out/commands/ask.js +20 -11
  8. package/out/commands/codemap.d.ts +1 -1
  9. package/out/commands/codemap.js +3 -3
  10. package/out/commands/commands-thin.js +4 -4
  11. package/out/commands/config.js +1 -1
  12. package/out/commands/cost.js +4 -4
  13. package/out/commands/hooks.js +1 -1
  14. package/out/commands/install.d.ts +1 -1
  15. package/out/commands/install.js +3 -2
  16. package/out/commands/instructions.js +1 -1
  17. package/out/commands/integrations.js +4 -4
  18. package/out/commands/keys.js +6 -6
  19. package/out/commands/login.js +97 -27
  20. package/out/commands/permissions.js +2 -2
  21. package/out/commands/plugins.js +3 -3
  22. package/out/commands/privacy.js +2 -2
  23. package/out/commands/repl.d.ts +4 -0
  24. package/out/commands/repl.js +563 -101
  25. package/out/commands/review.js +6 -6
  26. package/out/commands/settings.js +30 -123
  27. package/out/commands/skills.js +2 -2
  28. package/out/commands/unattended.js +6 -6
  29. package/out/commands/update.js +1 -1
  30. package/out/commands/welcome.d.ts +25 -1
  31. package/out/commands/welcome.js +65 -38
  32. package/out/commands/worktrees.d.ts +1 -1
  33. package/out/graph/sync.d.ts +1 -1
  34. package/out/graph/sync.js +6 -6
  35. package/out/lib/attach.js +4 -3
  36. package/out/lib/commandlist.d.ts +1 -1
  37. package/out/lib/commandlist.js +2 -2
  38. package/out/lib/config.d.ts +3 -2
  39. package/out/lib/config.js +7 -8
  40. package/out/lib/connection.js +1 -1
  41. package/out/lib/gateway.d.ts +9 -5
  42. package/out/lib/keyboard.d.ts +3 -0
  43. package/out/lib/keyboard.js +7 -0
  44. package/out/lib/lastlogin.d.ts +14 -0
  45. package/out/lib/lastlogin.js +105 -0
  46. package/out/lib/machine.js +1 -1
  47. package/out/lib/picker.d.ts +1 -0
  48. package/out/lib/picker.js +158 -0
  49. package/out/lib/project-ops.d.ts +1 -1
  50. package/out/lib/project-ops.js +4 -4
  51. package/out/lib/prompt.d.ts +3 -0
  52. package/out/lib/prompt.js +21 -0
  53. package/out/lib/queue.js +1 -1
  54. package/out/lib/readiness.d.ts +3 -30
  55. package/out/lib/readiness.js +13 -82
  56. package/out/lib/servicecommand.d.ts +14 -0
  57. package/out/lib/servicecommand.js +74 -0
  58. package/out/lib/sessions.js +3 -3
  59. package/out/lib/startcache.d.ts +13 -0
  60. package/out/lib/startcache.js +78 -0
  61. package/out/lib/ui.d.ts +11 -0
  62. package/out/lib/ui.js +28 -0
  63. package/out/lib/voice.d.ts +36 -0
  64. package/out/lib/voice.js +137 -2
  65. package/out/lib/words.d.ts +20 -0
  66. package/out/lib/words.js +27 -0
  67. package/out/machine/codemap/build.d.ts +45 -0
  68. package/out/machine/codemap/build.js +91 -0
  69. package/out/machine/codemap/facts.d.ts +47 -0
  70. package/out/machine/codemap/facts.js +12 -0
  71. package/out/machine/codemap/files.d.ts +45 -0
  72. package/out/machine/codemap/files.js +207 -0
  73. package/out/machine/codemap/read-locales.d.ts +29 -0
  74. package/out/machine/codemap/read-locales.js +246 -0
  75. package/out/machine/codemap/read-python.d.ts +11 -0
  76. package/out/machine/codemap/read-python.js +116 -0
  77. package/out/machine/codemap/read-typescript.d.ts +16 -0
  78. package/out/machine/codemap/read-typescript.js +292 -0
  79. package/out/machine/executor/browser.d.ts +14 -0
  80. package/out/machine/executor/browser.js +270 -0
  81. package/out/machine/executor/diagnostics.d.ts +2 -0
  82. package/out/machine/executor/diagnostics.js +181 -0
  83. package/out/machine/executor/documents.d.ts +40 -0
  84. package/out/machine/executor/documents.js +170 -0
  85. package/out/machine/executor/files.d.ts +2 -0
  86. package/out/machine/executor/files.js +590 -0
  87. package/out/machine/executor/git.d.ts +48 -0
  88. package/out/machine/executor/git.js +145 -0
  89. package/out/machine/executor/hooks.d.ts +51 -0
  90. package/out/machine/executor/hooks.js +154 -0
  91. package/out/machine/executor/index.d.ts +45 -0
  92. package/out/machine/executor/index.js +367 -0
  93. package/out/machine/executor/notebook.d.ts +2 -0
  94. package/out/machine/executor/notebook.js +147 -0
  95. package/out/machine/executor/paths.d.ts +20 -0
  96. package/out/machine/executor/paths.js +154 -0
  97. package/out/machine/executor/sandbox.d.ts +40 -0
  98. package/out/machine/executor/sandbox.js +299 -0
  99. package/out/machine/executor/shell.d.ts +86 -0
  100. package/out/machine/executor/shell.js +582 -0
  101. package/out/machine/executor/toolservers.d.ts +20 -0
  102. package/out/machine/executor/toolservers.js +189 -0
  103. package/out/machine/executor/worktree.d.ts +9 -0
  104. package/out/machine/executor/worktree.js +119 -0
  105. package/out/machine/folder/project.d.ts +28 -0
  106. package/out/machine/folder/project.js +114 -0
  107. package/out/machine/runtime/home.d.ts +2 -0
  108. package/out/machine/runtime/home.js +48 -0
  109. package/out/machine/runtime/needs.d.ts +30 -0
  110. package/out/machine/runtime/needs.js +89 -0
  111. package/out/machine/runtime/self.d.ts +23 -0
  112. package/out/machine/runtime/self.js +124 -0
  113. package/out/native/dictate +0 -0
  114. package/out/providers/index.js +2 -1
  115. package/out/thin.js +13 -12
  116. package/package.json +5 -4
@@ -78,6 +78,7 @@ const connection_1 = require("../lib/connection");
78
78
  const gateway_1 = require("../lib/gateway");
79
79
  const ui = __importStar(require("../lib/ui"));
80
80
  const prompt_1 = require("../lib/prompt");
81
+ const words_1 = require("../lib/words");
81
82
  const out = (s = '') => process.stdout.write(s + '\n');
82
83
  /** Where a named workspace lives. One format, stated once. */
83
84
  const WORKSPACE_DOMAIN = 'completionprism.illuminis.ai';
@@ -103,6 +104,21 @@ function workspaceUrl(typed) {
103
104
  return `https://${value}`;
104
105
  return `https://${value}.${WORKSPACE_DOMAIN}`;
105
106
  }
107
+ /**
108
+ * Where an organization signs in. A full address is used as typed. A bare name
109
+ * is turned into its address by the service, so every client follows one rule
110
+ * (service catalog 1).
111
+ */
112
+ async function addressOf(typed) {
113
+ const value = typed.trim().replace(/\/+$/, '');
114
+ if (/^[A-Za-z0-9][A-Za-z0-9-]{0,62}$/.test(value) && value.toLowerCase() !== 'localhost') {
115
+ const reply = await (0, gateway_1.askAt)(`https://${WORKSPACE_DOMAIN}`, { intent: 'resolve_workspace', prompt: value });
116
+ const url = reply.session?.workspace_url;
117
+ if (url)
118
+ return url.replace(/\/+$/, '');
119
+ }
120
+ return workspaceUrl(value);
121
+ }
106
122
  /** Localhost needs the tenant named, because there is no subdomain to read. */
107
123
  function tenantFor(url, typed, flagged) {
108
124
  if (flagged)
@@ -168,8 +184,8 @@ async function approveInBrowser(url, tenant, noBrowser) {
168
184
  const res = await fetch(`${url}/oauth/device_authorization`, form({ client_id: CLIENT_ID, scope: 'api:read api:write' }));
169
185
  if (!res.ok) {
170
186
  out(ui.fail(res.status === 404 || res.status === 405
171
- ? 'That workspace is running a build without browser sign in.'
172
- : 'The workspace would not start a browser sign in.'));
187
+ ? 'That organization is running a build without browser sign in.'
188
+ : 'The organization would not start a browser sign in.'));
173
189
  return '';
174
190
  }
175
191
  started = await res.json();
@@ -234,14 +250,40 @@ async function runLogin(args) {
234
250
  process.exitCode = 1;
235
251
  return;
236
252
  }
237
- out(ui.banner('Sign in'));
253
+ // Under the session's own mark when the session is about to open, so the
254
+ // name is not drawn twice in a row.
255
+ out(args.includes('--into-session') ? ` ${ui.c.bold('Sign in')}` : ui.banner('Sign in'));
238
256
  out();
239
257
  // Flags still work, for a script or a second machine. A person gets asked.
240
258
  const flag = (name) => {
241
259
  const i = args.indexOf(name);
242
260
  return i >= 0 ? args[i + 1] : undefined;
243
261
  };
244
- const username = flag('--username') || flag('--email') || await (0, prompt_1.ask)(' email: ');
262
+ // THE LAST PERSON, OFFERED. Signing in again is Enter: the email and the
263
+ // workspace they used last time, exactly as they were, so a local workspace
264
+ // stays local instead of being looked up again and sent to production.
265
+ const { readLast, saveLast, forgetLast, savedPassword, savePassword, forgetPassword, keychainAvailable } = await Promise.resolve().then(() => __importStar(require('../lib/lastlogin')));
266
+ if (args.includes('--forget')) {
267
+ forgetLast();
268
+ out(ui.ok('The last sign in and any saved password on this Mac are forgotten.'));
269
+ out();
270
+ return;
271
+ }
272
+ const last = flag('--username') || flag('--email') || (flag('--organization') || flag('--workspace')) ? null : readLast();
273
+ if (last) {
274
+ out(` ${ui.c.dim('last time')} ${ui.c.bold(last.email)} ${ui.c.dim('at')} ${ui.c.bold(last.workspace)}`);
275
+ out(` ${ui.c.dim('press Enter to sign in as them, or type another email')}`);
276
+ }
277
+ const typedEmail = flag('--username') || flag('--email') || await (0, prompt_1.askOrCancel)(' email: ');
278
+ // Ctrl+C is "never mind", not "yes, the last person".
279
+ if (typedEmail === null) {
280
+ out();
281
+ out(ui.c.dim(' sign in canceled'));
282
+ out();
283
+ return;
284
+ }
285
+ const username = typedEmail || last?.email || '';
286
+ const again = Boolean(last && username === last.email);
245
287
  if (!username) {
246
288
  out(ui.fail('An email address is needed.'));
247
289
  out();
@@ -249,14 +291,15 @@ async function runLogin(args) {
249
291
  return;
250
292
  }
251
293
  // Where this person's workspace is. Asked of the product, not of them.
252
- let typedWorkspace = flag('--workspace');
294
+ let typedWorkspace = (flag('--organization') || flag('--workspace')) || (again ? last?.workspace : undefined);
253
295
  // Captured BEFORE the email lookup can fill it in. A workspace the product
254
296
  // worked out is not a workspace the person typed, and only the second may be
255
- // a local address. See the fence in `writeConnection`.
256
- const typedByHand = Boolean(typedWorkspace);
297
+ // a local address. See the fence in `writeConnection`. The last sign in
298
+ // counts as typed only if it was typed then.
299
+ const typedByHand = Boolean((flag('--organization') || flag('--workspace'))) || Boolean(again && last?.typed);
257
300
  if (!typedWorkspace) {
258
301
  const live = new ui.LiveIndicator();
259
- live.start('finding your workspace');
302
+ live.start('finding your organization');
260
303
  try {
261
304
  typedWorkspace = (await resolveWorkspace(username)) || undefined;
262
305
  }
@@ -268,18 +311,18 @@ async function runLogin(args) {
268
311
  process.stdout.write('\r');
269
312
  if (!typedWorkspace) {
270
313
  out();
271
- out(ui.fail('No workspace is registered for that email address.'));
272
- out(` ${ui.c.dim('if your company uses a different domain, pass --workspace <name>')}`);
314
+ out(ui.fail('No organization is registered for that email address.'));
315
+ out(` ${ui.c.dim('if your company uses a different domain, pass --organization <name>')}`);
273
316
  out();
274
317
  process.exitCode = 1;
275
318
  return;
276
319
  }
277
320
  }
278
- const url = workspaceUrl(typedWorkspace);
321
+ const url = await addressOf(typedWorkspace);
279
322
  const tenant = tenantFor(url, typedWorkspace, flag('--tenant'));
280
323
  // Said before the password is asked for, so a person can see which company
281
324
  // they are about to sign in to (manual 1.3).
282
- out(` workspace: ${url}`);
325
+ out(` organization: ${url}`);
283
326
  // COMPANY LOGIN (manual 1.10). A workspace whose company signs in through
284
327
  // its own identity provider is signed in to in a browser; this tool never
285
328
  // sees that password. `--device` is the same thing for a machine with no
@@ -292,7 +335,11 @@ async function runLogin(args) {
292
335
  process.exitCode = 1;
293
336
  return;
294
337
  }
295
- const password = byCompany ? '' : await (0, prompt_1.askHidden)(' password: ');
338
+ // The keychain first, when the person chose to keep it there last time.
339
+ const kept = byCompany ? null : savedPassword(username, typedWorkspace);
340
+ if (kept)
341
+ out(` ${ui.c.dim('password: from your Mac keychain')}`);
342
+ const password = byCompany ? '' : kept || await (0, prompt_1.askHidden)(' password: ');
296
343
  if (!byCompany && !password) {
297
344
  out(ui.fail('A password is needed.'));
298
345
  out();
@@ -315,8 +362,8 @@ async function runLogin(args) {
315
362
  }, tenant);
316
363
  if (reply.served === false) {
317
364
  out();
318
- out(ui.fail('That workspace is running a build that cannot sign you in yet.'));
319
- out(` ${ui.c.dim(reply.message || 'the workspace is behind this copy of the tool')}`);
365
+ out(ui.fail('That organization is running a build that cannot sign you in yet.'));
366
+ out(` ${ui.c.dim(reply.message || 'the organization is behind this copy of the tool')}`);
320
367
  out();
321
368
  process.exitCode = 1;
322
369
  return;
@@ -357,9 +404,13 @@ async function runLogin(args) {
357
404
  }
358
405
  }
359
406
  if (!reply.sign_in?.token) {
407
+ // A kept password that no longer works is removed, so the next sign in
408
+ // asks for the new one instead of failing the same way again.
409
+ if (kept)
410
+ forgetPassword(username, typedWorkspace);
360
411
  out();
361
412
  out(ui.fail(reply.message || 'That username and password were not accepted.'));
362
- out(` ${ui.c.dim('check the workspace name too: a right password in the wrong workspace looks the same')}`);
413
+ out(` ${ui.c.dim('check the organization name too: a right password in the wrong organization looks the same')}`);
363
414
  out();
364
415
  process.exitCode = 1;
365
416
  return;
@@ -412,7 +463,7 @@ async function runLogin(args) {
412
463
  }
413
464
  catch (err) {
414
465
  out();
415
- out(ui.fail(err instanceof Error ? err.message : 'the workspace address was refused'));
466
+ out(ui.fail(err instanceof Error ? err.message : (0, words_1.word)('addressRefused')));
416
467
  out();
417
468
  process.exitCode = 1;
418
469
  return;
@@ -420,14 +471,33 @@ async function runLogin(args) {
420
471
  // So a new terminal presents the key just issued, not the last one or none.
421
472
  for (const profile of (await Promise.resolve().then(() => __importStar(require('./install')))).finishSetup())
422
473
  out(` Finishing setup: added one line to ${profile}`);
474
+ // Remembered for next time: who, and where, exactly as used now.
475
+ saveLast({ email: username, workspace: typedWorkspace, typed: typedByHand });
476
+ if (!byCompany && !kept && password && keychainAvailable()) {
477
+ const keep = (await (0, prompt_1.ask)(' keep your password in your Mac keychain, so next time is just Enter? (y/n) '))
478
+ .trim().toLowerCase();
479
+ if (keep === 'y' || keep === 'yes') {
480
+ out(savePassword(username, typedWorkspace, password)
481
+ ? ` ${ui.c.dim('kept in your keychain; remove it with')} ${ui.c.bold('comprism login --forget')}`
482
+ : ` ${ui.c.dim('the keychain would not take it; you will be asked next time')}`);
483
+ }
484
+ }
423
485
  out();
424
- out(ui.ok(`Signed in as ${ui.c.bold(username)} at ${ui.c.bold(signedIn?.workspace_url || url)}.`));
486
+ // Where this machine will actually talk to: the address typed, when one was.
487
+ const where = (typedByHand && url) || signedIn?.workspace_url || url;
488
+ const onLaptop = /localhost|127\.0\.0\.1/.test(where);
489
+ out(ui.ok(`Signed in as ${ui.c.bold(username)} ${onLaptop
490
+ ? `on this laptop (${ui.c.bold(where.replace(/^https?:\/\//, ''))})`
491
+ : `at ${ui.c.bold(where)}`}.`));
425
492
  if (workspaceKey) {
426
493
  out(` ${ui.c.dim('This machine is enrolled and can be revoked from Administration.')}`);
427
494
  // Straight into the welcome screen, so the first thing after signing in is
428
495
  // where they are rather than another instruction.
429
- const { showWelcome } = await Promise.resolve().then(() => __importStar(require('./welcome')));
430
- await showWelcome();
496
+ // Unless the session is about to open, which draws it itself.
497
+ if (!args.includes('--into-session')) {
498
+ const { showWelcome } = await Promise.resolve().then(() => __importStar(require('./welcome')));
499
+ await showWelcome();
500
+ }
431
501
  }
432
502
  else {
433
503
  process.exitCode = 1;
@@ -435,7 +505,7 @@ async function runLogin(args) {
435
505
  // The workspace's OWN reason, carried back with the sign in. It used to
436
506
  // come from a local variable set by a separate call, which meant a blank
437
507
  // line whenever that call had not been the thing that failed.
438
- out(` ${ui.c.dim(signInMessage || 'the workspace did not say why')}`);
508
+ out(` ${ui.c.dim(signInMessage || 'the organization did not say why')}`);
439
509
  out(` ${ui.c.dim('you are signed in; this machine cannot ask for work until it is enrolled')}`);
440
510
  }
441
511
  out();
@@ -446,13 +516,13 @@ async function loginWithKey(key, args) {
446
516
  const i = args.indexOf(name);
447
517
  return i >= 0 ? args[i + 1] : undefined;
448
518
  };
449
- const typed = flag('--workspace');
519
+ const typed = (flag('--organization') || flag('--workspace'));
450
520
  if (!key || !typed) {
451
- out(ui.fail('Signing in with a key needs the key and the workspace: comprism login --key <key> --workspace <address>'));
521
+ out(ui.fail('Signing in with a key needs the key and the organization: comprism login --key <key> --organization <address>'));
452
522
  process.exitCode = 1;
453
523
  return;
454
524
  }
455
- const url = workspaceUrl(typed);
525
+ const url = await addressOf(typed);
456
526
  const tenant = tenantFor(url, typed, flag('--tenant'));
457
527
  const { ask: askWith } = await Promise.resolve().then(() => __importStar(require('../lib/gateway')));
458
528
  const existing = (0, connection_1.readConnection)();
@@ -464,7 +534,7 @@ async function loginWithKey(key, args) {
464
534
  }, true);
465
535
  }
466
536
  catch (err) {
467
- out(ui.fail(err instanceof Error ? err.message : 'the workspace address was refused'));
537
+ out(ui.fail(err instanceof Error ? err.message : (0, words_1.word)('addressRefused')));
468
538
  process.exitCode = 1;
469
539
  return;
470
540
  }
@@ -501,7 +571,7 @@ async function resolveWorkspace(email) {
501
571
  //
502
572
  // Working against a local server is still supported and is now something a
503
573
  // person SAYS rather than something an environment does to them:
504
- // `comprism login --workspace localhost:8009`.
574
+ // `comprism login --organization localhost:8009`.
505
575
  // ASKED OF THE ONE SERVICE, at the product's own address.
506
576
  //
507
577
  // This used to post to the authentication route directly, which made the
@@ -511,7 +581,7 @@ async function resolveWorkspace(email) {
511
581
  const root = `https://${WORKSPACE_DOMAIN}`;
512
582
  const reply = await (0, gateway_1.askAt)(root, { intent: 'resolve_workspace', prompt: email });
513
583
  if (!reply.ok || reply.served === false || reply.complete === false) {
514
- throw new Error(reply.message || 'Your workspace could not be looked up. Try again later.');
584
+ throw new Error(reply.message || 'Your organization could not be looked up. Try again later.');
515
585
  }
516
586
  const url = reply.session?.workspace_url;
517
587
  if (!url)
@@ -64,7 +64,7 @@ async function cmdPermissions(args) {
64
64
  process.stderr.write(` ${USAGE}\n`);
65
65
  return 2;
66
66
  }
67
- const { resolveProject, asWire } = await Promise.resolve().then(() => __importStar(require('../lib/project')));
67
+ const { resolveProject, asWire } = await Promise.resolve().then(() => __importStar(require('../machine/folder/project')));
68
68
  const { currentWorkspace } = await Promise.resolve().then(() => __importStar(require('./settings')));
69
69
  const facts = resolveProject(currentWorkspace().path, []);
70
70
  const files = {};
@@ -85,7 +85,7 @@ async function cmdPermissions(args) {
85
85
  const lines = reply.permissions?.lines;
86
86
  if (!reply.ok || !Array.isArray(lines)) {
87
87
  process.stderr.write(ui.fail(reply.served === false
88
- ? 'Your workspace is running a build without permission answers yet.'
88
+ ? 'Your organization is running a build without permission answers yet.'
89
89
  : (0, sessions_1.failure)(reply)) + '\n');
90
90
  return (0, sessions_1.exitFor)(reply);
91
91
  }
@@ -48,7 +48,7 @@ const fs = __importStar(require("fs"));
48
48
  const path = __importStar(require("path"));
49
49
  const readline = __importStar(require("readline"));
50
50
  const gateway_1 = require("../lib/gateway");
51
- const project_1 = require("../lib/project");
51
+ const project_1 = require("../machine/folder/project");
52
52
  const ui = __importStar(require("../lib/ui"));
53
53
  const out = (s = "") => process.stdout.write(`${s}\n`);
54
54
  const MAX_FILES = 200;
@@ -81,7 +81,7 @@ async function call(payload) {
81
81
  const reply = await (0, gateway_1.ask)({ intent: "plugins", prompt: "", pluginsPayload: payload });
82
82
  const body = reply.plugins;
83
83
  if (!reply.ok || reply.served === false || !body) {
84
- out(` ${ui.fail(reply.message || "Your plugins could not be read from your workspace.")}`);
84
+ out(` ${ui.fail(reply.message || "Your plugins could not be read from your organization.")}`);
85
85
  return null;
86
86
  }
87
87
  if (body.error) {
@@ -136,7 +136,7 @@ async function cmdPlugins(args) {
136
136
  out(` ${l}`);
137
137
  let scope = args.indexOf("--scope") >= 0 ? args[args.indexOf("--scope") + 1] : undefined;
138
138
  if (!scope) {
139
- const said = await question(` Install for: 1 this project 2 just me 3 cancel `);
139
+ const said = await question(` Install for: 1 this workspace 2 just me 3 cancel `);
140
140
  scope = said === "1" ? "project" : said === "2" ? "personal" : undefined;
141
141
  if (!scope) {
142
142
  out(" Nothing was installed.");
@@ -45,8 +45,8 @@ async function cmdPrivacy() {
45
45
  const reply = await (0, gateway_1.ask)({ intent: "privacy", prompt: "" });
46
46
  if (!reply.ok || reply.served === false) {
47
47
  out(ui.fail(reply.served === false
48
- ? "Your workspace is running an older build that does not answer this yet."
49
- : `Your workspace could not be reached: ${reply.message || "no answer"}`));
48
+ ? "Your organization is running an older build that does not answer this yet."
49
+ : `Your organization could not be reached: ${reply.message || "no answer"}`));
50
50
  return 1;
51
51
  }
52
52
  out();
@@ -4,5 +4,9 @@ export interface Opening {
4
4
  latest?: boolean;
5
5
  resume?: string;
6
6
  pick?: boolean;
7
+ /** Set once signing in has been offered, so it is never offered twice. */
8
+ noSignIn?: boolean;
9
+ /** The mark is already on screen (signing in drew it). */
10
+ noMark?: boolean;
7
11
  }
8
12
  export declare function runRepl(how?: Opening): Promise<void>;