agoric 0.21.2-other-dev-1f26562.0 → 0.21.2-other-dev-3eb1a1d.0

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.
@@ -1,11 +1,12 @@
1
1
  // @ts-check
2
- /* global process */
3
- import { Fail } from '@agoric/assert';
2
+ /* eslint-env node */
3
+ import { makeWalletUtils } from '@agoric/client-utils';
4
+ import { Fail } from '@endo/errors';
4
5
  import { CommanderError } from 'commander';
5
6
  import { normalizeAddressWithOptions } from '../lib/chain.js';
7
+ import { getNetworkConfig } from '../lib/network-config.js';
8
+ import { sendAction } from '../lib/wallet.js';
6
9
  import { bigintReplacer } from '../lib/format.js';
7
- import { getNetworkConfig } from '../lib/rpc.js';
8
- import { makeWalletUtils, sendAction } from '../lib/wallet.js';
9
10
 
10
11
  /**
11
12
  * Make commands for testing.
@@ -38,10 +39,11 @@ export const makeTestCommand = (
38
39
  try {
39
40
  // XXX pass fetch to getNetworkConfig() explicitly
40
41
  // await null above makes this await safe
41
- // eslint-disable-next-line @jessie.js/no-nested-await
42
- const networkConfig = await getNetworkConfig(env);
43
- return makeWalletUtils({ fetch, execFileSync, delay }, networkConfig);
42
+ const networkConfig = await getNetworkConfig({ env, fetch });
43
+ return makeWalletUtils({ fetch, delay }, networkConfig);
44
44
  } catch (err) {
45
+ // CommanderError is a class constructor, and so
46
+ // must be invoked with `new`.
45
47
  throw new CommanderError(1, 'RPC_FAIL', err.message);
46
48
  }
47
49
  };
@@ -83,7 +85,13 @@ export const makeTestCommand = (
83
85
  publicInvitationMaker: 'makeInvitation',
84
86
  },
85
87
  proposal: {
86
- want: { Tokens: { brand: agoricNames.brand.GoodStuff, value: 32n } },
88
+ want: {
89
+ Tokens: {
90
+ // @ts-expect-error BoardRemote not a Brand object
91
+ brand: agoricNames.brand.GoodStuff,
92
+ value: 32n,
93
+ },
94
+ },
87
95
  },
88
96
  };
89
97
  const result = await sendAction(
@@ -1,16 +1,17 @@
1
- /* eslint-disable no-await-in-loop */
2
- /* eslint-disable @jessie.js/no-nested-await */
3
1
  // @ts-check
4
2
  /* eslint-disable func-names */
5
- /* global fetch, process */
6
- import { Command } from 'commander';
3
+ /* eslint-env node */
4
+ import { makeVstorageKit } from '@agoric/client-utils';
7
5
  import {
8
6
  lookupOfferIdForVault,
9
7
  Offers,
10
8
  } from '@agoric/inter-protocol/src/clientSupport.js';
9
+ import { Command } from 'commander';
11
10
  import { normalizeAddressWithOptions } from '../lib/chain.js';
12
- import { makeRpcUtils } from '../lib/rpc.js';
13
11
  import { getCurrent, outputExecuteOfferAction } from '../lib/wallet.js';
12
+ import { getNetworkConfig } from '../lib/network-config.js';
13
+
14
+ const networkConfig = await getNetworkConfig({ env: process.env, fetch });
14
15
 
