@tiny-fish/cli 0.57.0 → 0.57.1-next.465

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 (52) hide show
  1. package/dist/commands/auth.js +2 -2
  2. package/dist/commands/connect.js +3 -3
  3. package/dist/commands/onboard.js +1 -1
  4. package/dist/commands/profile.js +1 -1
  5. package/dist/commands/upgrade.js +1 -1
  6. package/dist/lib/claude-plugin.js +1 -1
  7. package/dist/lib/cli-install.js +1 -1
  8. package/dist/lib/config/connect-config-file.d.ts +2 -2
  9. package/dist/lib/config/connect-config-file.js +4 -4
  10. package/dist/lib/config/omp-config.js +1 -1
  11. package/dist/lib/{connect-all-auth.js → connect/connect-all-auth.js} +3 -3
  12. package/dist/lib/{connect-all-summary.js → connect/connect-all-summary.js} +2 -2
  13. package/dist/lib/{connect-all-uninstall.d.ts → connect/connect-all-uninstall.d.ts} +1 -1
  14. package/dist/lib/{connect-all-uninstall.js → connect/connect-all-uninstall.js} +15 -15
  15. package/dist/lib/{connect-all.d.ts → connect/connect-all.d.ts} +2 -2
  16. package/dist/lib/{connect-all.js → connect/connect-all.js} +11 -11
  17. package/dist/lib/{connect-auth.js → connect/connect-auth.js} +3 -3
  18. package/dist/lib/{connect-clients.d.ts → connect/connect-clients.d.ts} +2 -2
  19. package/dist/lib/{connect-clients.js → connect/connect-clients.js} +10 -10
  20. package/dist/lib/{connect-fallback.js → connect/connect-fallback.js} +5 -5
  21. package/dist/lib/{connect-harness.js → connect/connect-harness.js} +2 -2
  22. package/dist/lib/{connect-native.js → connect/connect-native.js} +38 -17
  23. package/dist/lib/{connect-openclaw.js → connect/connect-openclaw.js} +4 -4
  24. package/dist/lib/{connect-picker.d.ts → connect/connect-picker.d.ts} +1 -1
  25. package/dist/lib/{connect-picker.js → connect/connect-picker.js} +1 -1
  26. package/dist/lib/{connect-preflight.d.ts → connect/connect-preflight.d.ts} +1 -1
  27. package/dist/lib/{connect-preflight.js → connect/connect-preflight.js} +6 -6
  28. package/dist/lib/{connect-runtime.d.ts → connect/connect-runtime.d.ts} +9 -4
  29. package/dist/lib/{connect-runtime.js → connect/connect-runtime.js} +26 -9
  30. package/dist/lib/{connect-steps.d.ts → connect/connect-steps.d.ts} +1 -1
  31. package/dist/lib/{connect-steps.js → connect/connect-steps.js} +5 -5
  32. package/dist/lib/doctor-repairs.js +2 -2
  33. package/dist/lib/hermes-env.js +1 -1
  34. package/dist/lib/hermes-plugin.js +1 -1
  35. package/dist/lib/registration-detect.d.ts +1 -1
  36. package/dist/lib/registration-detect.js +1 -1
  37. package/dist/lib/setup-telemetry.d.ts +2 -0
  38. package/dist/lib/setup-telemetry.js +4 -2
  39. package/dist/lib/sign-in-url.d.ts +1 -1
  40. package/dist/lib/skill-install.d.ts +1 -1
  41. package/dist/lib/skill-install.js +2 -2
  42. package/dist/lib/skill-vendor.js +1 -1
  43. package/dist/lib/suggested-prompt.d.ts +12 -0
  44. package/dist/lib/suggested-prompt.js +17 -0
  45. package/package.json +1 -1
  46. /package/dist/lib/{connect-all-auth.d.ts → connect/connect-all-auth.d.ts} +0 -0
  47. /package/dist/lib/{connect-all-summary.d.ts → connect/connect-all-summary.d.ts} +0 -0
  48. /package/dist/lib/{connect-auth.d.ts → connect/connect-auth.d.ts} +0 -0
  49. /package/dist/lib/{connect-fallback.d.ts → connect/connect-fallback.d.ts} +0 -0
  50. /package/dist/lib/{connect-harness.d.ts → connect/connect-harness.d.ts} +0 -0
  51. /package/dist/lib/{connect-native.d.ts → connect/connect-native.d.ts} +0 -0
  52. /package/dist/lib/{connect-openclaw.d.ts → connect/connect-openclaw.d.ts} +0 -0
@@ -2,8 +2,8 @@ import { spawn } from 'child_process';
2
2
  import * as readline from 'readline';
3
3
  import { Option } from 'commander';
4
4
  import { CONNECT_ATTEMPT_ENV, clearConfig, getDashboardUrl, loadConfig, maskKey, persistApiKeyToEnvironment, savePendingConnectAttempt, saveConfig, validateKeyFormat, } from '../lib/auth.js';
5
- import { createStdinPrompt } from '../lib/connect-fallback.js';
6
- import { ConnectInterruptedError } from '../lib/connect-runtime.js';
5
+ import { createStdinPrompt } from '../lib/connect/connect-fallback.js';
6
+ import { ConnectInterruptedError } from '../lib/connect/connect-runtime.js';
7
7
  import { TINYFISH_API_KEY_VAR } from '../lib/constants.js';
8
8
  import { err, errLine, out, outLine, warnLine } from '../lib/output.js';
9
9
  import { verifyMcpAuth } from '../lib/verify.js';
@@ -2,16 +2,16 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { Option } from 'commander';
4
4
  import { saveConnectConfigDir, validateKeyFormat, validatedApiKey } from '../lib/auth.js';
5
- import { runConnectAll } from '../lib/connect-all.js';
5
+ import { runConnectAll } from '../lib/connect/connect-all.js';
6
6
  import { ALL_HARNESSES } from '../lib/harness/harness-detect.js';
7
7
  import { HARNESS_CHOICES, resolveHarnessName } from '../lib/harness/harness-spec.js';
8
8
  import { detectHumanInitiated } from '../lib/harness.js';
9
9
  import { emitNotice } from '../lib/notice.js';
10
10
  import { errLine } from '../lib/output.js';
11
11
  import { z } from 'zod';
12
- import { gateApiKey } from '../lib/connect-preflight.js';
12
+ import { gateApiKey } from '../lib/connect/connect-preflight.js';
13
13
  import { DEFAULT_MCP_URL } from '../lib/mcp-endpoint.js';
14
- import { connectHarness } from '../lib/connect-harness.js';
14
+ import { connectHarness } from '../lib/connect/connect-harness.js';
15
15
  // The route 400s anything else, losing the event; drop it instead.
16
16
  const TRIGGER_FORMAT = /^[a-z0-9-]{1,32}$/;
17
17
  /** Cline reads CLINE_DIR itself, so setting it steers the add, the remove and our own probe. */
@@ -3,7 +3,7 @@ import { getApiKey, saveConfig } from '../lib/auth.js';
3
3
  import { fetchContentGet, searchQuery } from '../lib/client.js';
4
4
  import { BASE_URL, TINYFISH_API_KEY_VAR } from '../lib/constants.js';
5
5
  import { errLine, handleApiError, outLine } from '../lib/output.js';
