@jinn-network/client 0.1.6-canary.fb9c8196 → 0.1.6

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 (76) hide show
  1. package/dist/api/bootstrap-endpoint.js +0 -45
  2. package/dist/api/bootstrap-endpoint.js.map +1 -1
  3. package/dist/api/fleet-build.d.ts +0 -1
  4. package/dist/api/fleet-build.js +1 -2
  5. package/dist/api/fleet-build.js.map +1 -1
  6. package/dist/api/gather-status.js +1 -68
  7. package/dist/api/gather-status.js.map +1 -1
  8. package/dist/api/hermes-doctor-endpoint.d.ts +0 -10
  9. package/dist/api/hermes-doctor-endpoint.js +23 -30
  10. package/dist/api/hermes-doctor-endpoint.js.map +1 -1
  11. package/dist/api/setup-endpoints.d.ts +0 -16
  12. package/dist/api/setup-endpoints.js +0 -28
  13. package/dist/api/setup-endpoints.js.map +1 -1
  14. package/dist/api/status-build.d.ts +0 -14
  15. package/dist/api/status-build.js +18 -23
  16. package/dist/api/status-build.js.map +1 -1
  17. package/dist/build-info.json +4 -4
  18. package/dist/build-meta.json +1 -1
  19. package/dist/cli/commands/solver-nets.js +9 -24
  20. package/dist/cli/commands/solver-nets.js.map +1 -1
  21. package/dist/config.d.ts +0 -9
  22. package/dist/config.js +0 -7
  23. package/dist/config.js.map +1 -1
  24. package/dist/daemon/daemon.d.ts +0 -8
  25. package/dist/daemon/daemon.js +0 -17
  26. package/dist/daemon/daemon.js.map +1 -1
  27. package/dist/dashboard/assets/{index-CarzUepP.css → index-DOlzFN8a.css} +1 -1
  28. package/dist/dashboard/assets/index-NkZ7CTAT.js +140 -0
  29. package/dist/dashboard/index.html +2 -2
  30. package/dist/earning/bootstrap.d.ts +0 -59
  31. package/dist/earning/bootstrap.js +41 -139
  32. package/dist/earning/bootstrap.js.map +1 -1
  33. package/dist/earning/contracts.d.ts +0 -12
  34. package/dist/earning/contracts.js +0 -7
  35. package/dist/earning/contracts.js.map +1 -1
  36. package/dist/earning/funding-plan.js.map +1 -1
  37. package/dist/earning/jinn-rewards.d.ts +0 -46
  38. package/dist/earning/jinn-rewards.js +0 -32
  39. package/dist/earning/jinn-rewards.js.map +1 -1
  40. package/dist/earning/testnet-setup-migration.d.ts +0 -12
  41. package/dist/earning/testnet-setup-migration.js +1 -17
  42. package/dist/earning/testnet-setup-migration.js.map +1 -1
  43. package/dist/earning/types.d.ts +0 -15
  44. package/dist/harnesses/impls/hermes-agent/harness.d.ts +1 -23
  45. package/dist/harnesses/impls/hermes-agent/harness.js +0 -49
  46. package/dist/harnesses/impls/hermes-agent/harness.js.map +1 -1
  47. package/dist/harnesses/impls/index.d.ts +0 -2
  48. package/dist/harnesses/impls/index.js +1 -5
  49. package/dist/harnesses/impls/index.js.map +1 -1
  50. package/dist/main.js +30 -204
  51. package/dist/main.js.map +1 -1
  52. package/dist/operator-errors.d.ts +0 -7
  53. package/dist/operator-errors.js +1 -13
  54. package/dist/operator-errors.js.map +1 -1
  55. package/dist/solver-nets/prediction-operator-ux.js +3 -24
  56. package/dist/solver-nets/prediction-operator-ux.js.map +1 -1
  57. package/dist/solver-nets/registry.d.ts +0 -1
  58. package/dist/solver-nets/registry.js +1 -1
  59. package/dist/solver-nets/registry.js.map +1 -1
  60. package/package.json +1 -1
  61. package/dist/api/setup-retry-endpoint.d.ts +0 -19
  62. package/dist/api/setup-retry-endpoint.js +0 -32
  63. package/dist/api/setup-retry-endpoint.js.map +0 -1
  64. package/dist/daemon/eviction-loop.d.ts +0 -40
  65. package/dist/daemon/eviction-loop.js +0 -67
  66. package/dist/daemon/eviction-loop.js.map +0 -1
  67. package/dist/dashboard/assets/index-C_QnE4YV.js +0 -140
  68. package/dist/harnesses/cost-estimates.d.ts +0 -145
  69. package/dist/harnesses/cost-estimates.js +0 -297
  70. package/dist/harnesses/cost-estimates.js.map +0 -1
  71. package/dist/restart-daemon.d.ts +0 -71
  72. package/dist/restart-daemon.js +0 -82
  73. package/dist/restart-daemon.js.map +0 -1
  74. package/dist/setup/halt-mode.d.ts +0 -14
  75. package/dist/setup/halt-mode.js +0 -17
  76. package/dist/setup/halt-mode.js.map +0 -1