15
16
  /**
16
17
  * @param {import('anylogger').Logger} logger
@@ -38,10 +39,10 @@ export const makeVaultsCommand = logger => {
38
39
  normalizeAddress,
39
40
  )
40
41
  .action(async function (opts) {
41
- const { readLatestHead } = await makeRpcUtils({ fetch });
42
+ const { readPublished } = await makeVstorageKit({ fetch }, networkConfig);
42
43
 
43
44
  const current = await getCurrent(opts.from, {
44
- readLatestHead,
45
+ readPublished,
45
46
  });
46
47
 
47
48
  const vaultStoragePaths = current.offerToPublicSubscriberPaths.map(
@@ -56,16 +57,16 @@ export const makeVaultsCommand = logger => {
56
57
 
57
58
  vaults
58
59
  .command('open')
59
- .description('open a new vault')
60
+ .description('Prepare an offer to open a new vault')
60
61
  .requiredOption('--giveCollateral <number>', 'Collateral to give', Number)
61
62
  .requiredOption('--wantMinted <number>', 'Minted wants', Number)
62
63
  .option('--offerId <string>', 'Offer id', String, `openVault-${Date.now()}`)
63
64
  .option('--collateralBrand <string>', 'Collateral brand key', 'ATOM')
64
65
  .action(async function (opts) {
65
66
  logger.warn('running with options', opts);
66
- const { agoricNames } = await makeRpcUtils({ fetch });
67
+ const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig);
67
68
 
68
- const offer = Offers.vaults.OpenVault(agoricNames.brand, {
69
+ const offer = Offers.vaults.OpenVault(agoricNames, {
69
70
  giveCollateral: opts.giveCollateral,
70
71
  wantMinted: opts.wantMinted,
71
72
  offerId: opts.offerId,
@@ -78,7 +79,7 @@ export const makeVaultsCommand = logger => {
78
79
 
79
80
  vaults
80
81
  .command('adjust')
81
- .description('adjust an existing vault')
82
+ .description('Prepare an offer to adjust an existing vault')
82
83
  .requiredOption(
83
84
  '--from <address>',
84
85
  'wallet address literal or name',
@@ -98,15 +99,18 @@ export const makeVaultsCommand = logger => {
98
99
  .requiredOption('--vaultId <string>', 'Key of vault (e.g. vault1)')
99
100
  .action(async function (opts) {
100
101
  logger.warn('running with options', opts);
101
- const { agoricNames, readLatestHead } = await makeRpcUtils({ fetch });
102
+ const { agoricNames, readPublished } = await makeVstorageKit(
103
+ { fetch },
104
+ networkConfig,
105
+ );
102
106
 
103
107
  const previousOfferId = await lookupOfferIdForVault(
104
108
  opts.vaultId,
105
- getCurrent(opts.from, { readLatestHead }),
109
+ getCurrent(opts.from, { readPublished }),
106
110
  );
107
111
 
108
112
  const offer = Offers.vaults.AdjustBalances(
109
- agoricNames.brand,
113
+ agoricNames,
110
114
  {
111
115
  giveCollateral: opts.giveCollateral,
112
116
  wantCollateral: opts.wantCollateral,
@@ -123,7 +127,7 @@ export const makeVaultsCommand = logger => {
123
127
 
124
128
  vaults
125
129
  .command('close')
126
- .description('close an existing vault')
130
+ .description('Prepare an offer to close an existing vault')
127
131
  .requiredOption(
128
132
  '--from <address>',
129
133
  'wallet address literal or name',
@@ -139,15 +143,18 @@ export const makeVaultsCommand = logger => {
139
143
  )
140
144
  .action(async function (opts) {
141
145
  logger.warn('running with options', opts);
142
- const { agoricNames, readLatestHead } = await makeRpcUtils({ fetch });
146
+ const { agoricNames, readPublished } = await makeVstorageKit(
147
+ { fetch },
148
+ networkConfig,
149
+ );
143
150
 
144
151
  const previousOfferId = await lookupOfferIdForVault(
145
152
  opts.vaultId,
146
- getCurrent(opts.from, { readLatestHead }),
153
+ getCurrent(opts.from, { readPublished }),
147
154
  );
148
155
 
149
156
  const offer = Offers.vaults.CloseVault(
150
- agoricNames.brand,
157
+ agoricNames,
151
158
  {
152
159
  giveMinted: opts.giveMinted,
153
160
  offerId: opts.offerId,
@@ -1,6 +1,6 @@
1
1
  // @ts-check
2
2
  /* eslint-disable func-names */
