redkite 0.1.6 → 0.1.8
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/README.md +323 -35
- package/dist/checks.d.ts.map +1 -1
- package/dist/checks.js +4 -0
- package/dist/checks.js.map +1 -1
- package/dist/cli/agent.d.ts +2 -0
- package/dist/cli/agent.d.ts.map +1 -1
- package/dist/cli/agent.js +23 -1
- package/dist/cli/agent.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +98 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -1
- package/dist/config.js.map +1 -1
- package/dist/deploy.d.ts +4 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +77 -23
- package/dist/deploy.js.map +1 -1
- package/dist/dockerfile.js +6 -7
- package/dist/dockerfile.js.map +1 -1
- package/dist/environment.d.ts +5 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +20 -0
- package/dist/environment.js.map +1 -0
- package/dist/host.d.ts +2 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +6 -0
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/localHost.d.ts.map +1 -1
- package/dist/localHost.js +2 -0
- package/dist/localHost.js.map +1 -1
- package/dist/plugin.d.ts +15 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +21 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugins/bitwarden.d.ts +11 -0
- package/dist/plugins/bitwarden.d.ts.map +1 -0
- package/dist/plugins/bitwarden.js +40 -0
- package/dist/plugins/bitwarden.js.map +1 -0
- package/dist/plugins/digitalOcean.d.ts +19 -0
- package/dist/plugins/digitalOcean.d.ts.map +1 -0
- package/dist/plugins/digitalOcean.js +71 -0
- package/dist/plugins/digitalOcean.js.map +1 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +5 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/rds.d.ts +14 -0
- package/dist/plugins/rds.d.ts.map +1 -0
- package/dist/plugins/rds.js +86 -0
- package/dist/plugins/rds.js.map +1 -0
- package/dist/plugins/snapshot.d.ts +7 -0
- package/dist/plugins/snapshot.d.ts.map +1 -0
- package/dist/plugins/snapshot.js +29 -0
- package/dist/plugins/snapshot.js.map +1 -0
- package/dist/presets/nodeApp.d.ts +1 -2
- package/dist/presets/nodeApp.d.ts.map +1 -1
- package/dist/presets/nodeApp.js +0 -1
- package/dist/presets/nodeApp.js.map +1 -1
- package/dist/recover.d.ts +19 -0
- package/dist/recover.d.ts.map +1 -0
- package/dist/recover.js +58 -0
- package/dist/recover.js.map +1 -0
- package/dist/secrets/store.d.ts +5 -2
- package/dist/secrets/store.d.ts.map +1 -1
- package/dist/secrets/store.js +25 -14
- package/dist/secrets/store.js.map +1 -1
- package/dist/sshHost.d.ts +2 -0
- package/dist/sshHost.d.ts.map +1 -1
- package/dist/sshHost.js +29 -11
- package/dist/sshHost.js.map +1 -1
- package/dist/steps.d.ts +0 -7
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +6 -3
- package/dist/steps.js.map +1 -1
- package/dist/types.d.ts +4 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/checks.ts +4 -0
- package/src/cli/agent.ts +28 -1
- package/src/cli/index.ts +118 -29
- package/src/config.ts +19 -1
- package/src/deploy.ts +101 -29
- package/src/dockerfile.ts +7 -11
- package/src/environment.ts +24 -0
- package/src/host.ts +11 -0
- package/src/index.ts +4 -1
- package/src/localHost.ts +3 -0
- package/src/plugin.ts +50 -0
- package/src/plugins/bitwarden.ts +57 -0
- package/src/plugins/digitalOcean.ts +111 -0
- package/src/plugins/index.ts +4 -0
- package/src/plugins/rds.ts +126 -0
- package/src/plugins/snapshot.ts +44 -0
- package/src/presets/nodeApp.ts +1 -3
- package/src/recover.ts +90 -0
- package/src/secrets/store.ts +39 -20
- package/src/sshHost.ts +35 -11
- package/src/steps.ts +7 -6
- package/src/types.ts +22 -12
- package/dist/secrets/bitwarden.d.ts +0 -3
- package/dist/secrets/bitwarden.d.ts.map +0 -1
- package/dist/secrets/bitwarden.js +0 -6
- package/dist/secrets/bitwarden.js.map +0 -1
- package/src/secrets/bitwarden.ts +0 -7
package/README.md
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
</h1>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<a href="https://www.npmjs.com/package/redkite
|
|
7
|
-
<a href="https://www.npmjs.com/package/redkite
|
|
8
|
-
<a href="https://nodejs.org"><img alt="node" src="https://img.shields.io/node/v/redkite
|
|
9
|
-
<a href="./LICENSE"><img alt="license" src="https://img.shields.io/npm/l/redkite
|
|
6
|
+
<a href="https://www.npmjs.com/package/redkite"><img alt="npm version" src="https://img.shields.io/npm/v/redkite.svg"></a>
|
|
7
|
+
<a href="https://www.npmjs.com/package/redkite"><img alt="npm downloads" src="https://img.shields.io/npm/dm/redkite.svg"></a>
|
|
8
|
+
<a href="https://nodejs.org"><img alt="node" src="https://img.shields.io/node/v/redkite.svg"></a>
|
|
9
|
+
<a href="./LICENSE"><img alt="license" src="https://img.shields.io/npm/l/redkite.svg"></a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
@@ -30,8 +30,10 @@ between deploys.
|
|
|
30
30
|
- [Requirements](#requirements)
|
|
31
31
|
- [Configuration](#configuration)
|
|
32
32
|
- [Hooks](#hooks)
|
|
33
|
+
- [Plugins](#plugins)
|
|
33
34
|
- [Verifying a build](#verifying-a-build)
|
|
34
35
|
- [CLI](#cli)
|
|
36
|
+
- [GitHub Actions](#github-actions)
|
|
35
37
|
- [How a deploy runs](#how-a-deploy-runs)
|
|
36
38
|
- [Design](#design)
|
|
37
39
|
- [Contributing](#contributing)
|
|
@@ -40,13 +42,13 @@ between deploys.
|
|
|
40
42
|
## Quick start
|
|
41
43
|
|
|
42
44
|
```sh
|
|
43
|
-
npm install redkite
|
|
45
|
+
npm install redkite
|
|
44
46
|
```
|
|
45
47
|
|
|
46
48
|
Add `redkite.config.ts` at the root of your project:
|
|
47
49
|
|
|
48
50
|
```ts
|
|
49
|
-
import { defineDeployment, nextApp, nodeApp, redis } from "redkite
|
|
51
|
+
import { defineDeployment, nextApp, nodeApp, redis } from "redkite";
|
|
50
52
|
|
|
51
53
|
export default defineDeployment({
|
|
52
54
|
project: "acme",
|
|
@@ -137,7 +139,7 @@ One file each, beside the deployment, named `redkite.<environment>.config.ts`:
|
|
|
137
139
|
|
|
138
140
|
```ts
|
|
139
141
|
// redkite.production.config.ts
|
|
140
|
-
import { defineEnvironment } from "redkite
|
|
142
|
+
import { defineEnvironment } from "redkite";
|
|
141
143
|
|
|
142
144
|
export default defineEnvironment({
|
|
143
145
|
branch: "main",
|
|
@@ -276,7 +278,7 @@ the `branch` an environment names is not consulted at all.
|
|
|
276
278
|
|
|
277
279
|
The release is the content of the working tree, taken with git's own addressing
|
|
278
280
|
over a scratch index. It covers what is committed, what is modified and what is
|
|
279
|
-
untracked, and honours `.gitignore
|
|
281
|
+
untracked, and honours `.gitignore`, which is the same set the build reads. So
|
|
280
282
|
an edit you never committed is a new release and gets built, and a change under
|
|
281
283
|
an ignored `node_modules` is not and does not:
|
|
282
284
|
|
|
@@ -387,6 +389,25 @@ one lockfile for every package in it, so the install has to see all of them,
|
|
|
387
389
|
and `node_modules` is where that put it. An app with its own lockfile in a
|
|
388
390
|
subdirectory is not covered by `dir` alone.
|
|
389
391
|
|
|
392
|
+
### Reaching the deploy host
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
host: { bastion: "deploy@acme.example", hostKeys: "accept-new" }
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The host's key is checked before anything is handed to it. `accept-new`, the
|
|
399
|
+
default, trusts it the first time and refuses it if the key ever changes after
|
|
400
|
+
that: no setup, and nothing to intercept once the first deploy has happened.
|
|
401
|
+
`strict` refuses any host not already in `known_hosts`, which is stronger and
|
|
402
|
+
means putting the key there yourself. `off` checks nothing, for a host whose
|
|
403
|
+
address is handed out again and again and only where nothing on the way to it
|
|
404
|
+
can listen.
|
|
405
|
+
|
|
406
|
+
ssh is never left able to ask a question, whichever of the three it is under: a
|
|
407
|
+
prompt nobody is there to answer is a deploy that hangs rather than one that
|
|
408
|
+
fails. Cloning is separate and always `accept-new`, because the deploy host
|
|
409
|
+
reaches GitHub rather than reaching you.
|
|
410
|
+
|
|
390
411
|
### Services
|
|
391
412
|
|
|
392
413
|
Long-lived containers shared by the apps. The proxy is not one of them: apps
|
|
@@ -428,13 +449,54 @@ An id is a pointer, not a credential, so it belongs in the config while the
|
|
|
428
449
|
credentials arrive at deploy time.
|
|
429
450
|
|
|
430
451
|
```ts
|
|
431
|
-
|
|
432
|
-
|
|
452
|
+
plugins: [bitwarden()],
|
|
453
|
+
// ...
|
|
454
|
+
secrets: bitwarden.item("00000000-0000-4000-8000-000000000001"),
|
|
455
|
+
files: { "/app/service-account.json": bitwarden.item("...") },
|
|
433
456
|
```
|
|
434
457
|
|
|
435
|
-
|
|
436
|
-
`
|
|
437
|
-
|
|
458
|
+
The vault is a [plugin](#plugins) like any other, so `bitwarden()` has to be
|
|
459
|
+
registered before `bitwarden.item()` resolves to anything. A deployment that
|
|
460
|
+
names a provider nothing registers is refused before it builds, rather than
|
|
461
|
+
reaching for a vault by name.
|
|
462
|
+
|
|
463
|
+
It unlocks with `BW_KEY`, a session obtained elsewhere, and falls back to
|
|
464
|
+
`BW_CLIENT_ID`, `BW_CLIENT_SECRET` and `BW_PASSWORD` when that is not set. A
|
|
465
|
+
config that would rather name its own variable passes the session in:
|
|
466
|
+
`bitwarden({ secrets: process.env.MY_VAULT_SESSION })`. One that reads no
|
|
467
|
+
secrets at all needs none of them: redkite only opens the stores your config
|
|
468
|
+
actually names.
|
|
469
|
+
|
|
470
|
+
#### Where a secret is, and where it is not
|
|
471
|
+
|
|
472
|
+
**Nothing a vault resolves is ever written into an image.** During the build it
|
|
473
|
+
is mounted as `.env` at the app's root for the length of each step and gone
|
|
474
|
+
after it, so a build can read a credential without shipping one, and no layer
|
|
475
|
+
ever holds it. Copying it in and deleting it later would not do: a deleted file
|
|
476
|
+
is still readable in the layer underneath.
|
|
477
|
+
|
|
478
|
+
At runtime it arrives as the container's own environment, written to the host
|
|
479
|
+
and handed to `docker create --env-file`, so no value appears in an argument
|
|
480
|
+
list and the file goes with the rest of the deploy's scratch. Read it from
|
|
481
|
+
`process.env`; there is no `.env` to read.
|
|
482
|
+
|
|
483
|
+
The same is true of the migrations and checks that run in the builder image:
|
|
484
|
+
they are given `--env-file` too, rather than finding a file the build left
|
|
485
|
+
behind.
|
|
486
|
+
|
|
487
|
+
If you do want one in the image, say so, in a build step where the mount is
|
|
488
|
+
still there:
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
steps: ["yarn build", "cp .env dist/.env"],
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
`files` is the other way to put a credential in an image on purpose, for the
|
|
495
|
+
ones that have to be a file rather than a variable:
|
|
496
|
+
|
|
497
|
+
```ts
|
|
498
|
+
files: { "/app/service-account.json": bitwarden.item("...") },
|
|
499
|
+
```
|
|
438
500
|
|
|
439
501
|
## Hooks
|
|
440
502
|
|
|
@@ -468,12 +530,12 @@ config that registers a step at the same point replaces it. That is how one is
|
|
|
468
530
|
turned off: put something there that does less.
|
|
469
531
|
|
|
470
532
|
```ts
|
|
471
|
-
import { defineStep } from "redkite
|
|
533
|
+
import { defineStep } from "redkite";
|
|
472
534
|
|
|
473
535
|
export default defineDeployment({
|
|
474
536
|
// ...
|
|
475
537
|
steps: [
|
|
476
|
-
defineStep("build:after:
|
|
538
|
+
defineStep("build:after:report", async (built, context) => {
|
|
477
539
|
for (const app of built.apps) {
|
|
478
540
|
context.task.detail(`${app.name} at ${app.release.slice(0, 7)}`);
|
|
479
541
|
}
|
|
@@ -513,7 +575,7 @@ A migration is a step like any other. `migrate()` answers with one at
|
|
|
513
575
|
the old containers are still serving, and throws before anything retires.
|
|
514
576
|
|
|
515
577
|
```ts
|
|
516
|
-
import { migrate } from "redkite
|
|
578
|
+
import { migrate } from "redkite";
|
|
517
579
|
|
|
518
580
|
export default defineDeployment({
|
|
519
581
|
steps: [migrate({ app: "backend", command: "yarn db:migrate" })],
|
|
@@ -548,7 +610,7 @@ migrate({ app: "backend", command: "yarn db:migrate", network: "deployment" })
|
|
|
548
610
|
`attachment()` answers with the same flags for a step of your own:
|
|
549
611
|
|
|
550
612
|
```ts
|
|
551
|
-
import { attachment, defineStep } from "redkite
|
|
613
|
+
import { attachment, defineStep } from "redkite";
|
|
552
614
|
|
|
553
615
|
defineStep("swap:before:seed", async (built, context) => {
|
|
554
616
|
const image = built.apps.find((app) => app.name === "backend")?.builderTag;
|
|
@@ -563,37 +625,181 @@ defineStep("swap:before:seed", async (built, context) => {
|
|
|
563
625
|
});
|
|
564
626
|
```
|
|
565
627
|
|
|
566
|
-
###
|
|
628
|
+
### Snapshotting a database before a swap
|
|
567
629
|
|
|
568
|
-
A
|
|
569
|
-
|
|
630
|
+
A migration that goes wrong is the one thing a blue-green swap cannot undo:
|
|
631
|
+
putting the container back does not put the rows back. These take a snapshot
|
|
632
|
+
first, and they sit at `swap:before` so they run while the old containers are
|
|
633
|
+
still serving.
|
|
570
634
|
|
|
571
635
|
```ts
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
defineStep("cleanup:after:notify", async (finished) => {
|
|
578
|
-
await fetch(webhook, { method: "POST", body: `released ${finished.released.join(", ")}` });
|
|
579
|
-
return finished;
|
|
580
|
-
}),
|
|
581
|
-
];
|
|
636
|
+
steps: [
|
|
637
|
+
// Above the migrate, because steps run in the order they are listed
|
|
638
|
+
rdsSnapshot({ instance: "acme-production", region: "eu-west-1" }),
|
|
639
|
+
migrate({ app: "backend", command: "yarn db:migrate" }),
|
|
640
|
+
]
|
|
582
641
|
```
|
|
583
642
|
|
|
584
|
-
|
|
585
|
-
|
|
643
|
+
`rdsSnapshot` goes through the AWS CLI, which every runner already has with the
|
|
644
|
+
credentials the job was given; signing a request by hand is a page of crypto
|
|
645
|
+
that nothing here could check. It takes an `instance`, or a `cluster` for
|
|
646
|
+
Aurora, and refuses a config naming both. RDS captures the data when the
|
|
647
|
+
snapshot begins rather than when it finishes, so it does not wait by default:
|
|
648
|
+
`wait: true` turns a snapshot that silently failed into a deploy that stops
|
|
649
|
+
before the migration, at the cost of however long the snapshot takes.
|
|
586
650
|
|
|
587
651
|
```ts
|
|
588
|
-
|
|
589
|
-
|
|
652
|
+
digitalOceanSnapshot({ volume: "e7f8...", tokenFrom: "DIGITALOCEAN_TOKEN" })
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
DigitalOcean's managed databases have no endpoint that takes a snapshot on
|
|
656
|
+
demand: their backups are automatic and the API only lists them. So what this
|
|
657
|
+
snapshots is the block storage `volume` the data sits on, which for redkite's
|
|
658
|
+
own postgres service is the disk under the container, or the `droplet` when the
|
|
659
|
+
database is the whole machine. A volume snapshot of a running Postgres is crash
|
|
660
|
+
consistent rather than clean, which Postgres is built to survive.
|
|
661
|
+
|
|
662
|
+
The token is named rather than given: a config is committed and a token is not.
|
|
663
|
+
Both plugins check what they can before the run starts, so a missing token or a
|
|
664
|
+
config naming two databases fails while the host is still untouched.
|
|
665
|
+
|
|
666
|
+
## Plugins
|
|
667
|
+
|
|
668
|
+
A plugin is what a deployment opts into. It adds steps to the run, or teaches
|
|
669
|
+
it to resolve a kind of secret, and **nothing it carries happens until the
|
|
670
|
+
config lists it** in `plugins`. Redkite's own vault is one of these rather than
|
|
671
|
+
something wired in behind them, so the rule has no exceptions to remember.
|
|
672
|
+
|
|
673
|
+
```ts
|
|
674
|
+
import { bitwarden, defineDeployment, digitalOceanSnapshot, rdsSnapshot } from "redkite";
|
|
590
675
|
|
|
591
676
|
export default defineDeployment({
|
|
677
|
+
project: "acme",
|
|
678
|
+
plugins: [
|
|
679
|
+
bitwarden(),
|
|
680
|
+
rdsSnapshot({ instance: "acme-production", region: "eu-west-1" }),
|
|
681
|
+
],
|
|
592
682
|
// ...
|
|
593
|
-
steps: [...slack(webhook)],
|
|
594
683
|
});
|
|
595
684
|
```
|
|
596
685
|
|
|
686
|
+
`plan` prints what a deployment opted into and where each plugin's steps land,
|
|
687
|
+
so what a run will do is readable without running it:
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
plugins
|
|
691
|
+
bitwarden 0 steps resolves bitwarden
|
|
692
|
+
rds-snapshot-acme-db 1 step
|
|
693
|
+
|
|
694
|
+
pipeline (deploy)
|
|
695
|
+
setup redkite
|
|
696
|
+
build redkite
|
|
697
|
+
swap:before:snapshot-acme-db rds-snapshot-acme-db
|
|
698
|
+
swap:before:migrate-backend
|
|
699
|
+
swap redkite
|
|
700
|
+
cleanup redkite
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
A plugin's steps run above the deployment's own, which is why the snapshot
|
|
704
|
+
lands before the migration written under `steps`. Registering the same plugin
|
|
705
|
+
twice is refused, and so is a second plugin claiming a provider another already
|
|
706
|
+
resolves.
|
|
707
|
+
|
|
708
|
+
The ones redkite ships are `bitwarden()`, [`rdsSnapshot()` and
|
|
709
|
+
`digitalOceanSnapshot()`](#snapshotting-a-database-before-a-swap). None of them
|
|
710
|
+
is on unless you say so.
|
|
711
|
+
|
|
712
|
+
### Writing plugins
|
|
713
|
+
|
|
714
|
+
A plugin is an object with a name, and steps or stores. `definePlugin` is
|
|
715
|
+
identity, but it checks the points where the plugin is written rather than
|
|
716
|
+
where it is registered, so a typo is the plugin's own failure:
|
|
717
|
+
|
|
718
|
+
```ts
|
|
719
|
+
import { definePlugin, defineStep, type Plugin } from "redkite";
|
|
720
|
+
|
|
721
|
+
export function announce(options: { url: string }): Plugin {
|
|
722
|
+
return definePlugin({
|
|
723
|
+
name: "announce",
|
|
724
|
+
steps: [
|
|
725
|
+
defineStep("swap:after:announce", async (input, context) => {
|
|
726
|
+
if (!input.ok) return input;
|
|
727
|
+
|
|
728
|
+
context.task.detail(`announcing ${input.released.join(", ")}`);
|
|
729
|
+
await fetch(options.url, { method: "POST", body: input.released.join(",") });
|
|
730
|
+
|
|
731
|
+
return input;
|
|
732
|
+
}),
|
|
733
|
+
],
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
The input and output types come from the point: a step at `swap:after` is
|
|
739
|
+
handed what the swap answered with, and must answer with the same, which is
|
|
740
|
+
what makes `input.released` typed without annotating anything.
|
|
741
|
+
|
|
742
|
+
A plugin resolving secrets registers a store per provider tag instead. It is
|
|
743
|
+
opened once, and only when a ref actually names that provider:
|
|
744
|
+
|
|
745
|
+
```ts
|
|
746
|
+
definePlugin({
|
|
747
|
+
name: "onepassword",
|
|
748
|
+
stores: {
|
|
749
|
+
onepassword: async ({ detail }) => {
|
|
750
|
+
detail("unlocking");
|
|
751
|
+
return { read: async (id: string) => await read(id) };
|
|
752
|
+
},
|
|
753
|
+
},
|
|
754
|
+
});
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
Then a ref pointing at it is `{ provider: "onepassword", id }`, which is what a
|
|
758
|
+
helper like `bitwarden.item()` answers with.
|
|
759
|
+
|
|
760
|
+
### As a separate package
|
|
761
|
+
|
|
762
|
+
There is nothing to register: a package exports a function, a config imports it
|
|
763
|
+
and lists what it answers with. The one thing to know is that **a plugin has to
|
|
764
|
+
ship JavaScript**. Node strips types from a config file, but it refuses to do
|
|
765
|
+
so for anything under `node_modules`, so a package shipping `.ts` fails to load
|
|
766
|
+
with `Stripping types is currently unsupported for files under node_modules`.
|
|
767
|
+
Compile it and ship `dist`, the way redkite itself does:
|
|
768
|
+
|
|
769
|
+
```json
|
|
770
|
+
{
|
|
771
|
+
"name": "redkite-plugin-announce",
|
|
772
|
+
"type": "module",
|
|
773
|
+
"main": "./dist/index.js",
|
|
774
|
+
"types": "./dist/index.d.ts",
|
|
775
|
+
"files": ["dist"],
|
|
776
|
+
"scripts": { "build": "tsc index.ts --outDir dist --declaration" },
|
|
777
|
+
"peerDependencies": { "redkite": ">=0.1.7" }
|
|
778
|
+
}
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
`redkite` belongs in `peerDependencies` rather than `dependencies`: a plugin
|
|
782
|
+
extends the redkite the deployment is already running, and a second copy of it
|
|
783
|
+
would be a second set of types that do not match.
|
|
784
|
+
|
|
785
|
+
```sh
|
|
786
|
+
npm install redkite-plugin-announce
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
```ts
|
|
790
|
+
import { announce } from "redkite-plugin-announce";
|
|
791
|
+
|
|
792
|
+
plugins: [announce({ url: process.env.SLACK_WEBHOOK ?? "" })],
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
A complete one is in [examples/plugin](examples/plugin). Two things worth
|
|
796
|
+
copying from it: take what the plugin needs as options rather than reading the
|
|
797
|
+
environment at import time, and name the variable a token comes from rather
|
|
798
|
+
than the token itself, so a config stays committable. Anything a plugin can
|
|
799
|
+
check about its own configuration it should check when it is constructed, so a
|
|
800
|
+
mistake is a config that fails to load rather than a deploy that stops with the
|
|
801
|
+
swap ahead of it.
|
|
802
|
+
|
|
597
803
|
## Verifying a build
|
|
598
804
|
|
|
599
805
|
`redkite verify` is the same host, the same services and the same images as a
|
|
@@ -664,6 +870,8 @@ redkite <command> [environment]
|
|
|
664
870
|
plan [environment] Print the derived topology, the pipeline and the nginx
|
|
665
871
|
deploy [environment] Build, swap, health check, and revert on failure
|
|
666
872
|
verify [environment] Bring the services up, build, and run each app's checks
|
|
873
|
+
rollback [environment] Put back any app a run moved and did not finish
|
|
874
|
+
down [environment] Stop everything this environment named
|
|
667
875
|
|
|
668
876
|
--config <path> Defaults to redkite.config.ts at the root of the project
|
|
669
877
|
--local Build the images here and ship them to the host
|
|
@@ -767,6 +975,86 @@ the CPU and disk it is using. Nothing will clean up after it but you.
|
|
|
767
975
|
|
|
768
976
|
The sixth press leaves.
|
|
769
977
|
|
|
978
|
+
## GitHub Actions
|
|
979
|
+
|
|
980
|
+
There is a composite action in this repository. `verify` on a pull request,
|
|
981
|
+
`deploy` on merge:
|
|
982
|
+
|
|
983
|
+
```yaml
|
|
984
|
+
- uses: actions/checkout@v4
|
|
985
|
+
- uses: JVKdouk/redkite@v1
|
|
986
|
+
with:
|
|
987
|
+
command: deploy
|
|
988
|
+
environment: production
|
|
989
|
+
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
|
990
|
+
env:
|
|
991
|
+
BW_CLIENT_ID: ${{ secrets.BW_CLIENT_ID }}
|
|
992
|
+
BW_CLIENT_SECRET: ${{ secrets.BW_CLIENT_SECRET }}
|
|
993
|
+
BW_PASSWORD: ${{ secrets.BW_PASSWORD }}
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
Whole workflows are in [examples/actions](examples/actions). The action sets
|
|
997
|
+
Node up, caches `~/.cache/redkite` so the pinned Bitwarden CLI is installed once
|
|
998
|
+
rather than every run, loads the key into an agent for the job, and runs a
|
|
999
|
+
pinned `redkite`.
|
|
1000
|
+
|
|
1001
|
+
The view stands down on its own: it wants a terminal on both stdout and stdin,
|
|
1002
|
+
and a runner has neither, so what a job logs is one line per event.
|
|
1003
|
+
|
|
1004
|
+
A runner's `known_hosts` is empty every time, so the default `accept-new`
|
|
1005
|
+
trusts the deploy host on first sight each run. `hostKeys: "strict"` there means
|
|
1006
|
+
writing the key into `~/.ssh/known_hosts` before the deploy step.
|
|
1007
|
+
|
|
1008
|
+
**The key is only needed where something uses it.** A run that reaches a deploy
|
|
1009
|
+
host, or clones over ssh, wants an agent holding one. A `verify` that builds
|
|
1010
|
+
what the checkout already holds wants nothing: no host to reach, no clone. That
|
|
1011
|
+
is what makes a pull request from a fork's branch testable without handing the
|
|
1012
|
+
job a deploy key.
|
|
1013
|
+
|
|
1014
|
+
**Build on the host, not on the runner.** The obvious move is to point an app at
|
|
1015
|
+
the checkout the job already has, and it is usually the wrong one: a runner is
|
|
1016
|
+
thrown away, so BuildKit starts cold every time and the finished image has to be
|
|
1017
|
+
shipped over ssh. An app that names a `repo` is cloned by the deploy host into a
|
|
1018
|
+
mirror that is already warm, and nothing crosses the wire. Keep `path` for
|
|
1019
|
+
`verify`, where the point is to test the tree in the pull request including what
|
|
1020
|
+
was never pushed.
|
|
1021
|
+
|
|
1022
|
+
**Two runs would race.** Redkite holds no lock, so give the deploy job a
|
|
1023
|
+
`concurrency` group. Leave `cancel-in-progress` false on that one: a deploy
|
|
1024
|
+
interrupted between retiring the old container and starting the new one is the
|
|
1025
|
+
one state nothing downstream can reason about.
|
|
1026
|
+
|
|
1027
|
+
### Cancelling a run
|
|
1028
|
+
|
|
1029
|
+
A run that is **asked** to stop puts back whatever it moved. Everything from
|
|
1030
|
+
retiring the old container to the health check is one guarded stretch, and an
|
|
1031
|
+
abort anywhere in it reverts the apps that had already moved, on a connection
|
|
1032
|
+
the stop cannot refuse.
|
|
1033
|
+
|
|
1034
|
+
A run that is **killed** never gets that far, which is what a cancelled job is:
|
|
1035
|
+
SIGINT, then the job is torn down after a grace period. So the recovery has to
|
|
1036
|
+
be something a different process can do, reading what the host is in rather
|
|
1037
|
+
than what the dead run remembered. A retired container is the whole signal, and
|
|
1038
|
+
that is what `rollback` looks for:
|
|
1039
|
+
|
|
1040
|
+
```yaml
|
|
1041
|
+
- if: cancelled()
|
|
1042
|
+
uses: JVKdouk/redkite@v1
|
|
1043
|
+
with:
|
|
1044
|
+
command: rollback
|
|
1045
|
+
environment: production
|
|
1046
|
+
ssh-key: ${{ secrets.DEPLOY_KEY }}
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
It does nothing when nothing was interrupted, so it is safe to leave in the
|
|
1050
|
+
workflow. `down` is its counterpart for an environment that exists to be built
|
|
1051
|
+
against rather than served from: it stops that environment's containers, the
|
|
1052
|
+
derived proxy included, and stops rather than removes them so the next run
|
|
1053
|
+
adopts them where it left off.
|
|
1054
|
+
|
|
1055
|
+
The build itself is still the one thing a killed job cannot take back with it:
|
|
1056
|
+
it keeps going on the deploy host. Nothing inside the job can change that.
|
|
1057
|
+
|
|
770
1058
|
## How a deploy runs
|
|
771
1059
|
|
|
772
1060
|
Everything happens on the deploy host, over a single multiplexed ssh connection
|
package/dist/checks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAapE,wBAAsB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAajF;AAiCD,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,QAOzC"}
|
package/dist/checks.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { envFlags } from "./environment.js";
|
|
1
2
|
import { appRoot } from "./layout.js";
|
|
2
3
|
import { quote } from "./shell.js";
|
|
3
4
|
import { attachment, builderOf } from "./steps.js";
|
|
@@ -24,6 +25,9 @@ async function checkApp(app, spec, input, context) {
|
|
|
24
25
|
const flags = [
|
|
25
26
|
"run --rm",
|
|
26
27
|
...attachment(spec.network ?? "deployment", context.topology),
|
|
28
|
+
// Before the named settings, so a check can override what the vault says
|
|
29
|
+
// without editing the vault
|
|
30
|
+
...(await envFlags(app, context)),
|
|
27
31
|
`--workdir ${appRoot(app.dir)}`,
|
|
28
32
|
...settings({ ...app.environment, ...spec.environment }),
|
|
29
33
|
builderOf(input, app.name),
|
package/dist/checks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGnD,4EAA4E;AAC5E,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,0EAA0E;AAE1E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAY,EAAE,OAAgB;IAC5D,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,MAAM;YAAE,SAAS;QAE1B,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,4EAA4E;IAC5E,4DAA4D;IAC5D,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,IAAgB,EAAE,KAAY,EAAE,OAAgB;IACpF,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,IAAI,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC;QAC7D,aAAa,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QAC/B,GAAG,QAAQ,CAAC,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACxD,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC;KAC3B,CAAC;IAEF,4EAA4E;IAC5E,qEAAqE;IACrE,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QAE/C,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAC7B,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAC7C,GAAG,GAAG,CAAC,IAAI,WAAW,OAAO,EAAE,EAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAClB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,WAAmC;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,yEAAyE;AACzE,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO;IAEvD,MAAM,IAAI,KAAK,CACb,2DAA2D;QACzD,0DAA0D,CAC7D,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGnD,4EAA4E;AAC5E,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,0EAA0E;AAE1E,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAY,EAAE,OAAgB;IAC5D,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,MAAM;YAAE,SAAS;QAE1B,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,4EAA4E;IAC5E,4DAA4D;IAC5D,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,IAAgB,EAAE,KAAY,EAAE,OAAgB;IACpF,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,IAAI,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC;QAC7D,yEAAyE;QACzE,4BAA4B;QAC5B,GAAG,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACjC,aAAa,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QAC/B,GAAG,QAAQ,CAAC,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACxD,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC;KAC3B,CAAC;IAEF,4EAA4E;IAC5E,qEAAqE;IACrE,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QAE/C,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAC7B,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAC7C,GAAG,GAAG,CAAC,IAAI,WAAW,OAAO,EAAE,EAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAClB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,WAAmC;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,yEAAyE;AACzE,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,IAAU;IACxC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO;IAEvD,MAAM,IAAI,KAAK,CACb,2DAA2D;QACzD,0DAA0D,CAC7D,CAAC;AACJ,CAAC"}
|
package/dist/cli/agent.d.ts
CHANGED
package/dist/cli/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9C,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAIjE;AAWD,wBAAgB,YAAY,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,UA4B3D"}
|
package/dist/cli/agent.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { environmentOf } from "../config.js";
|
|
2
3
|
// Cloning private repositories and opening the tunnel both go through the
|
|
3
4
|
// agent, so a deploy without one fails halfway rather than at the start
|
|
5
|
+
// Asked before one is demanded. A runner has no keys and no way to be prompted
|
|
6
|
+
// for one, and a deployment that reaches no other machine and clones nothing
|
|
7
|
+
// has no use for an agent: insisting on one there is a green run turned red
|
|
8
|
+
export function needsAgent(config, environment) {
|
|
9
|
+
if (environmentOf(config, environment)?.host?.bastion)
|
|
10
|
+
return true;
|
|
11
|
+
return config.apps.some((app) => app.repo !== undefined && overSsh(app.repo));
|
|
12
|
+
}
|
|
13
|
+
// A clone URL that names a transport of its own carries its own credentials.
|
|
14
|
+
// Anything else is the scp-like form, which is ssh and wants a key
|
|
15
|
+
function overSsh(repo) {
|
|
16
|
+
return !/^(https?|git|file):\/\//.test(repo);
|
|
17
|
+
}
|
|
4
18
|
// A plain writer rather than a Log, because this runs before the view opens:
|
|
5
19
|
// ssh-add may ask for a passphrase, and it cannot ask through a screen
|
|
6
20
|
// something else is drawing
|
|
@@ -18,7 +32,15 @@ export function requireAgent(warn) {
|
|
|
18
32
|
if (pid)
|
|
19
33
|
process.env["SSH_AGENT_PID"] = pid;
|
|
20
34
|
// Inherits stdio so a passphrase prompt reaches the person running this
|
|
21
|
-
|
|
35
|
+
try {
|
|
36
|
+
execFileSync("ssh-add", [], { stdio: "inherit" });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new Error("ssh-add found no key to load. This deployment reaches another machine " +
|
|
40
|
+
"or clones over ssh, so it needs an agent holding a key that can. On a " +
|
|
41
|
+
"runner, set one up before this step and leave SSH_AUTH_SOCK in the " +
|
|
42
|
+
"environment");
|
|
43
|
+
}
|
|
22
44
|
return socket;
|
|
23
45
|
}
|
|
24
46
|
//# sourceMappingURL=agent.js.map
|
package/dist/cli/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,0EAA0E;AAC1E,wEAAwE;AAExE,6EAA6E;AAC7E,uEAAuE;AACvE,4BAA4B;AAC5B,MAAM,UAAU,YAAY,CAAC,IAA+B;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;IACtC,IAAI,GAAG;QAAE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,GAAG,CAAC;IAE5C,wEAAwE;IACxE,YAAY,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/cli/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,0EAA0E;AAC1E,wEAAwE;AAExE,+EAA+E;AAC/E,6EAA6E;AAC7E,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,MAAkB,EAAE,WAAmB;IAChE,IAAI,aAAa,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IAEnE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,6EAA6E;AAC7E,mEAAmE;AACnE,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,6EAA6E;AAC7E,uEAAuE;AACvE,4BAA4B;AAC5B,MAAM,UAAU,YAAY,CAAC,IAA+B;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;IACtC,IAAI,GAAG;QAAE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,GAAG,CAAC;IAE5C,wEAAwE;IACxE,IAAI,CAAC;QACH,YAAY,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,wEAAwE;YACtE,wEAAwE;YACxE,qEAAqE;YACrE,aAAa,CAChB,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/cli/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AA8F1D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,YAgBxC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,2BASxC;AAuQD,wBAAgB,OAAO,CAAC,EAAE,EAAE;IAC1B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACxC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,cAwBA;AAkCD,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAehF"}
|