@tabbio-technologies/cli 1.2.8
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/README.md +763 -0
- package/dist/chunks/chunk-7LNC3FIV.js +2019 -0
- package/dist/chunks/chunk-7LNC3FIV.js.map +7 -0
- package/dist/chunks/chunk-NAWA6NCZ.js +259 -0
- package/dist/chunks/chunk-NAWA6NCZ.js.map +7 -0
- package/dist/chunks/chunk-NK5RPNSV.js +15 -0
- package/dist/chunks/chunk-NK5RPNSV.js.map +7 -0
- package/dist/chunks/chunk-QVR5KIEQ.js +1976 -0
- package/dist/chunks/chunk-QVR5KIEQ.js.map +7 -0
- package/dist/chunks/chunk-VHHZFMIF.js +162 -0
- package/dist/chunks/chunk-VHHZFMIF.js.map +7 -0
- package/dist/chunks/chunk-Y6GWIFHI.js +227 -0
- package/dist/chunks/chunk-Y6GWIFHI.js.map +7 -0
- package/dist/chunks/entry-WENOOT6W.js +3492 -0
- package/dist/chunks/entry-WENOOT6W.js.map +7 -0
- package/dist/chunks/mount-NGUARMCL.js +79 -0
- package/dist/chunks/mount-NGUARMCL.js.map +7 -0
- package/dist/chunks/program-O2BA5L6Z.js +2755 -0
- package/dist/chunks/program-O2BA5L6Z.js.map +7 -0
- package/dist/chunks/status-I5UAQPBY.js +16 -0
- package/dist/chunks/status-I5UAQPBY.js.map +7 -0
- package/dist/cli.js +66 -0
- package/dist/cli.js.map +7 -0
- package/package.json +65 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { createRequire as __tabbioCreateRequire } from 'node:module';
|
|
2
|
+
const require = __tabbioCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/ui/theme.ts
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
var BRAND_ACCENT = "#5e29ff";
|
|
7
|
+
var ACCENT_BY_BACKGROUND = { light: "#5e29ff", dark: "#9b87ff", unknown: "#7c5cff" };
|
|
8
|
+
function detectBackground(env = process.env) {
|
|
9
|
+
const forced = env.TABBIO_THEME?.trim().toLowerCase();
|
|
10
|
+
if (forced === "light" || forced === "dark") return forced;
|
|
11
|
+
const colorfgbg = env.COLORFGBG?.trim();
|
|
12
|
+
if (colorfgbg) {
|
|
13
|
+
const bg = Number.parseInt(colorfgbg.split(";").pop() ?? "", 10);
|
|
14
|
+
if (Number.isFinite(bg)) return bg === 7 || bg >= 9 && bg <= 15 ? "light" : "dark";
|
|
15
|
+
}
|
|
16
|
+
return "unknown";
|
|
17
|
+
}
|
|
18
|
+
function supportsUnicode(env = process.env) {
|
|
19
|
+
if (env.TABBIO_ASCII === "1") return false;
|
|
20
|
+
if (process.platform !== "win32") return env.TERM !== "linux";
|
|
21
|
+
return Boolean(
|
|
22
|
+
env.WT_SESSION || env.TERMINUS_SUBLIME || env.ConEmuTask === "{cmd::Cmder}" || env.TERM_PROGRAM === "Terminus-Sublime" || env.TERM_PROGRAM === "vscode" || env.TERM === "xterm-256color" || env.TERM === "alacritty" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm"
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
var UNICODE_SYMBOLS = {
|
|
26
|
+
success: "\u2713",
|
|
27
|
+
error: "\u2717",
|
|
28
|
+
warning: "!",
|
|
29
|
+
dot: "\u25CF",
|
|
30
|
+
pending: "\u25D0",
|
|
31
|
+
pointer: "\u203A",
|
|
32
|
+
line: "\u2500",
|
|
33
|
+
bar: "\u2503",
|
|
34
|
+
arrow: "\u25B8",
|
|
35
|
+
ellipsis: "\u2026",
|
|
36
|
+
// WP-C additions (research §5.3)
|
|
37
|
+
attention: "\u25C6",
|
|
38
|
+
caution: "\u25B2",
|
|
39
|
+
collapsed: "\u25B8",
|
|
40
|
+
expanded: "\u25BE",
|
|
41
|
+
cursor: "\u258D",
|
|
42
|
+
bullet: "\u2022",
|
|
43
|
+
gutter: "\u2502",
|
|
44
|
+
middot: "\xB7",
|
|
45
|
+
newline: "\u21B5",
|
|
46
|
+
upDown: "\u2191\u2193",
|
|
47
|
+
leftRight: "\u2190\u2192",
|
|
48
|
+
arrowRight: "\u2192",
|
|
49
|
+
// #512 artifact kinds (card rows)
|
|
50
|
+
kindDocument: "\u25A4",
|
|
51
|
+
kindSlides: "\u25A6",
|
|
52
|
+
kindImage: "\u25A3",
|
|
53
|
+
kindPage: "\u25EB",
|
|
54
|
+
kindFile: "\u25A2"
|
|
55
|
+
};
|
|
56
|
+
var ASCII_SYMBOLS = {
|
|
57
|
+
success: "+",
|
|
58
|
+
error: "x",
|
|
59
|
+
warning: "!",
|
|
60
|
+
dot: "*",
|
|
61
|
+
pending: "o",
|
|
62
|
+
pointer: ">",
|
|
63
|
+
line: "-",
|
|
64
|
+
bar: "|",
|
|
65
|
+
arrow: ">",
|
|
66
|
+
ellipsis: "...",
|
|
67
|
+
attention: "!",
|
|
68
|
+
caution: "!",
|
|
69
|
+
collapsed: ">",
|
|
70
|
+
expanded: "v",
|
|
71
|
+
cursor: "_",
|
|
72
|
+
bullet: "*",
|
|
73
|
+
gutter: "|",
|
|
74
|
+
middot: "-",
|
|
75
|
+
newline: "\\",
|
|
76
|
+
upDown: "up/down",
|
|
77
|
+
leftRight: "left/right",
|
|
78
|
+
arrowRight: "->",
|
|
79
|
+
kindDocument: "#",
|
|
80
|
+
kindSlides: "#",
|
|
81
|
+
kindImage: "#",
|
|
82
|
+
kindPage: "#",
|
|
83
|
+
kindFile: "#"
|
|
84
|
+
};
|
|
85
|
+
var SPINNER_FRAMES = {
|
|
86
|
+
unicode: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
|
|
87
|
+
ascii: ["-", "\\", "|", "/"]
|
|
88
|
+
};
|
|
89
|
+
var SPINNER_INTERVAL_MS = 80;
|
|
90
|
+
var WORDMARK_GRADIENT = {
|
|
91
|
+
light: ["#4a1fd6", "#5e29ff"],
|
|
92
|
+
dark: ["#9b87ff", "#b3a1ff"]
|
|
93
|
+
};
|
|
94
|
+
function animationsEnabled(env = process.env) {
|
|
95
|
+
return !(env.TABBIO_NO_ANIMATION === "1" || Boolean(env.CI) || env.INK_SCREEN_READER === "true");
|
|
96
|
+
}
|
|
97
|
+
function accentFor(ink, background) {
|
|
98
|
+
if (ink.level < 2) return ink.magenta;
|
|
99
|
+
const color = ink.hex(ACCENT_BY_BACKGROUND[background]);
|
|
100
|
+
return background === "unknown" ? color.bold : color;
|
|
101
|
+
}
|
|
102
|
+
function accentInkColor(ink, background) {
|
|
103
|
+
return ink.level < 2 ? "magenta" : ACCENT_BY_BACKGROUND[background];
|
|
104
|
+
}
|
|
105
|
+
function wordmarkGradientFor(ink, background) {
|
|
106
|
+
if (ink.level < 3 || background === "unknown") return null;
|
|
107
|
+
return WORDMARK_GRADIENT[background];
|
|
108
|
+
}
|
|
109
|
+
function build(ink, unicode, background) {
|
|
110
|
+
const accent = accentFor(ink, background);
|
|
111
|
+
return {
|
|
112
|
+
chalk: ink,
|
|
113
|
+
background,
|
|
114
|
+
accent,
|
|
115
|
+
accentBold: accent.bold,
|
|
116
|
+
success: ink.green,
|
|
117
|
+
error: ink.red,
|
|
118
|
+
warn: ink.yellow,
|
|
119
|
+
info: ink.cyan,
|
|
120
|
+
dim: ink.dim,
|
|
121
|
+
muted: ink.gray,
|
|
122
|
+
bold: ink.bold,
|
|
123
|
+
code: ink.cyan,
|
|
124
|
+
symbols: { ...unicode ? UNICODE_SYMBOLS : ASCII_SYMBOLS },
|
|
125
|
+
unicode,
|
|
126
|
+
// WP-C additions: semantic aliases (research §5.2) and Ink-facing values.
|
|
127
|
+
attention: ink.yellow,
|
|
128
|
+
danger: ink.red,
|
|
129
|
+
link: ink.cyan.underline,
|
|
130
|
+
italic: ink.italic,
|
|
131
|
+
underline: ink.underline,
|
|
132
|
+
strike: ink.strikethrough,
|
|
133
|
+
inverse: ink.inverse,
|
|
134
|
+
/** Border colour for Ink props; never a background. */
|
|
135
|
+
accentInk: accentInkColor(ink, background),
|
|
136
|
+
wordmarkGradient: wordmarkGradientFor(ink, background),
|
|
137
|
+
boxStyle: unicode ? "round" : "classic",
|
|
138
|
+
railStyle: unicode ? "bold" : "classic",
|
|
139
|
+
spinnerFrames: unicode ? SPINNER_FRAMES.unicode : SPINNER_FRAMES.ascii,
|
|
140
|
+
animations: animationsEnabled()
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
var theme = build(chalk, supportsUnicode(), detectBackground());
|
|
144
|
+
function configureTheme(opts = {}) {
|
|
145
|
+
if (opts.noColor) chalk.level = 0;
|
|
146
|
+
Object.assign(theme, build(chalk, supportsUnicode(), detectBackground()));
|
|
147
|
+
return theme;
|
|
148
|
+
}
|
|
149
|
+
var WEB_PAGE_PALETTE = {
|
|
150
|
+
light: { bg: "#fafafa", fg: "#0d0d0d", muted: "#5d5d5d", card: "#ffffff", line: "#e5e5e5" },
|
|
151
|
+
dark: { bg: "#0d0d0d", fg: "#f3f3f3", muted: "#a3a3a3", card: "#171717", line: "#2a2a2a" },
|
|
152
|
+
accent: BRAND_ACCENT,
|
|
153
|
+
onAccent: "#ffffff"
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
SPINNER_INTERVAL_MS,
|
|
158
|
+
theme,
|
|
159
|
+
configureTheme,
|
|
160
|
+
WEB_PAGE_PALETTE
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=chunk-VHHZFMIF.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ui/theme.ts"],
|
|
4
|
+
"sourcesContent": ["import chalk, { type ChalkInstance } from 'chalk';\n\n/**\n * Terminal theme (WP-A base; WP-C extends this object, keep existing keys).\n *\n * Rules (plan \u00A712.5): ANSI-named colours for status and muted text; hex only\n * for the brand accent, chosen by background: #5e29ff on light, #9b87ff on\n * dark, #7c5cff bold when unknown, plain magenta below 256 colours. Never a\n * background fill. Hex literals live only in this file.\n */\n\nexport const BRAND_ACCENT = '#5e29ff';\nexport const ACCENT_BY_BACKGROUND = { light: '#5e29ff', dark: '#9b87ff', unknown: '#7c5cff' } as const;\n\nexport type Background = 'light' | 'dark' | 'unknown';\n\n/** TABBIO_THEME=light|dark wins; else the COLORFGBG \"fg;bg\" heuristic; else unknown. */\nexport function detectBackground(env: NodeJS.ProcessEnv = process.env): Background {\n const forced = env.TABBIO_THEME?.trim().toLowerCase();\n if (forced === 'light' || forced === 'dark') return forced;\n const colorfgbg = env.COLORFGBG?.trim();\n if (colorfgbg) {\n const bg = Number.parseInt(colorfgbg.split(';').pop() ?? '', 10);\n if (Number.isFinite(bg)) return bg === 7 || (bg >= 9 && bg <= 15) ? 'light' : 'dark';\n }\n return 'unknown';\n}\n\n/** Mirrors `is-unicode-supported` without the dependency. */\nexport function supportsUnicode(env: NodeJS.ProcessEnv = process.env): boolean {\n if (env.TABBIO_ASCII === '1') return false;\n if (process.platform !== 'win32') return env.TERM !== 'linux';\n return Boolean(\n env.WT_SESSION ||\n env.TERMINUS_SUBLIME ||\n env.ConEmuTask === '{cmd::Cmder}' ||\n env.TERM_PROGRAM === 'Terminus-Sublime' ||\n env.TERM_PROGRAM === 'vscode' ||\n env.TERM === 'xterm-256color' ||\n env.TERM === 'alacritty' ||\n env.TERMINAL_EMULATOR === 'JetBrains-JediTerm',\n );\n}\n\nconst UNICODE_SYMBOLS = {\n success: '\u2713',\n error: '\u2717',\n warning: '!',\n dot: '\u25CF',\n pending: '\u25D0',\n pointer: '\u203A',\n line: '\u2500',\n bar: '\u2503',\n arrow: '\u25B8',\n ellipsis: '\u2026',\n // WP-C additions (research \u00A75.3)\n attention: '\u25C6',\n caution: '\u25B2',\n collapsed: '\u25B8',\n expanded: '\u25BE',\n cursor: '\u258D',\n bullet: '\u2022',\n gutter: '\u2502',\n middot: '\u00B7',\n newline: '\u21B5',\n upDown: '\u2191\u2193',\n leftRight: '\u2190\u2192',\n arrowRight: '\u2192',\n // #512 artifact kinds (card rows)\n kindDocument: '\u25A4',\n kindSlides: '\u25A6',\n kindImage: '\u25A3',\n kindPage: '\u25EB',\n kindFile: '\u25A2',\n} as const;\n\nexport type ThemeSymbols = Record<keyof typeof UNICODE_SYMBOLS, string>;\n\nconst ASCII_SYMBOLS: ThemeSymbols = {\n success: '+',\n error: 'x',\n warning: '!',\n dot: '*',\n pending: 'o',\n pointer: '>',\n line: '-',\n bar: '|',\n arrow: '>',\n ellipsis: '...',\n attention: '!',\n caution: '!',\n collapsed: '>',\n expanded: 'v',\n cursor: '_',\n bullet: '*',\n gutter: '|',\n middot: '-',\n newline: '\\\\',\n upDown: 'up/down',\n leftRight: 'left/right',\n arrowRight: '->',\n kindDocument: '#',\n kindSlides: '#',\n kindImage: '#',\n kindPage: '#',\n kindFile: '#',\n};\n\n/** One shared 80 ms spinner clock (research \u00A75.10): braille frames, ASCII fallback. */\nexport const SPINNER_FRAMES = {\n unicode: ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'],\n ascii: ['-', '\\\\', '|', '/'],\n} as const;\nexport const SPINNER_INTERVAL_MS = 80;\n\n/** Two-stop wordmark gradient per background (research \u00A75.4); truecolor only. */\nexport const WORDMARK_GRADIENT = {\n light: ['#4a1fd6', '#5e29ff'],\n dark: ['#9b87ff', '#b3a1ff'],\n} as const;\n\n/** Static glyphs instead of motion under TABBIO_NO_ANIMATION, CI or a screen reader. */\nexport function animationsEnabled(env: NodeJS.ProcessEnv = process.env): boolean {\n return !(env.TABBIO_NO_ANIMATION === '1' || Boolean(env.CI) || env.INK_SCREEN_READER === 'true');\n}\n\nexport function accentFor(ink: ChalkInstance, background: Background): ChalkInstance {\n if (ink.level < 2) return ink.magenta;\n const color = ink.hex(ACCENT_BY_BACKGROUND[background]);\n return background === 'unknown' ? color.bold : color;\n}\n\n/** Colour string for Ink props (borders): hex by background at 256+, magenta below. */\nfunction accentInkColor(ink: ChalkInstance, background: Background): string {\n return ink.level < 2 ? 'magenta' : ACCENT_BY_BACKGROUND[background];\n}\n\nfunction wordmarkGradientFor(ink: ChalkInstance, background: Background): readonly [string, string] | null {\n if (ink.level < 3 || background === 'unknown') return null;\n return WORDMARK_GRADIENT[background];\n}\n\nfunction build(ink: ChalkInstance, unicode: boolean, background: Background) {\n const accent = accentFor(ink, background);\n return {\n chalk: ink,\n background,\n accent,\n accentBold: accent.bold,\n success: ink.green,\n error: ink.red,\n warn: ink.yellow,\n info: ink.cyan,\n dim: ink.dim,\n muted: ink.gray,\n bold: ink.bold,\n code: ink.cyan,\n symbols: { ...(unicode ? UNICODE_SYMBOLS : ASCII_SYMBOLS) } as ThemeSymbols,\n unicode,\n // WP-C additions: semantic aliases (research \u00A75.2) and Ink-facing values.\n attention: ink.yellow,\n danger: ink.red,\n link: ink.cyan.underline,\n italic: ink.italic,\n underline: ink.underline,\n strike: ink.strikethrough,\n inverse: ink.inverse,\n /** Border colour for Ink props; never a background. */\n accentInk: accentInkColor(ink, background),\n wordmarkGradient: wordmarkGradientFor(ink, background),\n boxStyle: (unicode ? 'round' : 'classic') as 'round' | 'classic',\n railStyle: (unicode ? 'bold' : 'classic') as 'bold' | 'classic',\n spinnerFrames: (unicode ? SPINNER_FRAMES.unicode : SPINNER_FRAMES.ascii) as readonly string[],\n animations: animationsEnabled(),\n };\n}\n\nexport type Theme = ReturnType<typeof build>;\n\n/** The shared theme object. Updated in place by configureTheme(). */\nexport const theme: Theme = build(chalk, supportsUnicode(), detectBackground());\n\n/**\n * Re-reads the environment (the colour bootstrap in src/index.ts has already\n * set FORCE_COLOR) and applies `--no-color` defensively to this chalk copy.\n */\nexport function configureTheme(opts: { noColor?: boolean } = {}): Theme {\n if (opts.noColor) chalk.level = 0;\n Object.assign(theme, build(chalk, supportsUnicode(), detectBackground()));\n return theme;\n}\n\n/** Palette for the one HTML page the CLI serves (loopback sign-in result). */\nexport const WEB_PAGE_PALETTE = {\n light: { bg: '#fafafa', fg: '#0d0d0d', muted: '#5d5d5d', card: '#ffffff', line: '#e5e5e5' },\n dark: { bg: '#0d0d0d', fg: '#f3f3f3', muted: '#a3a3a3', card: '#171717', line: '#2a2a2a' },\n accent: BRAND_ACCENT,\n onAccent: '#ffffff',\n} as const;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { createRequire as __tabbioCreateRequire } from 'node:module';
|
|
2
|
+
const require = __tabbioCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
ApiClient,
|
|
5
|
+
CliError,
|
|
6
|
+
ExitCode,
|
|
7
|
+
McpSession,
|
|
8
|
+
configPaths,
|
|
9
|
+
describeMcpBearer,
|
|
10
|
+
fingerprint,
|
|
11
|
+
getGlobalOptions,
|
|
12
|
+
getMcpAccessState,
|
|
13
|
+
heading,
|
|
14
|
+
isInteractive,
|
|
15
|
+
loadCredentials,
|
|
16
|
+
notSignedInError,
|
|
17
|
+
printJson,
|
|
18
|
+
printKeyValues,
|
|
19
|
+
readCachedCatalog,
|
|
20
|
+
relativeTime,
|
|
21
|
+
resolveProfileWithSources,
|
|
22
|
+
setGlobalOptions,
|
|
23
|
+
writeOut
|
|
24
|
+
} from "./chunk-7LNC3FIV.js";
|
|
25
|
+
import {
|
|
26
|
+
theme
|
|
27
|
+
} from "./chunk-VHHZFMIF.js";
|
|
28
|
+
|
|
29
|
+
// src/core/context.ts
|
|
30
|
+
function readGlobalOptions(cmd) {
|
|
31
|
+
const raw = cmd ? cmd.optsWithGlobals() : {};
|
|
32
|
+
const current = getGlobalOptions();
|
|
33
|
+
return setGlobalOptions({
|
|
34
|
+
profile: raw.profile ?? current.profile,
|
|
35
|
+
apiUrl: raw.apiUrl ?? current.apiUrl,
|
|
36
|
+
appUrl: raw.appUrl ?? current.appUrl,
|
|
37
|
+
json: Boolean(raw.json ?? current.json),
|
|
38
|
+
color: raw.color ?? current.color,
|
|
39
|
+
debug: Boolean(raw.debug ?? current.debug),
|
|
40
|
+
yes: Boolean(raw.yes ?? current.yes),
|
|
41
|
+
quiet: Boolean(raw.quiet ?? current.quiet)
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function createCommandContext(cmd) {
|
|
45
|
+
const globals = readGlobalOptions(cmd);
|
|
46
|
+
const { profile, sources } = resolveProfileWithSources({
|
|
47
|
+
profile: globals.profile,
|
|
48
|
+
apiUrl: globals.apiUrl,
|
|
49
|
+
appUrl: globals.appUrl
|
|
50
|
+
});
|
|
51
|
+
const credentials = loadCredentials(profile.name);
|
|
52
|
+
const api = new ApiClient(profile, credentials);
|
|
53
|
+
let session = null;
|
|
54
|
+
return {
|
|
55
|
+
globals,
|
|
56
|
+
profile,
|
|
57
|
+
sources,
|
|
58
|
+
credentials,
|
|
59
|
+
api,
|
|
60
|
+
interactive: isInteractive() && !globals.json,
|
|
61
|
+
mcp() {
|
|
62
|
+
session ??= McpSession.connect(profile, api.credentials ?? credentials, { api });
|
|
63
|
+
return session;
|
|
64
|
+
},
|
|
65
|
+
async close() {
|
|
66
|
+
if (session) await (await session.catch(() => null))?.close();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/commands/whoami.ts
|
|
72
|
+
function pickMe(raw) {
|
|
73
|
+
if (!raw || typeof raw.id !== "string") return null;
|
|
74
|
+
const str = (value) => typeof value === "string" ? value : null;
|
|
75
|
+
return {
|
|
76
|
+
id: raw.id,
|
|
77
|
+
email: str(raw.email) ?? "",
|
|
78
|
+
name: str(raw.name),
|
|
79
|
+
username: str(raw.username),
|
|
80
|
+
role: str(raw.role),
|
|
81
|
+
status: str(raw.status),
|
|
82
|
+
...typeof raw.isOnboardingCompleted === "boolean" ? { isOnboardingCompleted: raw.isOnboardingCompleted } : {}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function registerWhoamiCommand(program) {
|
|
86
|
+
program.command("whoami").description("Show the signed-in account").action(async (_opts, cmd) => {
|
|
87
|
+
const ctx = createCommandContext(cmd);
|
|
88
|
+
const creds = ctx.credentials;
|
|
89
|
+
if (!creds?.accessToken && !creds?.mcpToken) throw notSignedInError(ctx.profile.name);
|
|
90
|
+
if (!creds.accessToken) {
|
|
91
|
+
if (ctx.globals.json) {
|
|
92
|
+
printJson({ profile: ctx.profile.name, mode: "mcp-token", user: creds.user ?? null, mcpToken: fingerprint(creds.mcpToken ?? "") });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
writeOut(creds.user?.email ?? `Personal MCP token ${fingerprint(creds.mcpToken ?? "")}`);
|
|
96
|
+
writeOut(theme.dim(" MCP-only sign-in; run `tabbio login` for full account details."));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const me = pickMe(await ctx.api.json("/api/users/me"));
|
|
100
|
+
if (!me) throw notSignedInError(ctx.profile.name);
|
|
101
|
+
if (ctx.globals.json) {
|
|
102
|
+
printJson({ profile: ctx.profile.name, mode: "session", user: me });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
writeOut(me.name ? `${me.name} <${me.email}>` : me.email);
|
|
106
|
+
if (me.username) writeOut(theme.dim(` @${me.username} \xB7 profile ${ctx.profile.name}`));
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/commands/status.ts
|
|
111
|
+
function settledError(result) {
|
|
112
|
+
if (result.status === "fulfilled") return null;
|
|
113
|
+
return result.reason instanceof CliError ? result.reason : null;
|
|
114
|
+
}
|
|
115
|
+
async function collectStatus(ctx) {
|
|
116
|
+
const { profile, credentials: creds } = ctx;
|
|
117
|
+
const report = {
|
|
118
|
+
profile: { ...profile, source: ctx.sources.name, configDir: configPaths().dir },
|
|
119
|
+
signedIn: Boolean(creds?.accessToken || creds?.mcpToken),
|
|
120
|
+
mode: creds?.accessToken ? "session" : creds?.mcpToken ? "mcp-token" : "none",
|
|
121
|
+
user: creds?.user ?? null,
|
|
122
|
+
plan: null,
|
|
123
|
+
session: creds?.accessToken ? {
|
|
124
|
+
token: fingerprint(creds.accessToken),
|
|
125
|
+
expiresAt: creds.accessTokenExpiresAt ?? null,
|
|
126
|
+
source: creds.origin?.accessToken ?? "store",
|
|
127
|
+
refreshable: Boolean(creds.refreshToken),
|
|
128
|
+
valid: null
|
|
129
|
+
} : null,
|
|
130
|
+
mcp: mcpSummary(creds),
|
|
131
|
+
pendingApprovals: null,
|
|
132
|
+
catalog: null,
|
|
133
|
+
problems: []
|
|
134
|
+
};
|
|
135
|
+
const cached = readCachedCatalog(profile, creds);
|
|
136
|
+
if (cached) {
|
|
137
|
+
report.catalog = { tools: cached.tools.length, fetchedAt: cached.fetchedAt.toISOString(), fresh: cached.fresh };
|
|
138
|
+
}
|
|
139
|
+
if (!creds?.accessToken) return report;
|
|
140
|
+
const [me, access, subscription] = await Promise.allSettled([
|
|
141
|
+
ctx.api.json("/api/users/me"),
|
|
142
|
+
getMcpAccessState(ctx.api),
|
|
143
|
+
ctx.api.json("/api/subscription/state")
|
|
144
|
+
]);
|
|
145
|
+
const authFailure = [me, access, subscription].map(settledError).find((error) => error?.exitCode === ExitCode.Auth);
|
|
146
|
+
if (report.session) report.session.valid = !authFailure;
|
|
147
|
+
if (authFailure) {
|
|
148
|
+
report.signedIn = Boolean(creds.mcpToken);
|
|
149
|
+
report.problems.push(`Session: ${authFailure.message}. Run \`tabbio login\`.`);
|
|
150
|
+
}
|
|
151
|
+
if (me.status === "fulfilled") report.user = pickMe(me.value) ?? report.user;
|
|
152
|
+
if (subscription.status === "fulfilled") report.plan = subscription.value?.snapshot?.tier ?? null;
|
|
153
|
+
if (access.status === "fulfilled") {
|
|
154
|
+
const state = access.value;
|
|
155
|
+
report.pendingApprovals = state.pendingApprovals?.length ?? 0;
|
|
156
|
+
} else if (!authFailure) {
|
|
157
|
+
const error = settledError(access);
|
|
158
|
+
report.problems.push(`Approvals: ${error?.message ?? "unavailable"}`);
|
|
159
|
+
}
|
|
160
|
+
return report;
|
|
161
|
+
}
|
|
162
|
+
function mcpSummary(creds) {
|
|
163
|
+
const bearer = describeMcpBearer(creds);
|
|
164
|
+
if (!bearer) return null;
|
|
165
|
+
const envName = bearer.kind === "personal-token" ? "TABBIO_TOKEN" : "TABBIO_ACCESS_TOKEN";
|
|
166
|
+
const base = bearer.kind === "app-session" ? "app session" : `personal token ${bearer.fingerprint}`;
|
|
167
|
+
return {
|
|
168
|
+
kind: bearer.kind,
|
|
169
|
+
source: bearer.source,
|
|
170
|
+
token: bearer.fingerprint,
|
|
171
|
+
label: bearer.source === "env" ? `${base} (from ${envName})` : base
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function printStatus(report) {
|
|
175
|
+
const user = report.user;
|
|
176
|
+
const who = user ? user.name ? `${user.name} <${user.email}>` : user.email : void 0;
|
|
177
|
+
const session = report.session;
|
|
178
|
+
const rows = [
|
|
179
|
+
["Profile", `${report.profile.name} ${theme.dim(`(${report.profile.source})`)}`],
|
|
180
|
+
["API", report.profile.apiUrl],
|
|
181
|
+
["MCP", report.profile.mcpUrl],
|
|
182
|
+
["Account", who ?? (report.signedIn ? theme.dim("personal MCP token (no session)") : theme.warn("not signed in"))],
|
|
183
|
+
["Plan", report.plan],
|
|
184
|
+
[
|
|
185
|
+
"Session",
|
|
186
|
+
session ? [
|
|
187
|
+
session.token,
|
|
188
|
+
session.source === "env" ? "from TABBIO_ACCESS_TOKEN" : null,
|
|
189
|
+
session.expiresAt ? `expires ${relativeTime(new Date(session.expiresAt))}` : null,
|
|
190
|
+
session.refreshable ? "auto-refresh" : null,
|
|
191
|
+
session.valid === false ? theme.error("expired") : null
|
|
192
|
+
].filter(Boolean).join(" \xB7 ") : void 0
|
|
193
|
+
],
|
|
194
|
+
["Tools via", report.mcp?.label],
|
|
195
|
+
[
|
|
196
|
+
"Approvals",
|
|
197
|
+
report.pendingApprovals === null ? void 0 : report.pendingApprovals > 0 ? `${theme.accent(`${report.pendingApprovals} pending`)} ${theme.dim("\u2192 tabbio approvals")}` : "none pending"
|
|
198
|
+
],
|
|
199
|
+
[
|
|
200
|
+
"Catalog",
|
|
201
|
+
report.catalog ? `${report.catalog.tools} tools \xB7 cached ${relativeTime(new Date(report.catalog.fetchedAt))}${report.catalog.fresh ? "" : theme.dim(" (stale)")}` : void 0
|
|
202
|
+
]
|
|
203
|
+
];
|
|
204
|
+
writeOut(heading("Tabbio CLI status"));
|
|
205
|
+
printKeyValues(rows);
|
|
206
|
+
for (const problem of report.problems) writeOut(`${theme.warn(theme.symbols.warning)} ${problem}`);
|
|
207
|
+
if (!report.signedIn) writeOut(theme.dim("Run `tabbio login` to sign in."));
|
|
208
|
+
}
|
|
209
|
+
function registerStatusCommand(program) {
|
|
210
|
+
program.command("status").description("Show profile, account, plan, tokens (fingerprints only), approvals and catalog age").action(async (_opts, cmd) => {
|
|
211
|
+
const ctx = createCommandContext(cmd);
|
|
212
|
+
const report = await collectStatus(ctx);
|
|
213
|
+
if (ctx.globals.json) printJson(report);
|
|
214
|
+
else printStatus(report);
|
|
215
|
+
if (!report.signedIn) process.exitCode = ExitCode.Auth;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
readGlobalOptions,
|
|
221
|
+
createCommandContext,
|
|
222
|
+
registerWhoamiCommand,
|
|
223
|
+
collectStatus,
|
|
224
|
+
mcpSummary,
|
|
225
|
+
registerStatusCommand
|
|
226
|
+
};
|
|
227
|
+
//# sourceMappingURL=chunk-Y6GWIFHI.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/core/context.ts", "../../src/commands/whoami.ts", "../../src/commands/status.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Command } from 'commander';\nimport { type Profile, type ResolvedProfile, resolveProfileWithSources } from './config';\nimport { type Credentials, loadCredentials } from './credentials';\nimport { ApiClient } from './http';\nimport { McpSession } from './mcp';\nimport { type GlobalOptions, getGlobalOptions, isInteractive, setGlobalOptions } from './runtime';\n\n/**\n * Everything a command needs, resolved from the global flags. Commands call\n * `createCommandContext(cmd)` (the commander `this`/last action arg) and use:\n *\n * ctx.api.json<T>('/api/\u2026') app-JWT endpoints (refresh handled)\n * await ctx.mcp() shared McpSession (lazily connected)\n * ctx.globals.json / .yes / .quiet\n *\n * Call `await ctx.close()` when done (closes the MCP session if opened).\n */\nexport type CommandContext = {\n globals: GlobalOptions;\n profile: Profile;\n sources: ResolvedProfile['sources'];\n credentials: Credentials | null;\n api: ApiClient;\n mcp(): Promise<McpSession>;\n interactive: boolean;\n close(): Promise<void>;\n};\n\ntype RawGlobals = {\n profile?: string;\n apiUrl?: string;\n appUrl?: string;\n json?: boolean;\n color?: boolean;\n debug?: boolean;\n yes?: boolean;\n quiet?: boolean;\n};\n\n/** Reads global flags from any (sub)command, merged with the process-wide defaults. */\nexport function readGlobalOptions(cmd?: Command): GlobalOptions {\n const raw = (cmd ? cmd.optsWithGlobals() : {}) as RawGlobals;\n const current = getGlobalOptions();\n return setGlobalOptions({\n profile: raw.profile ?? current.profile,\n apiUrl: raw.apiUrl ?? current.apiUrl,\n appUrl: raw.appUrl ?? current.appUrl,\n json: Boolean(raw.json ?? current.json),\n color: raw.color ?? current.color,\n debug: Boolean(raw.debug ?? current.debug),\n yes: Boolean(raw.yes ?? current.yes),\n quiet: Boolean(raw.quiet ?? current.quiet),\n });\n}\n\nexport function createCommandContext(cmd?: Command): CommandContext {\n const globals = readGlobalOptions(cmd);\n const { profile, sources } = resolveProfileWithSources({\n profile: globals.profile,\n apiUrl: globals.apiUrl,\n appUrl: globals.appUrl,\n });\n const credentials = loadCredentials(profile.name);\n const api = new ApiClient(profile, credentials);\n let session: Promise<McpSession> | null = null;\n\n return {\n globals,\n profile,\n sources,\n credentials,\n api,\n interactive: isInteractive() && !globals.json,\n mcp() {\n // Use the API client's credentials so a refresh done there is visible here.\n session ??= McpSession.connect(profile, api.credentials ?? credentials, { api });\n return session;\n },\n async close() {\n if (session) await (await session.catch(() => null))?.close();\n },\n };\n}\n", "import type { Command } from 'commander';\nimport { createCommandContext } from '../core/context';\nimport { fingerprint } from '../core/credentials';\nimport { notSignedInError } from '../core/errors';\nimport { printJson, writeOut } from '../core/io';\nimport { theme } from '../ui/theme';\n\n/** Fields of `GET /api/users/me` that are safe and useful to print. */\nexport type Me = {\n id: string;\n email: string;\n name: string | null;\n username: string | null;\n role?: string | null;\n status?: string | null;\n isOnboardingCompleted?: boolean;\n};\n\nexport function pickMe(raw: Record<string, unknown> | null | undefined): Me | null {\n if (!raw || typeof raw.id !== 'string') return null;\n const str = (value: unknown) => (typeof value === 'string' ? value : null);\n return {\n id: raw.id,\n email: str(raw.email) ?? '',\n name: str(raw.name),\n username: str(raw.username),\n role: str(raw.role),\n status: str(raw.status),\n ...(typeof raw.isOnboardingCompleted === 'boolean' ? { isOnboardingCompleted: raw.isOnboardingCompleted } : {}),\n };\n}\n\nexport function registerWhoamiCommand(program: Command): void {\n program\n .command('whoami')\n .description('Show the signed-in account')\n .action(async (_opts: unknown, cmd: Command) => {\n const ctx = createCommandContext(cmd);\n const creds = ctx.credentials;\n if (!creds?.accessToken && !creds?.mcpToken) throw notSignedInError(ctx.profile.name);\n\n if (!creds.accessToken) {\n // MCP-only: identity is not queryable without the app session.\n if (ctx.globals.json) {\n printJson({ profile: ctx.profile.name, mode: 'mcp-token', user: creds.user ?? null, mcpToken: fingerprint(creds.mcpToken ?? '') });\n return;\n }\n writeOut(creds.user?.email ?? `Personal MCP token ${fingerprint(creds.mcpToken ?? '')}`);\n writeOut(theme.dim(' MCP-only sign-in; run `tabbio login` for full account details.'));\n return;\n }\n\n const me = pickMe(await ctx.api.json<Record<string, unknown>>('/api/users/me'));\n if (!me) throw notSignedInError(ctx.profile.name);\n if (ctx.globals.json) {\n printJson({ profile: ctx.profile.name, mode: 'session', user: me });\n return;\n }\n writeOut(me.name ? `${me.name} <${me.email}>` : me.email);\n if (me.username) writeOut(theme.dim(` @${me.username} \u00B7 profile ${ctx.profile.name}`));\n });\n}\n", "import type { Command } from 'commander';\nimport type { SubscriptionStateResult } from '@tabbio/types';\nimport { type McpAccessState, getMcpAccessState } from '../core/auth';\nimport { configPaths } from '../core/config';\nimport { type CommandContext, createCommandContext } from '../core/context';\nimport { type Credentials, fingerprint } from '../core/credentials';\nimport { CliError, ExitCode } from '../core/errors';\nimport { type KvRow, heading, printJson, printKeyValues, relativeTime, writeOut } from '../core/io';\nimport { type McpCredentialKind, describeMcpBearer, readCachedCatalog } from '../core/mcp';\nimport { theme } from '../ui/theme';\nimport { type Me, pickMe } from './whoami';\n\nexport type StatusReport = {\n profile: { name: string; source: string; apiUrl: string; appUrl: string; mcpUrl: string; configDir: string };\n signedIn: boolean;\n mode: 'session' | 'mcp-token' | 'none';\n user: Me | { id: string; email: string; name?: string | null } | null;\n plan: string | null;\n session: { token: string; expiresAt: string | null; source: string; refreshable: boolean; valid: boolean | null } | null;\n /** Credential used for MCP tool calls (never the secret itself). */\n mcp: { kind: McpCredentialKind; source: 'env' | 'store'; token: string; label: string } | null;\n pendingApprovals: number | null;\n catalog: { tools: number; fetchedAt: string; fresh: boolean } | null;\n problems: string[];\n};\n\nfunction settledError(result: PromiseSettledResult<unknown>): CliError | null {\n if (result.status === 'fulfilled') return null;\n return result.reason instanceof CliError ? result.reason : null;\n}\n\nexport async function collectStatus(ctx: CommandContext): Promise<StatusReport> {\n const { profile, credentials: creds } = ctx;\n const report: StatusReport = {\n profile: { ...profile, source: ctx.sources.name, configDir: configPaths().dir },\n signedIn: Boolean(creds?.accessToken || creds?.mcpToken),\n mode: creds?.accessToken ? 'session' : creds?.mcpToken ? 'mcp-token' : 'none',\n user: creds?.user ?? null,\n plan: null,\n session: creds?.accessToken\n ? {\n token: fingerprint(creds.accessToken),\n expiresAt: creds.accessTokenExpiresAt ?? null,\n source: creds.origin?.accessToken ?? 'store',\n refreshable: Boolean(creds.refreshToken),\n valid: null,\n }\n : null,\n mcp: mcpSummary(creds),\n pendingApprovals: null,\n catalog: null,\n problems: [],\n };\n\n const cached = readCachedCatalog(profile, creds);\n if (cached) {\n report.catalog = { tools: cached.tools.length, fetchedAt: cached.fetchedAt.toISOString(), fresh: cached.fresh };\n }\n if (!creds?.accessToken) return report;\n\n const [me, access, subscription] = await Promise.allSettled([\n ctx.api.json<Record<string, unknown>>('/api/users/me'),\n getMcpAccessState(ctx.api),\n ctx.api.json<SubscriptionStateResult>('/api/subscription/state'),\n ]);\n\n const authFailure = [me, access, subscription]\n .map(settledError)\n .find((error) => error?.exitCode === ExitCode.Auth);\n if (report.session) report.session.valid = !authFailure;\n if (authFailure) {\n report.signedIn = Boolean(creds.mcpToken);\n report.problems.push(`Session: ${authFailure.message}. Run \\`tabbio login\\`.`);\n }\n\n if (me.status === 'fulfilled') report.user = pickMe(me.value) ?? report.user;\n if (subscription.status === 'fulfilled') report.plan = subscription.value?.snapshot?.tier ?? null;\n\n if (access.status === 'fulfilled') {\n const state: McpAccessState = access.value;\n report.pendingApprovals = state.pendingApprovals?.length ?? 0;\n } else if (!authFailure) {\n const error = settledError(access);\n report.problems.push(`Approvals: ${error?.message ?? 'unavailable'}`);\n }\n return report;\n}\n\nexport function mcpSummary(creds: Credentials | null): StatusReport['mcp'] {\n const bearer = describeMcpBearer(creds);\n if (!bearer) return null;\n const envName = bearer.kind === 'personal-token' ? 'TABBIO_TOKEN' : 'TABBIO_ACCESS_TOKEN';\n const base = bearer.kind === 'app-session' ? 'app session' : `personal token ${bearer.fingerprint}`;\n return {\n kind: bearer.kind,\n source: bearer.source,\n token: bearer.fingerprint,\n label: bearer.source === 'env' ? `${base} (from ${envName})` : base,\n };\n}\n\nfunction printStatus(report: StatusReport): void {\n const user = report.user;\n const who = user ? (user.name ? `${user.name} <${user.email}>` : user.email) : undefined;\n const session = report.session;\n const rows: KvRow[] = [\n ['Profile', `${report.profile.name} ${theme.dim(`(${report.profile.source})`)}`],\n ['API', report.profile.apiUrl],\n ['MCP', report.profile.mcpUrl],\n ['Account', who ?? (report.signedIn ? theme.dim('personal MCP token (no session)') : theme.warn('not signed in'))],\n ['Plan', report.plan],\n [\n 'Session',\n session\n ? [\n session.token,\n session.source === 'env' ? 'from TABBIO_ACCESS_TOKEN' : null,\n session.expiresAt ? `expires ${relativeTime(new Date(session.expiresAt))}` : null,\n session.refreshable ? 'auto-refresh' : null,\n session.valid === false ? theme.error('expired') : null,\n ]\n .filter(Boolean)\n .join(' \u00B7 ')\n : undefined,\n ],\n ['Tools via', report.mcp?.label],\n [\n 'Approvals',\n report.pendingApprovals === null\n ? undefined\n : report.pendingApprovals > 0\n ? `${theme.accent(`${report.pendingApprovals} pending`)} ${theme.dim('\u2192 tabbio approvals')}`\n : 'none pending',\n ],\n [\n 'Catalog',\n report.catalog\n ? `${report.catalog.tools} tools \u00B7 cached ${relativeTime(new Date(report.catalog.fetchedAt))}${report.catalog.fresh ? '' : theme.dim(' (stale)')}`\n : undefined,\n ],\n ];\n writeOut(heading('Tabbio CLI status'));\n printKeyValues(rows);\n for (const problem of report.problems) writeOut(`${theme.warn(theme.symbols.warning)} ${problem}`);\n if (!report.signedIn) writeOut(theme.dim('Run `tabbio login` to sign in.'));\n}\n\nexport function registerStatusCommand(program: Command): void {\n program\n .command('status')\n .description('Show profile, account, plan, tokens (fingerprints only), approvals and catalog age')\n .action(async (_opts: unknown, cmd: Command) => {\n const ctx = createCommandContext(cmd);\n const report = await collectStatus(ctx);\n if (ctx.globals.json) printJson(report);\n else printStatus(report);\n if (!report.signedIn) process.exitCode = ExitCode.Auth;\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|