@prohost/cli 0.10.2 → 0.10.3
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 +15 -0
- package/dist/usage/project.d.ts +2 -0
- package/dist/usage/project.js +20 -3
- package/dist/usage/scanner.d.ts +11 -1
- package/dist/usage/scanner.js +56 -9
- package/dist/usage/service.d.ts +12 -0
- package/dist/usage/service.js +47 -2
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ Versions follow [semver](https://semver.org/). Publishing is automated: merging
|
|
|
4
4
|
a version bump to `main` triggers `.github/workflows/npm-publish-cli.yml`, which
|
|
5
5
|
builds via `prepack`, runs the suite, publishes, and tags `cli-v<version>`.
|
|
6
6
|
|
|
7
|
+
## 0.10.3
|
|
8
|
+
|
|
9
|
+
Two fixes to the 0.10.2 repository attribution.
|
|
10
|
+
|
|
11
|
+
- **A bare repository is named without `.git`.** A session whose working
|
|
12
|
+
directory is a bare repository (`tools.git`, with `HEAD`, `objects/` and
|
|
13
|
+
`refs/` and no `.git` inside), or a directory within it, counts toward
|
|
14
|
+
`tools`, the same name its linked worktrees get. A plain folder that only
|
|
15
|
+
ends in `.git` keeps its name.
|
|
16
|
+
- **Days 0.10.1 had not uploaded yet are not lost in the upgrade.** The rows
|
|
17
|
+
of any (day, login) still waiting to upload when the scan state was rebuilt
|
|
18
|
+
are sent as 0.10.1 had them, before any rebuilt row. A day whose log has
|
|
19
|
+
since been removed, or reads back smaller, still reaches the server with
|
|
20
|
+
the total 0.10.1 counted.
|
|
21
|
+
|
|
7
22
|
## 0.10.2
|
|
8
23
|
|
|
9
24
|
Token totals are attributed to the repository, not the directory a session ran in.
|
package/dist/usage/project.d.ts
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* 3. A `.git` file is a linked worktree (or a submodule): its `gitdir:` names
|
|
13
13
|
* `<repo>/.git/worktrees/<name>`, whose `commondir` leads back to
|
|
14
14
|
* `<repo>/.git`. A submodule's gitdir has neither, so it is its own project.
|
|
15
|
+
* A bare repository (`HEAD`, `objects/`, `refs/` and no `.git`) is its own
|
|
16
|
+
* root, named without a `.git` suffix: `tools.git` is `tools`.
|
|
15
17
|
* 4. A directory that no longer exists (a removed worktree) is recognised by
|
|
16
18
|
* its layout — `…/.worktrees/<repo>/<name>` or `…/<repo>/.claude/worktrees/<name>`
|
|
17
19
|
* — and is otherwise named by its basename.
|
package/dist/usage/project.js
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* 3. A `.git` file is a linked worktree (or a submodule): its `gitdir:` names
|
|
13
13
|
* `<repo>/.git/worktrees/<name>`, whose `commondir` leads back to
|
|
14
14
|
* `<repo>/.git`. A submodule's gitdir has neither, so it is its own project.
|
|
15
|
+
* A bare repository (`HEAD`, `objects/`, `refs/` and no `.git`) is its own
|
|
16
|
+
* root, named without a `.git` suffix: `tools.git` is `tools`.
|
|
15
17
|
* 4. A directory that no longer exists (a removed worktree) is recognised by
|
|
16
18
|
* its layout — `…/.worktrees/<repo>/<name>` or `…/<repo>/.claude/worktrees/<name>`
|
|
17
19
|
* — and is otherwise named by its basename.
|
|
@@ -69,7 +71,7 @@ function resolveProjectRoot(dir) {
|
|
|
69
71
|
}
|
|
70
72
|
return dir;
|
|
71
73
|
}
|
|
72
|
-
/** The main repository root when `dir` holds a `.git
|
|
74
|
+
/** The main repository root when `dir` holds a `.git` or is a bare repository; `undefined` otherwise. */
|
|
73
75
|
function repoRootAt(dir) {
|
|
74
76
|
const dotGit = path.join(dir, '.git');
|
|
75
77
|
let stat;
|
|
@@ -77,7 +79,7 @@ function repoRootAt(dir) {
|
|
|
77
79
|
stat = statSync(dotGit);
|
|
78
80
|
}
|
|
79
81
|
catch {
|
|
80
|
-
return undefined;
|
|
82
|
+
return isBareRepo(dir) ? withoutGitSuffix(dir) : undefined;
|
|
81
83
|
}
|
|
82
84
|
if (stat.isDirectory())
|
|
83
85
|
return dir;
|
|
@@ -115,7 +117,22 @@ function mainRepoOf(gitDir) {
|
|
|
115
117
|
// `<repo>/.git` → `<repo>`; a bare `<repo>.git` common dir names the repo itself.
|
|
116
118
|
if (path.basename(common) === '.git')
|
|
117
119
|
return path.dirname(common);
|
|
118
|
-
return common
|
|
120
|
+
return withoutGitSuffix(common);
|
|
121
|
+
}
|
|
122
|
+
/** `<repo>.git` → `<repo>`; anything else as it is. */
|
|
123
|
+
function withoutGitSuffix(dir) {
|
|
124
|
+
return dir.replace(/\.git$/, '') || dir;
|
|
125
|
+
}
|
|
126
|
+
/** A bare repository's own directory: `HEAD`, `objects/` and `refs/` with no worktree. */
|
|
127
|
+
function isBareRepo(dir) {
|
|
128
|
+
try {
|
|
129
|
+
return (statSync(path.join(dir, 'HEAD')).isFile() &&
|
|
130
|
+
statSync(path.join(dir, 'objects')).isDirectory() &&
|
|
131
|
+
statSync(path.join(dir, 'refs')).isDirectory());
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
119
136
|
}
|
|
120
137
|
/** The repository a removed worktree path belonged to, from the two layouts agents use. */
|
|
121
138
|
function removedWorktreeRepo(dir) {
|
package/dist/usage/scanner.d.ts
CHANGED
|
@@ -82,6 +82,13 @@ export interface ScanState {
|
|
|
82
82
|
* the pair is replaced whole on the server, or is given up on.
|
|
83
83
|
*/
|
|
84
84
|
legacy: Record<string, Totals>;
|
|
85
|
+
/**
|
|
86
|
+
* Bucket key → totals: the version-1 rows of pairs version 1 had not
|
|
87
|
+
* uploaded yet (still dirty). The server never took them, so its copy is
|
|
88
|
+
* not the right total; they go out as they were, before any rebuilt row,
|
|
89
|
+
* and an entry goes once the server takes its pair or never will.
|
|
90
|
+
*/
|
|
91
|
+
legacyUnsent: Record<string, Totals>;
|
|
85
92
|
}
|
|
86
93
|
/** A dirty entry: one account's rows for one day. */
|
|
87
94
|
export declare function pendingKey(day: string, accountKey: string): string;
|
|
@@ -116,7 +123,8 @@ export declare function emptyScanState(): ScanState;
|
|
|
116
123
|
/**
|
|
117
124
|
* Load the scan state. A version-1 state (per-directory projects) is replaced
|
|
118
125
|
* by an empty one that re-reads every log, keeping its per-pair totals as
|
|
119
|
-
* {@link ScanState.legacy}
|
|
126
|
+
* {@link ScanState.legacy} and the rows it had not uploaded as
|
|
127
|
+
* {@link ScanState.legacyUnsent}.
|
|
120
128
|
*/
|
|
121
129
|
export declare function loadScanState(file: string): ScanState;
|
|
122
130
|
/**
|
|
@@ -137,6 +145,8 @@ export declare function bucketKey(day: string, accountKey: string, runtime: Acco
|
|
|
137
145
|
export declare function scanUsage(accounts: ScanAccount[], state: ScanState, options?: ScanOptions): ScanSummary;
|
|
138
146
|
/** The rows for the given days, in upload shape. Zero-token buckets are left out. */
|
|
139
147
|
export declare function rowsForDays(state: ScanState, days: Iterable<string>): TokenRow[];
|
|
148
|
+
/** The version-1 rows not yet uploaded ({@link ScanState.legacyUnsent}), in upload shape. */
|
|
149
|
+
export declare function legacyUnsentRows(state: ScanState): TokenRow[];
|
|
140
150
|
/** The rows for the given `day|accountKey` pairs, in upload shape. */
|
|
141
151
|
export declare function rowsForPending(state: ScanState, pairs: Iterable<string>): TokenRow[];
|
|
142
152
|
/** One `POST /v1/usage/token-totals` body's rows, and what it says about each (day, account) pair. */
|
package/dist/usage/scanner.js
CHANGED
|
@@ -65,7 +65,7 @@ export function pendingDays(state) {
|
|
|
65
65
|
return [...new Set(state.dirty.map(pendingDay))].sort();
|
|
66
66
|
}
|
|
67
67
|
export function emptyScanState() {
|
|
68
|
-
return { version: 2, files: {}, buckets: {}, seen: {}, dirty: [], strikes: {}, legacy: {} };
|
|
68
|
+
return { version: 2, files: {}, buckets: {}, seen: {}, dirty: [], strikes: {}, legacy: {}, legacyUnsent: {} };
|
|
69
69
|
}
|
|
70
70
|
const pairList = (value) => Array.isArray(value) ? value.filter((d) => typeof d === 'string' && d.includes('|')) : [];
|
|
71
71
|
const isTotals = (value) => Array.isArray(value) && value.length === 4 && value.every((n) => typeof n === 'number' && Number.isFinite(n));
|
|
@@ -95,10 +95,42 @@ function legacyTotals(buckets) {
|
|
|
95
95
|
}
|
|
96
96
|
return out;
|
|
97
97
|
}
|
|
98
|
+
/** The version-1 buckets of the pairs it still had dirty. */
|
|
99
|
+
function legacyUnsentBuckets(buckets, dirty) {
|
|
100
|
+
const out = {};
|
|
101
|
+
if (!buckets || typeof buckets !== 'object' || dirty.length === 0)
|
|
102
|
+
return out;
|
|
103
|
+
const wanted = new Set(dirty);
|
|
104
|
+
for (const [key, totals] of Object.entries(buckets)) {
|
|
105
|
+
if (!isTotals(totals) || !isBucketKey(key))
|
|
106
|
+
continue;
|
|
107
|
+
const [day, accountKey] = JSON.parse(key);
|
|
108
|
+
if (wanted.has(pendingKey(day, accountKey)))
|
|
109
|
+
out[key] = totals;
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/** A {@link bucketKey}: `[day, accountKey, runtime, model, project]`. */
|
|
114
|
+
function isBucketKey(key) {
|
|
115
|
+
try {
|
|
116
|
+
const parts = JSON.parse(key);
|
|
117
|
+
return (Array.isArray(parts) &&
|
|
118
|
+
parts.length === 5 &&
|
|
119
|
+
parts.slice(0, 4).every((part) => typeof part === 'string') &&
|
|
120
|
+
(parts[4] === null || typeof parts[4] === 'string'));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const totalsRecord = (value, validKey) => value && typeof value === 'object'
|
|
127
|
+
? Object.fromEntries(Object.entries(value).filter(([key, t]) => validKey(key) && isTotals(t)))
|
|
128
|
+
: {};
|
|
98
129
|
/**
|
|
99
130
|
* Load the scan state. A version-1 state (per-directory projects) is replaced
|
|
100
131
|
* by an empty one that re-reads every log, keeping its per-pair totals as
|
|
101
|
-
* {@link ScanState.legacy}
|
|
132
|
+
* {@link ScanState.legacy} and the rows it had not uploaded as
|
|
133
|
+
* {@link ScanState.legacyUnsent}.
|
|
102
134
|
*/
|
|
103
135
|
export function loadScanState(file) {
|
|
104
136
|
let parsed;
|
|
@@ -108,8 +140,13 @@ export function loadScanState(file) {
|
|
|
108
140
|
catch {
|
|
109
141
|
return emptyScanState();
|
|
110
142
|
}
|
|
111
|
-
if (parsed?.version === 1)
|
|
112
|
-
return {
|
|
143
|
+
if (parsed?.version === 1) {
|
|
144
|
+
return {
|
|
145
|
+
...emptyScanState(),
|
|
146
|
+
legacy: legacyTotals(parsed.buckets),
|
|
147
|
+
legacyUnsent: legacyUnsentBuckets(parsed.buckets, pairList(parsed.dirty)),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
113
150
|
if (parsed?.version !== 2)
|
|
114
151
|
return emptyScanState();
|
|
115
152
|
return {
|
|
@@ -119,9 +156,8 @@ export function loadScanState(file) {
|
|
|
119
156
|
seen: parsed.seen && typeof parsed.seen === 'object' ? parsed.seen : {},
|
|
120
157
|
dirty: pairList(parsed.dirty),
|
|
121
158
|
strikes: parsed.strikes && typeof parsed.strikes === 'object' ? parsed.strikes : {},
|
|
122
|
-
legacy: parsed.legacy
|
|
123
|
-
|
|
124
|
-
: {},
|
|
159
|
+
legacy: totalsRecord(parsed.legacy, (pair) => pair.includes('|')),
|
|
160
|
+
legacyUnsent: totalsRecord(parsed.legacyUnsent, isBucketKey),
|
|
125
161
|
};
|
|
126
162
|
}
|
|
127
163
|
/**
|
|
@@ -421,6 +457,10 @@ export function scanUsage(accounts, state, options = {}) {
|
|
|
421
457
|
for (const pair of Object.keys(state.legacy))
|
|
422
458
|
if (pendingDay(pair) < pass.cutoffDay)
|
|
423
459
|
delete state.legacy[pair];
|
|
460
|
+
for (const key of Object.keys(state.legacyUnsent)) {
|
|
461
|
+
if (dayOfBucket(key) < pass.cutoffDay)
|
|
462
|
+
delete state.legacyUnsent[key];
|
|
463
|
+
}
|
|
424
464
|
for (const pair of Object.keys(state.strikes))
|
|
425
465
|
if (!state.dirty.includes(pair))
|
|
426
466
|
delete state.strikes[pair];
|
|
@@ -449,9 +489,16 @@ function prune(state, cutoffDay, cutoffMs) {
|
|
|
449
489
|
/** The rows for the given days, in upload shape. Zero-token buckets are left out. */
|
|
450
490
|
export function rowsForDays(state, days) {
|
|
451
491
|
const wanted = new Set(days);
|
|
492
|
+
return bucketRows(state.buckets, (key) => wanted.has(dayOfBucket(key)));
|
|
493
|
+
}
|
|
494
|
+
/** The version-1 rows not yet uploaded ({@link ScanState.legacyUnsent}), in upload shape. */
|
|
495
|
+
export function legacyUnsentRows(state) {
|
|
496
|
+
return bucketRows(state.legacyUnsent, () => true);
|
|
497
|
+
}
|
|
498
|
+
function bucketRows(buckets, include) {
|
|
452
499
|
const rows = [];
|
|
453
|
-
for (const [key, totals] of Object.entries(
|
|
454
|
-
if (!
|
|
500
|
+
for (const [key, totals] of Object.entries(buckets)) {
|
|
501
|
+
if (!include(key) || isZero(totals))
|
|
455
502
|
continue;
|
|
456
503
|
const [day, accountKey, runtime, model, project] = JSON.parse(key);
|
|
457
504
|
rows.push({
|
package/dist/usage/service.d.ts
CHANGED
|
@@ -132,8 +132,20 @@ export declare class UsageService {
|
|
|
132
132
|
* {@link REPLACE_PROBE_INTERVAL_MS}; other pairs go out meanwhile. A pair
|
|
133
133
|
* whose rebuild counted less than version 1 had (a log removed or rewritten
|
|
134
134
|
* since) is not sent at all: its old rows are mis-attributed but total right.
|
|
135
|
+
*
|
|
136
|
+
* First, though, the version-1 rows version 1 never uploaded
|
|
137
|
+
* (`scan.legacyUnsent`) go out as they were, without `completeDays` — the
|
|
138
|
+
* server's copy of those pairs is behind, so it is not the right total
|
|
139
|
+
* until they land. A rebuilt complete pair sent after them replaces them.
|
|
135
140
|
*/
|
|
136
141
|
private uploadDirty;
|
|
142
|
+
/**
|
|
143
|
+
* Upload the version-1 rows version 1 had not uploaded, as plain rows (the
|
|
144
|
+
* upsert version 1 would have sent). A pair's rows go once the server takes
|
|
145
|
+
* them or never will (a permanent skip); `not_reported` waits for a report.
|
|
146
|
+
* Returns `false` when a call failed, so nothing else is sent this tick.
|
|
147
|
+
*/
|
|
148
|
+
private uploadLegacyUnsent;
|
|
137
149
|
/**
|
|
138
150
|
* Whether the server deletes the rows a complete day no longer carries: an
|
|
139
151
|
* empty body is answered with `replacedDays` only by one that does. A yes
|
package/dist/usage/service.js
CHANGED
|
@@ -17,7 +17,7 @@ import { Backoff } from './backoff.js';
|
|
|
17
17
|
import { resolveUsageKey, usageStateDir, writePrivateFile } from './config.js';
|
|
18
18
|
import { accountConfigDir } from './discovery.js';
|
|
19
19
|
import { buildReportFrame, defaultProber, probeAccounts } from './quota.js';
|
|
20
|
-
import { loadScanState, pendingAccount, pendingDay, pendingKey, rebuildFellShort, rowsForPending, saveScanState, scanUsage, uploadBatches, } from './scanner.js';
|
|
20
|
+
import { loadScanState, pendingAccount, pendingDay, legacyUnsentRows, pendingKey, rebuildFellShort, rowsForPending, saveScanState, scanUsage, uploadBatches, } from './scanner.js';
|
|
21
21
|
export const REPORTS_PATH = '/v1/usage/reports';
|
|
22
22
|
export const TOKEN_TOTALS_PATH = '/v1/usage/token-totals';
|
|
23
23
|
/** Tick cadence. */
|
|
@@ -193,7 +193,8 @@ export class UsageService {
|
|
|
193
193
|
// The state can run to megabytes; rewrite it only when a file was read.
|
|
194
194
|
if (scanned.filesRead > 0)
|
|
195
195
|
saveScanState(scanStatePath(this.env), this.scan);
|
|
196
|
-
|
|
196
|
+
const pending = this.scan.dirty.length > 0 || Object.keys(this.scan.legacyUnsent).length > 0;
|
|
197
|
+
if (this.totalsBackoff.ready() && pending) {
|
|
197
198
|
result.uploadedRows = await this.uploadDirty(api, machineId, machine);
|
|
198
199
|
}
|
|
199
200
|
}
|
|
@@ -236,6 +237,11 @@ export class UsageService {
|
|
|
236
237
|
* {@link REPLACE_PROBE_INTERVAL_MS}; other pairs go out meanwhile. A pair
|
|
237
238
|
* whose rebuild counted less than version 1 had (a log removed or rewritten
|
|
238
239
|
* since) is not sent at all: its old rows are mis-attributed but total right.
|
|
240
|
+
*
|
|
241
|
+
* First, though, the version-1 rows version 1 never uploaded
|
|
242
|
+
* (`scan.legacyUnsent`) go out as they were, without `completeDays` — the
|
|
243
|
+
* server's copy of those pairs is behind, so it is not the right total
|
|
244
|
+
* until they land. A rebuilt complete pair sent after them replaces them.
|
|
239
245
|
*/
|
|
240
246
|
async uploadDirty(api, machineId, machine) {
|
|
241
247
|
const scan = this.scan;
|
|
@@ -247,6 +253,10 @@ export class UsageService {
|
|
|
247
253
|
for (const pair of scan.dirty)
|
|
248
254
|
if (!pendingWithRows.has(pair))
|
|
249
255
|
done.add(pair);
|
|
256
|
+
if (!(await this.uploadLegacyUnsent(api, machineId, machine))) {
|
|
257
|
+
saveScanState(scanStatePath(this.env), scan);
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
250
260
|
const legacyReady = new Set(ready.map((r) => pendingKey(r.day, r.accountKey)).filter((pair) => scan.legacy[pair] !== undefined));
|
|
251
261
|
if (legacyReady.size > 0) {
|
|
252
262
|
if (!(await this.serverReplacesDays(api, machineId, machine))) {
|
|
@@ -341,6 +351,41 @@ export class UsageService {
|
|
|
341
351
|
saveScanState(scanStatePath(this.env), scan);
|
|
342
352
|
return sent;
|
|
343
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* Upload the version-1 rows version 1 had not uploaded, as plain rows (the
|
|
356
|
+
* upsert version 1 would have sent). A pair's rows go once the server takes
|
|
357
|
+
* them or never will (a permanent skip); `not_reported` waits for a report.
|
|
358
|
+
* Returns `false` when a call failed, so nothing else is sent this tick.
|
|
359
|
+
*/
|
|
360
|
+
async uploadLegacyUnsent(api, machineId, machine) {
|
|
361
|
+
const scan = this.scan;
|
|
362
|
+
const rows = legacyUnsentRows(scan).filter((r) => this.reportedKeys.has(r.accountKey));
|
|
363
|
+
for (const batch of uploadBatches(rows)) {
|
|
364
|
+
const body = { machineId, machine, days: batch.rows };
|
|
365
|
+
const response = await postJson(api, TOKEN_TOTALS_PATH, body, undefined, true);
|
|
366
|
+
this.note(this.totalsBackoff, response);
|
|
367
|
+
const acceptance = response.ok ? parseAcceptance(response.body, batch.rows.length) : { accepted: 0 };
|
|
368
|
+
this.status.lastTotals = { ...this.callRecord(response, batch.rows.length), accepted: acceptance.accepted };
|
|
369
|
+
if (!response.ok)
|
|
370
|
+
return false;
|
|
371
|
+
const settled = new Set();
|
|
372
|
+
for (const row of batch.rows) {
|
|
373
|
+
const pair = pendingKey(row.day, row.accountKey);
|
|
374
|
+
const taken = acceptance.keys ? acceptance.keys.has(row.accountKey) : acceptance.accepted >= batch.rows.length;
|
|
375
|
+
const reason = acceptance.skipped?.get(row.accountKey);
|
|
376
|
+
if ((taken && batch.last.includes(pair)) || (reason && PERMANENT_SKIPS.has(reason)))
|
|
377
|
+
settled.add(pair);
|
|
378
|
+
else if (!taken && reason !== 'throttled')
|
|
379
|
+
this.reportedKeys.delete(row.accountKey);
|
|
380
|
+
}
|
|
381
|
+
for (const key of Object.keys(scan.legacyUnsent)) {
|
|
382
|
+
const [day, accountKey] = JSON.parse(key);
|
|
383
|
+
if (settled.has(pendingKey(day, accountKey)))
|
|
384
|
+
delete scan.legacyUnsent[key];
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
344
389
|
/**
|
|
345
390
|
* Whether the server deletes the rows a complete day no longer carries: an
|
|
346
391
|
* empty body is answered with `replacedDays` only by one that does. A yes
|
package/dist/version.d.ts
CHANGED
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
* `package.json`, so a release bump that forgets this file fails the suite
|
|
8
8
|
* instead of shipping a `User-Agent` that lies about which build is calling.
|
|
9
9
|
*/
|
|
10
|
-
export declare const CLI_VERSION = "0.10.
|
|
10
|
+
export declare const CLI_VERSION = "0.10.3";
|
|
11
11
|
/** Sent on every HTTP request the CLI makes back into ProhostAI. */
|
|
12
|
-
export declare const USER_AGENT = "prohost-cli/0.10.
|
|
12
|
+
export declare const USER_AGENT = "prohost-cli/0.10.3";
|
package/dist/version.js
CHANGED
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
* `package.json`, so a release bump that forgets this file fails the suite
|
|
8
8
|
* instead of shipping a `User-Agent` that lies about which build is calling.
|
|
9
9
|
*/
|
|
10
|
-
export const CLI_VERSION = '0.10.
|
|
10
|
+
export const CLI_VERSION = '0.10.3';
|
|
11
11
|
/** Sent on every HTTP request the CLI makes back into ProhostAI. */
|
|
12
12
|
export const USER_AGENT = `prohost-cli/${CLI_VERSION}`;
|