cloudhop 0.1.0 → 1.0.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.
- package/LICENSE +202 -21
- package/NOTICE +4 -0
- package/README.md +105 -43
- package/dist/cli.js +73 -46
- package/package.json +13 -8
package/LICENSE
CHANGED
|
@@ -1,21 +1,202 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/NOTICE
ADDED
package/README.md
CHANGED
|
@@ -1,61 +1,123 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/dayepesb/cloudhop/main/assets/logo.svg" width="88" height="88" alt="cloudhop logo">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
[](https://www.npmjs.com/package/cloudhop)
|
|
5
|
+
<h1 align="center">cloudhop</h1>
|
|
5
6
|
|
|
6
|
-
>
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Every cloud account, one short alias away.</strong><br>
|
|
9
|
+
Sign in once per portal, give each account and role a short alias, and let
|
|
10
|
+
cloudhop log you in again only when a session has expired. No access keys.
|
|
11
|
+
</p>
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
<p align="center">
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
[](https://www.npmjs.com/package/cloudhop)
|
|
16
|
+
[](https://github.com/dayepesb/cloudhop/actions/workflows/pipeline.yml)
|
|
17
|
+
[](https://github.com/dayepesb/cloudhop/blob/main/LICENSE)
|
|
18
|
+
[](https://dayepesb.github.io/cloudhop/)
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install --global cloudhop
|
|
24
|
+
cloudhop setup # add your SSO portal, sign in, pick accounts
|
|
25
|
+
hop acme-prod s3 ls # runs `aws s3 ls` as that account, role and region
|
|
18
26
|
```
|
|
19
27
|
|
|
20
|
-
## Why
|
|
28
|
+
## Why cloudhop
|
|
29
|
+
|
|
30
|
+
Working with several AWS SSO portals and personal accounts usually means
|
|
31
|
+
copying access keys, editing `~/.aws/config` by hand and running
|
|
32
|
+
`aws sso login` again and again. cloudhop does that part for you:
|
|
33
|
+
|
|
34
|
+
- **One sign-in per portal.** Add an IAM Identity Center portal once; cloudhop
|
|
35
|
+
finds every account and role you can use and turns the ones you pick into
|
|
36
|
+
aliases.
|
|
37
|
+
- **Logs in only when needed.** Nothing runs in the background. When you use
|
|
38
|
+
an alias with an expired session, cloudhop renews it silently or opens the
|
|
39
|
+
browser, refreshes that portal's accounts, then runs your command.
|
|
40
|
+
- **No access keys, ever.** Only temporary credentials: IAM Identity Center
|
|
41
|
+
for companies, `aws login` for personal accounts.
|
|
42
|
+
- **Works with your tools.** Aliases are real profiles in `~/.aws/config`, so
|
|
43
|
+
Terraform, the AWS SDKs and your IDE see them too. `cloudhop exec` covers
|
|
44
|
+
everything else.
|
|
45
|
+
- **Terminal or browser.** `cloudhop ui` opens a local page to add portals,
|
|
46
|
+
pick accounts and change regions.
|
|
47
|
+
|
|
48
|
+
## Everyday use
|
|
49
|
+
|
|
50
|
+
| You want to | Run |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| Run any `aws` command as an alias | `hop acme-prod ec2 describe-instances` |
|
|
53
|
+
| Check who you are | `hop acme-prod` |
|
|
54
|
+
| Use another region once | `hop acme-prod s3 ls --region eu-west-1` |
|
|
55
|
+
| Give any tool temporary credentials | `cloudhop exec acme-prod -- terraform plan` |
|
|
56
|
+
| See your portals and aliases | `cloudhop ls` |
|
|
57
|
+
| Add another portal or personal account | `cloudhop add` |
|
|
58
|
+
| Create more aliases from a portal | `cloudhop alias acme` |
|
|
59
|
+
| Change an alias' region | `cloudhop region acme-prod us-east-2` |
|
|
60
|
+
| Remove an alias or a portal | `cloudhop rm acme-dev` |
|
|
61
|
+
| Do all of it from the browser | `cloudhop ui` |
|
|
62
|
+
|
|
63
|
+
Every setup command also works with flags, for scripts and dotfiles. See the
|
|
64
|
+
[command reference](https://dayepesb.github.io/cloudhop/reference/commands/).
|
|
65
|
+
|
|
66
|
+
## The local web UI
|
|
21
67
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
cloudhop is a thin proxy over the AWS CLI that:
|
|
68
|
+
`cloudhop ui` serves a page on your own computer (and only there) to manage
|
|
69
|
+
portals, aliases and regions.
|
|
25
70
|
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
|
|
71
|
+
<p align="center">
|
|
72
|
+
<img src="https://raw.githubusercontent.com/dayepesb/cloudhop/main/assets/ui-screenshot.png" alt="cloudhop ui listing two portals with their aliases, regions and session state" width="840">
|
|
73
|
+
</p>
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
- Node.js 20 or newer.
|
|
78
|
+
- AWS CLI v2 to run commands through aliases (`cloudhop setup` offers to
|
|
79
|
+
install it). Personal accounts need AWS CLI 2.32.0 or newer.
|
|
80
|
+
- macOS, Linux or Windows.
|
|
81
|
+
|
|
82
|
+
## Security
|
|
83
|
+
|
|
84
|
+
- No long-lived secrets: sessions live in the AWS CLI's own token cache, and
|
|
85
|
+
`~/.aws/credentials` is never written.
|
|
86
|
+
- cloudhop only edits its own block in `~/.aws/config` and never overwrites
|
|
87
|
+
profiles you wrote by hand.
|
|
88
|
+
- The web UI listens on `127.0.0.1` only and needs a one-time key per run.
|
|
89
|
+
- Releases are published by GitHub Actions after a maintainer's approval,
|
|
90
|
+
with npm provenance. Verify with `npm audit signatures`.
|
|
91
|
+
|
|
92
|
+
Found a vulnerability? Please
|
|
93
|
+
[report it privately](https://github.com/dayepesb/cloudhop/security/advisories/new).
|
|
34
94
|
|
|
35
95
|
## Documentation
|
|
36
96
|
|
|
37
|
-
https://dayepesb.github.io/cloudhop
|
|
97
|
+
**[dayepesb.github.io/cloudhop](https://dayepesb.github.io/cloudhop/)**, in
|
|
98
|
+
English and [Spanish](https://dayepesb.github.io/cloudhop/es/):
|
|
99
|
+
[getting started](https://dayepesb.github.io/cloudhop/getting-started/),
|
|
100
|
+
[company SSO portals](https://dayepesb.github.io/cloudhop/guides/aws-sso/),
|
|
101
|
+
[personal accounts](https://dayepesb.github.io/cloudhop/guides/personal-accounts/),
|
|
102
|
+
[other tools](https://dayepesb.github.io/cloudhop/guides/other-tools/) and
|
|
103
|
+
[troubleshooting](https://dayepesb.github.io/cloudhop/reference/troubleshooting/).
|
|
38
104
|
|
|
39
|
-
##
|
|
105
|
+
## Roadmap
|
|
40
106
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
pnpm typecheck
|
|
48
|
-
pnpm lint
|
|
49
|
-
pnpm build # bundles packages/cli/dist/cli.js
|
|
50
|
-
node packages/cli/dist/cli.js --help
|
|
51
|
-
pnpm docs:dev # documentation site
|
|
52
|
-
```
|
|
107
|
+
AWS is fully supported. **Azure** and **Google Cloud** are next, as providers
|
|
108
|
+
in the same package. The work is broken down into
|
|
109
|
+
[issues on the roadmap](https://github.com/dayepesb/cloudhop/issues?q=is%3Aopen+label%3Aroadmap);
|
|
110
|
+
pick one up!
|
|
111
|
+
|
|
112
|
+
## Contributing
|
|
53
113
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
114
|
+
Contributions are welcome. Start with
|
|
115
|
+
[CONTRIBUTING.md](https://github.com/dayepesb/cloudhop/blob/main/CONTRIBUTING.md)
|
|
116
|
+
and [ARCHITECTURE.md](https://github.com/dayepesb/cloudhop/blob/main/ARCHITECTURE.md),
|
|
117
|
+
and follow the
|
|
118
|
+
[Code of Conduct](https://github.com/dayepesb/cloudhop/blob/main/CODE_OF_CONDUCT.md).
|
|
58
119
|
|
|
59
120
|
## License
|
|
60
121
|
|
|
61
|
-
|
|
122
|
+
[Apache License 2.0](https://github.com/dayepesb/cloudhop/blob/main/LICENSE).
|
|
123
|
+
See [NOTICE](https://github.com/dayepesb/cloudhop/blob/main/NOTICE).
|
package/dist/cli.js
CHANGED
|
@@ -10663,10 +10663,19 @@ function answer(value) {
|
|
|
10663
10663
|
if (isCancel(value)) throw new PromptCancelled();
|
|
10664
10664
|
return value;
|
|
10665
10665
|
}
|
|
10666
|
-
var
|
|
10667
|
-
var
|
|
10668
|
-
var
|
|
10669
|
-
var
|
|
10666
|
+
var colorful = (stream2) => Boolean(stream2.isTTY) && !process.env.NO_COLOR;
|
|
10667
|
+
var truecolor = /truecolor|24bit/i.test(process.env.COLORTERM ?? "");
|
|
10668
|
+
var dim = (text3) => colorful(process.stderr) ? `\x1B[2m${text3}\x1B[22m` : text3;
|
|
10669
|
+
var bold = (text3) => colorful(process.stdout) ? `\x1B[1m${text3}\x1B[22m` : text3;
|
|
10670
|
+
var STYLES = {
|
|
10671
|
+
dim: ["2", "22"],
|
|
10672
|
+
green: ["32", "39"],
|
|
10673
|
+
yellow: ["33", "39"],
|
|
10674
|
+
red: ["31", "39"],
|
|
10675
|
+
sky: [truecolor ? "38;2;59;184;245" : "38;5;75", "39"],
|
|
10676
|
+
coral: [truecolor ? "38;2;255;122;89" : "38;5;209", "39"]
|
|
10677
|
+
};
|
|
10678
|
+
var paint = (style, text3) => colorful(process.stdout) ? `\x1B[${STYLES[style][0]}m${text3}\x1B[${STYLES[style][1]}m` : text3;
|
|
10670
10679
|
var BANNER = [
|
|
10671
10680
|
" _ _ _",
|
|
10672
10681
|
" ___ | | ___ _ _ __| || |__ ___ _ __",
|
|
@@ -10674,9 +10683,12 @@ var BANNER = [
|
|
|
10674
10683
|
"| (__ | || (_) || |_| || (_| || | | || (_) || |_) |",
|
|
10675
10684
|
" \\___||_| \\___/ \\__,_| \\__,_||_| |_| \\___/ | .__/",
|
|
10676
10685
|
" |_|"
|
|
10677
|
-
]
|
|
10686
|
+
];
|
|
10687
|
+
var HOP_COLUMN = 30;
|
|
10678
10688
|
function printBanner() {
|
|
10679
|
-
|
|
10689
|
+
for (const line of BANNER) {
|
|
10690
|
+
console.log(paint("sky", line.slice(0, HOP_COLUMN)) + paint("coral", line.slice(HOP_COLUMN)));
|
|
10691
|
+
}
|
|
10680
10692
|
}
|
|
10681
10693
|
function notify(message) {
|
|
10682
10694
|
process.stderr.write(`${dim("cloudhop \u203A")} ${message}
|
|
@@ -10975,7 +10987,9 @@ async function listCommand(app, sourceId) {
|
|
|
10975
10987
|
const state = await provider.sessionState(source);
|
|
10976
10988
|
const where = source.settings.startUrl ?? source.kind;
|
|
10977
10989
|
if (index > 0) console.log("");
|
|
10978
|
-
console.log(
|
|
10990
|
+
console.log(
|
|
10991
|
+
`${bold(paint("sky", source.id))} ${paint("dim", `${provider.displayName} \xB7 ${where}`)}`
|
|
10992
|
+
);
|
|
10979
10993
|
console.log(` ${SESSION_LABEL[state]}`);
|
|
10980
10994
|
const own = aliases.filter((a2) => a2.alias.source === source.id);
|
|
10981
10995
|
if (own.length === 0) {
|
|
@@ -11626,42 +11640,48 @@ var assets_default = `<!doctype html>
|
|
|
11626
11640
|
<meta charset="utf-8" />
|
|
11627
11641
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
11628
11642
|
<title>cloudhop</title>
|
|
11629
|
-
<link
|
|
11630
|
-
rel="icon"
|
|
11631
|
-
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='16' r='14' fill='%230ea5b7'/%3E%3Cpath d='M9 19c2-6 12-6 14 0' stroke='white' stroke-width='3' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"
|
|
11632
|
-
/>
|
|
11643
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 64 64%22 role=%22img%22 aria-label=%22cloudhop%22%3E%3Cdefs%3E%3ClinearGradient id=%22ch-bg%22 x1=%220%22 y1=%220%22 x2=%221%22 y2=%221%22%3E%3Cstop offset=%220%22 stop-color=%22%233BB8F5%22/%3E%3Cstop offset=%221%22 stop-color=%22%231450A8%22/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width=%2264%22 height=%2264%22 rx=%2215%22 fill=%22url(%23ch-bg)%22/%3E%3Cpath d=%22M8.5 47.5a5.5 5.5 0 0 1 5-5.5 6.8 6.8 0 0 1 13 1.6 4.4 4.4 0 0 1-.9 8.7H13.4a4.9 4.9 0 0 1-4.9-4.8z%22 fill=%22%23fff%22 fill-opacity=%22.55%22/%3E%3Cpath d=%22M31 44.6a7.6 7.6 0 0 1 7-7.6 9.6 9.6 0 0 1 18.2 2.6 6.3 6.3 0 0 1-1.3 12.5H38.3A7.4 7.4 0 0 1 31 44.6z%22 fill=%22%23fff%22/%3E%3Cpath d=%22M18 37.5C19 21 33 13.5 40.6 23%22 fill=%22none%22 stroke=%22%23fff%22 stroke-width=%223.6%22 stroke-linecap=%22round%22 stroke-dasharray=%220.01 6.3%22/%3E%3Cpath d=%22M46 30.2l-7.4-2.1 5.4-4.3z%22 fill=%22%23fff%22 stroke=%22%23fff%22 stroke-width=%222.4%22 stroke-linejoin=%22round%22/%3E%3C/svg%3E" />
|
|
11633
11644
|
<style>
|
|
11645
|
+
/* cloudhop palette "sky and coral": sky/blue for accents and focus, coral for the main action. */
|
|
11634
11646
|
:root {
|
|
11635
|
-
--bg: #
|
|
11647
|
+
--bg: #f6f8fc;
|
|
11636
11648
|
--surface: #ffffff;
|
|
11637
|
-
--surface-2: #
|
|
11638
|
-
--border: #
|
|
11639
|
-
--text: #
|
|
11640
|
-
--muted: #
|
|
11641
|
-
--accent: #
|
|
11642
|
-
--accent-strong: #
|
|
11643
|
-
--accent-soft: #
|
|
11644
|
-
--
|
|
11645
|
-
--
|
|
11646
|
-
--
|
|
11649
|
+
--surface-2: #eef2f9;
|
|
11650
|
+
--border: #dde3ef;
|
|
11651
|
+
--text: #0f1730;
|
|
11652
|
+
--muted: #55617d;
|
|
11653
|
+
--accent: #1767c2;
|
|
11654
|
+
--accent-strong: #0f4e99;
|
|
11655
|
+
--accent-soft: #dcebfb;
|
|
11656
|
+
--cta: #c2410c;
|
|
11657
|
+
--cta-strong: #9a3412;
|
|
11658
|
+
--on-cta: #ffffff;
|
|
11659
|
+
--ok: #1a7f52;
|
|
11660
|
+
--warn: #8a5a00;
|
|
11661
|
+
--bad: #be123c;
|
|
11662
|
+
--on-bad: #ffffff;
|
|
11647
11663
|
--radius: 10px;
|
|
11648
|
-
--shadow: 0 1px 2px rgb(
|
|
11664
|
+
--shadow: 0 1px 2px rgb(15 23 48 / 6%), 0 1px 3px rgb(15 23 48 / 8%);
|
|
11649
11665
|
color-scheme: light;
|
|
11650
11666
|
}
|
|
11651
11667
|
@media (prefers-color-scheme: dark) {
|
|
11652
11668
|
:root {
|
|
11653
|
-
--bg: #
|
|
11654
|
-
--surface: #
|
|
11655
|
-
--surface-2: #
|
|
11656
|
-
--border: #
|
|
11657
|
-
--text: #
|
|
11658
|
-
--muted: #
|
|
11659
|
-
--accent: #
|
|
11660
|
-
--accent-strong: #
|
|
11661
|
-
--accent-soft: #
|
|
11662
|
-
--
|
|
11663
|
-
--
|
|
11664
|
-
--
|
|
11669
|
+
--bg: #0b1124;
|
|
11670
|
+
--surface: #141c33;
|
|
11671
|
+
--surface-2: #1b2540;
|
|
11672
|
+
--border: #2a3555;
|
|
11673
|
+
--text: #e8ecf7;
|
|
11674
|
+
--muted: #9aa6c3;
|
|
11675
|
+
--accent: #3bb8f5;
|
|
11676
|
+
--accent-strong: #7fd0fa;
|
|
11677
|
+
--accent-soft: #12304f;
|
|
11678
|
+
--cta: #ff7a59;
|
|
11679
|
+
--cta-strong: #ff9478;
|
|
11680
|
+
--on-cta: #2a0e05;
|
|
11681
|
+
--ok: #4cd19a;
|
|
11682
|
+
--warn: #f5b84b;
|
|
11683
|
+
--bad: #fb7185;
|
|
11684
|
+
--on-bad: #2b0509;
|
|
11665
11685
|
--shadow: none;
|
|
11666
11686
|
color-scheme: dark;
|
|
11667
11687
|
}
|
|
@@ -11688,8 +11708,8 @@ var assets_default = `<!doctype html>
|
|
|
11688
11708
|
align-items: center;
|
|
11689
11709
|
gap: 16px;
|
|
11690
11710
|
}
|
|
11691
|
-
.logo { font-weight: 700; font-size: 20px; letter-spacing: -0.02em; }
|
|
11692
|
-
.logo span { color: var(--
|
|
11711
|
+
.logo { font-weight: 700; font-size: 20px; letter-spacing: -0.02em; display: flex; align-items: center; gap: 10px; }
|
|
11712
|
+
.logo span span { color: var(--cta); }
|
|
11693
11713
|
.tagline { color: var(--muted); font-size: 14px; }
|
|
11694
11714
|
.spacer { flex: 1; }
|
|
11695
11715
|
main { max-width: 1040px; margin: 0 auto; padding: 24px 20px 64px; }
|
|
@@ -11724,8 +11744,8 @@ var assets_default = `<!doctype html>
|
|
|
11724
11744
|
}
|
|
11725
11745
|
button:hover { background: var(--surface-2); }
|
|
11726
11746
|
button:focus-visible, input:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
11727
|
-
button.primary { background: var(--
|
|
11728
|
-
button.primary:hover { background: var(--
|
|
11747
|
+
button.primary { background: var(--cta); border-color: var(--cta); color: var(--on-cta); font-weight: 600; }
|
|
11748
|
+
button.primary:hover { background: var(--cta-strong); border-color: var(--cta-strong); }
|
|
11729
11749
|
button.danger { color: var(--bad); }
|
|
11730
11750
|
button.link { border: none; background: none; color: var(--muted); padding: 4px 6px; }
|
|
11731
11751
|
button.link:hover { color: var(--bad); }
|
|
@@ -11740,7 +11760,12 @@ var assets_default = `<!doctype html>
|
|
|
11740
11760
|
padding: 6px 10px;
|
|
11741
11761
|
min-width: 0;
|
|
11742
11762
|
}
|
|
11743
|
-
table
|
|
11763
|
+
/* Fixed columns so every source's table lines up with the others. */
|
|
11764
|
+
table { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
|
11765
|
+
th:nth-child(1) { width: 26%; }
|
|
11766
|
+
th:nth-child(2) { width: 190px; }
|
|
11767
|
+
th:nth-child(4) { width: 56px; }
|
|
11768
|
+
td { overflow-wrap: anywhere; }
|
|
11744
11769
|
th {
|
|
11745
11770
|
text-align: left;
|
|
11746
11771
|
font-size: 12px;
|
|
@@ -11751,7 +11776,7 @@ var assets_default = `<!doctype html>
|
|
|
11751
11776
|
padding: 8px 16px;
|
|
11752
11777
|
}
|
|
11753
11778
|
td { padding: 8px 16px; border-top: 1px solid var(--border); vertical-align: middle; }
|
|
11754
|
-
td.alias { font-weight: 600;
|
|
11779
|
+
td.alias { font-weight: 600; }
|
|
11755
11780
|
.region { display: flex; gap: 6px; align-items: center; }
|
|
11756
11781
|
.region input { width: 140px; }
|
|
11757
11782
|
.badge {
|
|
@@ -11841,7 +11866,7 @@ var assets_default = `<!doctype html>
|
|
|
11841
11866
|
box-shadow: 0 6px 20px rgb(0 0 0 / 25%);
|
|
11842
11867
|
font-size: 14px;
|
|
11843
11868
|
}
|
|
11844
|
-
.toast.error { background: var(--bad); color:
|
|
11869
|
+
.toast.error { background: var(--bad); color: var(--on-bad); }
|
|
11845
11870
|
.toast small { display: block; opacity: 0.85; }
|
|
11846
11871
|
.notice {
|
|
11847
11872
|
border: 1px solid var(--border);
|
|
@@ -11858,13 +11883,15 @@ var assets_default = `<!doctype html>
|
|
|
11858
11883
|
td, th { padding: 8px 10px; }
|
|
11859
11884
|
td.alias { white-space: normal; overflow-wrap: anywhere; }
|
|
11860
11885
|
.region input { width: 96px; }
|
|
11886
|
+
th:nth-child(1) { width: auto; }
|
|
11887
|
+
th:nth-child(2) { width: 124px; }
|
|
11861
11888
|
}
|
|
11862
11889
|
</style>
|
|
11863
11890
|
</head>
|
|
11864
11891
|
<body>
|
|
11865
11892
|
<header>
|
|
11866
11893
|
<div class="bar">
|
|
11867
|
-
<div class="logo">cloud<span>hop</span></div>
|
|
11894
|
+
<div class="logo"><img src="data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 64 64%22 role=%22img%22 aria-label=%22cloudhop%22%3E%3Cdefs%3E%3ClinearGradient id=%22ch-bg%22 x1=%220%22 y1=%220%22 x2=%221%22 y2=%221%22%3E%3Cstop offset=%220%22 stop-color=%22%233BB8F5%22/%3E%3Cstop offset=%221%22 stop-color=%22%231450A8%22/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width=%2264%22 height=%2264%22 rx=%2215%22 fill=%22url(%23ch-bg)%22/%3E%3Cpath d=%22M8.5 47.5a5.5 5.5 0 0 1 5-5.5 6.8 6.8 0 0 1 13 1.6 4.4 4.4 0 0 1-.9 8.7H13.4a4.9 4.9 0 0 1-4.9-4.8z%22 fill=%22%23fff%22 fill-opacity=%22.55%22/%3E%3Cpath d=%22M31 44.6a7.6 7.6 0 0 1 7-7.6 9.6 9.6 0 0 1 18.2 2.6 6.3 6.3 0 0 1-1.3 12.5H38.3A7.4 7.4 0 0 1 31 44.6z%22 fill=%22%23fff%22/%3E%3Cpath d=%22M18 37.5C19 21 33 13.5 40.6 23%22 fill=%22none%22 stroke=%22%23fff%22 stroke-width=%223.6%22 stroke-linecap=%22round%22 stroke-dasharray=%220.01 6.3%22/%3E%3Cpath d=%22M46 30.2l-7.4-2.1 5.4-4.3z%22 fill=%22%23fff%22 stroke=%22%23fff%22 stroke-width=%222.4%22 stroke-linejoin=%22round%22/%3E%3C/svg%3E" alt="" width="28" height="28" /><span>cloud<span>hop</span></span></div>
|
|
11868
11895
|
<div class="tagline">Hop between cloud accounts, roles and regions</div>
|
|
11869
11896
|
<div class="spacer"></div>
|
|
11870
11897
|
<button type="button" class="primary" id="add-source" hidden>+ Add source</button>
|
|
@@ -12623,7 +12650,7 @@ function createApp(env = process.env) {
|
|
|
12623
12650
|
}
|
|
12624
12651
|
|
|
12625
12652
|
// src/cli.ts
|
|
12626
|
-
var HELP = `cloudhop ${"
|
|
12653
|
+
var HELP = `cloudhop ${"1.0.0"}
|
|
12627
12654
|
Hop between cloud accounts, roles and regions with one command.
|
|
12628
12655
|
|
|
12629
12656
|
Usage
|
|
@@ -12653,7 +12680,7 @@ Options
|
|
|
12653
12680
|
--device-code Log in with a code instead of the browser redirect
|
|
12654
12681
|
-v, --version Show the version
|
|
12655
12682
|
|
|
12656
|
-
Docs: https://github.
|
|
12683
|
+
Docs: https://dayepesb.github.io/cloudhop/`;
|
|
12657
12684
|
function takeGlobalFlags(argv) {
|
|
12658
12685
|
const rest = [];
|
|
12659
12686
|
for (const arg of argv) {
|
|
@@ -12669,7 +12696,7 @@ async function main(argv) {
|
|
|
12669
12696
|
return 0;
|
|
12670
12697
|
}
|
|
12671
12698
|
if (command === "--version" || command === "-v" || command === "version") {
|
|
12672
|
-
console.log("
|
|
12699
|
+
console.log("1.0.0");
|
|
12673
12700
|
return 0;
|
|
12674
12701
|
}
|
|
12675
12702
|
const app = createApp();
|
package/package.json
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudhop",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Every cloud account, one short alias away. Sign in to AWS SSO portals and personal accounts once, hop between accounts, roles and regions with one command. No access keys.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
7
7
|
"aws",
|
|
8
|
+
"aws-cli",
|
|
9
|
+
"aws-sso",
|
|
8
10
|
"sso",
|
|
9
11
|
"iam-identity-center",
|
|
10
12
|
"aws-login",
|
|
11
13
|
"multi-account",
|
|
12
14
|
"profiles",
|
|
13
15
|
"credentials",
|
|
14
|
-
"
|
|
16
|
+
"terraform",
|
|
17
|
+
"cloud",
|
|
18
|
+
"devops"
|
|
15
19
|
],
|
|
16
|
-
"license": "
|
|
20
|
+
"license": "Apache-2.0",
|
|
17
21
|
"author": "dayepesb",
|
|
18
|
-
"homepage": "https://github.
|
|
22
|
+
"homepage": "https://dayepesb.github.io/cloudhop/",
|
|
19
23
|
"repository": {
|
|
20
24
|
"type": "git",
|
|
21
25
|
"url": "git+https://github.com/dayepesb/cloudhop.git",
|
|
@@ -30,7 +34,8 @@
|
|
|
30
34
|
"hop": "dist/cli.js"
|
|
31
35
|
},
|
|
32
36
|
"files": [
|
|
33
|
-
"dist"
|
|
37
|
+
"dist",
|
|
38
|
+
"NOTICE"
|
|
34
39
|
],
|
|
35
40
|
"engines": {
|
|
36
41
|
"node": ">=20"
|
|
@@ -39,8 +44,8 @@
|
|
|
39
44
|
"@clack/prompts": "^1.8.1",
|
|
40
45
|
"@cloudhop/core": "0.0.0",
|
|
41
46
|
"@cloudhop/adapters-node": "0.0.0",
|
|
42
|
-
"@cloudhop/
|
|
43
|
-
"@cloudhop/
|
|
47
|
+
"@cloudhop/provider-aws": "0.0.0",
|
|
48
|
+
"@cloudhop/ui": "0.0.0"
|
|
44
49
|
},
|
|
45
50
|
"scripts": {
|
|
46
51
|
"build": "tsup",
|