@ashlr/hub 3.2.6 → 3.2.7

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 (73) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/build-identity.json +2 -2
  3. package/dist/cli/completions.js +3 -1
  4. package/dist/cli/completions.js.map +1 -1
  5. package/dist/cli/conductor-permit.d.ts +1 -0
  6. package/dist/cli/conductor-permit.js +122 -0
  7. package/dist/cli/conductor-permit.js.map +1 -0
  8. package/dist/cli/goals.d.ts +2 -0
  9. package/dist/cli/goals.js +90 -5
  10. package/dist/cli/goals.js.map +1 -1
  11. package/dist/cli/help.js +2 -0
  12. package/dist/cli/help.js.map +1 -1
  13. package/dist/cli/index.js +6 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/loop.js +26 -5
  16. package/dist/cli/loop.js.map +1 -1
  17. package/dist/core/comms/elon-dialogue.js +16 -7
  18. package/dist/core/comms/elon-dialogue.js.map +1 -1
  19. package/dist/core/daemon/activation-permit.d.ts +89 -0
  20. package/dist/core/daemon/activation-permit.js +397 -0
  21. package/dist/core/daemon/activation-permit.js.map +1 -1
  22. package/dist/core/daemon/goal-conductor-permit-operator.d.ts +75 -0
  23. package/dist/core/daemon/goal-conductor-permit-operator.js +842 -0
  24. package/dist/core/daemon/goal-conductor-permit-operator.js.map +1 -0
  25. package/dist/core/daemon/loop.js +102 -20
  26. package/dist/core/daemon/loop.js.map +1 -1
  27. package/dist/core/fleet/quota.d.ts +74 -7
  28. package/dist/core/fleet/quota.js +688 -34
  29. package/dist/core/fleet/quota.js.map +1 -1
  30. package/dist/core/fleet/status.js +6 -5
  31. package/dist/core/fleet/status.js.map +1 -1
  32. package/dist/core/goals/advance.js +34 -5
  33. package/dist/core/goals/advance.js.map +1 -1
  34. package/dist/core/goals/conductor-quota.d.ts +38 -0
  35. package/dist/core/goals/conductor-quota.js +110 -0
  36. package/dist/core/goals/conductor-quota.js.map +1 -0
  37. package/dist/core/goals/conductor-target.d.ts +24 -0
  38. package/dist/core/goals/conductor-target.js +35 -0
  39. package/dist/core/goals/conductor-target.js.map +1 -0
  40. package/dist/core/goals/conductor.d.ts +15 -0
  41. package/dist/core/goals/conductor.js +116 -9
  42. package/dist/core/goals/conductor.js.map +1 -1
  43. package/dist/core/goals/store.d.ts +29 -5
  44. package/dist/core/goals/store.js +179 -26
  45. package/dist/core/goals/store.js.map +1 -1
  46. package/dist/core/goals/timestamp-repair.d.ts +50 -0
  47. package/dist/core/goals/timestamp-repair.js +740 -0
  48. package/dist/core/goals/timestamp-repair.js.map +1 -0
  49. package/dist/core/integrations/pulse-sync.js +13 -4
  50. package/dist/core/integrations/pulse-sync.js.map +1 -1
  51. package/dist/core/run/best-of-n.d.ts +18 -0
  52. package/dist/core/run/best-of-n.js +163 -18
  53. package/dist/core/run/best-of-n.js.map +1 -1
  54. package/dist/core/run/orchestrator.js +54 -0
  55. package/dist/core/run/orchestrator.js.map +1 -1
  56. package/dist/core/strategy/goal-planner.js +7 -1
  57. package/dist/core/strategy/goal-planner.js.map +1 -1
  58. package/dist/core/swarm/planner.d.ts +2 -2
  59. package/dist/core/swarm/planner.js +52 -5
  60. package/dist/core/swarm/planner.js.map +1 -1
  61. package/dist/core/swarm/runner.js +29 -3
  62. package/dist/core/swarm/runner.js.map +1 -1
  63. package/dist/core/types.d.ts +39 -0
  64. package/dist/core/types.js.map +1 -1
  65. package/dist/core/web/control.js +5 -2
  66. package/dist/core/web/control.js.map +1 -1
  67. package/dist/release-dependency-inventory.json +1 -1
  68. package/dist/tui/app.js +2 -2
  69. package/dist/tui/app.js.map +1 -1
  70. package/dist/tui/render.d.ts +2 -0
  71. package/dist/tui/render.js +162 -4
  72. package/dist/tui/render.js.map +1 -1
  73. package/package.json +1 -1
