-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Expand file tree
/
Copy pathstatus-guidance.ts
More file actions
105 lines (98 loc) · 3.89 KB
/
Copy pathstatus-guidance.ts
File metadata and controls
105 lines (98 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
* Onboarding guidance shown by `auth status` when nothing is configured.
*
* Kept separate from `status.ts` so the wording is pure (it depends only
* on colors, not on the credential resolver / API client / system probe)
* and can be unit-tested without booting the whole CLI dependency graph.
* Environment detection lives in `status.ts`; this module only renders.
*/
import { c } from "../../ui/colors.js";
export interface UnconfiguredContext {
/** A human can act on guidance now — a TTY, or a coding agent driving the CLI. */
interactive: boolean;
}
/** The local engine a workflow will fall back to, and whether it's ready. */
export interface OfflineEngineLine {
capability: "voice" | "music";
/** Engine label, e.g. "Kokoro" / "MusicGen". */
label: string;
/** Deps installed (local) or key present (cloud) — usable right now. */
ready: boolean;
/** How to make it ready, shown when `ready` is false. */
setupHint?: string;
}
/** The recommended first step; sign-in and sign-up are the same OAuth flow. */
const RECOMMENDED_ACTION = "npx hyperframes auth login";
/**
* Render the "what offline will use" block from probed engine readiness.
* Falls back to a generic one-liner when readiness wasn't probed (e.g. a
* caller that didn't want to spawn Python).
*/
function offlineEngineLines(engines?: OfflineEngineLine[]): string[] {
if (!engines || engines.length === 0) {
return [
c.dim("Prefer offline? Just continue — local engines (Kokoro · MusicGen) need no account."),
];
}
const lines = ["Prefer offline? Workflows will use these local engines:"];
for (const e of engines) {
const cap = e.capability.padEnd(5);
if (e.ready) {
lines.push(` ${cap} → ${e.label} ${c.success("✓ ready")}`);
} else {
lines.push(` ${cap} → ${e.label} ${c.warn("⚠ deps missing")}`);
if (e.setupHint) lines.push(` ${c.dim(e.setupHint)}`);
}
}
if (engines.some((e) => !e.ready)) {
lines.push(c.dim(" (or run `hyperframes doctor` to check the local toolchain)"));
}
return lines;
}
/**
* Human guidance for an unconfigured machine — registration-first.
* Both paths use `npx hyperframes` (zero-install via npm): browser OAuth
* (sign-in / sign-up) and `--api-key` both write `~/.heygen`. The separate
* `heygen` CLI shares that file but needs its own install (no `npx heygen`),
* so it's left to the docs — not dangled here as a command a fresh machine
* can't run. Names the local fallback so "no key" never reads as a failure,
* and never steers users toward a per-repo `.env`. Mirrors the
* hyperframes-media skill's Preflight section.
*/
export function buildUnconfiguredLines(
ctx: UnconfiguredContext,
engines?: OfflineEngineLine[],
): string[] {
if (!ctx.interactive) {
return [
c.warn("Not signed in to HeyGen (non-interactive)."),
c.dim(
"Set HEYGEN_API_KEY to use HeyGen, or workflows fall back to local engines (Kokoro voice · MusicGen music).",
),
];
}
return [
c.warn("Not signed in to HeyGen — voice & music will use local engines (free, offline)."),
"",
"Sign in or sign up (browser OAuth, writes ~/.heygen — no per-repo .env):",
` ${c.accent("npx hyperframes auth login")} ${c.dim("# browser sign-in / sign-up")}`,
"",
"Or paste an existing HeyGen API key (get one at app.heygen.com/settings/api):",
` ${c.accent("npx hyperframes auth login --api-key")} ${c.dim("# paste at the prompt")}`,
"",
...offlineEngineLines(engines),
];
}
/** Machine-readable form of the unconfigured guidance for `--json`. */
export function buildUnconfiguredJson(
ctx: UnconfiguredContext,
engines?: OfflineEngineLine[],
): Record<string, unknown> {
return {
configured: false,
interactive: ctx.interactive,
recommended_action: RECOMMENDED_ACTION,
fallback: "local",
...(engines ? { offline_engines: engines } : {}),
};
}