agoric 0.21.2-other-dev-8f8782b.0 → 0.21.2-other-dev-fbe72e7.0.fbe72e7

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 (44) hide show
  1. package/README.md +0 -73
  2. package/package.json +60 -43
  3. package/src/anylogger-agoric.js +31 -16
  4. package/src/bin-agops.js +8 -12
  5. package/src/chain-config.js +42 -16
  6. package/src/commands/auction.js +22 -19
  7. package/src/commands/gov.js +475 -0
  8. package/src/commands/inter.js +44 -62
  9. package/src/commands/oracle.js +144 -87
  10. package/src/commands/perf.js +20 -16
  11. package/src/commands/psm.js +29 -26
  12. package/src/commands/reserve.js +13 -6
  13. package/src/commands/test-upgrade.js +15 -8
  14. package/src/commands/vaults.js +31 -18
  15. package/src/commands/wallet.js +121 -48
  16. package/src/cosmos.js +3 -3
  17. package/src/deploy.js +10 -5
  18. package/src/entrypoint.js +2 -5
  19. package/src/follow.js +14 -10
  20. package/src/helpers.js +10 -5
  21. package/src/init.js +2 -9
  22. package/src/install.js +18 -25
  23. package/src/lib/bundles.js +102 -0
  24. package/src/lib/chain.js +71 -35
  25. package/src/lib/format.js +28 -34
  26. package/src/lib/index.js +7 -0
  27. package/src/lib/packageManager.js +24 -0
  28. package/src/lib/wallet.js +44 -144
  29. package/src/main-publish.js +2 -3
  30. package/src/main.js +95 -125
  31. package/src/open.js +8 -10
  32. package/src/publish.js +4 -9
  33. package/src/scripts.js +14 -32
  34. package/src/sdk-package-names.js +22 -9
  35. package/src/set-defaults.js +2 -1
  36. package/src/start.js +59 -68
  37. package/tools/getting-started.js +272 -0
  38. package/tools/resm-plugin/deploy.js +18 -0
  39. package/tools/resm-plugin/package.json +12 -0
  40. package/tools/resm-plugin/src/output.js +1 -0
  41. package/tools/resm-plugin/src/plugin.js +17 -0
  42. package/CHANGELOG.md +0 -1069
  43. package/src/commands/ec.js +0 -314
  44. package/src/lib/rpc.js +0 -272
@@ -0,0 +1,24 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @import { execFileSync } from 'child_process';
5
+ */
6
+
7
+ /**
8
+ * Omits the root
9
+ *
10
+ * @param {{ execFileSync: execFileSync }} io
11
+ * @param {string} [root]
12
+ * @returns {Array<{ location: string, name: string }>}
13
+ */
14
+ export const listWorkspaces = ({ execFileSync }, root) => {
15
+ const out = execFileSync('npm', ['query', '.workspace'], {
16
+ stdio: ['ignore', 'pipe', 'inherit'],
17
+ shell: true,
18
+ encoding: 'utf-8',
19
+ cwd: root,
20
+ });
21
+ /** @type {Array<{ location: string, name: string, description: string }>} */
22
+ const result = JSON.parse(out);
23
+ return result.filter(({ location }) => location !== '.');
24
+ };
package/src/lib/wallet.js CHANGED
@@ -1,16 +1,18 @@
1
1
  // @ts-check
2
- /* global process */
2
+ /* eslint-env node */
3
3
 
4
4
  import { iterateReverse } from '@agoric/casting';
5
+ import { boardSlottingMarshaller } from '@agoric/client-utils';
5
6
  import { makeWalletStateCoalescer } from '@agoric/smart-wallet/src/utils.js';
6
- import { execSwingsetTransaction, pollBlocks, pollTx } from './chain.js';
7
- import { boardSlottingMarshaller, makeRpcUtils } from './rpc.js';
7
+ import { Fail } from '@endo/errors';
8
+ import { execSwingsetTransaction, pollTx } from './chain.js';
8
9
 