6
- import { connectHarness, launchAgent } from '../lib/connect-harness.js';
6
+ import { connectHarness, launchAgent } from '../lib/connect/connect-harness.js';
7
7
  import { HARNESS_DISPLAY_NAMES } from '../lib/harness/harness-detect.js';
8
8
  const EXAMPLE_QUERIES = [
9
9
  'What are recent changes in the AI dev stack? Give me the top 5 changes that matter, why they matter, and any action needed.',
@@ -354,7 +354,7 @@ function signInNextStep(profileId) {
354
354
  async function handOffSignIn(profile, opts, created) {
355
355
  const setupUrl = profileSetupUrl(profile.id, opts.site);
356
356
  if (detectHumanInitiated()) {
357
- const { openExternalUrl } = await import('../lib/connect-clients.js');
357
+ const { openExternalUrl } = await import('../lib/connect/connect-clients.js');
358
358
  openExternalUrl(setupUrl);
359
359
  }
360
360
  if (!opts.pretty) {
@@ -8,7 +8,7 @@ import { sendUpgradeCompleted, telemetryDisabled, } from '../lib/setup-telemetry
8
8
  import { installSignalGuard, SIGNAL_EXIT_CODES } from '../lib/signals.js';
9
9
  import { installTinyFishCli } from '../lib/cli-install.js';
10
10
  import { updateWebSkill } from '../lib/skill-install.js';
11
- import { ConnectInterruptedError } from '../lib/connect-runtime.js';
11
+ import { ConnectInterruptedError } from '../lib/connect/connect-runtime.js';
12
12
  const VERSION_READ_TIMEOUT_MS = 2_000;
13
13
  const INTERRUPTED_MESSAGE = 'Upgrade interrupted — run `tinyfish upgrade` again to finish.';
14
14
  function attempt(label, run) {
@@ -2,7 +2,7 @@ import spawn from 'cross-spawn';
2
2
  import { z } from 'zod';
3
3
  import { loadConfig, matchesCliKey } from './auth.js';
4
4
  import { captureStdio, capturedOutput, replay } from './cli-install.js';
5
- import { throwIfInterrupted } from './connect-runtime.js';
5
+ import { throwIfInterrupted } from './connect/connect-runtime.js';
6
6
  import { CLAUDE_PLUGIN_ID, HARNESS_PROBE_TIMEOUT_MS, PLUGIN_CONNECT_ATTEMPT_VAR, TINYFISH_API_KEY_VAR, } from './constants.js';
7
7
  import { claudeSettingsPath, readSettingsEnv, writeSettingsEnv } from './config/claude-config.js';
8
8
  import { noColourEnv, parseJson } from './output.js';
@@ -1,5 +1,5 @@
1
1
  import spawn from 'cross-spawn';
2
- import { spawnStepError } from './connect-runtime.js';
2
+ import { spawnStepError } from './connect/connect-runtime.js';
3
3
  import { TINYFISH_CLI_PACKAGE } from './constants.js';
4
4
  import { installRoot } from './install-root.js';
5
5
  import { errLine } from './output.js';
@@ -1,5 +1,5 @@
1
- import { type OnWalkthroughDecided, type WalkthroughOutcome } from '../connect-clients.js';
2
- import { type ConnectAuthMode } from '../connect-runtime.js';
1
+ import { type OnWalkthroughDecided, type WalkthroughOutcome } from '../connect/connect-clients.js';
2
+ import { type ConnectAuthMode } from '../connect/connect-runtime.js';
3
3
  import { cursorMcpPath, writeCursorMcpConfig } from './cursor-config.js';
4
4
  import { commandCodeMcpPath, writeCommandCodeMcpConfig } from './command-code-config.js';
5
5
  import { ompMcpPath, writeOmpMcpConfig } from './omp-config.js';
@@ -1,9 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import { CONNECT_SOURCE, saveConnectContext, validatedApiKey } from '../auth.js';
3
- import { CURSOR_SKILL_TARGET, KEYLESS_ONBOARDING_PROMPT, launchCommandCodeWalkthrough, launchOmpWalkthrough, launchPiWalkthrough, openExternalUrl, } from '../connect-clients.js';
4
- import { ensureCliAuthenticated } from '../connect-auth.js';
3
+ import { CURSOR_SKILL_TARGET, KEYLESS_ONBOARDING_PROMPT, launchCommandCodeWalkthrough, launchOmpWalkthrough, launchPiWalkthrough, openExternalUrl, } from '../connect/connect-clients.js';
4
+ import { ensureCliAuthenticated } from '../connect/connect-auth.js';
5
5
  import { installWebSkill } from '../skill-install.js';
6
- import { ConnectStepError, createConnectTelemetry, runGuarded, settle, } from '../connect-runtime.js';
6
+ import { ConnectStepError, createConnectTelemetry, runGuarded, settle, } from '../connect/connect-runtime.js';
7
7
  import { cursorInstallDeeplink, cursorMcpPath, readCursorTinyfishEntry, writeCursorMcpConfig, } from './cursor-config.js';
8
8
  import { commandCodeMcpPath, readCommandCodeTinyfishEntry, writeCommandCodeMcpConfig, } from './command-code-config.js';
9
9
  import { ompMcpPath, readOmpTinyfishEntry, writeOmpMcpConfig } from './omp-config.js';
@@ -14,7 +14,7 @@ import { detectHumanInitiated } from '../harness.js';
14
14
  import { errLine } from '../output.js';
15
15
  import { verifyMcpAuth } from '../verify.js';
16
16
  import { apiBaseFromMcpUrl } from '../mcp-endpoint.js';
17
- import { finishSetupHint, requireKeylessMcp, trackPostInstallFailure, walkthroughPhase, } from '../connect-steps.js';
17
+ import { finishSetupHint, requireKeylessMcp, trackPostInstallFailure, walkthroughPhase, } from '../connect/connect-steps.js';
18
18
  const PI_RELOAD_COPY = 'TinyFish is configured in pi. Restart pi, then run `/mcp-auth tinyfish` there if it asks you ' +
19
19
  'to sign in.';
20
20
  // The skill is the working path either way, so the note must not read as a failure.
@@ -1,6 +1,6 @@
1
1
  import * as path from 'path';
2
2
  import spawn from 'cross-spawn';
3
- import { ConnectStepError } from '../connect-runtime.js';
3
+ import { ConnectStepError } from '../connect/connect-runtime.js';
4
4
  import { HARNESS_PROBE_TIMEOUT_MS } from '../constants.js';
5
5
  import { buildTinyfishKeylessServerEntry, planWrite, readTinyfishEntry, removeServer, writeMcpConfig, } from './mcp-json-config.js';
6
6
  const UNRESOLVED_REASON = '`omp config path` did not report a config directory';
@@ -1,8 +1,8 @@
1
1
  import { NATIVE_BY_HARNESS } from './connect-clients.js';
2
- import { harnessSpec } from './harness/harness-spec.js';
2
+ import { harnessSpec } from '../harness/harness-spec.js';
3
3
  import { ConnectInterruptedError, ConnectStepError, SignInTimeoutError, probeSupportVariant, } from './connect-runtime.js';
4
- import { ALL_HARNESSES, HARNESS_DISPLAY_NAMES as DISPLAY_NAMES, } from './harness/harness-detect.js';
5
- import { errLine } from './output.js';
4
+ import { ALL_HARNESSES, HARNESS_DISPLAY_NAMES as DISPLAY_NAMES, } from '../harness/harness-detect.js';
5
+ import { errLine } from '../output.js';
6
6
  // Must undercut agent tool-call budgets (Claude Code Bash defaults to 120s).
7
7
  export const OAUTH_SIGN_IN_TIMEOUT_MS = 90_000;
8
8
  // A probe that exits non-zero is an install so old the subcommand is missing entirely.
@@ -1,6 +1,6 @@
1
1
  import { finishSetupCommand } from './connect-runtime.js';
2
- import { harnessSpec } from './harness/harness-spec.js';
3
- import { HARNESS_COMMANDS, HARNESS_DISPLAY_NAMES as DISPLAY_NAMES, RELOAD_ACTION, } from './harness/harness-detect.js';
2
+ import { harnessSpec } from '../harness/harness-spec.js';
3
+ import { HARNESS_COMMANDS, HARNESS_DISPLAY_NAMES as DISPLAY_NAMES, RELOAD_ACTION, } from '../harness/harness-detect.js';
4
4
  // Naming a harness the user does not have is the noise PF-3708 cut.
5
5
  const HIDDEN_ONCE_SOMETHING_WORKED = new Set([
6
6
  'deselected',
@@ -1,4 +1,4 @@
1
- import { type Harness } from './harness/harness-detect.js';
1
+ import { type Harness } from '../harness/harness-detect.js';
2
2
  import type { HarnessRunResult } from './connect-all.js';
3
3
  export declare function planText(harness: Harness, mcpUrl: string, apiKey?: string): string;
4
4
  export declare function uninstallPlanText(harness: Harness): string;
@@ -1,21 +1,21 @@
1
1
  import * as path from 'path';
2
- import { clearConnectContext, connectContextState } from './auth.js';
2
+ import { clearConnectContext, connectContextState } from '../auth.js';
3
3
  import { NATIVE_BY_HARNESS, openclawSkillUninstall } from './connect-clients.js';
4
4
  import { ConnectInterruptedError, spawnRemoval } from './connect-runtime.js';
5
- import { removeCursorMcpServer, planCursorWrite } from './config/cursor-config.js';
6
- import { commandCodeMcpPath, planCommandCodeWrite, removeCommandCodeMcpServer, } from './config/command-code-config.js';
7
- import { planOmpWrite, removeOmpMcpServer } from './config/omp-config.js';
8
- import { piMcpPath, planPiWrite, removePiMcpServer } from './config/pi-config.js';
9
- import { HERMES_KEY_VAR, hermesEnvPath, removeHermesKey, resolveHermesHome } from './hermes-env.js';
10
- import { clearHermesWebBackends } from './hermes-plugin.js';
11
- import { removeClaudeSettingsKey } from './claude-plugin.js';
12
- import { claudeSettingsPath } from './config/claude-config.js';
13
- import { HARNESS_DISPLAY_NAMES as DISPLAY_NAMES, harnessDisplayPath, } from './harness/harness-detect.js';
14
- import { ALL_HARNESSES, harnessSpec } from './harness/harness-spec.js';
15
- import { skillRootDir } from './skill-paths.js';
16
- import { removeWebSkills } from './skill-vendor.js';
17
- import { isOpencodeStyle, opencodeStyleConfigPath } from './config/opencode-config.js';
18
- import { errLine } from './output.js';
5
+ import { removeCursorMcpServer, planCursorWrite } from '../config/cursor-config.js';
6
+ import { commandCodeMcpPath, planCommandCodeWrite, removeCommandCodeMcpServer, } from '../config/command-code-config.js';
7
+ import { planOmpWrite, removeOmpMcpServer } from '../config/omp-config.js';
8
+ import { piMcpPath, planPiWrite, removePiMcpServer } from '../config/pi-config.js';
9
+ import { HERMES_KEY_VAR, hermesEnvPath, removeHermesKey, resolveHermesHome, } from '../hermes-env.js';
10
+ import { clearHermesWebBackends } from '../hermes-plugin.js';
11
+ import { removeClaudeSettingsKey } from '../claude-plugin.js';
12
+ import { claudeSettingsPath } from '../config/claude-config.js';
13
+ import { HARNESS_DISPLAY_NAMES as DISPLAY_NAMES, harnessDisplayPath, } from '../harness/harness-detect.js';
14
+ import { ALL_HARNESSES, harnessSpec } from '../harness/harness-spec.js';
15
+ import { skillRootDir } from '../skill-paths.js';
16
+ import { removeWebSkills } from '../skill-vendor.js';
17
+ import { isOpencodeStyle, opencodeStyleConfigPath } from '../config/opencode-config.js';
18
+ import { errLine } from '../output.js';
19
19
  export function planText(harness, mcpUrl, apiKey) {
20
20
  if (harness === 'cursor')
21
21
  return planCursorWrite(mcpUrl, apiKey);
@@ -1,5 +1,5 @@
1
- import { type Harness, type HarnessDetection } from './harness/harness-detect.js';
2
- import { type VerifyDepth } from './verify.js';
1
+ import { type Harness, type HarnessDetection } from '../harness/harness-detect.js';
2
+ import { type VerifyDepth } from '../verify.js';
3
3
  export type Outcome = 'not_detected' | 'not_installed' | 'stale_config' | 'needs_first_run' | 'installed' | 'failed' | 'harness_too_old' | 'interrupted' | 'auth_pending' | 'no_tty_auth_skip' | 'uninstalled' | 'uninstall_noop' | 'uninstall_pointer' | 'dry_run' | 'not_reached' | 'deselected';
4
4
  export type HarnessResultBase = {
5
5
  harness: Harness;
@@ -1,11 +1,11 @@
1
- import { CLAUDE_PLUGIN_SERVER, connectedViaClaudePlugin } from './claude-plugin.js';
1
+ import { CLAUDE_PLUGIN_SERVER, connectedViaClaudePlugin } from '../claude-plugin.js';
2
2
  import * as readline from 'node:readline/promises';
3
- import { harnessSpec } from './harness/harness-spec.js';
3
+ import { harnessSpec } from '../harness/harness-spec.js';
4
4
  import spawn from 'cross-spawn';
5
5
  import { connectHarness } from './connect-harness.js';
6
- import { loadConfig, validatedApiKey } from './auth.js';
7
- import { installTinyFishCli, } from './cli-install.js';
8
- import { cliInstallNeeded } from './cli-presence.js';
6
+ import { loadConfig, validatedApiKey } from '../auth.js';
7
+ import { installTinyFishCli, } from '../cli-install.js';
8
+ import { cliInstallNeeded } from '../cli-presence.js';
9
9
  import { authGate, mapConnectError, OAUTH_SIGN_IN_TIMEOUT_MS } from './connect-all-auth.js';
10
10
  import { actionable, computeExitCode, reloadHint, renderSummary } from './connect-all-summary.js';
11
11
  import { planText, uninstallHarness, uninstallPlanText } from './connect-all-uninstall.js';
@@ -14,12 +14,12 @@ import { KEYLESS_ONBOARDING_PROMPT, useServerLine } from './connect-clients.js';
14
14
  import { gateApiKey } from './connect-preflight.js';
15
15
  import { ConnectInterruptedError } from './connect-runtime.js';
16
16
  import { pickHarnesses } from './connect-picker.js';
17
- import { commandOnPath, detectInstalledHarnesses, isStaleConfig, AuthMode, HARNESS_COMMANDS, HARNESS_DISPLAY_NAMES as DISPLAY_NAMES, ALL_HARNESSES, } from './harness/harness-detect.js';
18
- import { detectHumanInitiated } from './harness.js';
19
- import { emitNotice } from './notice.js';
20
- import { errLine, outLine, setErrIndent } from './output.js';
21
- import { sendSetupCompleted, sendSetupStarted, } from './setup-telemetry.js';
22
- import { verifyMcpAuth, verifyMcpHealth } from './verify.js';
17
+ import { commandOnPath, detectInstalledHarnesses, isStaleConfig, AuthMode, HARNESS_COMMANDS, HARNESS_DISPLAY_NAMES as DISPLAY_NAMES, ALL_HARNESSES, } from '../harness/harness-detect.js';
18
+ import { detectHumanInitiated } from '../harness.js';
19
+ import { emitNotice } from '../notice.js';
20
+ import { errLine, outLine, setErrIndent } from '../output.js';
21
+ import { sendSetupCompleted, sendSetupStarted, } from '../setup-telemetry.js';
22
+ import { verifyMcpAuth, verifyMcpHealth } from '../verify.js';
23
23
  const STEP_INDENT = ' ';
24
24
  /** Undefined means Ctrl+C: the caller stops the whole run. */
25
25
  function runHoistedCliInstall(verbose) {
@@ -1,8 +1,8 @@
1
1
  import spawn from 'cross-spawn';
2
- import { TINYFISH_API_KEY_VAR } from './constants.js';
3
- import { persistApiKeyToEnvironment, validateKeyFormat, writeConfig } from './auth.js';
2
+ import { TINYFISH_API_KEY_VAR } from '../constants.js';
3
+ import { persistApiKeyToEnvironment, validateKeyFormat, writeConfig } from '../auth.js';
4
4
  import { commandNotFound, ConnectStepError, spawnStepError, throwIfInterrupted, NON_INTERACTIVE_TIMEOUT_MS, } from './connect-runtime.js';
5
- import { errLine } from './output.js';
5
+ import { errLine } from '../output.js';
6
6
  export const TINYFISH_CLI_NOT_FOUND_MESSAGE = 'TinyFish CLI installed but is not available on PATH. Open a new terminal and retry.';
7
7
  export function ensureCliAuthenticated(source, apiKey, opts) {
8
8
  const envKey = apiKey ?? process.env[TINYFISH_API_KEY_VAR];
@@ -1,7 +1,7 @@
1
1
  import spawn from 'cross-spawn';
2
2
  import { type AgentClient, type SupportedCommand } from './connect-runtime.js';
3
- import { type HarnessSpec, type SkillAgent } from './harness/harness-spec.js';
4
- import { installClaudeDirectoryPlugin } from './claude-plugin.js';
3
+ import { type HarnessSpec, type SkillAgent } from '../harness/harness-spec.js';
4
+ import { installClaudeDirectoryPlugin } from '../claude-plugin.js';
5
5
  export declare function openclawSkillInstallArgs(ackFlag: string | undefined): string[];
6
6
  /** `openclaw skills` has no uninstall; ClawHub removes from the global dir. */
7
7
  export declare function openclawSkillUninstall(): {
@@ -1,15 +1,15 @@
1
1
  import spawn from 'cross-spawn';
2
- import { SKILL_INSTALL_TIMEOUT_MS } from './cli-install.js';
3
- import { detectHumanInitiated } from './harness.js';
4
- import { harnessConfigPath } from './harness/harness-detect.js';
5
- import { errLine, sanitizeLine, warnLine } from './output.js';
2
+ import { SKILL_INSTALL_TIMEOUT_MS } from '../cli-install.js';
3
+ import { detectHumanInitiated } from '../harness.js';
4
+ import { harnessConfigPath } from '../harness/harness-detect.js';
5
+ import { errLine, sanitizeLine, warnLine } from '../output.js';
6
6
  import { ConnectInterruptedError, ConnectStepError, spawnStepError, } from './connect-runtime.js';
7
- import { TINYFISH_API_KEY_VAR } from './constants.js';
8
- import { HARNESS_SPECS, NATIVE_HARNESSES, harnessSpec, } from './harness/harness-spec.js';
9
- import { HERMES_KEY_VAR, captureHermesKeyRestore, hermesEnvPath, resolveHermesHome, writeHermesKey, } from './hermes-env.js';
10
- import { hermesConfigPath, readHermesEntry } from './config/hermes-config.js';
11
- import { installHermesPlugin, removeHermesMcpEntry, setHermesWebBackends, writeHermesMcpEntry, } from './hermes-plugin.js';
12
- import { CLAUDE_PLUGIN_SERVER, installClaudeDirectoryPlugin } from './claude-plugin.js';
7
+ import { TINYFISH_API_KEY_VAR } from '../constants.js';
8
+ import { HARNESS_SPECS, NATIVE_HARNESSES, harnessSpec, } from '../harness/harness-spec.js';
9
+ import { HERMES_KEY_VAR, captureHermesKeyRestore, hermesEnvPath, resolveHermesHome, writeHermesKey, } from '../hermes-env.js';
10
+ import { hermesConfigPath, readHermesEntry } from '../config/hermes-config.js';
11
+ import { installHermesPlugin, removeHermesMcpEntry, setHermesWebBackends, writeHermesMcpEntry, } from '../hermes-plugin.js';
12
+ import { CLAUDE_PLUGIN_SERVER, installClaudeDirectoryPlugin } from '../claude-plugin.js';
13
13
  const HERMES_SEED_TIMEOUT_MS = 120_000;
14
14
  const OPENCLAW_SKILL = '@tinyfish/tinyfish';
15
15
  // --force makes this an unconditional overwrite, so the same call installs and refreshes.
@@ -1,12 +1,12 @@
1
1
  import * as readline from 'node:readline/promises';
2
2
  import spawn from 'cross-spawn';
3
- import { resolvedApiKey, validateKeyFormat } from './auth.js';
4
- import { installTinyFishCli } from './cli-install.js';
5
- import { cliInstallNeeded } from './cli-presence.js';
3
+ import { resolvedApiKey, validateKeyFormat } from '../auth.js';
4
+ import { installTinyFishCli } from '../cli-install.js';
5
+ import { cliInstallNeeded } from '../cli-presence.js';
6
6
  import { ensureCliAuthenticated, TINYFISH_CLI_NOT_FOUND_MESSAGE } from './connect-auth.js';
7
- import { TINYFISH_API_KEY_VAR } from './constants.js';
7
+ import { TINYFISH_API_KEY_VAR } from '../constants.js';
8
8
  import { commandNotFound, ConnectInterruptedError, ConnectStepError, throwIfInterrupted, } from './connect-runtime.js';
9
- import { errLine, outLine } from './output.js';
9
+ import { errLine, outLine } from '../output.js';
10
10
  export const SEARCH_RETRY = 'tinyfish search query --pretty -- "<your query>"';
11
11
  // Echoes the finale suggestion, so headless rescues rehearse the same task.
12
12
  export const DEFAULT_VERIFICATION_QUERY = "today's top Hacker News story";
@@ -1,8 +1,8 @@
1
1
  import { NATIVE_BY_HARNESS, launchNativeMcpClient, launchCommandCodeWalkthrough, launchOmpWalkthrough, launchPiWalkthrough, launchOpenClawWalkthrough, } from './connect-clients.js';
2
- import { errLine } from './output.js';
2
+ import { errLine } from '../output.js';
3
3
  import { connectNativeMcpClient } from './connect-native.js';
4
4
  import { connectOpenClaw } from './connect-openclaw.js';
5
- import { connectConfigFileHarness, connectCursor } from './config/connect-config-file.js';
5
+ import { connectConfigFileHarness, connectCursor } from '../config/connect-config-file.js';
6
6
  /** Total over the non-native harnesses: a new one fails to compile until wired here. */
7
7
  const LAUNCH_OVERRIDES = {
8
8
  omp: () => launchOmpWalkthrough(),
@@ -1,22 +1,23 @@
1
1
  import spawn from 'cross-spawn';
2
- import { CONNECT_SOURCE, persistApiKeyToEnvironment, saveConnectContext, validatedApiKey, } from './auth.js';
2
+ import { CONNECT_SOURCE, persistApiKeyToEnvironment, saveConnectContext, validatedApiKey, } from '../auth.js';
3
3
  import { KEYLESS_ONBOARDING_PROMPT, launchNativeMcpClient, onboardingPrompt, } from './connect-clients.js';
4
- import { captureStdio, capturedOutput, replay, SKILL_INSTALL_TIMEOUT_MS, STEP_MAX_BUFFER, } from './cli-install.js';
4
+ import { captureStdio, capturedOutput, replay, SKILL_INSTALL_TIMEOUT_MS, STEP_MAX_BUFFER, } from '../cli-install.js';
5
5
  import { ensureCliAuthenticated } from './connect-auth.js';
6
- import { installWebSkill } from './skill-install.js';
7
- import { waitForSignInUrl } from './sign-in-url.js';
6
+ import { installWebSkill } from '../skill-install.js';
7
+ import { waitForSignInUrl } from '../sign-in-url.js';
8
8
  import { ConnectInterruptedError, ConnectStepError, createConnectTelemetry, runGuarded, settle, SignInTimeoutError, spawnRemoval, spawnStepError, } from './connect-runtime.js';
9
- import { DASHBOARD_URL, TINYFISH_API_KEY_VAR } from './constants.js';
10
- import { strayProjectKeyFiles } from './config/opencode-config.js';
11
- import { AuthMode, HARNESS_COMMANDS, RELOAD_ACTION, resolveCommand, } from './harness/harness-detect.js';
12
- import { opencodeStrayKeyNote } from './harness/harness-messages.js';
13
- import { SIGN_IN_PROBES, TINYFISH_LIST_ROW } from './registration-detect.js';
14
- import { errLine, sanitizeLine, warnLine } from './output.js';
15
- import { verifyMcpAuth } from './verify.js';
16
- import { dotenvMarkerHead, harnessDotenvPath, writeDotenvKey } from './dotenv-file.js';
17
- import { apiBaseFromMcpUrl, isDefaultEndpoint } from './mcp-endpoint.js';
18
- import { removeWebSkills } from './skill-vendor.js';
9
+ import { DASHBOARD_URL, TINYFISH_API_KEY_VAR } from '../constants.js';
10
+ import { strayProjectKeyFiles } from '../config/opencode-config.js';
11
+ import { AuthMode, HARNESS_COMMANDS, RELOAD_ACTION, resolveCommand, } from '../harness/harness-detect.js';
12
+ import { opencodeStrayKeyNote } from '../harness/harness-messages.js';
13
+ import { SIGN_IN_PROBES, TINYFISH_LIST_ROW } from '../registration-detect.js';
14
+ import { errLine, sanitizeLine, warnLine } from '../output.js';
15
+ import { verifyMcpAuth } from '../verify.js';
16
+ import { dotenvMarkerHead, harnessDotenvPath, writeDotenvKey } from '../dotenv-file.js';
17
+ import { apiBaseFromMcpUrl, isDefaultEndpoint } from '../mcp-endpoint.js';
18
+ import { removeWebSkills } from '../skill-vendor.js';
19
19
  import { finishSetupHint, requireKeylessMcp, requireSupportOrRescue, runCliInstallStep, trackPostInstallFailure, walkthroughPhase, } from './connect-steps.js';
20
+ import { SUGGESTED_PROMPTS } from '../suggested-prompt.js';
20
21
  /** Several installs can disagree; every later spawn reuses this one. */
21
22
  function pinExecutable(client) {
22
23
  const resolved = resolveCommand(client.command);
@@ -446,6 +447,28 @@ export async function connectNativeMcpClient(unpinned, options) {
446
447
  });
447
448
  return state.authMode;
448
449
  }
450
+ /** `cli_connect_suggested_prompt` A/B; control records exposure without printing. */
451
+ async function printSuggestedPrompt(client, telemetry) {
452
+ if (client.connectClient !== 'claude-code')
453
+ return;
454
+ const variant = await telemetry.suggestedPromptVariant();
455
+ if (!variant)
456
+ return;
457
+ const line = SUGGESTED_PROMPTS[variant];
458
+ if (line)
459
+ errLine(line);
460
+ telemetry.track('checkpoint', {
461
+ phase: 'suggested_prompt_shown',
462
+ suggestedPromptVariant: variant,
463
+ });
464
+ }
465
+ async function printConnectedMessage(client, options, telemetry, signInDeferred, failed) {
466
+ // Under --all the summary replaces this; sign-in hints still print.
467
+ if (signInDeferred || !options.deferOutro)
468
+ errLine(connectedLine(client, signInDeferred));
469
+ if (!options.deferOutro && !failed)
470
+ await printSuggestedPrompt(client, telemetry);
471
+ }
449
472
  function connectedLine(client, signInDeferred) {
450
473
  // The CLI never observes deferred auth, so don't claim "connected".
451
474
  if (signInDeferred) {
@@ -528,9 +551,7 @@ async function runPostInstallSteps(client, options, state, telemetry, signInDefe
528
551
  if (client.postConnectNote)
529
552
  errLine(client.postConnectNote);
530
553
  if (!options.launch) {
531
- // Under --all the summary replaces this; sign-in hints still print.
532
- if (signInDeferred || !options.deferOutro)
533
- errLine(connectedLine(client, signInDeferred));
554
+ await printConnectedMessage(client, options, telemetry, signInDeferred, failed);
534
555
  }
535
556
  else {
536
557
  await attempt('walkthrough_launch', async () => {
@@ -1,11 +1,11 @@
1
1
  import spawn from 'cross-spawn';
2
- import { saveConnectContext } from './auth.js';
2
+ import { saveConnectContext } from '../auth.js';
3
3
  import { OPENCLAW, openclawSkillInstallArgs, launchOpenClawWalkthrough, } from './connect-clients.js';
4
- import { captureStdio, capturedOutput, replay } from './cli-install.js';
4
+ import { captureStdio, capturedOutput, replay } from '../cli-install.js';
5
5
  import { ensureCliAuthenticated } from './connect-auth.js';
6
6
  import { createConnectTelemetry, runGuarded, settle, spawnStepError, } from './connect-runtime.js';
7
- import { RELOAD_ACTION } from './harness/harness-detect.js';
8
- import { errLine } from './output.js';
7
+ import { RELOAD_ACTION } from '../harness/harness-detect.js';
8
+ import { errLine } from '../output.js';
9
9
  import { finishSetupHint, requireSupportOrRescue, runCliInstallStep, trackPostInstallFailure, walkthroughPhase, } from './connect-steps.js';
10
10
  /** Skill install only: no key handoff or post-install callback to honour. */
11
11
  export async function connectOpenClaw(options) {
@@ -1,5 +1,5 @@
1
1
  import type { Readable } from 'node:stream';
2
- import { type Harness, type HarnessDetection } from './harness/harness-detect.js';
2
+ import { type Harness, type HarnessDetection } from '../harness/harness-detect.js';
3
3
  type PickSelection = Harness[] | 'cancel';
4
4
  export interface PickResult {
5
5
  selection: PickSelection;
@@ -1,5 +1,5 @@
1
1
  import * as readline from 'node:readline';
2
- import { HARNESS_DISPLAY_NAMES, } from './harness/harness-detect.js';
2
+ import { HARNESS_DISPLAY_NAMES, } from '../harness/harness-detect.js';
3
3
  const KEY_HELP = ' ↑↓ move space toggle one a none/all q cancel';
4
4
  function header(count) {
5
5
  return `Found ${count} agent config${count === 1 ? '' : 's'} on this machine.\n\n`;
@@ -1,4 +1,4 @@
1
- import { type SetupBlockedMode } from './setup-telemetry.js';
1
+ import { type SetupBlockedMode } from '../setup-telemetry.js';
2
2
  export type PreflightOutcome = 'ok' | 'blocked';
3
3
  interface PreflightOptions {
4
4
  apiKey?: string;
@@ -1,9 +1,9 @@
1
- import { apiKeyStatus, configFile, validateKeyFormat } from './auth.js';
2
- import { TINYFISH_API_KEY_VAR } from './constants.js';
3
- import { apiBaseFromMcpUrl } from './mcp-endpoint.js';
4
- import { errLine, warnLine } from './output.js';
5
- import { sendSetupBlocked, } from './setup-telemetry.js';
6
- import { verifyMcpAuth } from './verify.js';
1
+ import { apiKeyStatus, configFile, validateKeyFormat } from '../auth.js';
2
+ import { TINYFISH_API_KEY_VAR } from '../constants.js';
3
+ import { apiBaseFromMcpUrl } from '../mcp-endpoint.js';
4
+ import { errLine, warnLine } from '../output.js';
5
+ import { sendSetupBlocked, } from '../setup-telemetry.js';
6
+ import { verifyMcpAuth } from '../verify.js';
7
7
  function sourceAdvice(source) {
8
8
  switch (source) {
9
9
  case 'env':
@@ -1,6 +1,7 @@
1
- import { AuthMode } from './harness/harness-detect.js';
2
- import type { Harness, HarnessSupportCheck } from './harness/harness-spec.js';
3
- import type { PiAdapterState } from './config/pi-config.js';
1
+ import { AuthMode } from '../harness/harness-detect.js';
2
+ import type { Harness, HarnessSupportCheck } from '../harness/harness-spec.js';
3
+ import type { PiAdapterState } from '../config/pi-config.js';
4
+ import { type SuggestedPromptVariant } from '../suggested-prompt.js';
4
5
  export declare const NON_INTERACTIVE_TIMEOUT_MS = 10000;
5
6
  export type AgentClient = Harness;
6
7
  type ConnectStage = 'started' | 'checkpoint' | 'completed' | 'failed' | 'aborted' | 'post_install_failed';
@@ -8,7 +9,7 @@ export type ConnectFailureStage = 'prerequisite_check' | 'registration_cleanup'
8
9
  export declare const CONNECT_FAILURE_REASONS: readonly ["harness_not_installed", "harness_command_unsupported", "harness_too_old", "key_auth_unsupported", "command_not_found", "timeout", "spawn_error", "nonzero_exit", "invalid_config", "user_abandoned", "process_terminated", "unexpected_error"];
9
10
  export type ConnectFailureReason = (typeof CONNECT_FAILURE_REASONS)[number];
10
11
  export type ConnectAuthMode = Exclude<AuthMode, AuthMode.Unknown> | 'deferred';
11
- export type ConnectCheckpoint = 'prerequisite_ok' | 'registered' | 'oauth_done' | 'cli_installed' | 'skill_installed' | 'plugin_installed' | 'authenticated' | 'cli_verified' | 'walkthrough_launched' | 'walkthrough_prompt_printed';
12
+ export type ConnectCheckpoint = 'prerequisite_ok' | 'registered' | 'oauth_done' | 'cli_installed' | 'skill_installed' | 'plugin_installed' | 'authenticated' | 'cli_verified' | 'walkthrough_launched' | 'walkthrough_prompt_printed' | 'suggested_prompt_shown';
12
13
  export type CliFallbackOutcome = 'cli_verified' | 'cli_install_failed' | 'no_credentials' | 'invalid_credentials' | 'authentication_failed' | 'verification_failed' | 'abandoned';
13
14
  /** Ctrl+C killed a setup child — abandonment, not error. */
14
15
  export declare class ConnectInterruptedError extends Error {
@@ -83,6 +84,8 @@ interface ConnectStageDetail {
83
84
  piAdapterState?: PiAdapterState;
84
85
  /** claude-code only: why connect skipped the Directory plugin. */
85
86
  pluginFallbackReason?: string;
87
+ /** Only with `suggested_prompt_shown` (route refine). */
88
+ suggestedPromptVariant?: SuggestedPromptVariant;
86
89
  }
87
90
  export interface ConnectTelemetry {
88
91
  attemptId: string;
@@ -90,6 +93,8 @@ export interface ConnectTelemetry {
90
93
  setHarnessVersion(version?: string): void;
91
94
  setFallbackOutcome(outcome: CliFallbackOutcome): void;
92
95
  flush(): Promise<void>;
96
+ /** Waits up to 2s for in-flight events; the variant rides `completed`. */
97
+ suggestedPromptVariant(): Promise<SuggestedPromptVariant | undefined>;
93
98
  }
94
99
  /** Terminal events exactly once, whichever of flow or signal handler wins. */
95
100
  export declare function settle(state: ConnectRunState, telemetry: ConnectTelemetry, stage: ConnectStage, detail?: ConnectStageDetail): void;
@@ -1,13 +1,16 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import spawn from 'cross-spawn';
3
- import { CONNECT_ATTEMPT_ENV, isAttemptId, resolvedApiKey, takePendingConnectAttempt, } from './auth.js';
4
- import { CLI_INVOCATION_ID, CLI_VERSION } from './constants.js';
5
- import { detectHarness, detectHumanInitiated, detectRuntimeEnv } from './harness.js';
6
- import { boundedVersion, errLine, noColourEnv, sanitizeLine } from './output.js';
7
- import { isOlder } from './cli-presence.js';
8
- import { postConnectEvent, telemetryDisabled } from './setup-telemetry.js';
9
- import { installSignalGuard } from './signals.js';
3
+ import { CONNECT_ATTEMPT_ENV, isAttemptId, resolvedApiKey, takePendingConnectAttempt, } from '../auth.js';
4
+ import { CLI_INVOCATION_ID, CLI_VERSION } from '../constants.js';
5
+ import { detectHarness, detectHumanInitiated, detectRuntimeEnv } from '../harness.js';
6
+ import { boundedVersion, errLine, noColourEnv, sanitizeLine } from '../output.js';
7
+ import { isOlder } from '../cli-presence.js';
8
+ import { parseSuggestedPromptVariant } from '../suggested-prompt.js';
9
+ import { postConnectEvent, telemetryDisabled } from '../setup-telemetry.js';
10
+ import { installSignalGuard } from '../signals.js';
10
11
  export const NON_INTERACTIVE_TIMEOUT_MS = 10_000;
12
+ // One POST attempt; a retried `completed` skips the prompt instead of stalling connect.
13
+ const SUGGESTED_PROMPT_WAIT_MS = 2_000;
11
14
  // Mirrors the route's Zod enum; tests both sides pin it.
12
15
  export const CONNECT_FAILURE_REASONS = [
13
16
  'harness_not_installed',
@@ -339,6 +342,10 @@ export function createConnectTelemetry(mcpUrl, client, opts) {
339
342
  let lastTrackAt;
340
343
  let harnessVersion;
341
344
  let fallbackOutcome;
345
+ let suggestedPromptVariant;
346
+ async function flush() {
347
+ await Promise.all(pending.splice(0));
348
+ }
342
349
  async function deliver(body) {
343
350
  // Ahead of the key read; postConnectEvent's own opt-out check is too late to skip it.
344
351
  if (telemetryDisabled())
@@ -350,6 +357,9 @@ export function createConnectTelemetry(mcpUrl, client, opts) {
350
357
  attempts: 2,
351
358
  apiKey: resolvedApiKey(opts?.apiKey),
352
359
  label: 'connect',
360
+ onResponse: (headers) => {
361
+ suggestedPromptVariant ??= parseSuggestedPromptVariant(headers);
362
+ },
353
363
  });
354
364
  }
355
365
  function eventBody(stage, detail, stageDurationMs) {
@@ -371,6 +381,7 @@ export function createConnectTelemetry(mcpUrl, client, opts) {
371
381
  harness_degraded: d.harnessDegraded,
372
382
  pi_adapter_state: d.piAdapterState,
373
383
  plugin_fallback_reason: d.pluginFallbackReason,
384
+ suggested_prompt_variant: d.suggestedPromptVariant,
374
385
  stage_duration_ms: stageDurationMs,
375
386
  runtime_platform: process.platform,
376
387
  node_version: process.version,
@@ -405,8 +416,14 @@ export function createConnectTelemetry(mcpUrl, client, opts) {
405
416
  },
406
417
  // Awaited in finally so in-flight events land before exit. Drains, so the signal-guard
407
418
  // flush and the finally flush do not re-await the same events.
408
- async flush() {
409
- await Promise.all(pending.splice(0));
419
+ flush,
420
+ async suggestedPromptVariant() {
421
+ // Snapshot, not drain: the final flush still awaits these.
422
+ await Promise.race([
423
+ Promise.all([...pending]),
424
+ new Promise((resolve) => setTimeout(resolve, SUGGESTED_PROMPT_WAIT_MS).unref()),
425
+ ]);
426
+ return suggestedPromptVariant;
410
427
  },
411
428
  };
412
429
  }
@@ -1,4 +1,4 @@
1
- import { type TakeHoistedCliInstall } from './cli-install.js';
1
+ import { type TakeHoistedCliInstall } from '../cli-install.js';
2
2
  import { type ConnectCheckpoint, requireCommandSupport, type AgentClient, type ConnectRunState, type ConnectTelemetry, type SupportedCommand } from './connect-runtime.js';
3
3
  import type { WalkthroughOutcome } from './connect-clients.js';
4
4
  export interface NativeConnectOptions {
@@ -1,9 +1,9 @@
1
- import { verifyMcpHealth } from './verify.js';
2
- import { installTinyFishCli } from './cli-install.js';
3
- import { cliInstallNeeded } from './cli-presence.js';
1
+ import { verifyMcpHealth } from '../verify.js';
2
+ import { installTinyFishCli } from '../cli-install.js';
3
+ import { cliInstallNeeded } from '../cli-presence.js';
4
4
  import { createStdinPrompt, runCliFallback } from './connect-fallback.js';
5
- import { detectHumanInitiated } from './harness.js';
6
- import { errLine } from './output.js';
5
+ import { detectHumanInitiated } from '../harness.js';
6
+ import { errLine } from '../output.js';
7
7
  import { ConnectInterruptedError, ConnectStepError, HoistedFailureReportedError, finishSetupCommand, requireCommandSupport, settle, stageDurationOf, withStageDuration, } from './connect-runtime.js';
8
8
  export async function requireKeylessMcp(mcpUrl) {
9
9
  if ((await verifyMcpHealth(mcpUrl, true)).ok)
@@ -1,6 +1,6 @@
1
1
  import spawn from 'cross-spawn';
2
- import { connectHarness } from './connect-harness.js';
3
- import { OAUTH_SIGN_IN_TIMEOUT_MS } from './connect-all-auth.js';
2
+ import { connectHarness } from './connect/connect-harness.js';
3
+ import { OAUTH_SIGN_IN_TIMEOUT_MS } from './connect/connect-all-auth.js';
4
4
  import { Registered } from './harness/harness-detect.js';
5
5
  import { detectHumanInitiated } from './harness.js';
6
6
  import { errLine } from './output.js';
@@ -2,7 +2,7 @@ import os from 'node:os';
2
2
  import path from 'node:path';
3
3
  import spawn from 'cross-spawn';
4
4
  import { HERMES_COLD_START_TIMEOUT_MS } from './constants.js';
5
- import { throwIfInterrupted } from './connect-runtime.js';
5
+ import { throwIfInterrupted } from './connect/connect-runtime.js';
6
6
  import { noColourEnv, sanitizeLine } from './output.js';
7
7
  import { captureDotenvKeyRestore, dotenvMarkerHead, readDotenvKey, removeDotenvKey, writeDotenvKey, } from './dotenv-file.js';
8
8
  // display_hermes_home() abbreviates under $HOME, so the value is not always absolute.
@@ -1,7 +1,7 @@
1
1
  import spawn from 'cross-spawn';
2
2
  import { z } from 'zod';
3
3
  import { captureStdio, capturedOutput, replay, STEP_MAX_BUFFER, } from './cli-install.js';
4
- import { commandNotFound, ConnectStepError, spawnStepError, throwIfInterrupted, } from './connect-runtime.js';
4
+ import { commandNotFound, ConnectStepError, spawnStepError, throwIfInterrupted, } from './connect/connect-runtime.js';
5
5
  import { HARNESS_PROBE_TIMEOUT_MS, TINYFISH_ACCESS_MODE_HEADER, TINYFISH_KEYLESS_ACCESS_MODE, } from './constants.js';
6
6
  import { HERMES_HEADER_TEMPLATE, HERMES_MCP_SERVER_KEY } from './config/hermes-config.js';
7
7
  import { errLine, noColourEnv, parseJson, sanitizeLine } from './output.js';
@@ -1,5 +1,5 @@
1
1
  import { type RecordedAuthMode } from './auth.js';
2
- import type { AgentClient } from './connect-runtime.js';
2
+ import type { AgentClient } from './connect/connect-runtime.js';
3
3
  import { AuthMode, type Harness, Registered } from './harness/harness-detect.js';
4
4
  export interface RegistrationStatus {
5
5
  harness: Harness;
@@ -3,7 +3,7 @@ import * as path from 'path';
3
3
  import spawn from 'cross-spawn';
4
4
  import { z } from 'zod';
5
5
  import { loadConfig, matchesCliKey } from './auth.js';
6
- import { NATIVE_BY_HARNESS } from './connect-clients.js';
6
+ import { NATIVE_BY_HARNESS } from './connect/connect-clients.js';
7
7
  import { HARNESS_PROBE_TIMEOUT_MS } from './constants.js';
8
8
  import { errLine, noColourEnv } from './output.js';
9
9
  import { readClineTinyfishEntry } from './config/cline-config.js';
@@ -19,6 +19,8 @@ export declare function postConnectEvent(options: {
19
19
  attempts: number;
20
20
  label: string;
21
21
  apiKey?: string;
22
+ /** Trusted origins only, like the notice. */
23
+ onResponse?: (headers: Headers) => void;
22
24
  }): Promise<void>;
23
25
  declare const harnessResultSchema: z.ZodObject<{
24
26
  harness: z.ZodEnum<{
@@ -53,7 +53,7 @@ function telemetryHeaders(endpoint, apiKey) {
53
53
  * being installed against, upgrade has none and uses BASE_URL.
54
54
  */
55
55
  export async function postConnectEvent(options) {
56
- const { endpoint, body, attempts, label, apiKey } = options;
56
+ const { endpoint, body, attempts, label, apiKey, onResponse } = options;
57
57
  if (telemetryDisabled())
58
58
  return;
59
59
  // Swallows its own write failure so callers can treat this function as total.
@@ -80,8 +80,10 @@ export async function postConnectEvent(options) {
80
80
  });
81
81
  // Before the ok branch so a rejected event still yields a notice; gated on origin so a
82
82
  // `--url` host cannot print its own text as a TinyFish advisory.
83
- if (trusted)
83
+ if (trusted) {
84
84
  captureNotice(response.headers);
85
+ onResponse?.(response.headers);
86
+ }
85
87
  if (response.ok)
86
88
  return;
87
89
  // 4xx will reject the same body again (schema mismatch, e.g. new stages on an old server).
@@ -1,4 +1,4 @@
1
- import type { SpawnStepResult } from './connect-runtime.js';
1
+ import type { SpawnStepResult } from './connect/connect-runtime.js';
2
2
  export interface SignInUrlRun {
3
3
  url?: string;
4
4
  output: string;
@@ -1,5 +1,5 @@
1
1
  import { type InstallOptions } from './cli-install.js';
2
- import { type SkillAgent } from './connect-clients.js';
2
+ import { type SkillAgent } from './connect/connect-clients.js';
3
3
  export declare function installWebSkill(client: {
4
4
  skillAgent?: SkillAgent;
5
5
  displayName: string;
@@ -3,8 +3,8 @@ import * as path from 'node:path';
3
3
  import spawn from 'cross-spawn';
4
4
  import { loadConfig } from './auth.js';
5
5
  import { captureStdio, capturedOutput, replay } from './cli-install.js';
6
- import { OPENCLAW, openclawSkillInstallArgs } from './connect-clients.js';
7
- import { ConnectInterruptedError, ConnectStepError, probeSupportVariant, throwIfInterrupted, } from './connect-runtime.js';
6
+ import { OPENCLAW, openclawSkillInstallArgs } from './connect/connect-clients.js';
7
+ import { ConnectInterruptedError, ConnectStepError, probeSupportVariant, throwIfInterrupted, } from './connect/connect-runtime.js';
8
8
  import { WEB_SKILL_NAMES } from './constants.js';
9
9
  import { installedPackageDir, installRoot } from './install-root.js';
10
10
  import { ALL_HARNESSES, harnessSpec } from './harness/harness-spec.js';
@@ -2,7 +2,7 @@ import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import { bundledSkillsRoot } from './bundled-skill.js';
4
4
  import { LEGACY_SKILL_NAMES, WEB_SKILL_NAMES } from './constants.js';
5
- import { ConnectStepError } from './connect-runtime.js';
5
+ import { ConnectStepError } from './connect/connect-runtime.js';
6
6
  import { errLine } from './output.js';
7
7
  import { skillLockPath, skillRootDir } from './skill-paths.js';
8
8
  // A younger staging dir may belong to a live concurrent connect.
@@ -0,0 +1,12 @@
1
+ import { z } from 'zod';
2
+ declare const suggestedPromptVariantSchema: z.ZodEnum<{
3
+ search: "search";
4
+ control: "control";
5
+ fetch: "fetch";
6
+ }>;
7
+ export type SuggestedPromptVariant = z.infer<typeof suggestedPromptVariantSchema>;
8
+ /** CLI-owned copy: the server sends only the key. Control prints nothing. */
9
+ export declare const SUGGESTED_PROMPTS: Record<SuggestedPromptVariant, string | undefined>;
10
+ /** Unknown or missing header = unenrolled. */
11
+ export declare function parseSuggestedPromptVariant(headers: Headers): SuggestedPromptVariant | undefined;
12
+ export {};
@@ -0,0 +1,17 @@
1
+ import { z } from 'zod';
2
+ // Mirrors suggestedPromptVariantSchema in frontend/app/api/cli/connect-event/schemas.ts.
3
+ const suggestedPromptVariantSchema = z.enum(['control', 'search', 'fetch']);
4
+ const VARIANT_HEADER = 'x-tf-suggested-prompt-variant';
5
+ /** CLI-owned copy: the server sends only the key. Control prints nothing. */
6
+ export const SUGGESTED_PROMPTS = {
7
+ control: undefined,
8
+ search: 'Next: in Claude Code, ask "Use TinyFish to search the web for today\'s top AI news and summarize it."',
9
+ fetch: 'Next: in Claude Code, ask "Use TinyFish to fetch https://news.ycombinator.com and summarize the top 3 stories."',
10
+ };
11
+ /** Unknown or missing header = unenrolled. */
12
+ export function parseSuggestedPromptVariant(headers) {
13
+ // A throw here would read as a failed POST and retry it.
14
+ if (typeof headers?.get !== 'function')
15
+ return undefined;
16
+ return suggestedPromptVariantSchema.safeParse(headers.get(VARIANT_HEADER)?.trim()).data;
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-fish/cli",
3
- "version": "0.57.0",
3
+ "version": "0.57.1-next.465",
4
4
  "description": "TinyFish CLI — run web automations from your terminal",
5
5
  "type": "module",
6
6
  "bin": {