getaura 0.1.5 → 0.1.6

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/dist/index.js CHANGED
@@ -990,10 +990,10 @@ function mergeDefs(...defs) {
990
990
  function cloneDef(schema) {
991
991
  return mergeDefs(schema._zod.def);
992
992
  }
993
- function getElementAtPath(obj, path21) {
994
- if (!path21)
993
+ function getElementAtPath(obj, path22) {
994
+ if (!path22)
995
995
  return obj;
996
- return path21.reduce((acc, key) => acc?.[key], obj);
996
+ return path22.reduce((acc, key) => acc?.[key], obj);
997
997
  }
998
998
  function promiseAllObject(promisesObj) {
999
999
  const keys = Object.keys(promisesObj);
@@ -1333,11 +1333,11 @@ function explicitlyAborted(x, startIndex = 0) {
1333
1333
  }
1334
1334
  return false;
1335
1335
  }
1336
- function prefixIssues(path21, issues) {
1336
+ function prefixIssues(path22, issues) {
1337
1337
  return issues.map((iss) => {
1338
1338
  var _a3;
1339
1339
  (_a3 = iss).path ?? (_a3.path = []);
1340
- iss.path.unshift(path21);
1340
+ iss.path.unshift(path22);
1341
1341
  return iss;
1342
1342
  });
1343
1343
  }
@@ -1787,16 +1787,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
1787
1787
  }
1788
1788
  function formatError(error62, mapper = (issue2) => issue2.message) {
1789
1789
  const fieldErrors = { _errors: [] };
1790
- const processError = (error63, path21 = []) => {
1790
+ const processError = (error63, path22 = []) => {
1791
1791
  for (const issue2 of error63.issues) {
1792
1792
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1793
- issue2.errors.map((issues) => processError({ issues }, [...path21, ...issue2.path]));
1793
+ issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
1794
1794
  } else if (issue2.code === "invalid_key") {
1795
- processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
1795
+ processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
1796
1796
  } else if (issue2.code === "invalid_element") {
1797
- processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
1797
+ processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
1798
1798
  } else {
1799
- const fullpath = [...path21, ...issue2.path];
1799
+ const fullpath = [...path22, ...issue2.path];
1800
1800
  if (fullpath.length === 0) {
1801
1801
  fieldErrors._errors.push(mapper(issue2));
1802
1802
  } else {
@@ -1835,17 +1835,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
1835
1835
  }
1836
1836
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
1837
1837
  const result = { errors: [] };
1838
- const processError = (error63, path21 = []) => {
1838
+ const processError = (error63, path22 = []) => {
1839
1839
  var _a3;
1840
1840
  for (const issue2 of error63.issues) {
1841
1841
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1842
- issue2.errors.map((issues) => processError({ issues }, [...path21, ...issue2.path]));
1842
+ issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
1843
1843
  } else if (issue2.code === "invalid_key") {
1844
- processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
1844
+ processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
1845
1845
  } else if (issue2.code === "invalid_element") {
1846
- processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
1846
+ processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
1847
1847
  } else {
1848
- const fullpath = [...path21, ...issue2.path];
1848
+ const fullpath = [...path22, ...issue2.path];
1849
1849
  if (fullpath.length === 0) {
1850
1850
  result.errors.push(mapper(issue2));
1851
1851
  continue;
@@ -1884,8 +1884,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
1884
1884
  }
1885
1885
  function toDotPath(_path) {
1886
1886
  const segs = [];
1887
- const path21 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1888
- for (const seg of path21) {
1887
+ const path22 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1888
+ for (const seg of path22) {
1889
1889
  if (typeof seg === "number")
1890
1890
  segs.push(`[${seg}]`);
1891
1891
  else if (typeof seg === "symbol")
@@ -18987,13 +18987,13 @@ function resolveRef(ref, ctx) {
18987
18987
  if (!ref.startsWith("#")) {
18988
18988
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
18989
18989
  }
18990
- const path21 = ref.slice(1).split("/").filter(Boolean);
18991
- if (path21.length === 0) {
18990
+ const path22 = ref.slice(1).split("/").filter(Boolean);
18991
+ if (path22.length === 0) {
18992
18992
  return ctx.rootSchema;
18993
18993
  }
18994
18994
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
18995
- if (path21[0] === defsKey) {
18996
- const key = path21[1] === void 0 ? void 0 : decodeJSONPointerSegment(path21[1]);
18995
+ if (path22[0] === defsKey) {
18996
+ const key = path22[1] === void 0 ? void 0 : decodeJSONPointerSegment(path22[1]);
18997
18997
  if (!key || !ctx.defs[key]) {
18998
18998
  throw new Error(`Reference not found: ${ref}`);
18999
18999
  }
@@ -20429,7 +20429,7 @@ function pmCommands(pm) {
20429
20429
  // package.json
20430
20430
  var package_default = {
20431
20431
  name: "getaura",
20432
- version: "0.1.5",
20432
+ version: "0.1.6",
20433
20433
  description: "Aura helps you and your coding agent follow best practices while you vibe code.",
20434
20434
  type: "module",
20435
20435
  bin: {
@@ -21545,7 +21545,7 @@ var AuraClient = class _AuraClient {
21545
21545
  get hasKey() {
21546
21546
  return Boolean(this.key);
21547
21547
  }
21548
- async request(method, path21, body, timeoutMs = 6e4) {
21548
+ async request(method, path22, body, timeoutMs = 6e4) {
21549
21549
  if (!this.key) throw new AuraApiError("no_key", "No pilot key");
21550
21550
  let payload;
21551
21551
  if (body !== void 0) {
@@ -21555,7 +21555,7 @@ var AuraClient = class _AuraClient {
21555
21555
  }
21556
21556
  let res;
21557
21557
  try {
21558
- res = await fetch(`${this.baseUrl}/v1/${path21}`, {
21558
+ res = await fetch(`${this.baseUrl}/v1/${path22}`, {
21559
21559
  method,
21560
21560
  headers: { authorization: `Bearer ${this.key}`, "content-type": "application/json", "user-agent": `getaura/${AURA_VERSION}` },
21561
21561
  body: payload,
@@ -21857,8 +21857,8 @@ var typecheck = {
21857
21857
  async run(ctx) {
21858
21858
  if (ctx.options.fast) return { status: "unknown", summary: "Skipped in fast mode." };
21859
21859
  const { existsSync: existsSync17 } = await import("fs");
21860
- const path21 = await import("path");
21861
- const tsc = path21.join(ctx.root, "node_modules", ".bin", process.platform === "win32" ? "tsc.cmd" : "tsc");
21860
+ const path22 = await import("path");
21861
+ const tsc = path22.join(ctx.root, "node_modules", ".bin", process.platform === "win32" ? "tsc.cmd" : "tsc");
21862
21862
  if (!existsSync17(tsc)) return { status: "unknown", summary: "Dependencies not installed, so the type check was skipped." };
21863
21863
  const r = await run(tsc, ["--noEmit", "--pretty", "false"], { cwd: ctx.root, timeoutMs: 18e4 });
21864
21864
  if (r.timedOut) return { status: "unknown", summary: "Type check timed out." };
@@ -24019,7 +24019,7 @@ async function undoPlan(root, plan) {
24019
24019
 
24020
24020
  // src/commands/init.ts
24021
24021
  import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
24022
- import { spawnSync as spawnSync2 } from "child_process";
24022
+ import { spawnSync as spawnSync3 } from "child_process";
24023
24023
 
24024
24024
  // src/brief.ts
24025
24025
  import path18 from "path";
@@ -24110,6 +24110,7 @@ async function draftBrief(client, answers, summary) {
24110
24110
  }
24111
24111
 
24112
24112
  // src/core/aura-command.ts
24113
+ import { spawnSync as spawnSync2 } from "child_process";
24113
24114
  function hasAuraCommand() {
24114
24115
  return commandExists("aura");
24115
24116
  }
@@ -24119,6 +24120,10 @@ async function installAuraCommand() {
24119
24120
  if (r.code !== 0) return { ok: false, needsAdmin: /EACCES|EPERM|permission denied/i.test(r.stderr + r.stdout) };
24120
24121
  return { ok: true, onPath: await hasAuraCommand() };
24121
24122
  }
24123
+ async function installWithSudo() {
24124
+ const r = spawnSync2("sudo", ["npm", "install", "-g", `getaura@${AURA_VERSION}`], { stdio: "inherit" });
24125
+ return r.status === 0 && await hasAuraCommand();
24126
+ }
24122
24127
  function installFallback(result, platform = process.platform) {
24123
24128
  const admin = result.needsAdmin && platform !== "win32" ? `Run \`sudo ${INSTALL_AURA}\` and enter your computer password, or use` : "Use";
24124
24129
  return `${admin} \`npx getaura <command>\` in place of \`aura <command>\` (for example \`npx getaura scan\`).`;
@@ -24213,7 +24218,7 @@ function detectAgents(root) {
24213
24218
  }
24214
24219
  function openEditor(file2) {
24215
24220
  const editor = process.env.VISUAL || process.env.EDITOR || (process.platform === "win32" ? "notepad" : "nano");
24216
- const r = spawnSync2(editor, [file2], { stdio: "inherit", shell: process.platform === "win32" });
24221
+ const r = spawnSync3(editor, [file2], { stdio: "inherit", shell: process.platform === "win32" });
24217
24222
  return r.status === 0;
24218
24223
  }
24219
24224
  var EXAMPLE_ANSWERS = '{"whatItDoes": "\u2026", "audience": "\u2026", "chargesMoney": false, "dataHandled": ["personal"], "userRegions": ["Canada"]}';
@@ -24405,7 +24410,10 @@ async function initCommand(flags) {
24405
24410
  s.stop(installed.onPath ? "Installed. Run `aura scan` from any folder." : "Installed. Open a new terminal window, then run `aura scan`.");
24406
24411
  else {
24407
24412
  s.stop("Couldn\u2019t install the aura command");
24408
- say.warn(installFallback(installed));
24413
+ const useSudo = installed.needsAdmin && process.platform !== "win32" && unwrap(await p.confirm({ message: "Your computer needs your password to install it. Enter your password now?", initialValue: true }));
24414
+ if (!useSudo) say.warn(installFallback(installed));
24415
+ else if (await installWithSudo()) say.ok("Installed. Run `aura scan` from any folder.");
24416
+ else say.warn(installFallback({ needsAdmin: false }));
24409
24417
  }
24410
24418
  } else say.dim(`Use \`npx getaura <command>\` instead, or install it later with \`${INSTALL_AURA}\`.`);
24411
24419
  } else {
@@ -24525,10 +24533,62 @@ ${body}`);
24525
24533
  return 0;
24526
24534
  }
24527
24535
 
24536
+ // src/index.ts
24537
+ import pc4 from "picocolors";
24538
+
24539
+ // src/core/update-check.ts
24540
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync16, writeFileSync as writeFileSync8 } from "fs";
24541
+ import os6 from "os";
24542
+ import path21 from "path";
24543
+ var DAY_MS = 24 * 60 * 60 * 1e3;
24544
+ var cacheFile = () => path21.join(os6.homedir(), ".aura", "update-check.json");
24545
+ function isNewer(a, b) {
24546
+ if (!/^\d+\.\d+\.\d+$/.test(a) || !/^\d+\.\d+\.\d+$/.test(b)) return false;
24547
+ const [x, y] = [a, b].map((v) => v.split(".").map(Number));
24548
+ for (let i = 0; i < 3; i++) if (x[i] !== y[i]) return x[i] > y[i];
24549
+ return false;
24550
+ }
24551
+ async function fetchLatest() {
24552
+ try {
24553
+ const res = await fetch("https://registry.npmjs.org/getaura/latest", { signal: AbortSignal.timeout(1500) });
24554
+ const body = await res.json();
24555
+ return res.ok && typeof body.version === "string" ? body.version : null;
24556
+ } catch {
24557
+ return null;
24558
+ }
24559
+ }
24560
+ async function newerVersion(opts = {}) {
24561
+ const now = opts.now ?? Date.now();
24562
+ let latest = null;
24563
+ try {
24564
+ const cached2 = JSON.parse(readFileSync16(cacheFile(), "utf8"));
24565
+ if (now - cached2.checkedAt < DAY_MS) latest = cached2.latest;
24566
+ else throw new Error("stale");
24567
+ } catch {
24568
+ latest = await (opts.fetchLatest ?? fetchLatest)();
24569
+ try {
24570
+ mkdirSync6(path21.dirname(cacheFile()), { recursive: true });
24571
+ writeFileSync8(cacheFile(), JSON.stringify({ checkedAt: now, latest }));
24572
+ } catch {
24573
+ }
24574
+ }
24575
+ return latest && isNewer(latest, opts.current ?? AURA_VERSION) ? latest : null;
24576
+ }
24577
+ function startUpdateCheck() {
24578
+ if (!process.stdout.isTTY || process.env.CI || process.env.AURA_NO_UPDATE_CHECK) return Promise.resolve(null);
24579
+ return newerVersion().catch(() => null);
24580
+ }
24581
+ function updateNotice(latest, argv1 = process.argv[1] ?? "") {
24582
+ const viaNpx = /[\\/]_npx[\\/]/.test(argv1);
24583
+ const how = viaNpx ? "use `npx getaura@latest`" : "update with `npm install -g getaura@latest`";
24584
+ return `Aura ${latest} is available (you have ${AURA_VERSION}): ${how}.`;
24585
+ }
24586
+
24528
24587
  // src/index.ts
24529
24588
  var program = new Command();
24530
24589
  program.name("aura").description("Aura helps you and your coding agent follow best practices while you vibe code.").version(AURA_VERSION).showHelpAfterError();
24531
24590
  program.addHelpText("before", () => interactive() ? banner() : "");
24591
+ var update = startUpdateCheck();
24532
24592
  function action(fn) {
24533
24593
  return async (...args) => {
24534
24594
  try {
@@ -24542,6 +24602,9 @@ function action(fn) {
24542
24602
  if (process.env.AURA_DEBUG) console.error(err);
24543
24603
  process.exitCode = 1;
24544
24604
  }
24605
+ const latest = await update;
24606
+ if (latest) console.error(pc4.dim(`
24607
+ ${updateNotice(latest)}`));
24545
24608
  };
24546
24609
  }
24547
24610
  program.command("init").description("Set up Aura: pick your agent, write the product brief, install the Aura skill and run the first scan").option("--agent <id...>", "coding agent(s): claude, codex, cursor, pi").option("-y, --yes", "no prompts; use detected defaults").option("--key <key>", "Aura pilot key, for CI and scripts (otherwise a browser page asks for it)").option("--wait <seconds>", "how long to wait for the browser sign-in (default: until the link expires; 90 for agents)").option("--brief-file <path>", "use this file as the product brief").option("--answers <path>", "JSON file with the setup answers").option("--no-scan", "skip the first scan").addOption(new Option("--telemetry", "share scores and action names with the Aura team")).addOption(new Option("--no-telemetry", "don\u2019t share anything")).action(action((flags) => initCommand(flags)));