@whisperr/wizard 0.1.12 → 0.1.14

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/dist/index.js +110 -4
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/index.ts
4
+ import { readFileSync, realpathSync } from "fs";
5
+ import { dirname, join as join3 } from "path";
6
+ import { fileURLToPath } from "url";
7
+
3
8
  // src/cli.ts
4
9
  import { resolve } from "path";
5
10
  import * as p from "@clack/prompts";
@@ -73,7 +78,7 @@ var systemPrompt = `
73
78
  This SDK is published on pub.dev. Integrate it as follows.
74
79
 
75
80
  1) Dependency. Add to pubspec.yaml under dependencies:
76
- whisperr: ^0.2.0
81
+ whisperr: ^0.2.2
77
82
  Then the SDK expects \`flutter pub get\` to be run (run it via bash).
78
83
 
79
84
  2) Initialize once, early, before runApp(), in lib/main.dart:
@@ -1539,6 +1544,51 @@ async function pollFirstEvent(config, session, opts = {}) {
1539
1544
  return { received: false };
1540
1545
  }
1541
1546
 
1547
+ // src/core/postflight.ts
1548
+ import { spawn as spawn2 } from "child_process";
1549
+ var MAX_OUTPUT = 4e3;
1550
+ var DEFAULT_TIMEOUT_MS = 18e4;
1551
+ function runVerifyCommand(repoPath, command, opts = {}) {
1552
+ if (!command || !command.trim()) {
1553
+ return Promise.resolve({ ran: false, ok: true, output: "" });
1554
+ }
1555
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1556
+ return new Promise((resolve2) => {
1557
+ const child = spawn2(command, { cwd: repoPath, shell: true, env: process.env });
1558
+ let out = "";
1559
+ const append = (d) => {
1560
+ out += d.toString();
1561
+ if (out.length > MAX_OUTPUT * 4) out = out.slice(-MAX_OUTPUT * 2);
1562
+ };
1563
+ child.stdout?.on("data", append);
1564
+ child.stderr?.on("data", append);
1565
+ const timer = setTimeout(() => {
1566
+ child.kill("SIGKILL");
1567
+ resolve2({ ran: true, ok: false, command, output: tail(out), timedOut: true });
1568
+ }, timeoutMs);
1569
+ child.on("close", (code) => {
1570
+ clearTimeout(timer);
1571
+ resolve2({
1572
+ ran: true,
1573
+ ok: code === 0,
1574
+ command,
1575
+ exitCode: code,
1576
+ output: tail(out),
1577
+ // 127 = "command not found": the verify tool isn't on PATH here.
1578
+ toolMissing: code === 127
1579
+ });
1580
+ });
1581
+ child.on("error", () => {
1582
+ clearTimeout(timer);
1583
+ resolve2({ ran: true, ok: false, command, output: tail(out), toolMissing: true });
1584
+ });
1585
+ });
1586
+ }
1587
+ function tail(s) {
1588
+ const t = s.trim();
1589
+ return t.length > MAX_OUTPUT ? `\u2026${t.slice(-MAX_OUTPUT)}` : t;
1590
+ }
1591
+
1542
1592
  // src/core/report.ts
1543
1593
  async function postRunReport(config, session, report) {
1544
1594
  if (config.offline) return;
@@ -1705,6 +1755,40 @@ Flutter is live today; ${theme.bright(
1705
1755
  return 1;
1706
1756
  }
1707
1757
  }
1758
+ let verified = null;
1759
+ if (chosen.playbook.verifyCommand && files.length) {
1760
+ const cmd = chosen.playbook.verifyCommand;
1761
+ const vspin = p.spinner();
1762
+ vspin.start(`Verifying the integration \u2014 ${theme.muted(cmd)}`);
1763
+ const verdict = await runVerifyCommand(repoPath, cmd);
1764
+ if (verdict.toolMissing) {
1765
+ vspin.stop(
1766
+ theme.warn("Couldn't verify automatically") + theme.muted(` \u2014 \`${cmd}\` isn't available here. Run it yourself before committing.`)
1767
+ );
1768
+ } else if (verdict.timedOut) {
1769
+ vspin.stop(
1770
+ theme.warn(`Verification timed out \u2014 \`${cmd}\``) + theme.muted(" \u2014 run it yourself before committing.")
1771
+ );
1772
+ } else if (verdict.ok) {
1773
+ verified = true;
1774
+ vspin.stop(theme.success("Verified \u2713") + theme.muted(` (${cmd})`));
1775
+ } else {
1776
+ verified = false;
1777
+ vspin.stop(theme.alert(`Verification failed \u2014 ${cmd}`));
1778
+ if (verdict.output) {
1779
+ p.note(verdict.output, theme.warn("Verifier output"));
1780
+ }
1781
+ const reverted = await maybeRevert(
1782
+ repoPath,
1783
+ checkpoint,
1784
+ "The integration didn't pass its build/lint check, so the edits may be broken."
1785
+ );
1786
+ if (reverted) {
1787
+ p.outro(theme.muted("Reverted \u2014 nothing was left in your working tree."));
1788
+ return 1;
1789
+ }
1790
+ }
1791
+ }
1708
1792
  const wiredMap = await scanWiredEvents(
1709
1793
  repoPath,
1710
1794
  files,
@@ -1719,6 +1803,7 @@ Flutter is live today; ${theme.bright(
1719
1803
  target: chosen.playbook.target.id,
1720
1804
  repo_fingerprint: fingerprint,
1721
1805
  identify_wired: outcome.coreOk,
1806
+ verified,
1722
1807
  cost_usd: outcome.costUsd,
1723
1808
  duration_ms: outcome.durationMs,
1724
1809
  summary: outcome.summary.slice(0, 4e3),
@@ -1726,7 +1811,7 @@ Flutter is live today; ${theme.bright(
1726
1811
  });
1727
1812
  p.log.info(
1728
1813
  theme.muted(
1729
- `${wiredMap.size}/${manifest.events.length} events wired \xB7 ${files.length} file${files.length === 1 ? "" : "s"} changed \xB7 ${Math.round(outcome.durationMs / 1e3)}s`
1814
+ `${wiredMap.size}/${manifest.events.length} events wired \xB7 ${files.length} file${files.length === 1 ? "" : "s"} changed \xB7 ` + (verified === true ? "verified \xB7 " : verified === false ? "unverified \xB7 " : "") + `${Math.round(outcome.durationMs / 1e3)}s`
1730
1815
  )
1731
1816
  );
1732
1817
  if (!config.offline) {
@@ -1859,6 +1944,12 @@ function summarizeManifest(m) {
1859
1944
  }
1860
1945
 
1861
1946
  // src/index.ts
1947
+ var modulePath = fileURLToPath(import.meta.url);
1948
+ function packageVersion() {
1949
+ const packagePath = join3(dirname(modulePath), "..", "package.json");
1950
+ const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
1951
+ return pkg.version ?? "0.0.0";
1952
+ }
1862
1953
  function parseArgs(argv) {
1863
1954
  const args = [...argv];
1864
1955
  const opts = {};
@@ -1922,7 +2013,7 @@ async function main() {
1922
2013
  return;
1923
2014
  }
1924
2015
  if ("version" in parsed) {
1925
- console.log("0.1.12");
2016
+ console.log(packageVersion());
1926
2017
  return;
1927
2018
  }
1928
2019
  try {
@@ -1933,4 +2024,19 @@ async function main() {
1933
2024
  process.exit(1);
1934
2025
  }
1935
2026
  }
1936
- void main();
2027
+ function isCliEntry() {
2028
+ if (!process.argv[1]) return false;
2029
+ try {
2030
+ return realpathSync(modulePath) === realpathSync(process.argv[1]);
2031
+ } catch {
2032
+ return modulePath === process.argv[1];
2033
+ }
2034
+ }
2035
+ if (isCliEntry()) {
2036
+ void main();
2037
+ }
2038
+ export {
2039
+ main,
2040
+ packageVersion,
2041
+ parseArgs
2042
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whisperr/wizard",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Whisperr Wizard — one command to integrate the Whisperr SDK into your app. Authenticates with your onboarded account and uses an AI coding agent to wire up identify() and your business events automatically.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -22,6 +22,7 @@
22
22
  "dev": "tsup --watch",
23
23
  "start": "node dist/index.js",
24
24
  "typecheck": "tsc --noEmit",
25
+ "test": "node --import tsx --test test/*.test.ts",
25
26
  "prepublishOnly": "npm run build",
26
27
  "dev:local": "tsx src/index.ts"
27
28
  },