balladeer 1.0.17 → 1.0.19

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 (47) hide show
  1. package/dist/anchor-budget.d.ts +40 -0
  2. package/dist/anchor-budget.js +110 -0
  3. package/dist/anchoring.d.ts +241 -0
  4. package/dist/anchoring.js +766 -0
  5. package/dist/anchors-client.d.ts +62 -0
  6. package/dist/anchors-client.js +197 -0
  7. package/dist/anchors-schema.d.ts +85 -0
  8. package/dist/anchors-schema.js +246 -0
  9. package/dist/checkout-form.d.ts +11 -0
  10. package/dist/checkout-form.js +14 -0
  11. package/dist/cli.js +9 -4
  12. package/dist/commands/anchor-usage.d.ts +6 -0
  13. package/dist/commands/anchor-usage.js +19 -0
  14. package/dist/commands/anchor.d.ts +127 -0
  15. package/dist/commands/anchor.js +303 -0
  16. package/dist/commands/guidance.js +23 -8
  17. package/dist/commands/judge.d.ts +69 -21
  18. package/dist/commands/judge.js +354 -89
  19. package/dist/commands/map.js +2 -0
  20. package/dist/commands/mcp.js +5 -9
  21. package/dist/commands/setup.js +5 -23
  22. package/dist/currency.d.ts +2 -0
  23. package/dist/currency.js +2 -1
  24. package/dist/guidance-hook.mjs +166 -57
  25. package/dist/guidance-runtime.d.ts +26 -0
  26. package/dist/guidance-runtime.js +71 -1
  27. package/dist/guidance.d.ts +7 -0
  28. package/dist/guidance.js +10 -1
  29. package/dist/headless-agent.d.ts +19 -1
  30. package/dist/headless-agent.js +22 -5
  31. package/dist/judge-brief.d.ts +20 -2
  32. package/dist/judge-brief.js +26 -2
  33. package/dist/promise-meaning.d.ts +17 -0
  34. package/dist/promise-meaning.js +15 -6
  35. package/dist/risk/git.d.ts +3 -1
  36. package/dist/risk/git.js +3 -3
  37. package/dist/risk/graph-cache.d.ts +83 -0
  38. package/dist/risk/graph-cache.js +291 -0
  39. package/dist/risk/import-graph.d.ts +43 -0
  40. package/dist/risk/import-graph.js +88 -34
  41. package/dist/risk/pipeline.d.ts +13 -0
  42. package/dist/risk/pipeline.js +15 -4
  43. package/dist/self-update.d.ts +3 -3
  44. package/dist/self-update.js +38 -8
  45. package/dist/wire.d.ts +18 -2
  46. package/dist/wire.js +1 -1
  47. package/package.json +7 -2
@@ -1,6 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { delimiter, dirname, join } from "node:path";
4
+ import { older } from "./currency.js";
4
5
  import { HOOK_SPECIFIER } from "./release.js";
5
6
  import { configHome } from "./store.js";
6
7
  /**
@@ -24,10 +25,22 @@ import { configHome } from "./store.js";
24
25
  * and what happened is kept in a small state file the next hook fire reports
25
26
  * to the server, so a laptop that cannot update is visible on the scorecard
26
27
  * instead of looking merely behind.
28
+ *
29
+ * What changed on 1 October 2026, from Robert's own laptop: it stayed on
30
+ * 1.0.16 through two releases while in use all day. Two rules held it. Only a
31
+ * session start began an install, and his sessions run for days, so the hooks
32
+ * that did fire (a prompt, a subagent) never asked. And the day's stamp was
33
+ * one stamp for every version: an attempt toward 1.0.15 at 03:20 held back
34
+ * 1.0.17 until 03:20 the next day, though a manual update had already passed
35
+ * 1.0.15. Now any guidance hook fire can begin the install, and a release
36
+ * newer than the one the last attempt aimed at may begin one an hour after
37
+ * it, rather than a day.
27
38
  */
28
39
  const STAMP = "self-update.json";
29
40
  const STATE = "self-update-state.json";
30
41
  const DAY_MS = 24 * 60 * 60 * 1000;
42
+ const HOUR_MS = 60 * 60 * 1000;
43
+ const VERSION = /^\d{1,4}\.\d{1,4}\.\d{1,4}$/;
31
44
  /** Set on the child so the install it runs can record how it ended. */
32
45
  export const SELF_UPDATE_ENVIRONMENT = "BALLADEER_SELF_UPDATE";
33
46
  const STATE_PATTERN = /^(?:started|unstartable|installed|failed):[A-Za-z0-9._-]{1,40}$/;