9
- /** @typedef {import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord} CurrentWalletRecord */
10
- /** @typedef {import('@agoric/vats/tools/board-utils.js').AgoricNamesRemotes} AgoricNamesRemotes */
10
+ /**
11
+ * @import {CurrentWalletRecord} from '@agoric/smart-wallet/src/smartWallet.js';
12
+ * @import {AgoricNamesRemotes} from '@agoric/vats/tools/board-utils.js';
13
+ * @import {MinimalNetworkConfig, VstorageKit} from '@agoric/client-utils';
14
+ */
11
15
 
12
- const { values } = Object;
13
- const { Fail } = assert;
14
16
  const marshaller = boardSlottingMarshaller();
15
17
 
16
18
  /** @type {CurrentWalletRecord} */
@@ -23,18 +25,18 @@ const emptyCurrentRecord = {
23
25
 
24
26
  /**
25
27
  * @param {string} addr
26
- * @param {Pick<import('./rpc.js').RpcUtils, 'readLatestHead'>} io
27
- * @returns {Promise<import('@agoric/smart-wallet/src/smartWallet').CurrentWalletRecord>}
28
+ * @param {Pick<VstorageKit, 'readPublished'>} io
29
+ * @returns {Promise<import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord>}
28
30
  */
29
- export const getCurrent = async (addr, { readLatestHead }) => {
31
+ export const getCurrent = async (addr, { readPublished }) => {
30
32
  // Partial because older writes may not have had all properties
31
33
  // NB: assumes changes are only additions
32
34
  let current =
33
- /** @type {Partial<import('@agoric/smart-wallet/src/smartWallet').CurrentWalletRecord> | undefined} */ (
34
- await readLatestHead(`published.wallet.${addr}.current`)
35
+ /** @type {Partial<import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord> | undefined} */ (
36
+ await readPublished(`wallet.${addr}.current`)
35
37
  );
36
38
  if (current === undefined) {
37
- throw new Error(`undefined current node for ${addr}`);
39
+ throw Error(`undefined current node for ${addr}`);
38
40
  }
39
41
 
40
42
  // Repair a type misunderstanding seen in the wild.
@@ -58,16 +60,15 @@ export const getCurrent = async (addr, { readLatestHead }) => {
58
60
 
59
61
  /**
60
62
  * @param {string} addr
61
- * @param {Pick<import('./rpc.js').RpcUtils, 'readLatestHead'>} io
62
- * @returns {Promise<import('@agoric/smart-wallet/src/smartWallet').UpdateRecord>}
63
+ * @param {Pick<VstorageKit, 'readPublished'>} io
64
+ * @returns {Promise<import('@agoric/smart-wallet/src/smartWallet.js').UpdateRecord>}
63
65
  */
64
- export const getLastUpdate = (addr, { readLatestHead }) => {
65
- // @ts-expect-error cast
66
- return readLatestHead(`published.wallet.${addr}`);
66
+ export const getLastUpdate = (addr, { readPublished }) => {
67
+ return readPublished(`wallet.${addr}`);
67
68
  };
68
69
 
69
70
  /**
70
- * @param {import('@agoric/smart-wallet/src/smartWallet').BridgeAction} bridgeAction
71
+ * @param {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} bridgeAction
71
72
  * @param {Pick<import('stream').Writable,'write'>} [stdout]
72
73
  */
73
74
  export const outputAction = (bridgeAction, stdout = process.stdout) => {
@@ -76,11 +77,11 @@ export const outputAction = (bridgeAction, stdout = process.stdout) => {
76
77
  stdout.write('\n');
77
78
  };
78
79
 
79
- const sendHint =
80
+ export const sendHint =
80
81
  'Now use `agoric wallet send ...` to sign and broadcast the offer.\n';
81
82
 
82
83
  /**
83
- * @param {import('@agoric/smart-wallet/src/smartWallet').BridgeAction} bridgeAction
84
+ * @param {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} bridgeAction
84
85
  * @param {{
85
86
  * stdout: Pick<import('stream').Writable,'write'>,
86
87
  * stderr: Pick<import('stream').Writable,'write'>,
@@ -94,25 +95,38 @@ export const outputActionAndHint = (bridgeAction, { stdout, stderr }) => {
94
95
  /**
95
96
  * @param {import('@agoric/smart-wallet/src/offers.js').OfferSpec} offer
96
97
  * @param {Pick<import('stream').Writable,'write'>} [stdout]
98
+ * @param {Pick<import('stream').Writable,'write'>} [stderr]
97
99
  */
98
- export const outputExecuteOfferAction = (offer, stdout = process.stdout) => {
99
- /** @type {import('@agoric/smart-wallet/src/smartWallet').BridgeAction} */
100
+ export const outputExecuteOfferAction = (
101
+ offer,
102
+ stdout = process.stdout,
103
+ stderr = process.stderr,
104
+ ) => {
105
+ /** @type {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} */
100
106
  const spendAction = {
101
107
  method: 'executeOffer',
102
108
  offer,
103
109
  };
104
110
  outputAction(spendAction, stdout);
111
+ stderr.write(sendHint);
105
112
  };
106
113
 
107
114
  /**
108
115
  * @deprecated use `.current` node for current state
109
- * @param {import('@agoric/casting').Follower<import('@agoric/casting').ValueFollowerElement<import('@agoric/smart-wallet/src/smartWallet').UpdateRecord>>} follower
116
+ * @param {import('@agoric/casting').Follower<import('@agoric/casting').ValueFollowerElement<import('@agoric/smart-wallet/src/smartWallet.js').UpdateRecord>>} follower
110
117
  * @param {Brand<'set'>} [invitationBrand]
111
118
  */
112
119
  export const coalesceWalletState = async (follower, invitationBrand) => {
113
120
  // values with oldest last
114
121
  const history = [];
115
122
  for await (const followerElement of iterateReverse(follower)) {
123
+ if ('error' in followerElement) {
124
+ console.error(
125
+ 'Skipping wallet update due to error:',
126
+ followerElement.error,
127
+ );
128
+ continue;
129
+ }
116
130
  history.push(followerElement.value);
117
131
  }
118
132
 
@@ -129,12 +143,13 @@ export const coalesceWalletState = async (follower, invitationBrand) => {
129
143
  * Sign and broadcast a wallet-action.
130
144
  *
131
145
  * @throws { Error & { code: number } } if transaction fails
132
- * @param {import('@agoric/smart-wallet/src/smartWallet').BridgeAction} bridgeAction
133
- * @param {import('./rpc').MinimalNetworkConfig & {
146
+ * @param {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} bridgeAction
147
+ * @param {MinimalNetworkConfig & {
134
148
  * from: string,
149
+ * fees?: string,
135
150
  * verbose?: boolean,
136
151
  * keyring?: {home?: string, backend: string},
137
- * stdout: Pick<import('stream').Writable, 'write'>,
152
+ * stdout?: Pick<import('stream').Writable, 'write'>,
138
153
  * execFileSync: typeof import('child_process').execFileSync,
139
154
  * delay: (ms: number) => Promise<void>,
140
155
  * dryRun?: boolean,
@@ -159,7 +174,7 @@ export const sendAction = async (bridgeAction, opts) => {
159
174
  assert(out); // not dry run
160
175
  const tx = JSON.parse(out);
161
176
  if (tx.code !== 0) {
162
- const err = Error(`failed to send action. code: ${tx.code}`);
177
+ const err = Error(`failed to send tx: ${tx.raw_log} code: ${tx.code}`);
163
178
  // @ts-expect-error XXX how to add properties to an error?
164
179
  err.code = tx.code;
165
180
  throw err;
@@ -174,7 +189,7 @@ export const sendAction = async (bridgeAction, opts) => {
174
189
  */
175
190
  export const findContinuingIds = (current, agoricNames) => {
176
191
  // XXX should runtime type-check
177
- /** @type {{ offerToUsedInvitation: [string, Amount<'set'>][]}} */
192
+ /** @type {{ offerToUsedInvitation: [string, InvitationAmount][]}} */
178
193
  const { offerToUsedInvitation: entries } = /** @type {any} */ (current);
179
194
 
180
195
  Array.isArray(entries) || Fail`entries must be an array: ${entries}`;
@@ -198,118 +213,3 @@ export const findContinuingIds = (current, agoricNames) => {
198
213
  }
199
214
  return found;
200
215
  };
201
-
202
- export const makeWalletUtils = async (
203
- { fetch, execFileSync, delay },
204
- networkConfig,
205
- ) => {
206
- const { agoricNames, fromBoard, readLatestHead, vstorage } =
207
- await makeRpcUtils({ fetch }, networkConfig);
208
- /**
209
- * @param {string} from
210
- * @param {number|string} [minHeight]
211
- */
212
- const storedWalletState = async (from, minHeight = undefined) => {
213
- const m = boardSlottingMarshaller(fromBoard.convertSlotToVal);
214
-
215
- const history = await vstorage.readFully(
216
- `published.wallet.${from}`,
217
- minHeight,
218
- );
219
-
220
- /** @type {{ Invitation: Brand<'set'> }} */
221
- // @ts-expect-error XXX how to narrow AssetKind to set?
222
- const { Invitation } = agoricNames.brand;
223
- const coalescer = makeWalletStateCoalescer(Invitation);
224
- // update with oldest first
225
- for (const txt of history.reverse()) {
226
- const { body, slots } = JSON.parse(txt);
227
- const record = m.fromCapData({ body, slots });
228
- coalescer.update(record);
229
- }
230
- const coalesced = coalescer.state;
231
- harden(coalesced);
232
- return coalesced;
233
- };
234
-
235
- /**
236
- * Get OfferStatus by id, polling until available.
237
- *
238
- * @param {string} from
239
- * @param {string|number} id
240
- * @param {number|string} minHeight
241
- * @param {boolean} [untilNumWantsSatisfied]
242
- */
243
- const pollOffer = async (
244
- from,
245
- id,
246
- minHeight,
247
- untilNumWantsSatisfied = false,
248
- ) => {
249
- const lookup = async () => {
250
- // eslint-disable-next-line @jessie.js/no-nested-await, no-await-in-loop
251
- const { offerStatuses } = await storedWalletState(from, minHeight);
252
- const offerStatus = [...offerStatuses.values()].find(s => s.id === id);
253
- if (!offerStatus) throw Error('retry');
254
- harden(offerStatus);
255
- if (untilNumWantsSatisfied && !('numWantsSatisfied' in offerStatus)) {
256
- throw Error('retry (no numWantsSatisfied yet)');
257
- }
258
- return offerStatus;
259
- };
260
- const retryMessage = 'offer not in wallet at block';
261
- const opts = { ...networkConfig, execFileSync, delay, retryMessage };
262
- return pollBlocks(opts)(lookup);
263
- };
264
-
265
- return {
266
- networkConfig,
267
- agoricNames,
268
- fromBoard,
269
- vstorage,
270
- readLatestHead,
271
- storedWalletState,
272
- pollOffer,
273
- };
274
- };
275
-
276
- /**
277
- * @param {{
278
- * brand: Record<string, Brand>,
279
- * vbankAsset: Record<string, { brand: Brand, displayInfo: DisplayInfo }>,
280
- * }} agoricNames
281
- * @param {(msg: string) => Error} makeError error constructor
282
- * @returns {(a: string) => Amount<'nat'>}
283
- */
284
- export const makeParseAmount =
285
- (agoricNames, makeError = msg => RangeError(msg)) =>
286
- opt => {
287
- assert.typeof(opt, 'string', 'parseAmount expected string');
288
- const m = opt.match(/^(?<value>[\d_]+(\.[\d_]+)?)(?<brand>[A-Z]\w*?)$/);
289
- if (!m || !m.groups) {
290
- throw makeError(`invalid amount: ${opt}`);
291
- }
292
- const anyBrand = agoricNames.brand[m.groups.brand];
293
- if (!anyBrand) {
294
- throw makeError(`unknown brand: ${m.groups.brand}`);
295
- }
296
- const assetDesc = values(agoricNames.vbankAsset).find(
297
- d => d.brand === anyBrand,
298
- );
299
- if (!assetDesc) {
300
- throw makeError(`unknown brand: ${m.groups.brand}`);
301
- }
302
- const { displayInfo } = assetDesc;
303
- if (!displayInfo.decimalPlaces || displayInfo.assetKind !== 'nat') {
304
- throw makeError(`bad brand: ${displayInfo}`);
305
- }
306
- const value = BigInt(
307
- Number(m.groups.value.replace(/_/g, '')) *
308
- 10 ** displayInfo.decimalPlaces,
309
- );
310
- /** @type {Brand<'nat'>} */
311
- // @ts-expect-error dynamic cast
312
- const natBrand = anyBrand;
313
- const amt = { value, brand: natBrand };
314
- return amt;
315
- };
@@ -1,4 +1,4 @@
1
- /* global process */
1
+ /* eslint-env node */
2
2
  // @ts-check
3
3
 
4
4
  import path from 'path';
@@ -31,9 +31,9 @@ const publishMain = async (progname, rawArgs, powers, opts) => {
31
31
  chainID,
32
32
  };
33
33
 
34
+ await null;
34
35
  for (const bundlePath of rawArgs.slice(1)) {
35
36
  // AWAIT
36
- // eslint-disable-next-line no-await-in-loop,@jessie.js/no-nested-await
37
37
  const bundleText = await fs.readFile(bundlePath, 'utf-8');
38
38
  const bundle = parseLocatedJson(bundleText, bundlePath);
39
39
 
@@ -53,7 +53,6 @@ const publishMain = async (progname, rawArgs, powers, opts) => {
53
53
  });
54
54
 
55
55
  // AWAIT
56
- // eslint-disable-next-line no-await-in-loop,@jessie.js/no-nested-await
57
56
  const hashedBundle = await publishBundle(bundle, connectionSpec);
58
57
  process.stdout.write(`${JSON.stringify(hashedBundle)}\n`);
59
58
  }
package/src/main.js CHANGED
@@ -1,26 +1,26 @@
1
- /* eslint-disable @jessie.js/no-nested-await */
2
- /* global process */
1
+ /* eslint-env node */
3
2
  import { Command } from 'commander';
4
3
  import path from 'path';
5
4
  import url from 'url';
6
- import { assert, details as X } from '@agoric/assert';
5
+ import { assert, X } from '@endo/errors';
7
6
  import {
8
7
  DEFAULT_KEEP_POLLING_SECONDS,
9
8
  DEFAULT_JITTER_SECONDS,
10
9
  } from '@agoric/casting';
10
+ import { makeWalletCommand } from './commands/wallet.js';
11
11
  import cosmosMain from './cosmos.js';
12
12
  import deployMain from './deploy.js';
13
- import runMain from './run.js';
14
- import publishMain from './main-publish.js';
13
+ import followMain from './follow.js';
15
14
  import initMain from './init.js';
16
15
  import installMain from './install.js';
16
+ import { statPlans } from './lib/bundles.js';
17
+ import publishMain from './main-publish.js';
18
+ import walletMain from './open.js';
19
+ import runMain from './run.js';
17
20
  import setDefaultsMain from './set-defaults.js';
18
21
  import startMain from './start.js';
19
- import followMain from './follow.js';
20
- import walletMain from './open.js';
21
- import { makeWalletCommand } from './commands/wallet.js';
22
22
 
23
- const DEFAULT_DAPP_TEMPLATE = 'dapp-fungible-faucet';
23
+ const DEFAULT_DAPP_TEMPLATE = 'dapp-offer-up';
24
24
  const DEFAULT_DAPP_URL_BASE = 'https://github.com/Agoric/';
25
25
  const DEFAULT_DAPP_BRANCH = undefined;
26
26
 
@@ -36,6 +36,7 @@ const main = async (progname, rawArgs, powers) => {
36
36
  const program = new Command();
37
37
 
38
38
  async function isNotBasedir() {
39
+ await null;
39
40
  try {
40
41
  await fs.stat(STAMP);
41
42
  return false;
@@ -46,6 +47,7 @@ const main = async (progname, rawArgs, powers) => {
46
47
  return true;
47
48
  }
48
49
 
50
+ // XXX exits process when fn resolves
49
51
  function subMain(fn, args, options) {
50
52
  return fn(progname, args, powers, options).then(
51
53
  // This seems to be the only way to propagate the exit code.
@@ -57,46 +59,40 @@ const main = async (progname, rawArgs, powers) => {
57
59
  const pkg = JSON.parse(pj);
58
60
  program.name(pkg.name).version(pkg.version);
59
61
 
60
- program
61
- .option('--sdk', 'use the Agoric SDK containing this program')
62
- .option('--no-sdk', 'do not use the Agoric SDK containing this program')
63
- .option('--docker-tag <tag>', 'image tag to use for Docker containers')
64
- .option(
62
+ const cmdOpts = { verbose: 0 };
63
+ const addCmdOpts = baseCmd =>
64
+ baseCmd.option(
65
65
  '-v, --verbose',
66
66
  'verbosity that can be increased',
67
- (_value, previous) => previous + 1,
68
- 0,
67
+ (_value, _previous) => (cmdOpts.verbose += 1),
69
68
  );
69
+ /** @type {typeof program.command} */
70
+ const baseCmd = (nameAndParams, ...rest) =>
71
+ addCmdOpts(program.command(nameAndParams, ...rest));
72
+
73
+ addCmdOpts(
74
+ program
75
+ .enablePositionalOptions()
76
+ .option('--sdk', 'use the Agoric SDK containing this program')
77
+ .option('--no-sdk', 'do not use the Agoric SDK containing this program'),
78
+ );
70
79
 
71
80
  // Add each of the commands.
72
- program
73
- .command('cosmos <command...>')
81
+ baseCmd('cosmos <command...>')
82
+ .passThroughOptions(true)
83
+ .option('--docker-tag <tag>', 'image tag to use for Docker containers')
74
84
  .description('client for an Agoric Cosmos chain')
75
85
  .action(async (command, _options, cmd) => {
76
- const opts = { ...program.opts(), ...cmd.opts() };
86
+ const opts = { ...program.opts(), ...cmd.opts(), ...cmdOpts };
77
87
  return subMain(cosmosMain, ['cosmos', ...command], opts);
78
88
  });
79
89
 
80
- const ibcSetup = path.join(
81
- dirname,
82
- '..',
83
- 'node_modules',
84
- '.bin',
85
- 'ibc-setup',
86
- );
87
- program.command(
88
- 'ibc-setup <command...>',
89
- 'set up Inter Blockchain Communication',
90
- { executableFile: ibcSetup },
91
- );
92
-
93
- program
94
- .command('open')
90
+ baseCmd('open')
95
91
  .description('launch the Agoric UI')
96
92
  .option(
97
93
  '--hostport <host:port>',
98
94
  'host and port to connect to VM',
99
- '127.0.0.1:8000',
95
+ 'localhost:8000',
100
96
  )
101
97
  .option('--no-browser', `just display the URL, don't open a browser`)
102
98
  .option(
@@ -112,12 +108,11 @@ const main = async (progname, rawArgs, powers) => {
112
108
  },
113
109
  )
114
110
  .action(async (_options, cmd) => {
115
- const opts = { ...program.opts(), ...cmd.opts() };
111
+ const opts = { ...program.opts(), ...cmd.opts(), ...cmdOpts };
116
112
  return subMain(walletMain, ['wallet'], opts);
117
113
  });
118
114
 
119
- program
120
- .command('init <project>')
115
+ baseCmd('init <project>')
121
116
  .description('create a new Dapp directory named <project>')
122
117
  .option(
123
118
  '--dapp-template <name>',
@@ -134,13 +129,17 @@ const main = async (progname, rawArgs, powers) => {
134
129
  'use this branch instead of the repository HEAD',
135
130
  DEFAULT_DAPP_BRANCH,
136
131
  )
132
+ // Tolerate @agoric/create-dapp's `agoric init --version` invocation.
133
+ .option('-V, --version', 'output the version number', () => {
134
+ console.log(pkg.version);
135
+ process.exit(0);
136
+ })
137
137
  .action(async (project, _options, cmd) => {
138
- const opts = { ...program.opts(), ...cmd.opts() };
138
+ const opts = { ...program.opts(), ...cmd.opts(), ...cmdOpts };
139
139
  return subMain(initMain, ['init', project], opts);
140
140
  });
141
141
 
142
- program
143
- .command('set-defaults <program> <config-dir>')
142
+ baseCmd('set-defaults <program> <config-dir>')
144
143
  .description('update the configuration files for <program> in <config-dir>')
145
144
  .option(
146
145
  '--enable-cors',
@@ -168,49 +167,28 @@ const main = async (progname, rawArgs, powers) => {
168
167
  '',
169
168
  )
170
169
  .action(async (prog, configDir, _options, cmd) => {
171
- const opts = { ...program.opts(), ...cmd.opts() };
170
+ const opts = { ...program.opts(), ...cmd.opts(), ...cmdOpts };
172
171
  return subMain(setDefaultsMain, ['set-defaults', prog, configDir], opts);
173
172
  });
174
173
 
175
- const ibcRelayer = path.join(
176
- dirname,
177
- '..',
178
- 'node_modules',
179
- '.bin',
180
- 'ibc-relayer',
181
- );
182
- program.command(
183
- 'ibc-relayer',
184
- 'run an Inter Blockchain Communications relayer',
185
- {
186
- executableFile: ibcRelayer,
187
- },
188
- );
189
-
190
- program
191
- .command('install [force-sdk-version]')
174
+ baseCmd('install [force-sdk-version]')
192
175
  .description('install Dapp dependencies')
193
176
  .action(async (forceSdkVersion, _options, cmd) => {
194
177
  await isNotBasedir();
195
- const opts = { ...program.opts(), ...cmd.opts() };
178
+ const opts = { ...program.opts(), ...cmd.opts(), ...cmdOpts };
196
179
  return subMain(installMain, ['install', forceSdkVersion], opts);
197
180
  });
198
181
 
199
- program
200
- .command('follow <path-spec...>')
182
+ baseCmd('follow <path-spec...>')
201
183
  .description('follow an Agoric Casting leader')
202
184
  .option(
203
- '--proof <strict | optimistic | none>',
204
- 'set proof mode',
185
+ '--proof <none>',
186
+ `set proof mode (currently only 'none' is supported)`,
205
187
  value => {
206
- assert(
207
- ['strict', 'optimistic', 'none'].includes(value),
208
- X`--proof must be one of 'strict', 'optimistic', or 'none'`,
209
- TypeError,
210
- );
188
+ assert.equal(value, 'none', X`--proof can only be 'none'`, TypeError);
211
189
  return value;
212
190
  },
213
- 'optimistic',
191
+ 'none',
214
192
  )
215
193
  .option(
216
194
  '--sleep <seconds>',
@@ -270,61 +248,59 @@ const main = async (progname, rawArgs, powers) => {
270
248
  )
271
249
  .option('-B, --bootstrap <config>', 'network bootstrap configuration')
272
250
  .action(async (pathSpecs, _options, cmd) => {
273
- const opts = { ...program.opts(), ...cmd.opts() };
251
+ const opts = { ...program.opts(), ...cmd.opts(), ...cmdOpts };
274
252
  return subMain(followMain, ['follow', ...pathSpecs], opts);
275
253
  });
276
254
 
277
- const addRunOptions = cmd =>
278
- cmd
279
- .option(
280
- '--allow-unsafe-plugins',
281
- `CAREFUL: installed Agoric VM plugins will also have all your user's privileges`,
282
- false,
283
- )
284
- .option(
285
- '--hostport <host:port>',
286
- 'host and port to connect to VM',
287
- '127.0.0.1:8000',
288
- )
289
- .option(
290
- '--need <subsystems>',
291
- 'comma-separated names of subsystems to wait for',
292
- 'local,agoric,wallet',
293
- )
294
- .option(
295
- '--provide <subsystems>',
296
- 'comma-separated names of subsystems this script initializes',
297
- '',
298
- );
299
-
300
- program
301
- .command('run <script> [script-args...]')
255
+ baseCmd('run <script> [script-args...]')
302
256
  .description(
303
257
  'run a script with all your user privileges and some Agoric endowments',
304
258
  )
259
+ .passThroughOptions(true)
305
260
  .action(async (script, scriptArgs, _options, cmd) => {
306
- const opts = { ...program.opts(), ...cmd.opts(), scriptArgs };
307
- return subMain(runMain, ['run', script], opts);
261
+ const opts = { ...program.opts(), ...cmd.opts(), ...cmdOpts, scriptArgs };
262
+ await runMain(progname, ['run', script], powers, opts);
263
+
264
+ if (opts.verbose) {
265
+ await statPlans(process.cwd());
266
+ }
308
267
  });
309
268
 
310
- addRunOptions(
311
- program
312
- .command('deploy [script...]')
313
- .option(
314
- '--target <target>',
315
- 'One of agoric, local, cosmos, or sim',
316
- 'agoric',
317
- )
318
- .description(
319
- 'run multiple scripts with all your user privileges against the local Agoric VM',
320
- ),
321
- ).action(async (scripts, _options, cmd) => {
322
- const opts = { ...program.opts(), ...cmd.opts() };
323
- return subMain(deployMain, ['deploy', ...scripts], opts);
324
- });
269
+ baseCmd('deploy [script...]')
270
+ .option(
271
+ '--target <target>',
272
+ 'One of agoric, local, cosmos, or sim',
273
+ 'agoric',
274
+ )
275
+ .option(
276
+ '--allow-unsafe-plugins',
277
+ `CAREFUL: installed Agoric VM plugins will also have all your user's privileges`,
278
+ false,
279
+ )
280
+ .option(
281
+ '--hostport <host:port>',
282
+ 'host and port to connect to VM',
283
+ '127.0.0.1:8000',
284
+ )
285
+ .option(
286
+ '--need <subsystems>',
287
+ 'comma-separated names of subsystems to wait for',
288
+ 'local,agoric,wallet',
289
+ )
290
+ .option(
291
+ '--provide <subsystems>',
292
+ 'comma-separated names of subsystems this script initializes',
293
+ '',
294
+ )
295
+ .description(
296
+ 'run multiple scripts with all your user privileges against the local Agoric VM',
297
+ )
298
+ .action(async (scripts, _options, cmd) => {
299
+ const opts = { ...program.opts(), ...cmd.opts() };
300
+ return subMain(deployMain, ['deploy', ...scripts], opts);
301
+ });
325
302
 
326
- program
327
- .command('publish [bundle...]')
303
+ baseCmd('publish [bundle...]')
328
304
  .option(
329
305
  '-c, --chain-id <chainID>',
330
306
  'The ID of the destination chain',
@@ -345,10 +321,9 @@ const main = async (progname, rawArgs, powers) => {
345
321
  return subMain(publishMain, ['publish', ...bundles], opts);
346
322
  });
347
323
 
348
- program.addCommand(await makeWalletCommand());
324
+ await makeWalletCommand(baseCmd);
349
325
 
350
- program
351
- .command('start [profile] [args...]')
326
+ baseCmd('start [profile] [args...]')
352
327
  .description(
353
328
  `\
354
329
  start an Agoric VM
@@ -360,6 +335,7 @@ agoric start local-solo [portNum] [provisionPowers] - local solo VM
360
335
  `,
361
336
  )
362
337
  .option('-d, --debug', 'run in JS debugger mode')
338
+ .option('--docker-tag <tag>', 'image tag to use for Docker containers')
363
339
  .option('--reset', 'clear all VM state before starting')
364
340
  .option('--no-restart', 'do not actually start the VM')
365
341
  .option('--pull', 'for Docker-based VM, pull the image before running')
@@ -383,19 +359,13 @@ agoric start local-solo [portNum] [provisionPowers] - local solo VM
383
359
  )
384
360
  .action(async (profile, args, _options, cmd) => {
385
361
  await isNotBasedir();
386
- const opts = { ...program.opts(), ...cmd.opts() };
362
+ const opts = { ...program.opts(), ...cmd.opts(), ...cmdOpts };
387
363
  return subMain(startMain, ['start', profile, ...args], opts);
388
364
  });
389
365
 
390
366
  // Throw an error instead of exiting directly.
391
367
  program.exitOverride();
392
368
 
393
- // Hack: cosmos arguments are always unparsed.
394
- const cosmosIndex = rawArgs.indexOf('cosmos');
395
- if (cosmosIndex >= 0) {
396
- rawArgs.splice(cosmosIndex + 1, 0, '--');
397
- }
398
-
399
369
  try {
400
370
  await program.parseAsync(rawArgs, { from: 'user' });
401
371
  } catch (e) {