@await-widget/runtime 0.0.47 → 0.0.49

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 (2) hide show
  1. package/bin/await-widget.js +27 -57
  2. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /* eslint-disable n/prefer-global/buffer, no-bitwise, unicorn/no-array-sort */
3
3
  import crypto from 'node:crypto';
4
+ import {execFileSync} from 'node:child_process';
4
5
  import fs from 'node:fs';
5
6
  import http from 'node:http';
6
7
  import os from 'node:os';
@@ -24,7 +25,6 @@ const crcTable = makeCrcTable();
24
25
  const bridgeInfoDirectory = '.await';
25
26
  const bridgeInfoFileName = 'bridge.json';
26
27
  const singleWidgetPath = '.';
27
- const widgetDirectoryError = 'Run await-widget from a package root or first-level widget folder whose package.json includes @await-widget/runtime.';
28
28
 
29
29
  function main() {
30
30
  const options = parseArgs(process.argv.slice(2));
@@ -138,16 +138,15 @@ function parseAppArgs(args) {
138
138
  }
139
139
 
140
140
  async function startWorkspaceServer(options) {
141
- let roots;
141
+ const workspaceRoot = process.cwd();
142
+ let widgetRoot;
142
143
  try {
143
- roots = await resolveWidgetServerRoots(process.cwd());
144
+ widgetRoot = await selectWidgetRoot(workspaceRoot);
144
145
  } catch (error) {
145
146
  console.error(error.message);
146
147
  process.exit(1);
147
148
  }
148
149
 
149
- const {packageRoot, widgetRoot} = roots;
150
-
151
150
  const token = crypto.randomBytes(6).toString('hex');
152
151
  const bridge = createBridgeState(widgetRoot);
153
152
  const server = http.createServer((request, response) => {
@@ -161,7 +160,7 @@ async function startWorkspaceServer(options) {
161
160
  server.listen(options.port, '0.0.0.0', () => {
162
161
  const address = server.address();
163
162
  const port = typeof address === 'object' && address ? address.port : options.port;
164
- writeBridgeInfo(packageRoot, port, token);
163
+ writeBridgeInfo(workspaceRoot, port, token);
165
164
  console.log(`Await computer connection serving ${widgetRoot}`);
166
165
  printServerUrls(port, token);
167
166
  console.log('Press Ctrl+C to stop.');
@@ -386,51 +385,29 @@ function widgetPathKey(widgets) {
386
385
  return widgets.map(widget => widget.path).sort((left, right) => left.localeCompare(right)).join('\n');
387
386
  }
388
387
 
389
- function findPackageRoot(start) {
388
+ function findBridgeRoot(start) {
390
389
  let current = path.resolve(start);
391
390
  while (true) {
392
- const candidate = path.join(current, 'package.json');
393
- if (fs.existsSync(candidate)) {
391
+ if (fs.existsSync(bridgeInfoPath(current))) {
394
392
  return current;
395
393
  }
396
394
 
397
395
  const parent = path.dirname(current);
398
396
  if (parent === current) {
399
- return null;
397
+ throw new Error('Cannot find Await bridge info. Run npx await-widget first.');
400
398
  }
401
399
 
402
400
  current = parent;
403
401
  }
404
402
  }
405
403
 
406
- async function resolveWidgetServerRoots(start) {
407
- const widgetRoot = path.resolve(start);
408
- const packageRoot = findPackageRoot(widgetRoot);
409
- if (
410
- !packageRoot
411
- || !hasRuntimeDependency(packageRoot)
412
- ) {
413
- throw new Error(widgetDirectoryError);
414
- }
415
-
416
- if (packageRoot === widgetRoot) {
417
- return {packageRoot, widgetRoot: await selectWidgetRoot(packageRoot)};
418
- }
419
-
420
- if (path.dirname(widgetRoot) !== packageRoot || !isValidTopLevelName(path.basename(widgetRoot))) {
421
- throw new Error(widgetDirectoryError);
422
- }
423
-
424
- return {packageRoot, widgetRoot};
425
- }
426
-
427
- function selectWidgetRoot(packageRoot) {
404
+ function selectWidgetRoot(directory) {
428
405
  const options = [
429
- {name: `${path.basename(packageRoot)} (root)`, path: packageRoot},
430
- ...fs.readdirSync(packageRoot, {withFileTypes: true})
431
- .filter(entry => entry.isDirectory() && isValidTopLevelName(entry.name))
406
+ {name: `${path.basename(directory)} (current directory)`, path: directory},
407
+ ...fs.readdirSync(directory, {withFileTypes: true})
408
+ .filter(entry => entry.isDirectory() && isSelectableDirectoryName(entry.name))
432
409
  .sort((left, right) => left.name.localeCompare(right.name))
433
- .map(entry => ({name: entry.name, path: path.join(packageRoot, entry.name)})),
410
+ .map(entry => ({name: entry.name, path: path.join(directory, entry.name)})),
434
411
  ];
435
412
  let selected = 0;
436
413
  let rendered = false;
@@ -478,11 +455,6 @@ function selectWidgetRoot(packageRoot) {
478
455
  });
479
456
  }
480
457
 
481
- function hasRuntimeDependency(packageRoot) {
482
- const manifest = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
483
- return Boolean(manifest.dependencies?.['@await-widget/runtime'] ?? manifest.devDependencies?.['@await-widget/runtime']);
484
- }
485
-
486
458
  function listDesktopWidgets(root) {
487
459
  return [{name: path.basename(root), path: singleWidgetPath}];
488
460
  }
@@ -517,7 +489,7 @@ function safeWidgetPath(root, widgetPath, options = {}) {
517
489
  return root;
518
490
  }
519
491
 
520
- function isValidTopLevelName(name) {
492
+ function isSelectableDirectoryName(name) {
521
493
  return Boolean(name) && !name.includes('/') && !name.includes('\\') && !isExcludedName(name);
522
494
  }
523
495
 
@@ -765,19 +737,11 @@ function resolveBridgeUrl(options) {
765
737
  return options.bridgeUrl;
766
738
  }
767
739
 
768
- const root = findPackageRoot(path.resolve(options.workspace ?? process.cwd()));
769
- if (!root) {
770
- throw new Error('Cannot find package.json for Await bridge lookup.');
771
- }
772
-
740
+ const root = findBridgeRoot(options.workspace ?? process.cwd());
773
741
  return readBridgeUrl(bridgeInfoPath(root));
774
742
  }
775
743
 
776
744
  function readBridgeUrl(infoPath) {
777
- if (!fs.existsSync(infoPath)) {
778
- throw new Error('Cannot find Await bridge info. Run npx await-widget first.');
779
- }
780
-
781
745
  const info = JSON.parse(fs.readFileSync(infoPath, 'utf8'));
782
746
  return info.bridgeUrl;
783
747
  }
@@ -811,7 +775,8 @@ function appCommandResult(options, tool, result) {
811
775
  }
812
776
 
813
777
  function saveCapture(options, result) {
814
- const root = findPackageRoot(options.workspace ? path.resolve(options.workspace) : process.cwd()) ?? process.cwd();
778
+ const workspace = path.resolve(options.workspace ?? process.cwd());
779
+ const root = options.bridgeUrl ? workspace : findBridgeRoot(workspace);
815
780
  const directory = path.join(root, bridgeInfoDirectory, 'captures');
816
781
  const name = safeCaptureFileName(String(result.widgetId ?? 'widget'));
817
782
  const filePath = path.join(directory, `${name}-${Date.now()}.png`);
@@ -921,6 +886,10 @@ function printServerUrls(port, token) {
921
886
  console.log('');
922
887
  console.log(recommended.url);
923
888
  console.log('');
889
+ if (process.platform === 'darwin') {
890
+ execFileSync('pbcopy', {input: recommended.url});
891
+ console.log('Connection URL copied to clipboard.');
892
+ }
924
893
  }
925
894
 
926
895
  if (otherUrls.length > 0) {
@@ -1016,14 +985,15 @@ function printHelp() {
1016
985
  await-widget [--port ${defaultPort}]
1017
986
  await-widget app <command> [options]
1018
987
 
1019
- Start the Await computer connection from a package root or first-level widget
1020
- folder whose package.json includes @await-widget/runtime. Starting from the
1021
- package root opens a directory selector.
988
+ Start the Await computer connection from any directory. Choose the current
989
+ directory or one of its direct subdirectories. No package.json or runtime
990
+ dependency is required to start the connection.
1022
991
 
1023
992
  What it does:
1024
993
  - Serves the selected widget folder to Await for live sync.
1025
994
  - Prints a URL to paste into Await's Connect Computer sheet.
1026
- - Writes .await/bridge.json in the package root for app commands.
995
+ - Writes .await/bridge.json in the directory where the connection was started.
996
+ - App commands search the current directory and its parents for bridge info.
1027
997
  - Sends one-shot JSON app commands with await-widget app <command>.
1028
998
 
1029
999
  Examples:
@@ -1035,7 +1005,7 @@ Examples:
1035
1005
  npx await-widget app get-recent-widget-logs --widget-id YourWidget
1036
1006
 
1037
1007
  App command options:
1038
- --workspace <path> Read .await/bridge.json from another package/widget path.
1008
+ --workspace <path> Search this directory and its parents for .await/bridge.json.
1039
1009
  --bridge-url <url> Send directly to a bridge URL instead of reading bridge.json.
1040
1010
  --json <json> Merge raw JSON arguments into the app command.
1041
1011
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@await-widget/runtime",
3
- "version": "0.0.47",
3
+ "version": "0.0.49",
4
4
  "description": "TypeScript declarations for Await widgets.",
5
5
  "license": "MIT",
6
6
  "author": "Maundy",