@stringsync/splates 0.0.52 → 0.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +31 -5
  2. package/package.json +2 -2
package/index.js CHANGED
@@ -702,6 +702,7 @@ import {
702
702
  } from "@stringsync/splates-server/coordinator";
703
703
  import { fail as fail5 } from "@stringsync/splates-server/exit";
704
704
  import { infraConfigure } from "@stringsync/splates-server/infra/configure";
705
+ import { secretsEnvironmentUrl } from "@stringsync/splates-server/infra/secrets";
705
706
  import { Projects } from "@stringsync/splates-server/projects";
706
707
  import { repository as repository7 } from "@stringsync/splates-server/records";
707
708
  import { savedTunnelOf } from "@stringsync/splates-server/server";
@@ -709,7 +710,7 @@ import { FsStorage as FsStorage2 } from "@stringsync/splates-server/storage";
709
710
  import { cli as cli8 } from "webappwiz/cmd";
710
711
  import { z as z9 } from "zod";
711
712
  var splatesInfra = cli8("infra").description("the Pulumi project that makes everything the server's box needs in AWS, Cloudflare and GitHub, which `splates server deploy` then installs splates on");
712
- splatesInfra.command("init").use(repository7({ needs: "own" })).description("write a Pulumi project in <dir>, its program a dozen lines using the components of @stringsync/splates-server/infra, and the stack's config from the flags; run again, it writes only what is not so already and keeps values you changed. It fills the stack's config from what splates keeps (the projects, the saved tunnel, the Cloudflare ids, and each secret from the creds store), requesting on the Creds page any cred not kept and exiting `requested`; run again once saved. When the Pulumi ESC environment `coordinator-access` makes (splates/aws) is there, the stack imports it. It records the directory in ~/.splates/coordinator/infra.json, where `splates server deploy` finds the stack. Then `bun add @stringsync/splates-server @pulumi/pulumi @pulumi/aws @pulumi/awsx @pulumi/cloudflare @pulumi/github @pulumi/tls @pulumi/random` there and `pulumi up`").arg("dir", z9.string(), { description: "where the Pulumi project goes" }).option("stack", z9.string(), { default: "prod", description: "the stack" }).option("host", z9.string(), {
713
+ splatesInfra.command("init").use(repository7({ needs: "own" })).description("write a Pulumi project in <dir>, its program a dozen lines using the components of @stringsync/splates-server/infra, and the stack's config from the flags; run again, it writes only what is not so already and keeps values you changed. It fills the stack's config from what splates keeps (the projects, the saved tunnel, the Cloudflare ids). The secrets never pass through splates: it makes the Pulumi ESC environment splates/secrets with a placeholder for each (the Cloudflare token, a GitHub token per owner, the Anthropic key), which the stack imports and the user replaces on the Pulumi site; `splates setup` has a step for each saying how to get it. When the Pulumi ESC environment `coordinator-access` makes (splates/aws) is there, the stack imports it. It records the directory in ~/.splates/coordinator/infra.json, where `splates server deploy` finds the stack. Its runtime is bun, which runs the program's TypeScript itself. Commit the project but not Pulumi.<stack>.yaml, which holds your own accounts and ids and which the .gitignore it writes keeps out of git; init writes it again from what splates keeps. Then `bun add @stringsync/splates-server @pulumi/pulumi @pulumi/aws @pulumi/awsx @pulumi/cloudflare @pulumi/github @pulumi/tls @pulumi/random` there and `pulumi up`").arg("dir", z9.string(), { description: "where the Pulumi project goes" }).option("stack", z9.string(), { default: "prod", description: "the stack" }).option("host", z9.string(), {
713
714
  default: "",
714
715
  description: "the public host name, as in splates.example.com; the saved tunnel's by default"
715
716
  }).option("email", z9.string(), {
@@ -754,9 +755,13 @@ splatesInfra.command("init").use(repository7({ needs: "own" })).description("wri
754
755
  stack: opts.stack
755
756
  });
756
757
  ctx.log.info(written.length === 0 ? "already so: nothing written" : `wrote ${written.join(", ")}`);
758
+ ctx.log.info(`Pulumi.${opts.stack}.yaml stays out of git: it holds your own accounts and ids, and init writes it again from what splates keeps`);
757
759
  for (const command of todo) {
758
760
  ctx.log.info(`still to run in ${opts.dir}: ${command}`);
759
761
  }
762
+ if (org !== null) {
763
+ ctx.log.info(`paste each secret over its placeholder at ${secretsEnvironmentUrl(org)}: \`splates setup\` has a step for each saying how to get it`);
764
+ }
760
765
  });
761
766
 
762
767
  // server.ts
@@ -869,9 +874,22 @@ splatesServer.command("ssh").description("open a root shell on the box over SSH,
869
874
  const { exitCode } = await ctx.ps.spawn(shell(ctx, standing).login(opts.command));
870
875
  ctx.ps.exit(exitCode);
871
876
  });
872
- splatesServer.command("destroy").description("say how to destroy the box: its Pulumi stack made it, so the stack unmakes it").action(async (_opts, ctx) => {
877
+ splatesServer.command("destroy").description("unmake the box and everything its Pulumi stack made (its role, snapshots, creds, tunnel and deploy keys), lifting the box's termination protection first: anything only on the box is lost. The stack and its config stay, so the setup's Make the box step, or `splates server deploy`, makes it again. Without --yes, says what it would destroy").option("yes", z10.boolean(), {
878
+ default: false,
879
+ description: "destroy without asking"
880
+ }).action(async (opts, ctx) => {
873
881
  const infra = await box(ctx).infra();
874
- fail6("usage", infra === null ? "no infra project here: run `pulumi destroy` in the one `splates server infra init` wrote" : `run \`pulumi destroy\` in ${infra.dir}, after lifting the termination protection (\`disableApiTermination\`) on the instance. Anything only on the box is lost`);
882
+ if (infra === null) {
883
+ fail6("not_found", "no infra project here: nothing to destroy, since `splates server infra init` has not written one");
884
+ }
885
+ const standing = await box(ctx).status();
886
+ const what = standing === null ? `what the stack in ${infra.dir} made` : `the box at ${standing.ipv4} (${standing.instanceId}) and everything the stack in ${infra.dir} made`;
887
+ if (!opts.yes) {
888
+ fail6("usage", `this destroys ${what}, and anything only on the box is lost: run again with --yes`, { dir: infra.dir, box: standing });
889
+ }
890
+ ctx.log.info(`Destroying ${what}, a few minutes…`);
891
+ await box(ctx).destroy();
892
+ ctx.log.info("Destroyed. The stack and its config stay for making it again.");
875
893
  });
876
894
  splatesServer.command("needs").description("kept for `splates server deploy`, which runs it on the box: print the name of each cred this box's store lacks of those the server needs, one per line").rest("roots", z10.string(), {
877
895
  description: "each project's clone on this machine"
@@ -1015,12 +1033,17 @@ function printProgress(log, progress) {
1015
1033
  const notes = [
1016
1034
  step.optional ? "optional" : "",
1017
1035
  step.status === "waiting" ? `after ${step.after.join(", ")}` : "",
1018
- step.problem ?? ""
1036
+ step.problem ?? "",
1037
+ step.warning === null ? "" : "to put right"
1019
1038
  ].filter(Boolean);
1020
1039
  log.info(` ${MARKS[step.status]} ${step.id} ${step.title}${notes.length > 0 ? color2.dim(` ${notes.join("; ")}`) : ""}`);
1021
1040
  }
1022
1041
  }
1023
- const next = progress.areas.flatMap((area) => area.steps).find((step) => step.id === progress.next);
1042
+ const steps = progress.areas.flatMap((area) => area.steps);
1043
+ const next = steps.find((step) => step.id === progress.next);
1044
+ for (const step of steps.filter((each) => each.warning !== null)) {
1045
+ log.info(`${color2.yellow("put right:")} ${step.title} ${color2.dim(`splates setup ${step.id}`)}`);
1046
+ }
1024
1047
  log.info(next === undefined ? color2.green("nothing left to set up") : `next: ${next.title} ${color2.dim(`splates setup ${next.id}`)}`);
1025
1048
  }
1026
1049
  function printStep(log, step) {
@@ -1029,6 +1052,9 @@ function printStep(log, step) {
1029
1052
  if (step.detail !== null) {
1030
1053
  log.info(step.detail);
1031
1054
  }
1055
+ if (step.warning !== null) {
1056
+ log.info(`${color2.yellow("put right:")} ${step.warning}`);
1057
+ }
1032
1058
  log.info(`you: ${step.user}`);
1033
1059
  log.info(`agent: ${step.agent}`);
1034
1060
  if (step.after.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stringsync/splates",
3
- "version": "0.0.52",
3
+ "version": "0.0.54",
4
4
  "description": "Runs several AI coding agents on one repository at once, each in its own git worktree",
5
5
  "license": "MIT",
6
6
  "author": "stringsync LLC",
@@ -17,7 +17,7 @@
17
17
  "access": "public"
18
18
  },
19
19
  "dependencies": {
20
- "@stringsync/splates-server": "^0.0.52",
20
+ "@stringsync/splates-server": "^0.0.54",
21
21
  "webappwiz": "0.0.47",
22
22
  "zod": "^4.4.3"
23
23
  },