@@ -1,145 +0,0 @@
1
- /**
2
- * Per-task cost estimates for paid-API-key harnesses.
3
- *
4
- * Background — Issue #331 (Run-mode `feat`, P0 tier under release-feedback
5
- * umbrella #328). The operator dashboard surfaces a harness/model selection
6
- * at SolverNet-join time and again in Settings. Operators routing a paid
7
- * API key (Anthropic, OpenAI, OpenRouter, Nous Portal) through the Hermes
8
- * harness — or a "raw API key" Claude Code variant if we ever add one —
9
- * have **no UI nudge** at join-time about per-task cost. The v0.1.6 dogfood
10
- * surfaced the concrete worry: a first-run operator could pick Opus 4.7 +
11
- * SWE-rebench v2 and burn $100s/hr before they figure out what Jinn does.
12
- *
13
- * This module captures the heuristic the SPA uses to render that estimate
14
- * and to gate the Save & Join action when the estimate exceeds a
15
- * configurable per-task threshold (default $1).
16
- *
17
- * Heuristic shape per the spec:
18
- * per-1k-token rate × typical task length, by model id.
19
- *
20
- * Subscription harnesses (Claude Code, Codex) are flagged via
21
- * `subscriptionPath: true` on the harness; in that case the surface shows
22
- * "Included in subscription, no per-task API cost" and **does not** trigger
23
- * the confirmation gate, regardless of the model selected.
24
- *
25
- * To add a new model: append an entry to `MODEL_COST_TABLE`. The id is the
26
- * exact `model` string persisted to `joinedSolverNets[<cid>].model`. To
27
- * shape a new harness: append to `HARNESS_BILLING`. Keep the units
28
- * consistent: token counts in tokens, rates in USD-per-1k-tokens.
29
- *
30
- * Units note: Anthropic + OpenAI publish prices per million tokens; we
31
- * convert to per-1k-tokens here so the multiplication reads as
32
- * `(tokens / 1000) * pricePer1k`. Avoids floating-point surprises when the
33
- * dashboard renders cents.
34
- *
35
- * Pricing references captured at the time of this commit (see PR body):
36
- * - Anthropic Claude Opus 4.7: $15/M input, $75/M output (≈ $0.015 / 1k
37
- * input, $0.075 / 1k output). Typical SWE-rebench v2 task estimated at
38
- * ~50k input + 20k output → ~$2.25/task. Anthropic public pricing.
39
- * - Anthropic Claude Sonnet 4.6: $3/M input, $15/M output.
40
- * - OpenAI GPT-5.4: $1.25/M input, $10/M output (OpenAI public pricing).
41
- * - OpenAI GPT-5.4 Mini: $0.25/M input, $2/M output.
42
- *
43
- * These are heuristics. Provider-API reconciliation (actual usage) is
44
- * deferred to the P1 follow-up tracked in #331.
45
- */
46
- export type Provider = 'anthropic' | 'openai' | 'openrouter' | 'nous' | 'other';
47
- export interface ModelCostEntry {
48
- /** Upstream API provider that owns the billing relationship. */
49
- provider: Provider;
50
- /** USD per 1k input tokens. */
51
- inputPer1kTokens: number;
52
- /** USD per 1k output tokens. */
53
- outputPer1kTokens: number;
54
- /** Typical input-token consumption for a single task. Heuristic. */
55
- typicalInputTokens: number;
56
- /** Typical output-token consumption for a single task. Heuristic. */
57
- typicalOutputTokens: number;
58
- /**
59
- * `true` when this model id is only ever reached via a subscription path
60
- * (e.g. a future "Claude Code subscription" pinned model). The default
61
- * gate logic prefers the harness-level flag — this exists so an
62
- * individual model entry can override it on a per-id basis.
63
- */
64
- subscriptionPath?: boolean;
65
- }
66
- /**
67
- * Per-model cost entries. Keyed by the exact `model` id persisted to
68
- * `joinedSolverNets[<cid>].model`. The dashboard model dropdown in
69
- * `claudeModels.ts` is the source of truth for which ids appear here.
70
- */
71
- export declare const MODEL_COST_TABLE: Readonly<Record<string, ModelCostEntry>>;
72
- /**
73
- * Harness-level billing classification.
74
- *
75
- * `subscriptionPath: true` means the harness shells out to a
76
- * subscription-billed CLI (Claude Code, Codex) and the operator does NOT
77
- * incur per-task API charges — the cost surface is suppressed entirely
78
- * and the confirmation gate is never triggered.
79
- *
80
- * `subscriptionPath: false` means the harness routes to a paid API key
81
- * (Hermes via OpenRouter / Anthropic API / Nous Portal). The cost surface
82
- * is shown and the gate fires above the configured threshold.
83
- */
84
- export declare const HARNESS_BILLING: Readonly<Record<string, {
85
- subscriptionPath: boolean;
86
- }>>;
87
- /** Default per-task USD threshold above which the confirmation gate fires. */
88
- export declare const DEFAULT_HIGH_COST_THRESHOLD_USD = 1;
89
- export interface CostEstimate {
90
- /** Estimated per-task cost in USD. */
91
- usd: number;
92
- /** Computed input cost in USD. */
93
- inputUsd: number;
94
- /** Computed output cost in USD. */
95
- outputUsd: number;
96
- /** Heuristic typical input tokens used. */
97
- typicalInputTokens: number;
98
- /** Heuristic typical output tokens used. */
99
- typicalOutputTokens: number;
100
- /** Underlying entry consulted. */
101
- entry: ModelCostEntry;
102
- }
103
- /**
104
- * Compute the per-task cost estimate for a given model id. Returns `null`
105
- * when the id has no entry in `MODEL_COST_TABLE` — callers should treat
106
- * that as "unknown, don't surface a number" rather than rendering $0.
107
- */
108
- export declare function estimateModelCost(modelId: string): CostEstimate | null;
109
- /**
110
- * `true` when the harness routes through a paid API key. Subscription
111
- * harnesses (Claude Code, Codex) return `false`; unknown harnesses
112
- * conservatively return `true` so a misnamed harness doesn't silently
113
- * skip the cost surface.
114
- */
115
- export declare function harnessUsesPaidApiKey(harness: string | undefined): boolean;
116
- export interface CostSurfaceDecision {
117
- /** Whether to show a numeric cost-per-task estimate at all. */
118
- showEstimate: boolean;
119
- /** Resolved estimate (may be `null` even when `showEstimate` is true if the model id is unknown). */
120
- estimate: CostEstimate | null;
121
- /** Whether the Save & Join action requires the high-cost confirmation. */
122
- requiresConfirmation: boolean;
123
- /**
124
- * Human-readable reason the surface is suppressed when `showEstimate`
125
- * is false — e.g. "Included in subscription, no per-task API cost".
126
- * `null` when the surface is shown.
127
- */
128
- suppressedReason: string | null;
129
- }
130
- /**
131
- * Decide what the cost surface should render for a given harness + model
132
- * combination, plus whether the confirmation gate fires.
133
- *
134
- * Defaults:
135
- * - threshold: $1 / task (see DEFAULT_HIGH_COST_THRESHOLD_USD).
136
- * - subscription harness → suppress surface + skip gate.
137
- * - unknown model on a paid harness → show estimate slot (caller may
138
- * render "estimate unavailable") but DO NOT trigger the gate.
139
- */
140
- export declare function decideCostSurface(harness: string | undefined, modelId: string | undefined, thresholdUsd?: number): CostSurfaceDecision;
141
- /**
142
- * Format a USD amount for compact display in the dashboard. Picks the
143
- * smallest fraction count that still distinguishes the value from $0.
144
- */
145
- export declare function formatUsd(amount: number): string;
@@ -1,297 +0,0 @@
1
- /**
2
- * Per-task cost estimates for paid-API-key harnesses.
3
- *
4
- * Background — Issue #331 (Run-mode `feat`, P0 tier under release-feedback
5
- * umbrella #328). The operator dashboard surfaces a harness/model selection
6
- * at SolverNet-join time and again in Settings. Operators routing a paid
7
- * API key (Anthropic, OpenAI, OpenRouter, Nous Portal) through the Hermes
8
- * harness — or a "raw API key" Claude Code variant if we ever add one —
9
- * have **no UI nudge** at join-time about per-task cost. The v0.1.6 dogfood
10
- * surfaced the concrete worry: a first-run operator could pick Opus 4.7 +
11
- * SWE-rebench v2 and burn $100s/hr before they figure out what Jinn does.
12
- *
13
- * This module captures the heuristic the SPA uses to render that estimate
14
- * and to gate the Save & Join action when the estimate exceeds a
15
- * configurable per-task threshold (default $1).
16
- *
17
- * Heuristic shape per the spec:
18
- * per-1k-token rate × typical task length, by model id.
19
- *
20
- * Subscription harnesses (Claude Code, Codex) are flagged via
21
- * `subscriptionPath: true` on the harness; in that case the surface shows
22
- * "Included in subscription, no per-task API cost" and **does not** trigger
23
- * the confirmation gate, regardless of the model selected.
24
- *
25
- * To add a new model: append an entry to `MODEL_COST_TABLE`. The id is the
26
- * exact `model` string persisted to `joinedSolverNets[<cid>].model`. To
27
- * shape a new harness: append to `HARNESS_BILLING`. Keep the units
28
- * consistent: token counts in tokens, rates in USD-per-1k-tokens.
29
- *
30
- * Units note: Anthropic + OpenAI publish prices per million tokens; we
31
- * convert to per-1k-tokens here so the multiplication reads as
32
- * `(tokens / 1000) * pricePer1k`. Avoids floating-point surprises when the
33
- * dashboard renders cents.
34
- *
35
- * Pricing references captured at the time of this commit (see PR body):
36
- * - Anthropic Claude Opus 4.7: $15/M input, $75/M output (≈ $0.015 / 1k
37
- * input, $0.075 / 1k output). Typical SWE-rebench v2 task estimated at
38
- * ~50k input + 20k output → ~$2.25/task. Anthropic public pricing.
39
- * - Anthropic Claude Sonnet 4.6: $3/M input, $15/M output.
40
- * - OpenAI GPT-5.4: $1.25/M input, $10/M output (OpenAI public pricing).
41
- * - OpenAI GPT-5.4 Mini: $0.25/M input, $2/M output.
42
- *
43
- * These are heuristics. Provider-API reconciliation (actual usage) is
44
- * deferred to the P1 follow-up tracked in #331.
45
- */
46
- import { CLAUDE_CODE_HARNESS, CODEX_HARNESS, HERMES_AGENT_HARNESS, canonicalHarnessName, } from './names.js';
47
- /**
48
- * Per-model cost entries. Keyed by the exact `model` id persisted to
49
- * `joinedSolverNets[<cid>].model`. The dashboard model dropdown in
50
- * `claudeModels.ts` is the source of truth for which ids appear here.
51
- */
52
- export const MODEL_COST_TABLE = {
53
- // ---------- Anthropic family (direct + via OpenRouter) ----------
54
- 'claude-opus-4-7': {
55
- provider: 'anthropic',
56
- inputPer1kTokens: 0.015,
57
- outputPer1kTokens: 0.075,
58
- typicalInputTokens: 50_000,
59
- typicalOutputTokens: 20_000,
60
- },
61
- 'claude-sonnet-4-6': {
62
- provider: 'anthropic',
63
- inputPer1kTokens: 0.003,
64
- outputPer1kTokens: 0.015,
65
- typicalInputTokens: 50_000,
66
- typicalOutputTokens: 20_000,
67
- },
68
- 'claude-haiku-4-5-20251001': {
69
- provider: 'anthropic',
70
- inputPer1kTokens: 0.001,
71
- outputPer1kTokens: 0.005,
72
- typicalInputTokens: 50_000,
73
- typicalOutputTokens: 20_000,
74
- },
75
- // OpenRouter routing of the same families (Hermes harness uses these).
76
- 'anthropic/claude-opus-4.7': {
77
- provider: 'openrouter',
78
- inputPer1kTokens: 0.015,
79
- outputPer1kTokens: 0.075,
80
- typicalInputTokens: 50_000,
81
- typicalOutputTokens: 20_000,
82
- },
83
- 'anthropic/claude-sonnet-4.6': {
84
- provider: 'openrouter',
85
- inputPer1kTokens: 0.003,
86
- outputPer1kTokens: 0.015,
87
- typicalInputTokens: 50_000,
88
- typicalOutputTokens: 20_000,
89
- },
90
- // ---------- OpenAI family ----------
91
- 'gpt-5.4': {
92
- provider: 'openai',
93
- inputPer1kTokens: 0.00125,
94
- outputPer1kTokens: 0.01,
95
- typicalInputTokens: 50_000,
96
- typicalOutputTokens: 20_000,
97
- },
98
- 'gpt-5.4-mini': {
99
- provider: 'openai',
100
- inputPer1kTokens: 0.00025,
101
- outputPer1kTokens: 0.002,
102
- typicalInputTokens: 50_000,
103
- typicalOutputTokens: 20_000,
104
- },
105
- 'gpt-5.5': {
106
- provider: 'openai',
107
- // Newer flagship; public pricing not confirmed at heuristic-capture
108
- // time, so use Opus-4.7-class rates as a conservative upper bound
109
- // until we get a verified figure.
110
- inputPer1kTokens: 0.015,
111
- outputPer1kTokens: 0.06,
112
- typicalInputTokens: 50_000,
113
- typicalOutputTokens: 20_000,
114
- },
115
- 'gpt-5.3-codex': {
116
- provider: 'openai',
117
- inputPer1kTokens: 0.00125,
118
- outputPer1kTokens: 0.01,
119
- typicalInputTokens: 50_000,
120
- typicalOutputTokens: 20_000,
121
- },
122
- 'gpt-5.3-codex-spark': {
123
- provider: 'openai',
124
- inputPer1kTokens: 0.00125,
125
- outputPer1kTokens: 0.01,
126
- typicalInputTokens: 50_000,
127
- typicalOutputTokens: 20_000,
128
- },
129
- // ---------- OpenRouter long-tail (Hermes) ----------
130
- // These rates are coarse — OpenRouter's effective price depends on the
131
- // route picked. We pick the published list-price upper bound so the
132
- // estimate biases toward over-warning rather than under-warning.
133
- 'tencent/hy3-preview': {
134
- provider: 'openrouter',
135
- inputPer1kTokens: 0.003,
136
- outputPer1kTokens: 0.015,
137
- typicalInputTokens: 50_000,
138
- typicalOutputTokens: 20_000,
139
- },
140
- 'deepseek/deepseek-v4-pro': {
141
- provider: 'openrouter',
142
- inputPer1kTokens: 0.0014,
143
- outputPer1kTokens: 0.0028,
144
- typicalInputTokens: 50_000,
145
- typicalOutputTokens: 20_000,
146
- },
147
- 'deepseek/deepseek-v4-flash': {
148
- provider: 'openrouter',
149
- inputPer1kTokens: 0.0001,
150
- outputPer1kTokens: 0.0004,
151
- typicalInputTokens: 50_000,
152
- typicalOutputTokens: 20_000,
153
- },
154
- 'google/gemini-3.1-flash-lite': {
155
- provider: 'openrouter',
156
- inputPer1kTokens: 0.0001,
157
- outputPer1kTokens: 0.0004,
158
- typicalInputTokens: 50_000,
159
- typicalOutputTokens: 20_000,
160
- },
161
- 'moonshotai/kimi-k2.6': {
162
- provider: 'openrouter',
163
- inputPer1kTokens: 0.0006,
164
- outputPer1kTokens: 0.0025,
165
- typicalInputTokens: 50_000,
166
- typicalOutputTokens: 20_000,
167
- },
168
- 'openrouter/owl-alpha': {
169
- provider: 'openrouter',
170
- inputPer1kTokens: 0.002,
171
- outputPer1kTokens: 0.008,
172
- typicalInputTokens: 50_000,
173
- typicalOutputTokens: 20_000,
174
- },
175
- 'minimax/minimax-m2.7': {
176
- provider: 'openrouter',
177
- inputPer1kTokens: 0.0008,
178
- outputPer1kTokens: 0.0032,
179
- typicalInputTokens: 50_000,
180
- typicalOutputTokens: 20_000,
181
- },
182
- 'nousresearch/hermes-4-405b': {
183
- provider: 'nous',
184
- inputPer1kTokens: 0.0009,
185
- outputPer1kTokens: 0.0009,
186
- typicalInputTokens: 50_000,
187
- typicalOutputTokens: 20_000,
188
- },
189
- };
190
- /**
191
- * Harness-level billing classification.
192
- *
193
- * `subscriptionPath: true` means the harness shells out to a
194
- * subscription-billed CLI (Claude Code, Codex) and the operator does NOT
195
- * incur per-task API charges — the cost surface is suppressed entirely
196
- * and the confirmation gate is never triggered.
197
- *
198
- * `subscriptionPath: false` means the harness routes to a paid API key
199
- * (Hermes via OpenRouter / Anthropic API / Nous Portal). The cost surface
200
- * is shown and the gate fires above the configured threshold.
201
- */
202
- export const HARNESS_BILLING = {
203
- [CLAUDE_CODE_HARNESS]: { subscriptionPath: true },
204
- [CODEX_HARNESS]: { subscriptionPath: true },
205
- [HERMES_AGENT_HARNESS]: { subscriptionPath: false },
206
- };
207
- /** Default per-task USD threshold above which the confirmation gate fires. */
208
- export const DEFAULT_HIGH_COST_THRESHOLD_USD = 1;
209
- /**
210
- * Compute the per-task cost estimate for a given model id. Returns `null`
211
- * when the id has no entry in `MODEL_COST_TABLE` — callers should treat
212
- * that as "unknown, don't surface a number" rather than rendering $0.
213
- */
214
- export function estimateModelCost(modelId) {
215
- const entry = MODEL_COST_TABLE[modelId];
216
- if (!entry)
217
- return null;
218
- const inputUsd = (entry.typicalInputTokens / 1000) * entry.inputPer1kTokens;
219
- const outputUsd = (entry.typicalOutputTokens / 1000) * entry.outputPer1kTokens;
220
- return {
221
- usd: inputUsd + outputUsd,
222
- inputUsd,
223
- outputUsd,
224
- typicalInputTokens: entry.typicalInputTokens,
225
- typicalOutputTokens: entry.typicalOutputTokens,
226
- entry,
227
- };
228
- }
229
- /**
230
- * `true` when the harness routes through a paid API key. Subscription
231
- * harnesses (Claude Code, Codex) return `false`; unknown harnesses
232
- * conservatively return `true` so a misnamed harness doesn't silently
233
- * skip the cost surface.
234
- */
235
- export function harnessUsesPaidApiKey(harness) {
236
- if (!harness)
237
- return false;
238
- const canonical = canonicalHarnessName(harness);
239
- const billing = HARNESS_BILLING[canonical];
240
- if (!billing)
241
- return true;
242
- return !billing.subscriptionPath;
243
- }
244
- /**
245
- * Decide what the cost surface should render for a given harness + model
246
- * combination, plus whether the confirmation gate fires.
247
- *
248
- * Defaults:
249
- * - threshold: $1 / task (see DEFAULT_HIGH_COST_THRESHOLD_USD).
250
- * - subscription harness → suppress surface + skip gate.
251
- * - unknown model on a paid harness → show estimate slot (caller may
252
- * render "estimate unavailable") but DO NOT trigger the gate.
253
- */
254
- export function decideCostSurface(harness, modelId, thresholdUsd = DEFAULT_HIGH_COST_THRESHOLD_USD) {
255
- if (!harnessUsesPaidApiKey(harness)) {
256
- return {
257
- showEstimate: false,
258
- estimate: null,
259
- requiresConfirmation: false,
260
- suppressedReason: 'Included in subscription, no per-task API cost.',
261
- };
262
- }
263
- const estimate = modelId ? estimateModelCost(modelId) : null;
264
- const modelOverridesSubscription = estimate?.entry.subscriptionPath === true;
265
- if (modelOverridesSubscription) {
266
- return {
267
- showEstimate: false,
268
- estimate: null,
269
- requiresConfirmation: false,
270
- suppressedReason: 'Included in subscription, no per-task API cost.',
271
- };
272
- }
273
- return {
274
- showEstimate: true,
275
- estimate,
276
- requiresConfirmation: estimate !== null && estimate.usd > thresholdUsd,
277
- suppressedReason: null,
278
- };
279
- }
280
- /**
281
- * Format a USD amount for compact display in the dashboard. Picks the
282
- * smallest fraction count that still distinguishes the value from $0.
283
- */
284
- export function formatUsd(amount) {
285
- if (!Number.isFinite(amount))
286
- return '—';
287
- if (amount === 0)
288
- return '$0';
289
- if (amount < 0.01)
290
- return `<$0.01`;
291
- if (amount < 1)
292
- return `$${amount.toFixed(2)}`;
293
- if (amount < 10)
294
- return `$${amount.toFixed(2)}`;
295
- return `$${amount.toFixed(2)}`;
296
- }
297
- //# sourceMappingURL=cost-estimates.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cost-estimates.js","sourceRoot":"","sources":["../../src/harnesses/cost-estimates.ts"],"names":[],"mappings":"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"}
@@ -1,71 +0,0 @@
1
- /**
2
- * In-process respawn helper for operator-triggered daemon restarts.
3
- *
4
- * Issue #289: clicking "Restart node" in the operator panel previously called
5
- * `process.exit(0)`, which killed the daemon and stranded the operator outside
6
- * the app (the panel went 502, the terminal got a shell prompt). Every
7
- * restart-required config change funnelled through the same handler:
8
- *
9
- * - POST /v1/setup/network — RPC URL change
10
- * - POST /v1/setup/change-password — keystore password rotation
11
- * - POST /v1/setup/solvernets/:name — SolverNet enable/disable
12
- * - POST /v1/operator/join/:cid — SolverNet join
13
- *
14
- * The fix is the smallest thing that makes the button mean what it says:
15
- * before the parent exits, spawn a detached copy of the current process,
16
- * inheriting argv (sans node binary), env, and stdio. The child takes over
17
- * the port; the panel reconnects within a couple of seconds.
18
- *
19
- * Headless gate: `JINN_NO_UI=1` (already the established headless flag in
20
- * main.ts) skips the respawn — operators running `jinn run --no-ui` from a
21
- * supervisor / systemd unit / docker entrypoint want the supervisor to
22
- * decide whether to restart, not the daemon.
23
- *
24
- * The helper is split out from main.ts so it's unit-testable without
25
- * touching the entry-point bootstrap path.
26
- */
27
- import { spawn } from 'node:child_process';
28
- /**
29
- * Options for `requestDaemonRestart`. All optional in production; the helper
30
- * defaults to `process` / `node:child_process`. Tests inject doubles.
31
- */
32
- export interface RequestDaemonRestartOptions {
33
- /** Defaults to `process.env`. */
34
- env?: NodeJS.ProcessEnv;
35
- /** Defaults to `process.argv` (`[node, scriptPath, ...args]`). */
36
- argv?: readonly string[];
37
- /** Defaults to `process.execPath` (the node binary). */
38
- execPath?: string;
39
- /**
40
- * Defaults to `node:child_process.spawn`. Injected for tests so we can
41
- * assert what was spawned without actually forking node.
42
- */
43
- spawnFn?: typeof spawn;
44
- /** Defaults to `(code) => process.exit(code)`. Injected for tests. */
45
- exitFn?: (code: number) => void;
46
- /** Defaults to `console.log`. Injected for tests to capture output. */
47
- log?: (message: string) => void;
48
- /**
49
- * Delay (ms) between spawning the child and exiting the parent. Gives the
50
- * child a moment to bind the API port before the parent vacates it.
51
- * Defaults to 250ms per the issue body. Tests can pass 0 for synchrony.
52
- */
53
- exitDelayMs?: number;
54
- }
55
- /**
56
- * Pure predicate: true when the current env is headless and respawn should
57
- * be skipped. Exposed so callers and tests can share the same check.
58
- */
59
- export declare function isHeadless(env?: NodeJS.ProcessEnv): boolean;
60
- /**
61
- * Handle an operator-triggered restart request.
62
- *
63
- * - In **interactive** mode (default), spawn a detached child that re-runs
64
- * the current node invocation, then exit after a short delay so the child
65
- * can bind the API port.
66
- * - In **headless** mode (`JINN_NO_UI=1`), exit without respawning. The
67
- * supervisor is responsible for relaunching the daemon if it wants to.
68
- *
69
- * Returns the action taken (for tests). Production callers ignore the return.
70
- */
71
- export declare function requestDaemonRestart(opts?: RequestDaemonRestartOptions): 'respawned' | 'headless-exit';
@@ -1,82 +0,0 @@
1
- /**
2
- * In-process respawn helper for operator-triggered daemon restarts.
3
- *
4
- * Issue #289: clicking "Restart node" in the operator panel previously called
5
- * `process.exit(0)`, which killed the daemon and stranded the operator outside
6
- * the app (the panel went 502, the terminal got a shell prompt). Every
7
- * restart-required config change funnelled through the same handler:
8
- *
9
- * - POST /v1/setup/network — RPC URL change
10
- * - POST /v1/setup/change-password — keystore password rotation
11
- * - POST /v1/setup/solvernets/:name — SolverNet enable/disable
12
- * - POST /v1/operator/join/:cid — SolverNet join
13
- *
14
- * The fix is the smallest thing that makes the button mean what it says:
15
- * before the parent exits, spawn a detached copy of the current process,
16
- * inheriting argv (sans node binary), env, and stdio. The child takes over
17
- * the port; the panel reconnects within a couple of seconds.
18
- *
19
- * Headless gate: `JINN_NO_UI=1` (already the established headless flag in
20
- * main.ts) skips the respawn — operators running `jinn run --no-ui` from a
21
- * supervisor / systemd unit / docker entrypoint want the supervisor to
22
- * decide whether to restart, not the daemon.
23
- *
24
- * The helper is split out from main.ts so it's unit-testable without
25
- * touching the entry-point bootstrap path.
26
- */
27
- import { spawn } from 'node:child_process';
28
- /**
29
- * Pure predicate: true when the current env is headless and respawn should
30
- * be skipped. Exposed so callers and tests can share the same check.
31
- */
32
- export function isHeadless(env = process.env) {
33
- return env['JINN_NO_UI'] === '1';
34
- }
35
- /**
36
- * Handle an operator-triggered restart request.
37
- *
38
- * - In **interactive** mode (default), spawn a detached child that re-runs
39
- * the current node invocation, then exit after a short delay so the child
40
- * can bind the API port.
41
- * - In **headless** mode (`JINN_NO_UI=1`), exit without respawning. The
42
- * supervisor is responsible for relaunching the daemon if it wants to.
43
- *
44
- * Returns the action taken (for tests). Production callers ignore the return.
45
- */
46
- export function requestDaemonRestart(opts = {}) {
47
- const env = opts.env ?? process.env;
48
- const argv = opts.argv ?? process.argv;
49
- const execPath = opts.execPath ?? process.execPath;
50
- const spawnFn = opts.spawnFn ?? spawn;
51
- const exitFn = opts.exitFn ?? ((code) => process.exit(code));
52
- const log = opts.log ?? ((message) => console.log(message));
53
- const exitDelayMs = opts.exitDelayMs ?? 250;
54
- if (isHeadless(env)) {
55
- log('[main] Restart requested via operator MCP, but JINN_NO_UI=1 — exiting without respawn (let the supervisor decide).');
56
- exitFn(0);
57
- return 'headless-exit';
58
- }
59
- log('[main] Restart requested via operator MCP. Spawning replacement and exiting...');
60
- // argv[0] is the node binary; argv[1..] are the script + flags. The child
61
- // re-runs the same script with the same flags, under the same node binary.
62
- const childArgs = argv.slice(1);
63
- const spawnOptions = {
64
- detached: true,
65
- stdio: 'inherit',
66
- env,
67
- };
68
- const child = spawnFn(execPath, childArgs, spawnOptions);
69
- // Detach so the parent can exit without taking the child with it.
70
- child.unref();
71
- // Give the child a moment to bind the API port before we vacate it.
72
- // The 250ms default matches the issue body's empirical measurement; tests
73
- // pass 0 for synchrony.
74
- if (exitDelayMs <= 0) {
75
- exitFn(0);
76
- }
77
- else {
78
- setTimeout(() => exitFn(0), exitDelayMs);
79
- }
80
- return 'respawned';
81
- }
82
- //# sourceMappingURL=restart-daemon.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"restart-daemon.js","sourceRoot":"","sources":["../src/restart-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AA8B9D;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,OAAO,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;AACnC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAoC,EAAE;IAEtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,GAAG,CAAC;IAE5C,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,GAAG,CACD,oHAAoH,CACrH,CAAC;QACF,MAAM,CAAC,CAAC,CAAC,CAAC;QACV,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,GAAG,CAAC,gFAAgF,CAAC,CAAC;IAEtF,0EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,YAAY,GAAiB;QACjC,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,SAAS;QAChB,GAAG;KACJ,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACzD,kEAAkE;IAClE,KAAK,CAAC,KAAK,EAAE,CAAC;IAEd,oEAAoE;IACpE,0EAA0E;IAC1E,wBAAwB;IACxB,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,CAAC,CAAC,CAAC;IACZ,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -1,14 +0,0 @@
1
- /**
2
- * Halt-and-resume gate (jinn-mono-hjex.6).
3
- *
4
- * When bootstrap fails after the setup API has come up, we want the dashboard
5
- * to stay alive so the operator can click Retry from `BootstrapErrorCard`
6
- * (see `main.ts` halt-and-resume loop). That mode is only safe when there is
7
- * actually a human (or watcher) on the other side; in CI / agent-driven flows
8
- * driven with `JINN_NO_UI=1` or `JINN_NO_DAEMON=1` no Retry click is coming,
9
- * so a halt must surface as a fatal exit immediately rather than suspending
10
- * in the retry loop forever.
11
- *
12
- * This predicate is the single source of truth for that gate.
13
- */
14
- export declare function keepSetupUiOnBootstrapError(env?: NodeJS.ProcessEnv): boolean;
@@ -1,17 +0,0 @@
1
- /**
2
- * Halt-and-resume gate (jinn-mono-hjex.6).
3
- *
4
- * When bootstrap fails after the setup API has come up, we want the dashboard
5
- * to stay alive so the operator can click Retry from `BootstrapErrorCard`
6
- * (see `main.ts` halt-and-resume loop). That mode is only safe when there is
7
- * actually a human (or watcher) on the other side; in CI / agent-driven flows
8
- * driven with `JINN_NO_UI=1` or `JINN_NO_DAEMON=1` no Retry click is coming,
9
- * so a halt must surface as a fatal exit immediately rather than suspending
10
- * in the retry loop forever.
11
- *
12
- * This predicate is the single source of truth for that gate.
13
- */
14
- export function keepSetupUiOnBootstrapError(env = process.env) {
15
- return env['JINN_NO_UI'] !== '1' && env['JINN_NO_DAEMON'] !== '1';
16
- }
17
- //# sourceMappingURL=halt-mode.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"halt-mode.js","sourceRoot":"","sources":["../../src/setup/halt-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC9E,OAAO,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,KAAK,GAAG,CAAC;AACpE,CAAC"}