burnwatch 0.4.1 → 0.4.2

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/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to burnwatch will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.2] - 2026-03-24
9
+
10
+ ### Fixed
11
+
12
+ - **Init is re-runnable**: `burnwatch init` no longer early-returns on already-initialized projects. Re-running init re-detects services and walks through interactive setup again, so users who initialized before v0.4.0 can configure budgets without manually running `burnwatch add` 14 times.
13
+ - **Budget prompt fires for all services**: Budget prompt was gated inside the `requiresKey` block - services without API key requirements never got asked. Now every non-excluded service gets a budget prompt during interactive init.
14
+ - **Untracked message is actionable**: Changed circular "run burnwatch status" message to "run burnwatch init to configure" so users know what to do next.
15
+
8
16
  ## [0.4.0] - 2026-03-24
9
17
 
10
18
  ### Added
@@ -43,5 +51,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
43
51
  - Snapshot system for delta computation across sessions
44
52
  - Claude Code skills: `/spend` (on-demand brief), `/setup-burnwatch` (guided onboarding)
45
53
 
54
+ [0.4.2]: https://github.com/RaleighSF/burnwatch/compare/v0.4.0...v0.4.2
46
55
  [0.4.0]: https://github.com/RaleighSF/burnwatch/compare/v0.1.0...v0.4.0
47
56
  [0.1.0]: https://github.com/RaleighSF/burnwatch/releases/tag/v0.1.0
package/dist/cli.js CHANGED
@@ -661,7 +661,7 @@ function buildBrief(projectName, snapshots, blindCount) {
661
661
  alerts.push({
662
662
  serviceId: "_blind",
663
663
  type: "blind_service",
664
- message: `${blindCount} service${blindCount > 1 ? "s" : ""} detected but untracked \u2014 run 'burnwatch status' to see`,
664
+ message: `${blindCount} service${blindCount > 1 ? "s" : ""} detected but untracked - run 'burnwatch init' to configure`,
665
665
  severity: "warning"
666
666
  });
667
667
  }
@@ -1007,11 +1007,7 @@ async function main() {
1007
1007
  async function cmdInit() {
1008
1008
  const projectRoot = process.cwd();
1009
1009
  const nonInteractive = flags.has("--non-interactive") || flags.has("--ni");
1010
- if (isInitialized(projectRoot)) {
1011
- console.log("\u2705 burnwatch is already initialized in this project.");
1012
- console.log(` Config: ${projectConfigDir(projectRoot)}/config.json`);
1013
- return;
1014
- }
1010
+ const alreadyInitialized = isInitialized(projectRoot);
1015
1011
  let projectName = path5.basename(projectRoot);
1016
1012
  try {
1017
1013
  const pkgPath = path5.join(projectRoot, "package.json");
@@ -1022,10 +1018,11 @@ async function cmdInit() {
1022
1018
  ensureProjectDirs(projectRoot);
1023
1019
  console.log("\u{1F50D} Scanning project for paid services...\n");
1024
1020
  const detected = detectServices(projectRoot);
1021
+ const existingConfig = alreadyInitialized ? readProjectConfig(projectRoot) : null;
1025
1022
  const config = {
1026
- projectName,
1027
- services: {},
1028
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1023
+ projectName: existingConfig?.projectName ?? projectName,
1024
+ services: existingConfig?.services ?? {},
1025
+ createdAt: existingConfig?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1029
1026
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1030
1027
  };
1031
1028
  if (!nonInteractive && detected.length > 0 && process.stdin.isTTY) {
@@ -1033,13 +1030,15 @@ async function cmdInit() {
1033
1030
  config.services = result.services;
1034
1031
  } else {
1035
1032
  for (const det of detected) {
1036
- const tracked2 = {
1037
- serviceId: det.service.id,
1038
- detectedVia: det.sources,
1039
- hasApiKey: false,
1040
- firstDetected: (/* @__PURE__ */ new Date()).toISOString()
1041
- };
1042
- config.services[det.service.id] = tracked2;
1033
+ if (!config.services[det.service.id]) {
1034
+ const tracked2 = {
1035
+ serviceId: det.service.id,
1036
+ detectedVia: det.sources,
1037
+ hasApiKey: false,
1038
+ firstDetected: (/* @__PURE__ */ new Date()).toISOString()
1039
+ };
1040
+ config.services[det.service.id] = tracked2;
1041
+ }
1043
1042
  }
1044
1043
  if (detected.length === 0) {
1045
1044
  console.log(" No paid services detected yet.");
@@ -1196,11 +1195,11 @@ async function cmdStatus() {
1196
1195
  if (blindCount > 0) {
1197
1196
  console.log(`\u26A0\uFE0F ${blindCount} service${blindCount > 1 ? "s" : ""} untracked:`);
1198
1197
  for (const snap of snapshots.filter((s) => s.tier === "blind")) {
1199
- console.log(
1200
- ` \u2022 ${snap.serviceId} \u2014 run 'burnwatch add ${snap.serviceId} --key YOUR_KEY --budget N'`
1201
- );
1198
+ console.log(` \u2022 ${snap.serviceId}`);
1202
1199
  }
1203
- console.log("");
1200
+ console.log(`
1201
+ Run 'burnwatch init' to configure budgets and API keys.
1202
+ `);
1204
1203
  }
1205
1204
  }
1206
1205
  function cmdServices() {