3
- /* global fetch, process */
3
+ /* eslint-env node */
4
4
  import {
5
5
  iterateLatest,
6
6
  makeCastingSpec,
@@ -8,12 +8,10 @@ import {
8
8
  makeLeader,
9
9
  makeLeaderFromRpcAddresses,
10
10
  } from '@agoric/casting';
11
- import { Command } from 'commander';
11
+ import { makeVstorageKit } from '@agoric/client-utils';
12
+ import { execFileSync } from 'child_process';
12
13
  import fs from 'fs';
13
14
  import util from 'util';
14
- import { execFileSync } from 'child_process';
15
- import { fmtRecordOfLines, summarize } from '../lib/format.js';
16
- import { makeRpcUtils, networkConfig } from '../lib/rpc.js';
17
15
 
18
16
  import { makeLeaderOptions } from '../lib/casting.js';
19
17
  import {
@@ -21,24 +19,43 @@ import {
21
19
  fetchSwingsetParams,
22
20
  normalizeAddressWithOptions,
23
21
  } from '../lib/chain.js';
22
+ import { getNetworkConfig } from '../lib/network-config.js';
24
23
  import { coalesceWalletState, getCurrent } from '../lib/wallet.js';
24
+ import {
25
+ summarize,
26
+ fmtRecordOfLines,
27
+ parseFiniteNumber,
28
+ } from '../lib/format.js';
29
+
30
+ const networkConfig = await getNetworkConfig({ env: process.env, fetch });
25
31
 
26
32
  const SLEEP_SECONDS = 3;
27
33
 
28
- export const makeWalletCommand = async () => {
29
- const wallet = new Command('wallet')
30
- .description('wallet commands')
31
- .option('--home <dir>', 'agd application home directory')
32
- .option(
33
- '--keyring-backend <os|file|test>',
34
- 'keyring\'s backend (os|file|test) (default "os")',
35
- );
34
+ /**
35
+ * @param {import('commander').Command['command']} command
36
+ * @returns {Promise<import('commander').Command>}
37
+ */
38
+ export const makeWalletCommand = async command => {
39
+ /**
40
+ * @param {import('commander').Command} baseCmd
41
+ */
42
+ const withSharedTxOptions = baseCmd =>
43
+ baseCmd
44
+ .option('--home <dir>', 'agd application home directory')
45
+ .option(
46
+ '--keyring-backend <os|file|test>',
47
+ 'keyring\'s backend (os|file|test) (default "os")',
48
+ );
49
+ /** @typedef {{home?: string, keyringBackend: 'os' | 'file' | 'test'}} SharedTxOptions */
50
+
51
+ const wallet = withSharedTxOptions(command('wallet')).description(
52
+ 'wallet commands',
53
+ );
36
54
 
37
55
  const normalizeAddress = literalOrName =>
38
56
  normalizeAddressWithOptions(literalOrName, wallet.opts());
39
57
 
40
- wallet
41
- .command('provision')
58
+ withSharedTxOptions(wallet.command('provision'))
42
59
  .description('provision a Smart Wallet')
43
60
  .requiredOption(
44
61
  '--account [address]',
@@ -48,8 +65,14 @@ export const makeWalletCommand = async () => {
48
65
  .option('--spend', 'confirm you want to spend')
49
66
  .option('--nickname <string>', 'nickname to use', 'my-wallet')
50
67
  .action(function (opts) {
51
- const { account, nickname, spend } = opts;
52
- const { home, keyringBackend: backend } = wallet.opts();
68
+ /** @typedef {{account: string, spend?: boolean, nickname: 'my-wallet' | string }} Opts */
69
+ const {
70
+ account,
71
+ nickname,
72
+ spend,
73
+ home,
74
+ keyringBackend: backend,
75
+ } = /** @type {SharedTxOptions & Opts} */ ({ ...wallet.opts(), ...opts });
53
76
  const tx = ['provision-one', nickname, account, 'SMART_WALLET'];
54
77
  if (spend) {
55
78
  execSwingsetTransaction(tx, {
@@ -86,7 +109,7 @@ export const makeWalletCommand = async () => {
86
109
  .action(async function (opts) {
87
110
  const offerStr = fs.readFileSync(opts.file).toString();
88
111
 
89
- const { unserializer } = await makeRpcUtils({ fetch });
112
+ const { unserializer } = await makeVstorageKit({ fetch }, networkConfig);
90
113
 
91
114
  const offerObj = unserializer.fromCapData(JSON.parse(offerStr));
92
115
  console.log(offerObj);
@@ -101,14 +124,13 @@ export const makeWalletCommand = async () => {
101
124
  .action(async function (opts) {
102
125
  const offerStr = fs.readFileSync(opts.offer).toString();
103
126
 
104
- const { unserializer } = await makeRpcUtils({ fetch });
127
+ const { unserializer } = await makeVstorageKit({ fetch }, networkConfig);
105
128
 
106
129
  const offerObj = unserializer.fromCapData(JSON.parse(offerStr));
107
130
  console.log(offerObj.offer.id);
108
131
  });
109
132
 
110
- wallet
111
- .command('send')
133
+ withSharedTxOptions(wallet.command('send'))
112
134
  .description('send a prepared offer')
113
135
  .requiredOption(
114
136
  '--from [address]',
@@ -117,24 +139,69 @@ export const makeWalletCommand = async () => {
117
139
  )
118
140
  .requiredOption('--offer [filename]', 'path to file with prepared offer')
119
141
  .option('--dry-run', 'spit out the command instead of running it')
142
+ .option('--gas', 'gas limit; "auto" [default] to calculate automatically')
143
+ .option(
144
+ '--gas-adjustment',
145
+ 'factor by which to multiply the --gas=auto calculation result [default 1.2]',
146
+ )
147
+ .option('--verbose', 'print command output')
120
148
  .action(function (opts) {
121
- const { dryRun, from, offer } = opts;
122
- const { home, keyringBackend: backend } = wallet.opts();
149
+ /**
150
+ * @typedef {{
151
+ * from: string,
152
+ * offer: string,
153
+ * dryRun: boolean,
154
+ * gas: string,
155
+ * gasAdjustment: string,
156
+ * verbose: boolean,
157
+ * }} Opts
158
+ */
159
+ const {
160
+ dryRun,
161
+ from,
162
+ gas = 'auto',
163
+ gasAdjustment = '1.2',
164
+ offer,
165
+ home,
166
+ verbose,
167
+ keyringBackend: backend,
168
+ } = /** @type {SharedTxOptions & Opts} */ ({ ...wallet.opts(), ...opts });
123
169
 
124
170
  const offerBody = fs.readFileSync(offer).toString();
125
- execSwingsetTransaction(['wallet-action', '--allow-spend', offerBody], {
126
- from,
127
- dryRun,
128
- keyring: { home, backend },
129
- ...networkConfig,
130
- });
171
+ const out = execSwingsetTransaction(
172
+ ['wallet-action', '--allow-spend', offerBody, '-ojson', '-bblock'],
173
+ {
174
+ ...networkConfig,
175
+ keyring: { home, backend },
176
+ from,
177
+ gas:
178
+ gas === 'auto'
179
+ ? ['auto', parseFiniteNumber(gasAdjustment)]
180
+ : parseFiniteNumber(gas),
181
+ dryRun,
182
+ verbose,
183
+ },
184
+ );
185
+
186
+ // see sendAction in {@link ../lib/wallet.js}
187
+ if (dryRun || !verbose) return;
188
+ try {
189
+ const tx = JSON.parse(/** @type {string} */ (out));
190
+ if (tx.code !== 0) {
191
+ console.error('failed to send tx', tx);
192
+ }
193
+ console.log(tx);
194
+ } catch (err) {
195
+ console.error('unexpected output', JSON.stringify(out));
196
+ throw err;
197
+ }
131
198
  });
132
199
 
133
200
  wallet
134
201
  .command('list')
135
202
  .description('list all wallets in vstorage')
136
203
  .action(async function () {
137
- const { vstorage } = await makeRpcUtils({ fetch });
204
+ const { vstorage } = await makeVstorageKit({ fetch }, networkConfig);
138
205
  const wallets = await vstorage.keys('published.wallet');
139
206
  process.stdout.write(wallets.join('\n'));
140
207
  });
@@ -148,23 +215,26 @@ export const makeWalletCommand = async () => {
148
215
  normalizeAddress,
149
216
  )
150
217
  .action(async function (opts) {
151
- const { agoricNames, unserializer, readLatestHead } = await makeRpcUtils({
152
- fetch,
153
- });
218
+ const { agoricNames, unserializer, readPublished } =
219
+ await makeVstorageKit(
220
+ {
221
+ fetch,
222
+ },
223
+ networkConfig,
224
+ );
154
225
 
155
226
  const leader = makeLeader(networkConfig.rpcAddrs[0]);
156
227
  const follower = await makeFollower(
157
228
  `:published.wallet.${opts.from}`,
158
229
  leader,
159
230
  {
160
- // @ts-expect-error xxx
161
231
  unserializer,
162
232
  },
163
233
  );
164
234
 
165
235
  const coalesced = await coalesceWalletState(follower);
166
236
 
167
- const current = await getCurrent(opts.from, { readLatestHead });
237
+ const current = await getCurrent(opts.from, { readPublished });
168
238
 
169
239
  console.warn(
170
240
  'got coalesced',
package/src/cosmos.js CHANGED
@@ -14,10 +14,10 @@ export default async function cosmosMain(progname, rawArgs, powers, opts) {
14
14
  const pspawnEnv = { ...process.env };
15
15
  if (popts.verbose > 1) {
16
16
  // Enable verbose logs.
17
- pspawnEnv.DEBUG = 'agoric';
17
+ pspawnEnv.DEBUG = 'agoric:info';
18
18
  } else if (!popts.verbose) {
19
19
  // Disable more logs.
20
- pspawnEnv.DEBUG = '';
20
+ pspawnEnv.DEBUG = 'agoric:none';
21
21
  }
22
22
 
23
23
  const pspawn = makePspawn({ env: pspawnEnv, log, spawn, chalk });
@@ -50,7 +50,7 @@ export default async function cosmosMain(progname, rawArgs, powers, opts) {
50
50
  },
51
51
  );
52
52
  // Ensure the build doesn't mess up stdout.
53
- ps.childProcess.stdout.pipe(process.stderr);
53
+ ps.childProcess.stdout?.pipe(process.stderr);
54
54
  return ps;
55
55
  }
56
56
  throw e;
package/src/deploy.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // @ts-check
2
- /* global process setTimeout setInterval clearInterval */
2
+ /* eslint-env node */
3
3
 
4
- import { E, makeCapTP } from '@endo/captp';
4
+ import { X } from '@endo/errors';
5
5
  import { makePromiseKit } from '@endo/promise-kit';
6
+ import { E, makeCapTP } from '@endo/captp';
6
7
  import { makeLeaderFromRpcAddresses } from '@agoric/casting';
7
8
  import path from 'path';
8
9
  import http from 'http';
@@ -20,8 +21,6 @@ import {
20
21
  import { makeJsonHttpClient } from './json-http-client-node.js';
21
22
  import { makeScriptLoader } from './scripts.js';
22
23
 
23
- const { details: X } = assert;
24
-
25
24
  // note: CapTP has its own HandledPromise instantiation, and the contract
26
25
  // must use the same one that CapTP uses. We achieve this by not bundling
27
26
  // captp, and doing a (non-isolated) dynamic import of the deploy script
package/src/entrypoint.js CHANGED
@@ -1,11 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ /* eslint-env node */
2
3
  // @jessie-check
3
4
 
4
- /* global process */
5
-
6
5
  import '@endo/init/pre.js';
7
6
  import 'esm';
8
- import '@agoric/casting/node-fetch-shim.js';
9
7
  import '@endo/init/legacy.js';
10
8
 
11
9
  import path from 'path';
package/src/follow.js CHANGED
@@ -142,9 +142,12 @@ export default async function followerMain(progname, rawArgs, powers, opts) {
142
142
  verbose && console.warn('Following', spec);
143
143
  const castingSpec = makeCastingSpec(spec);
144
144
  const follower = makeFollower(castingSpec, leader, followerOptions);
145
- for await (const { value, blockHeight, currentBlockHeight } of iterate(
146
- follower,
147
- )) {
145
+ for await (const obj of iterate(follower)) {
146
+ if ('error' in obj) {
147
+ console.error('Error following:', obj.error);
148
+ continue;
149
+ }
150
+ const { value, blockHeight, currentBlockHeight } = obj;
148
151
  const blockHeightPrefix = opts.blockHeight ? `${blockHeight}:` : '';
149
152
  const currentBlockHeightPrefix = opts.currentBlockHeight
150
153
  ? `${currentBlockHeight}:`
package/src/helpers.js CHANGED
@@ -1,7 +1,9 @@
1
- /* global process */
1
+ /* eslint-env node */
2
2
  // @ts-check
3
3
 
4
- /** @typedef {import('child_process').ChildProcess} ChildProcess */
4
+ /** @import { ChildProcess } from 'child_process' */
5
+
6
+ export { getNetworkConfig } from './lib/network-config.js';
5
7
 
6
8
  export const getSDKBinaries = ({
7
9
  jsPfx = '../..',
@@ -40,10 +42,12 @@ export const makePspawn = ({
40
42
  *
41
43
  * @param {string} cmd command name to run
42
44
  * @param {Array<string>} cargs arguments to the command
43
- * @param {object} param2
44
- * @param {string | [string, string, string]} [param2.stdio] standard IO
45
+ * @param {object} [opts]
46
+ * @param {string} [opts.cwd]
47
+ * @param {string | [string, string, string]} [opts.stdio] standard IO
45
48
  * specification
46
- * @param {Record<string, string | undefined>} [param2.env] environment
49
+ * @param {Record<string, string | undefined>} [opts.env] environment
50
+ * @param {boolean} [opts.detached] whether the child process should be detached
47
51
  * @returns {Promise<number> & { childProcess: ChildProcess }}} promise for
48
52
  * exit status. The return result has a `childProcess` property to obtain
49
53
  * control over the running process
package/src/init.js CHANGED
@@ -1,12 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { makePspawn } from './helpers.js';
3
3
 
4
- // Ambient types. Needed only for dev but this does a runtime import.
5
- // https://github.com/Agoric/agoric-sdk/issues/6512
6
- import '@endo/captp/src/types.js';
7
- import '@agoric/swingset-vat/exported.js';
8
- import '@agoric/swingset-vat/src/vats/network/types.js';
9
-
10
4
  // Use either an absolute template URL, or find it relative to DAPP_URL_BASE.
11
5
  const gitURL = (relativeOrAbsoluteURL, base) => {
12
6
  const url = new URL(relativeOrAbsoluteURL, base);
@@ -40,9 +34,10 @@ export default async function initMain(_progname, rawArgs, priv, opts) {
40
34
  dappBranch = ['-b', opts.dappBranch];
41
35
  }
42
36
 
37
+ const shallow = ['--depth', '1', '--shallow-submodules'];
43
38
  const exitStatus = await pspawn(
44
39
  'git',
45
- ['clone', '--origin=upstream', dappURL, DIR, ...dappBranch],
40
+ ['clone', '--origin=upstream', ...shallow, dappURL, DIR, ...dappBranch],
46
41
  {
47
42
  stdio: 'inherit',
48
43
  },
@@ -60,7 +55,6 @@ export default async function initMain(_progname, rawArgs, priv, opts) {
60
55
  const path = `${DIR}/${dir}package.json`;
61
56
  log('rewriting ', path);
62
57
 
63
- // eslint-disable-next-line no-await-in-loop
64
58
  const contents = await fs.readFile(path, 'utf-8');
65
59
  const pkg = JSON.parse(contents.replace(/@DIR@/g, DIR));
66
60
  if (dir === '') {
@@ -74,7 +68,6 @@ export default async function initMain(_progname, rawArgs, priv, opts) {
74
68
  pkg.name = `${DIR}${pkg.name.substr(topLevelName.length)}`;
75
69
  const json = JSON.stringify(pkg, undefined, 2);
76
70
 
77
- // eslint-disable-next-line no-await-in-loop
78
71
  await fs.writeFile(path, json);
79
72
  }
80
73
 
package/src/install.js CHANGED
@@ -1,4 +1,4 @@
1
- /* global process AggregateError Buffer */
1
+ /* eslint-env node */
2
2
  import path from 'path';
3
3
  import chalk from 'chalk';
4
4
  import { makePspawn } from './helpers.js';
@@ -9,8 +9,7 @@ const REQUIRED_AGORIC_START_PACKAGES = [
9
9
  '@agoric/cosmic-swingset',
10
10
  ];
11
11
 
12
- const filename = new URL(import.meta.url).pathname;
13
- const dirname = path.dirname(filename);
12
+ const dirname = path.dirname(new URL(import.meta.url).pathname);
14
13
 
15
14
  export default async function installMain(progname, rawArgs, powers, opts) {
16
15
  const { anylogger, fs, spawn } = powers;
@@ -38,19 +37,19 @@ export default async function installMain(progname, rawArgs, powers, opts) {
38
37
  stdio: ['inherit', 'pipe', 'inherit'],
39
38
  });
40
39
  const stdout = [];
41
- p.childProcess.stdout.on('data', out => stdout.push(out));
40
+ p.childProcess.stdout?.on('data', out => stdout.push(out));
42
41
  await p;
43
42
  const d = JSON.parse(Buffer.concat(stdout).toString('utf-8'));
44
- Object.entries(d).forEach(([name, { location }]) =>
45
- map.set(name, path.resolve(cwd, location)),
46
- );
43
+ for (const [name, { location }] of Object.entries(d)) {
44
+ map.set(name, path.resolve(cwd, location));
45
+ }
47
46
  return map;
48
47
  }
49
48
 
50
49
  let subdirs;
51
50
  const workTrees = ['.'];
52
51
  let sdkWorktree;
53
- /** @type {Map<string, string>} */
52
+ /** @type {Map<string, string | null>} */
54
53
  const sdkPackageToPath = new Map();
55
54
  const linkFolder = path.resolve(`_agstate/yarn-links`);
56
55
  const linkFlags = [];
@@ -61,7 +60,6 @@ export default async function installMain(progname, rawArgs, powers, opts) {
61
60
  const yarnInstallEachWorktree = async (phase, ...flags) => {
62
61
  for await (const workTree of workTrees) {
63
62
  log.info(`yarn install ${phase} in ${workTree}`);
64
- // eslint-disable-next-line no-await-in-loop
65
63
  const yarnInstall = await pspawn(
66
64
  'yarn',
67
65
  [...linkFlags, 'install', ...flags],
@@ -133,7 +131,6 @@ export default async function installMain(progname, rawArgs, powers, opts) {
133
131
  // Ensure we update the package.json before exiting.
134
132
  const updatePackageJson = async () => {
135
133
  // Don't update on exit anymore.
136
- // eslint-disable-next-line no-use-before-define
137
134
  process.off('beforeExit', updatePackageJsonOnExit);
138
135
  log.info(`updating ${pjson}`);
139
136
  await fs.writeFile(
@@ -172,12 +169,9 @@ export default async function installMain(progname, rawArgs, powers, opts) {
172
169
  .then(results => {
173
170
  // After all have settled, throw any errors.
174
171
  const failures = results.filter(
175
- ({ status }) => status !== 'fulfilled',
172
+ result => result.status !== 'fulfilled',
176
173
  );
177
174
  if (failures.length) {
178
- if (typeof AggregateError !== 'function') {
179
- throw failures[0].reason;
180
- }
181
175
  throw AggregateError(
182
176
  failures.map(({ reason }) => reason),
183
177
  'Failed to prune',
@@ -269,7 +263,9 @@ export default async function installMain(progname, rawArgs, powers, opts) {
269
263
  };
270
264
  await Promise.all(subdirs.map(removeNodeModulesSymlinks));
271
265
  } else {
272
- DEFAULT_SDK_PACKAGE_NAMES.forEach(name => sdkPackageToPath.set(name, null));
266
+ for (const name of DEFAULT_SDK_PACKAGE_NAMES) {
267
+ sdkPackageToPath.set(name, null);
268
+ }
273
269
  }
274
270
 
275
271
  if (forceSdkVersion !== undefined) {
@@ -287,7 +283,12 @@ export default async function installMain(progname, rawArgs, powers, opts) {
287
283
  // Create symlinks to the SDK packages.
288
284
  await Promise.all(
289
285
  [...sdkPackageToPath.entries()].map(async ([pjName, dir]) => {
286
+ if (typeof dir !== 'string') {
287
+ throw Error(`unexpected incomplete package mapping: ${pjName}`);
288
+ }
289
+
290
290
  const SUBOPTIMAL = false;
291
+ await null;
291
292
  if (SUBOPTIMAL) {
292
293
  // This use of yarn is noisy and slow.
293
294
  await pspawn('yarn', [...linkFlags, 'unlink', pjName]);
@@ -303,7 +304,7 @@ export default async function installMain(progname, rawArgs, powers, opts) {
303
304
  log('linking', linkName);
304
305
  return fs
305
306
  .mkdir(linkDir, { recursive: true })
306
- .then(_ => fs.symlink(path.relative(linkDir, dir), linkName));
307
+ .then(() => fs.symlink(path.relative(linkDir, dir), linkName));
307
308
  }),
308
309
  );
309
310