@tiny-fish/cli 0.51.1 → 0.51.2-next.417
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/dist/lib/connect-all-auth.js +1 -1
- package/dist/lib/connect-runtime.js +25 -9
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.js +2 -0
- package/dist/lib/harness/harness-spec.d.ts +8 -0
- package/dist/lib/harness/harness-spec.js +6 -1
- package/dist/lib/hermes-env.js +5 -2
- package/package.json +1 -1
|
@@ -86,7 +86,7 @@ export function mapConnectError(base, e, oauthBudget, spentBrowserSlot, fixComma
|
|
|
86
86
|
if (e instanceof ConnectStepError && e.failureReason === 'harness_not_installed') {
|
|
87
87
|
return { ...base, detected: false, outcome: 'not_installed' };
|
|
88
88
|
}
|
|
89
|
-
//
|
|
89
|
+
// Every too-old message already carries its upgrade nudge.
|
|
90
90
|
if (e instanceof ConnectStepError && TOO_OLD_REASONS.has(e.failureReason)) {
|
|
91
91
|
return { ...base, outcome: 'harness_too_old', errorMessage: e.message, fixCommand };
|
|
92
92
|
}
|
|
@@ -4,6 +4,7 @@ import { CONNECT_ATTEMPT_ENV, isAttemptId, resolvedApiKey, takePendingConnectAtt
|
|
|
4
4
|
import { CLI_INVOCATION_ID, CLI_VERSION } from './constants.js';
|
|
5
5
|
import { detectHarness, detectHumanInitiated, detectRuntimeEnv } from './harness.js';
|
|
6
6
|
import { boundedVersion, errLine, sanitizeLine } from './output.js';
|
|
7
|
+
import { isOlder } from './cli-presence.js';
|
|
7
8
|
import { postConnectEvent, telemetryDisabled } from './setup-telemetry.js';
|
|
8
9
|
import { installSignalGuard } from './signals.js';
|
|
9
10
|
export const NON_INTERACTIVE_TIMEOUT_MS = 10_000;
|
|
@@ -179,13 +180,19 @@ export async function runGuarded(state, telemetry, body) {
|
|
|
179
180
|
function probeTimeoutMs(client) {
|
|
180
181
|
return client.supportCheck.timeoutMs ?? NON_INTERACTIVE_TIMEOUT_MS;
|
|
181
182
|
}
|
|
183
|
+
/** Undefined when either side is unknown; callers pick the safe default. */
|
|
184
|
+
function isBelowMin(version, minVersion) {
|
|
185
|
+
// Hermes prints `Hermes Agent v0.22.4+33.g3fa571a (2026.9.24)`; compare the number only.
|
|
186
|
+
const number = version && /\d+(?:\.\d+)+(?:-[0-9A-Za-z.]+)?/.exec(version)?.[0];
|
|
187
|
+
if (!number || !minVersion)
|
|
188
|
+
return undefined;
|
|
189
|
+
return isOlder(number, minVersion);
|
|
190
|
+
}
|
|
182
191
|
// Flags go unseen for reasons besides age; state facts, not causes.
|
|
183
192
|
function unavailableMessage(client, version) {
|
|
184
193
|
const { minVersion } = client.supportCheck;
|
|
185
194
|
const found = version ? ` (found ${version})` : '';
|
|
186
|
-
|
|
187
|
-
const belowMin = minVersion && (!version || version.localeCompare(minVersion, 'en', { numeric: true }) < 0);
|
|
188
|
-
const required = belowMin
|
|
195
|
+
const required = minVersion && (isBelowMin(version, minVersion) ?? version === undefined)
|
|
189
196
|
? ` ${client.displayName} ${minVersion} or newer is required${found}.`
|
|
190
197
|
: '';
|
|
191
198
|
return (`${client.supportCheck.unavailableMessage}${required}` +
|
|
@@ -202,6 +209,7 @@ function throwProbeFailure(client, result) {
|
|
|
202
209
|
// It ran and exited non-zero, so the version is still answerable.
|
|
203
210
|
debugProbeOutput(client, sanitizeLine(`${result.stdout ?? ''}\n${result.stderr ?? ''}`));
|
|
204
211
|
const harnessVersion = probeHarnessVersion(client);
|
|
212
|
+
requireMinVersion(client, harnessVersion);
|
|
205
213
|
throw new ConnectStepError(unavailableMessage(client, harnessVersion), 'harness_command_unsupported', {
|
|
206
214
|
cause: result.error,
|
|
207
215
|
harnessVersion,
|
|
@@ -236,6 +244,7 @@ function requireEssential(client, output) {
|
|
|
236
244
|
return;
|
|
237
245
|
debugProbeOutput(client, output);
|
|
238
246
|
const harnessVersion = probeHarnessVersion(client);
|
|
247
|
+
requireMinVersion(client, harnessVersion);
|
|
239
248
|
throw new ConnectStepError(unavailableMessage(client, harnessVersion), 'harness_too_old', {
|
|
240
249
|
harnessVersion,
|
|
241
250
|
});
|
|
@@ -270,12 +279,19 @@ export function requireCommandSupport(client) {
|
|
|
270
279
|
const keyAuthSupported = keyAuthPattern ? keyAuthPattern.test(output) : true;
|
|
271
280
|
if (!optionalSupported || !keyAuthSupported)
|
|
272
281
|
debugProbeOutput(client, output);
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
282
|
+
const matchedVariant = resolveVariant(client, output);
|
|
283
|
+
const harnessVersion = probeHarnessVersion(client);
|
|
284
|
+
requireMinVersion(client, harnessVersion);
|
|
285
|
+
return { optionalSupported, keyAuthSupported, matchedVariant, harnessVersion };
|
|
286
|
+
}
|
|
287
|
+
// Old releases can list the flags yet mishandle them; unknown passes.
|
|
288
|
+
function requireMinVersion(client, harnessVersion) {
|
|
289
|
+
const { minVersion, updateCommand, enforceMinVersion } = client.supportCheck;
|
|
290
|
+
if (!enforceMinVersion || !isBelowMin(harnessVersion, minVersion))
|
|
291
|
+
return;
|
|
292
|
+
const fix = updateCommand ? `Run \`${updateCommand}\`` : `Update ${client.displayName}`;
|
|
293
|
+
throw new ConnectStepError(`${client.displayName} ${minVersion} or newer is required (found ${harnessVersion}). ` +
|
|
294
|
+
`${fix} and retry.`, 'harness_too_old', { harnessVersion });
|
|
279
295
|
}
|
|
280
296
|
/** Best-effort; the server rejects non-printable characters and >32 chars. */
|
|
281
297
|
function probeHarnessVersion(client) {
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -18,5 +18,6 @@ export declare const API_URL_OVERRIDE: string | undefined;
|
|
|
18
18
|
export declare function getDashboardUrl(source?: string): string;
|
|
19
19
|
export declare const DASHBOARD_URL: string;
|
|
20
20
|
export declare const HARNESS_PROBE_TIMEOUT_MS = 15000;
|
|
21
|
+
export declare const HERMES_COLD_START_TIMEOUT_MS = 60000;
|
|
21
22
|
/** Hermes' own id for the TinyFish web plugin. */
|
|
22
23
|
export declare const HERMES_PLUGIN_NAME = "tinyfish";
|
package/dist/lib/constants.js
CHANGED
|
@@ -62,5 +62,7 @@ export function getDashboardUrl(source = DEFAULT_DASHBOARD_SOURCE) {
|
|
|
62
62
|
}
|
|
63
63
|
export const DASHBOARD_URL = getDashboardUrl();
|
|
64
64
|
export const HARNESS_PROBE_TIMEOUT_MS = 15_000;
|
|
65
|
+
// A cold Hermes installs its Python venv first, measured 8.8-11s locally.
|
|
66
|
+
export const HERMES_COLD_START_TIMEOUT_MS = 60_000;
|
|
65
67
|
/** Hermes' own id for the TinyFish web plugin. */
|
|
66
68
|
export const HERMES_PLUGIN_NAME = 'tinyfish';
|
|
@@ -16,6 +16,10 @@ export interface HarnessSupportCheck {
|
|
|
16
16
|
timeoutMs?: number;
|
|
17
17
|
/** First release with the probed flags; bisected upstream, not derivable. */
|
|
18
18
|
minVersion?: string;
|
|
19
|
+
/** Refuse below minVersion even when the probed flags are listed. */
|
|
20
|
+
enforceMinVersion?: true;
|
|
21
|
+
/** Shown in the below-minVersion error as the one-step fix. */
|
|
22
|
+
updateCommand?: string;
|
|
19
23
|
unavailableMessage: string;
|
|
20
24
|
}
|
|
21
25
|
/** One entry per harness: every per-harness fact, and no behaviour. */
|
|
@@ -214,6 +218,10 @@ export declare const HARNESS_SPECS: {
|
|
|
214
218
|
args: string[];
|
|
215
219
|
patterns: RegExp[];
|
|
216
220
|
keyAuthPattern: RegExp;
|
|
221
|
+
timeoutMs: number;
|
|
222
|
+
minVersion: string;
|
|
223
|
+
enforceMinVersion: true;
|
|
224
|
+
updateCommand: string;
|
|
217
225
|
unavailableMessage: string;
|
|
218
226
|
};
|
|
219
227
|
urlStyle: "flag";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HERMES_PLUGIN_NAME } from '../constants.js';
|
|
1
|
+
import { HERMES_COLD_START_TIMEOUT_MS, HERMES_PLUGIN_NAME } from '../constants.js';
|
|
2
2
|
import { CLAUDE_CODE_DEFERRED_AUTH_NOTE, CLAUDE_CODE_KEYED_FALLBACK_NOTE, CLINE_MCP_ADD_UNAVAILABLE_MESSAGE, CODEX_DEFERRED_AUTH_NOTE, CODEX_KEYED_FALLBACK_NOTE, CODEX_MCP_URL_UNAVAILABLE_MESSAGE, GROK_HTTP_UNAVAILABLE_MESSAGE, GROK_SIGN_IN_HINT, HERMES_OAUTH_UNAVAILABLE_MESSAGE, HERMES_RESTART_NOTE, KILO_MCP_ADD_UNAVAILABLE_MESSAGE, MCP_ADD_UNAVAILABLE_MESSAGE, OPENCLAW_SKILL_UNAVAILABLE_MESSAGE, OPENCODE_MCP_ADD_UNAVAILABLE_MESSAGE, OPENCODE_MODEL_NOTE, } from './harness-messages.js';
|
|
3
3
|
const HEADER_FLAG = /(?:^|\s)--header(?:[\s<=]|$)/m;
|
|
4
4
|
/** One entry per harness; every per-harness list derives from it. */
|
|
@@ -140,6 +140,11 @@ export const HARNESS_SPECS = {
|
|
|
140
140
|
args: ['mcp', 'add', '--help'],
|
|
141
141
|
patterns: [/--auth\s+\{[^}]*oauth[^}]*\}/],
|
|
142
142
|
keyAuthPattern: /--auth\s+\{[^}]*header[^}]*\}/,
|
|
143
|
+
timeoutMs: HERMES_COLD_START_TIMEOUT_MS,
|
|
144
|
+
// Older `config set` saves our JSON entry as an unusable string.
|
|
145
|
+
minVersion: '0.21.2',
|
|
146
|
+
enforceMinVersion: true,
|
|
147
|
+
updateCommand: 'hermes update',
|
|
143
148
|
unavailableMessage: HERMES_OAUTH_UNAVAILABLE_MESSAGE,
|
|
144
149
|
},
|
|
145
150
|
urlStyle: 'flag',
|
package/dist/lib/hermes-env.js
CHANGED
|
@@ -3,7 +3,8 @@ import path from 'node:path';
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
5
|
import spawn from 'cross-spawn';
|
|
6
|
-
import {
|
|
6
|
+
import { HERMES_COLD_START_TIMEOUT_MS } from './constants.js';
|
|
7
|
+
import { throwIfInterrupted } from './connect-runtime.js';
|
|
7
8
|
import { sanitizeLine } from './output.js';
|
|
8
9
|
// display_hermes_home() abbreviates under $HOME, so the value is not always absolute.
|
|
9
10
|
const HERMES_HOME_LINE = /^\s*hermes_home:\s*(\S.*?)\s*$/m;
|
|
@@ -29,8 +30,10 @@ function probeHermesHome() {
|
|
|
29
30
|
const result = spawn.sync('hermes', ['dump'], {
|
|
30
31
|
encoding: 'utf8',
|
|
31
32
|
env: { ...process.env, FORCE_COLOR: '0', NO_COLOR: '1' },
|
|
32
|
-
timeout:
|
|
33
|
+
timeout: HERMES_COLD_START_TIMEOUT_MS,
|
|
33
34
|
});
|
|
35
|
+
// Ctrl+C would otherwise read as `exit` and be cached.
|
|
36
|
+
throwIfInterrupted(result);
|
|
34
37
|
if (result.error?.code === 'ETIMEDOUT') {
|
|
35
38
|
return { reason: 'timeout' };
|
|
36
39
|
}
|