@revturbine/cli 0.9.1 → 0.10.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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.js +55 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -63,6 +63,7 @@ Commands that read a config name the version explicitly — there is no default:
63
63
 
64
64
  | Command | What it does |
65
65
  |---|---|
66
+ | `init` (alias `create`) | Scaffold RevTurbine into this app: detect the package manager and stack, install the SDK, pin the CLI exactly, drop a starter Playbook, and install the Agent Skills. In a directory with no `package.json` it offers to start a new project (`--yes` to skip the prompt); `--dir`, `--dry-run`, `--no-skills`, `--json`. Runs the invoked CLI even inside a repo that pins a different one — setup establishes the pin, so it never delegates. |
66
67
  | `signup` | Create an account headlessly: email + password, then an emailed one-time code to verify, then a token is stored. |
67
68
  | `login` / `logout` | Device-flow auth; tokens stored at `~/.revturbine/credentials.json` (mode 0600). |
68
69
  | `whoami` | The resolved instance, tenant, credentials source, and whether the stored token works. |
package/dist/cli.js CHANGED
@@ -6566,10 +6566,21 @@ async function resolveActiveDraft(baseUrl, headers, fetchImpl = fetch) {
6566
6566
  // src/lib/delegate.ts
6567
6567
  var DELEGATION_ENV = "REVTURBINE_DELEGATED";
6568
6568
  var NO_LOCAL_FLAG = "--no-local";
6569
+ var SETUP_COMMANDS = ["init", "create"];
6570
+ function commandFromArgv(argv) {
6571
+ for (const arg of argv.slice(2)) {
6572
+ if (!arg.startsWith("-")) return arg;
6573
+ }
6574
+ return null;
6575
+ }
6569
6576
  function planDelegation(params) {
6570
6577
  if (params.env[DELEGATION_ENV]) {
6571
6578
  return { delegate: false, reason: "already delegated" };
6572
6579
  }
6580
+ const command = commandFromArgv(params.argv);
6581
+ if (command && SETUP_COMMANDS.includes(command)) {
6582
+ return { delegate: false, reason: `${command} establishes the repo pin \u2014 never delegated` };
6583
+ }
6573
6584
  if (params.argv.includes(NO_LOCAL_FLAG)) {
6574
6585
  return { delegate: false, reason: `${NO_LOCAL_FLAG} requested` };
6575
6586
  }
@@ -6639,6 +6650,13 @@ function detectStack(signals) {
6639
6650
  }
6640
6651
  var SDK_PACKAGE = "@revturbine/sdk";
6641
6652
  var CLI_PACKAGE = "@revturbine/cli";
6653
+ function projectNameFromDir(dirName) {
6654
+ const slug = dirName.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[-_.]+|[-_.]+$/g, "");
6655
+ return slug || "my-app";
6656
+ }
6657
+ function newProjectManifest(dirName) {
6658
+ return { name: projectNameFromDir(dirName), version: "0.1.0", private: true, type: "module" };
6659
+ }
6642
6660
  function planInstall(params) {
6643
6661
  const deps = params.dependencies ?? {};
6644
6662
  const devDeps = params.devDependencies ?? {};
@@ -7060,6 +7078,22 @@ async function confirmOrExit(promptText, yes) {
7060
7078
  process.exit(0);
7061
7079
  }
7062
7080
  }
7081
+ async function confirmNewProject(dir, yes) {
7082
+ if (yes) return;
7083
+ if (!process.stdin.isTTY) {
7084
+ fail(
7085
+ EXIT.USAGE,
7086
+ `No package.json in ${dir}. Re-run with --yes to start a new project here, or --dir <path> to target an existing one.`
7087
+ );
7088
+ }
7089
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
7090
+ const answer = (await rl.question(`No package.json in ${dir}. Start a new project here? [Y/n] `)).trim().toLowerCase();
7091
+ rl.close();
7092
+ if (answer === "n" || answer === "no") {
7093
+ diag("Aborted \u2014 no project created.");
7094
+ process.exit(0);
7095
+ }
7096
+ }
7063
7097
  function table(rows) {
7064
7098
  if (rows.length === 0) return " (none)";
7065
7099
  const widths = rows[0].map((_, col) => Math.max(...rows.map((r) => (r[col] ?? "").length)));
@@ -7185,20 +7219,30 @@ function runInstall(manager, args, cwd) {
7185
7219
  child.on("close", (code) => resolve(code ?? 1));
7186
7220
  });
7187
7221
  }