@@ -6,30 +6,70 @@
6
6
  * ledger records each dispatch and answers "how many in the last window?" and
7
7
  * "are we still under the configured cap?".
8
8
  *
9
- * Persistence discipline mirrors daemon/state.ts EXACTLY:
10
- * - Atomic writes (tmp file + POSIX rename).
11
- * - NEVER throws — load returns a fresh empty ledger on missing/corrupt file;
12
- * record swallows any persistence error.
9
+ * Observation compatibility remains deliberately tolerant: load returns a fresh
10
+ * empty ledger on missing/corrupt state and recordUse remains best-effort. The
11
+ * authority-bearing reservation API is stricter:
12
+ * - One local-store lock serializes read/check/append publication.
13
+ * - Configured limits fail closed on ambiguous or unavailable persistence.
14
+ * - Reservation identities are hashed and idempotent across retries.
15
+ * - The replacement file and containing directory are fsynced before success.
13
16
  * - mkdir -p the parent dir.
14
- * - Bounded history (last ~2000 events).
17
+ * - Bounded authority history (last 2000 events per known backend, max 30d).
15
18
  * - Homedir re-resolved at call time so tests can relocate HOME.
16
19
  *
17
20
  * No new runtime deps; node builtins only. evalQuota mirrors evalBudget's
18
21
  * three-level (ok/warn/over) semantics with a null-cap-disabled path.
19
22
  */
20
23
  import type { AshlrConfig, EngineId } from '../types.js';
24
+ import { type LocalStoreLock } from './local-store-lock.js';
21
25
  /** A single recorded backend dispatch. */
22
26
  export interface FleetQuotaEvent {
23
27
  /** Backend that was dispatched. */
24
28
  backend: EngineId;
25
29
  /** ISO timestamp of the dispatch. */
26
30
  ts: string;
31
+ /** Opaque idempotency identity for an authority-bearing reservation. */
32
+ reservationIdHash?: string;
27
33
  }
28
34
  /** The persisted fleet quota ledger. */
29
35
  export interface FleetQuota {
30
36
  /** Bounded list of recent dispatch events (oldest first). */
31
37
  events: FleetQuotaEvent[];
32
38
  }
39
+ export interface FleetQuotaReservationRequest {
40
+ backend: EngineId;
41
+ dispatchId: string;
42
+ }
43
+ export interface FleetQuotaReservationReceipt {
44
+ backend: EngineId;
45
+ status: 'unlimited' | 'reserved';
46
+ used: number;
47
+ limit: number | null;
48
+ }
49
+ export type FleetQuotaReservationResult = {
50
+ kind: 'unlimited' | 'reserved';
51
+ launchAuthorized: true;
52
+ reservations: FleetQuotaReservationReceipt[];
53
+ } | {
54
+ kind: 'invalid' | 'duplicate' | 'conflict' | 'exhausted' | 'unavailable' | 'capacity';
55
+ launchAuthorized: false;
56
+ backend?: EngineId;
57
+ used?: number;
58
+ limit?: number;
59
+ /** True means the durable reservation exists, but this call must not launch. */
60
+ reservationConsumed?: boolean;
61
+ };
62
+ export interface FleetQuotaReservationOptions {
63
+ /** Bounded local lock wait. Defaults to 250ms. */
64
+ lockWaitMs?: number;
65
+ }
66
+ export type FleetQuotaAuthorityHealth = 'unlimited' | 'healthy' | 'invalid' | 'unavailable' | 'capacity';
67
+ interface FleetQuotaTestHooks {
68
+ now?: () => number;
69
+ releaseLock?: (lock: LocalStoreLock) => boolean;
70
+ }
71
+ /** Test-only fault injection; production callers must never configure this. */
72
+ export declare function setFleetQuotaTestHooksForTests(hooks?: FleetQuotaTestHooks): void;
33
73
  /**
34
74
  * Convert a window label to milliseconds. Extends rollup.ts's day-granularity
35
75
  * vocabulary with sub-day windows used by rate limits. Unknown labels fall back
@@ -38,15 +78,37 @@ export interface FleetQuota {
38
78
  export declare function windowToMs(window: string): number;
39
79
  /** Absolute path to the fleet quota ledger file. */