@@ -37,18 +50,35 @@ function stampPath(environment) {
37
50
  function statePath(environment) {
38
51
  return join(configHome(environment), STATE);
39
52
  }
40
- function lastStarted(environment) {
53
+ /** The last attempt: when it started and which release it aimed at, when it said. */
54
+ function lastAttempt(environment) {
41
55
  const path = stampPath(environment);
42
56
  if (!existsSync(path))
43
- return 0;
57
+ return { startedAt: 0 };
44
58
  try {
45
59
  const parsed = JSON.parse(readFileSync(path, "utf8"));
46
- return typeof parsed.startedAt === "number" ? parsed.startedAt : 0;
60
+ const startedAt = typeof parsed.startedAt === "number" ? parsed.startedAt : 0;
61
+ return typeof parsed.toward === "string" && VERSION.test(parsed.toward)
62
+ ? { startedAt, toward: parsed.toward }
63
+ : { startedAt };
47
64
  }
48
65
  catch {
49
- return 0;
66
+ return { startedAt: 0 };
50
67
  }
51
68
  }
69
+ /**
70
+ * Whether an attempt toward `newer` may start now. Once a day toward the same
71
+ * release, so a laptop whose install keeps failing is not hammered; but a
72
+ * release newer than the last attempt's target is a new reason, and waits only
73
+ * an hour, so one stale attempt cannot hold back the next release for a day.
74
+ */
75
+ function due(newer, last, now) {
76
+ const since = now - last.startedAt;
77
+ if (since >= DAY_MS)
78
+ return true;
79
+ const newerTarget = last.toward === undefined || older(last.toward, newer);
80
+ return newerTarget && since >= HOUR_MS;
81
+ }
52
82
  function writePrivate(path, value, environment) {
53
83
  mkdirSync(configHome(environment), { recursive: true, mode: 0o700 });
54
84
  writeFileSync(path, JSON.stringify(value) + "\n", { mode: 0o600 });
@@ -109,17 +139,17 @@ function detached(command, args, environment) {
109
139
  return child.pid !== undefined;
110
140
  }
111
141
  /**
112
- * Start the update when the server named a newer release and none was
113
- * started today. Answers whether one was started, for the caller's own
142
+ * Start the update when the server named a newer release and an attempt
143
+ * toward it is due (`due`). Answers whether one was started, for the caller's own
114
144
  * record; the session hears nothing either way. A launch that could not start
115
- * leaves no stamp, so the next session start tries again rather than waiting
145
+ * leaves no stamp, so the next hook fire tries again rather than waiting
116
146
  * a day for the same failure.
117
147
  */
118
148
  export function startSelfUpdateIfDue(newer, deps) {
119
149
  if (newer === undefined)
120
150
  return false;
121
151
  const now = deps.now ?? Date.now;
122
- if (now() - lastStarted(deps.environment) < DAY_MS)
152
+ if (!due(newer, lastAttempt(deps.environment), now()))
123
153
  return false;
124
154
  const launch = resolveLaunch(HOOK_SPECIFIER, deps.environment, deps.execPath, deps.exists);
125
155
  let started;
package/dist/wire.d.ts CHANGED
@@ -5,14 +5,14 @@
5
5
  * runtime dependency at all: Node 22 builtins and global fetch, nothing else.
6
6
  * A contract test compares the scope list below against the server's.
7
7
  */
8
- export declare const CLI_VERSION = "1.0.17";
8
+ export declare const CLI_VERSION = "1.0.19";
9
9
  export declare const CLI_INVOCATION = "npx -y balladeer@latest";
10
10
  export declare const CLIENT_HEADER = "x-balladeer-client";
11
11
  /** What the last background update came to: `started:1.0.17`, `installed:1.0.17`, `failed:exit-1`, `unstartable:launcher`. */
12
12
  export declare const UPDATE_STATE_HEADER = "x-balladeer-update-state";
13
13
  /** Which host's hook made this guidance fetch: `claude` or `codex`. */
14
14
  export declare const HOOK_HOST_HEADER = "x-balladeer-hook";
15
- export declare const CLIENT_HEADER_VALUE = "balladeer/1.0.17";
15
+ export declare const CLIENT_HEADER_VALUE = "balladeer/1.0.19";
16
16
  export declare const DEFAULT_CONTROL_PLANE = "https://envelopes.balladeer.ai";
17
17
  export type DelegatedScope = "repository:enroll" | "agent:issue" | "ci:connect" | "workspace:invite" | "candidate:propose";
18
18
  export declare const DELEGATED_SCOPES: readonly DelegatedScope[];
@@ -729,7 +729,23 @@ export type JsonStep = Readonly<{
729
729
  * this machine, or judges still running when the time ran out. Verdicts
730
730
  * themselves are printed as `balladeer-judge-verdict/v1` objects.
731
731
  */
732
+ /**
733
+ * What the push check's anchoring did before it selected promises: which it
734
+ * anchored, which it could not and why, what the calls cost and how many
735
+ * anchorings are left today on this laptop. `message` is the line a person
736
+ * reads.
737
+ */
732
738
  | Readonly<{
739
+ step: "anchors";
740
+ message: string;
741
+ anchored: readonly string[];
742
+ notAnchored: readonly Readonly<{
743
+ promiseId: string;
744
+ reason: string;
745
+ }>[];
746
+ tokens: number;
747
+ remainingToday: number;
748
+ }> | Readonly<{
733
749
  step: "judge";
734
750
  status: "not_judged" | "still_judging" | "nothing_to_judge";
735
751
  reason: string;
package/dist/wire.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * runtime dependency at all: Node 22 builtins and global fetch, nothing else.
6
6
  * A contract test compares the scope list below against the server's.
7
7
  */
8
- export const CLI_VERSION = "1.0.17";
8
+ export const CLI_VERSION = "1.0.19";
9
9
  export const CLI_INVOCATION = "npx -y balladeer@latest";
10
10
  export const CLIENT_HEADER = "x-balladeer-client";
11
11
  /** What the last background update came to: `started:1.0.17`, `installed:1.0.17`, `failed:exit-1`, `unstartable:launcher`. */
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "balladeer",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "Set up Balladeer from your terminal, or from a coding agent's.",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,
7
- "//": "repository and homepage are deliberately absent: the source repository is private, and a registry page linking somewhere a reader cannot open is worse than one that links nowhere. Add both when the repository is public, and delete this note when you do.",
7
+ "//": "repository names this private GitHub repository because npm trusted publishing requires it: the release workflow (.github/workflows/release.yml) publishes with no npm token and no passkey only when package.json's repository matches the repository the workflow runs in. Robert approved the registry page showing the repository name on 30 September 2026. homepage stays absent while the repository is private.",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Bobby-tables1/balladeer.git",
11
+ "directory": "packages/cli"
12
+ },
8
13
  "type": "module",
9
14
  "publishConfig": {
10
15
  "access": "public"