7188
- program.command("init").alias("create").description("Scaffold RevTurbine into this app: detect the stack, install the SDK, pin the CLI, drop a starter Playbook, and install the Agent Skills.").option("-d, --dir <path>", "Target directory (defaults to the current directory)").option("--dry-run", "Report what would be installed without running the package manager").option("--no-skills", "Do not install the RevTurbine Agent Skills").option("--json", "Emit the scaffold plan as JSON").action(async (opts) => {
7222
+ program.command("init").alias("create").description("Scaffold RevTurbine into this app: detect the stack, install the SDK, pin the CLI, drop a starter Playbook, and install the Agent Skills. Offers to start a new project when the directory has no package.json.").option("-d, --dir <path>", "Target directory (defaults to the current directory)").option("-y, --yes", "Skip prompts \u2014 create a new project non-interactively when the directory has none").option("--dry-run", "Report what would be installed without running the package manager").option("--no-skills", "Do not install the RevTurbine Agent Skills").option("--json", "Emit the scaffold plan as JSON").action(async (opts) => {
7189
7223
  const dir = path2.resolve(opts.dir ?? process.cwd());
7190
7224
  const manifestPath = path2.join(dir, "package.json");
7191
- if (!existsSync2(manifestPath)) {
7192
- fail(EXIT.USAGE, `No package.json in ${dir} \u2014 run init inside a JavaScript project (or pass --dir).`);
7193
- }
7194
7225
  let manifest;
7195
- try {
7196
- manifest = JSON.parse(readFileSync2(manifestPath, "utf8"));
7197
- } catch (err) {
7198
- fail(EXIT.VALIDATION, `invalid JSON in ${manifestPath}: ${err.message}`);
7226
+ let createdProject = false;
7227
+ if (existsSync2(manifestPath)) {
7228
+ try {
7229
+ manifest = JSON.parse(readFileSync2(manifestPath, "utf8"));
7230
+ } catch (err) {
7231
+ fail(EXIT.VALIDATION, `invalid JSON in ${manifestPath}: ${err.message}`);
7232
+ }
7233
+ } else {
7234
+ manifest = newProjectManifest(path2.basename(dir));
7235
+ createdProject = true;
7236
+ if (!opts.dryRun) {
7237
+ await confirmNewProject(dir, opts.yes === true);
7238
+ mkdirSync2(dir, { recursive: true });
7239
+ writeFileSync2(manifestPath, `${JSON.stringify(manifest, null, 2)}
7240
+ `, "utf8");
7241
+ diag(`\u2713 Created a new project (package.json \u2014 ${manifest.name})`);
7242
+ }
7199
7243
  }
7200
7244
  const manager = detectPackageManager({
7201
- files: readdirSync(dir),
7245
+ files: existsSync2(dir) ? readdirSync(dir) : [],
7202
7246
  packageManagerField: manifest.packageManager,
7203
7247
  userAgent: process.env["npm_config_user_agent"]
7204
7248
  });
@@ -7219,6 +7263,7 @@ program.command("init").alias("create").description("Scaffold RevTurbine into th
7219
7263
  emit(
7220
7264
  {
7221
7265
  dir,
7266
+ project: createdProject ? "created" : "existing",
7222
7267
  manager: manager.name,
7223
7268
  stack,
7224
7269
  install: plan.install,
@@ -7230,6 +7275,7 @@ program.command("init").alias("create").description("Scaffold RevTurbine into th
7230
7275
  );
7231
7276
  }
7232
7277
  if (opts.dryRun) {
7278
+ if (createdProject) diag(`would create: package.json (new project \u2014 ${manifest.name})`);
7233
7279
  for (const step of plan.install) {
7234
7280
  diag(`would run: ${manager.name} ${installArgs(manager.name, step).join(" ")}`);
7235
7281
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revturbine/cli",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "revturbine — verify RevTurbine ExportedConfig files and ship them to a RevTurbine instance through the Change Set lifecycle.",
5
5
  "license": "MIT",
6
6
  "repository": {