40
80
  export declare function fleetQuotaPath(): string;
81
+ /**
82
+ * Private authority ledger. It is deliberately separate from quota.json:
83
+ * quota.json remains backwards-compatible, best-effort operator telemetry,
84
+ * while this file is the fail-closed idempotency/capacity boundary.
85
+ */
86
+ export declare function fleetQuotaReservationPath(): string;
87
+ /** Lock path used by the authority-bearing quota reservation transaction. */
88
+ export declare function fleetQuotaReservationLockPath(): string;
41
89
  /**
42
90
  * Read and parse fleetQuotaPath(). NEVER throws.
43
91
  * Returns a fresh empty ledger when the file is missing or malformed.
44
92
  */
45
93
  export declare function loadFleetQuota(): FleetQuota;
46
94
  /**
47
- * Append a dispatch event for `backend` (ts = now) and persist. Never throws.
95
+ * Append an actual dispatch-attempt event for `backend` (ts = now) and
96
+ * persist. Never throws. This is intentionally not launch authority; the
97
+ * strict reservation ledger above is separate so legacy 0644 telemetry files
98
+ * cannot block or overwrite authority state.
48
99
  */
49
100
  export declare function recordUse(backend: EngineId): void;
101
+ export declare function reserveFleetQuotaUses(requests: readonly FleetQuotaReservationRequest[], cfg: AshlrConfig, options?: FleetQuotaReservationOptions): FleetQuotaReservationResult;
102
+ /** Single-dispatch convenience wrapper over the atomic batch transaction. */
103
+ export declare function reserveFleetQuotaUse(backend: EngineId, cfg: AshlrConfig, dispatchId: string, options?: FleetQuotaReservationOptions): FleetQuotaReservationResult;
104
+ /** Read-only conservative health projection for operator/status surfaces. */
105
+ export declare function inspectFleetQuotaAuthority(backend: EngineId, cfg: AshlrConfig, now?: number): FleetQuotaAuthorityHealth;
106
+ /**
107
+ * Quota standing derived from reserved authority slots, not attempt telemetry.
108
+ * This intentionally counts conservative pre-effect reservations that may not
109
+ * have reached a provider: those slots still consume the configured window.
110
+ */
111
+ export declare function evalFleetQuotaAuthority(backend: EngineId, cfg: AshlrConfig, now?: number): 'ok' | 'warn' | 'over' | 'unlimited';
50
112
  /**
51
113
  * Count events for `backend` whose ts is within the last `windowMs`
52
114
  * (ts >= now - windowMs). Reads the ledger internally; `now` is injectable for
@@ -58,7 +120,11 @@ export declare function usesInWindow(backend: EngineId, windowMs: number, now?:
58
120
  *
59
121
  * Mirrors evalBudget's null-cap-disabled logic: when no
60
122
  * cfg.foundry.limits[backend] is configured, the backend is unlimited ⇒ always
61
- * within limit. Otherwise true iff usesInWindow(...) < limit.max. `now` is
123
+ * within limit. Healthy configured state follows reservation standing so a
124
+ * consumed slot can route to an eligible peer. Invalid, unavailable, or
125
+ * capacity-ambiguous authority deliberately remains advisory-eligible here so
126
+ * the final provider-effect reservation returns the structured fail-closed
127
+ * refusal instead of silently capability-downgrading to builtin. `now` is
62
128
  * injectable for tests.
63
129
  */
64
130
  export declare function withinLimit(backend: EngineId, cfg: AshlrConfig, now?: number): boolean;
@@ -68,3 +134,4 @@ export declare function withinLimit(backend: EngineId, cfg: AshlrConfig, now?: n
68
134
  * cap is configured the backend is unlimited ⇒ always 'ok'. `now` is injectable.
69
135
  */
70
136
  export declare function evalQuota(backend: EngineId, cfg: AshlrConfig, now?: number): 'ok' | 'warn' | 'over';
137
+ export {};