@pimmesz/afterburner 1.0.13 → 1.0.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.
package/README.md CHANGED
@@ -256,6 +256,7 @@ writes `.mjs` by default. There's a commented example in
256
256
  | `agent.modelByCategory` | sonnet/opus/haiku mix | Per-category model routing. Plain strings, so a new model never breaks the config. |
257
257
  | `agent.maxTaskTokens` | `200_000` | Hard per-task ceiling in Sonnet-equivalent tokens |
258
258
  | `agent.allowFable` | `false` | Explicit opt-in for Fable-family models |
259
+ | `notify.desktop` | `false` | Desktop banner per completed run (macOS/Linux/Windows), opt-in; the PR stays the primary signal |
259
260
  | `taskCategories` | all enabled, weighted | Per-category enable/disable plus a ranking weight |
260
261
 
261
262
  Task categories are `security`, `tests`, `types-lint`, `dead-code`, `perf`, `infra`, and
@@ -72,7 +72,8 @@ const config = {
72
72
  backend: 'dry-run',
73
73
  // Per-category model routing. Plain strings on purpose, so a new model
74
74
  // can't break the config. Omitted categories use the built-in defaults
75
- // (sonnet for most, opus for perf and infra, haiku for the simple end).
75
+ // (sonnet for security and tests, opus for perf and infra, haiku for the
76
+ // simple end: types-lint, dead-code, docs).
76
77
  modelByCategory: {
77
78
  perf: 'claude-opus-4-8',
78
79
  docs: 'claude-haiku-4-5',
@@ -495,7 +495,7 @@ function createBudgetProvider(config, opts = {}) {
495
495
 
496
496
  // src/core/scheduler/gate.ts
497
497
  function shouldIgnite(budget, estCostSonnetTokens, config) {
498
- if (!Number.isFinite(budget.weeklyRemainingPct) || !Number.isFinite(budget.weeklyRemainingTokensEst) || !Number.isFinite(estCostSonnetTokens) || !Number.isFinite(config.safetyMarginTokens)) {
498
+ if (!Number.isFinite(budget.weeklyRemainingPct) || !Number.isFinite(budget.weeklyRemainingTokensEst) || !Number.isFinite(estCostSonnetTokens) || !Number.isFinite(config.safetyMarginTokens) || !Number.isFinite(config.minWeeklyHeadroomPct)) {
499
499
  return { go: false, reason: "budget or estimate is not a finite number; refusing to ignite" };
500
500
  }
501
501
  if (config.requireSessionAvailable && !budget.sessionAvailable) {
@@ -514,7 +514,10 @@ function shouldIgnite(budget, estCostSonnetTokens, config) {
514
514
  reason: `weekly cap: task needs ~${needed.toLocaleString("en-US")} Sonnet-eq tokens (incl. ${config.safetyMarginTokens.toLocaleString("en-US")} safety margin) but only ~${budget.weeklyRemainingTokensEst.toLocaleString("en-US")} remain`
515
515
  };
516
516
  }
517
- return { go: true, reason: "session available and estimated cost fits within weekly headroom" };
517
+ return {
518
+ go: true,
519
+ reason: `${budget.sessionAvailable ? "session available" : "session check waived"} and estimated cost fits within weekly headroom`
520
+ };
518
521
  }
519
522
 
520
523
  // src/core/scheduler/native.ts
package/dist/cli/index.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  shouldIgnite,
26
26
  startWatch,
27
27
  writeUsageCache
28
- } from "../chunk-4TD2KS3A.js";
28
+ } from "../chunk-HAERJCAI.js";
29
29
  import {
30
30
  MCP_STUB_MESSAGE
31
31
  } from "../chunk-2NSOEZWY.js";
@@ -36,7 +36,7 @@ import { Command } from "commander";
36
36
  // package.json
37
37
  var package_default = {
38
38
  name: "@pimmesz/afterburner",
39
- version: "1.0.13",
39
+ version: "1.0.14",
40
40
  description: "Convert idle Claude subscription quota into shippable engineering work: budget-aware trigger, bounded task selection, PR-only output.",
41
41
  license: "Apache-2.0",
42
42
  publishConfig: {
@@ -485,7 +485,7 @@ ${nextCmd(cmd("doctor"))}`;
485
485
  const repoLine = repoNames.length <= 2 ? repoNames.join(", ") : `${repoNames.slice(0, 2).join(", ")} (and ${repoNames.length - 2} more)`;
486
486
  const engineLine = config.agent.backend === "dry-run" ? "dry-run \u2014 simulation only; set agent.backend: 'claude-code' in the config to do real work" : config.agent.backend === "claude-code" ? "claude-code \u2014 spends subscription quota you already pay for; PRs only with --live" : "api-key \u2014 bills your Anthropic API account per token (real money); PRs only with --live";
487
487
  const budgetLine = config.budget.provider === "manual" ? "manual \u2014 trusts budget.manual (automatic option: `afterburner statusline install`, then budget.provider: 'claude-usage')" : config.budget.provider === "claude-usage" ? "claude-usage \u2014 reads your real usage via the status line hook" : "claude-code-transcripts \u2014 estimates from local Claude Code session logs";
488
- const nextNote = config.agent.backend === "dry-run" ? "previews the next task; nothing is executed or spent" : `previews the next task (live execution ships in a future release; ${cmd("run-once --live")} currently validates and refuses)`;
488
+ const nextNote = config.agent.backend === "dry-run" ? "previews the next task; nothing is executed or spent" : `previews the next task (live execution ships in a future release; ${cmd("run-once --live")} currently arms LIVE then exits with a not-implemented error \u2014 no PR is opened)`;
489
489
  const stopLine = `\`afterburner schedule uninstall\` (or Ctrl-C for watch); ${cmd("log")} lists every past run`;
490
490
  if (opts.summary) {
491
491
  return `${section(emoji.flame, "Ready")}
@@ -1122,7 +1122,7 @@ async function collectAnswers(rl, opts, cwd = process.cwd()) {
1122
1122
  let targetDir = cwd;
1123
1123
  let target = join2(targetDir, "afterburner.config.mjs");
1124
1124
  console.log(
1125
- "Afterburner turns unused Claude subscription quota into small, reviewed pull requests.\nDry-run first: nothing executes or spends until a live engine is set in the config\nAND you pass --live. Three questions, then an optional health check.\n"
1125
+ "Afterburner turns unused Claude subscription quota into small, reviewed pull requests.\nDry-run first: nothing executes or spends until a live engine is set in the config\nAND you pass --live. (No run can open a PR yet \u2014 live execution ships in a future\nrelease.) Three questions, then an optional health check.\n"
1126
1126
  );
1127
1127
  console.log(bold("Step 1 of 3 \u2014 Engine (who does the work, and what it can spend)"));
1128
1128
  OFFERED_BACKENDS.forEach((name, i) => {
@@ -1354,7 +1354,7 @@ function registerMcp(program2) {
1354
1354
  // src/cli/commands/run-once.ts
1355
1355
  function registerRunOnce(program2) {
1356
1356
  program2.command("run-once").description(
1357
- "Run one ignition cycle: pick at most one bounded task per configured repo (dry-run by default)"
1357
+ "Run one ignition cycle: pick at most one bounded task per run (dry-run by default)"
1358
1358
  ).option("--config <path>", "path to a config file").option("--dry-run", "force a dry run (this is the default behavior)").option(
1359
1359
  "--live",
1360
1360
  "arm live execution; only takes effect when agent.backend is also a live engine in the config (two-part opt-in)"
@@ -1442,7 +1442,7 @@ ${section(emoji.rocket, "Next")}`);
1442
1442
  console.log(
1443
1443
  config.agent.backend === "dry-run" ? ` This was a preview. Live execution ships in a future release; once it does,
1444
1444
  set agent.backend: 'claude-code' in ${filepath}, then: ${liveCmd}` : ` This was a preview. Live execution ships in a future release;
1445
- ${liveCmd} currently validates the setup and refuses.`
1445
+ ${liveCmd} currently arms LIVE then exits with a not-implemented error (no PR is opened).`
1446
1446
  );
1447
1447
  }
1448
1448
  });
@@ -1910,7 +1910,7 @@ function renderWelcome(configPath) {
1910
1910
  cmd("afterburner run-once --dry-run", "preview the next task (no changes made)"),
1911
1911
  cmd(
1912
1912
  "afterburner run-once --live",
1913
- "real PRs (stubbed in this version; validates and refuses)"
1913
+ "real PRs (stubbed in this version; arms LIVE then errors out, no PR opened)"
1914
1914
  ),
1915
1915
  cmd("afterburner log", "recent run history")
1916
1916
  );
@@ -673,10 +673,12 @@ declare class JsonlRunStore implements RunStore {
673
673
  }
674
674
 
675
675
  /**
676
- * Notification seam. Core ships ONLY ConsoleNotifier: the pull request is the
677
- * real notification and the run store is the audit trail. This interface is
678
- * the documented extension point for a future opt-in generic webhook, vendor
679
- * SDKs are never bundled into core.
676
+ * Notification seam. ConsoleNotifier always runs its line is the audit trail
677
+ * that reaches the scheduler's stdout log and an opt-in DesktopNotifier
678
+ * (OS-native banner, gated by notify.desktop) layers on top via
679
+ * CompositeNotifier/createNotifier. The pull request stays the real
680
+ * notification and the run store the source of truth. Notifiers shell out to
681
+ * platform tools; vendor SDKs are never bundled into core.
680
682
  */
681
683
  interface Notifier {
682
684
  notify(record: RunRecord): Promise<void>;
@@ -748,11 +750,12 @@ interface GateDecision {
748
750
  reason: string;
749
751
  }
750
752
  /**
751
- * Both-caps gate, a non-negotiable rule encoded as a pure function: only fire
752
- * when a session window is available AND the estimated cost plus the safety
753
- * margin fits inside the remaining weekly budget (with the configured
754
- * headroom). Reasons are returned, not just booleans, so every skipped run is
755
- * explainable in the log.
753
+ * Both-caps gate encoded as a pure function: only fire when the estimated cost
754
+ * plus the safety margin fits inside the remaining weekly budget (with the
755
+ * configured headroom) the non-negotiable weekly cap AND, when
756
+ * config.requireSessionAvailable is set (the default), a 5-hour session window
757
+ * is also free. Reasons are returned, not just booleans, so every skipped run
758
+ * is explainable in the log.
756
759
  */
757
760
  declare function shouldIgnite(budget: Budget, estCostSonnetTokens: number, config: GateConfig): GateDecision;
758
761
 
@@ -49,7 +49,7 @@ import {
49
49
  summarizeTranscriptUsage,
50
50
  taskFingerprint,
51
51
  writeUsageCache
52
- } from "../chunk-4TD2KS3A.js";
52
+ } from "../chunk-HAERJCAI.js";
53
53
  export {
54
54
  ApiKeyRunner,
55
55
  BASE_TASK_TOKENS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pimmesz/afterburner",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Convert idle Claude subscription quota into shippable engineering work: budget-aware trigger, bounded task selection, PR-only output.",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {