@stigg/terminal 0.0.1-alpha → 0.1.0
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/LICENSE +18 -12
- package/README.md +2 -2
- package/dist/api/graphql-client.js +1 -1
- package/dist/api/operations.js +1 -4
- package/dist/auth/callback-server.js +1 -2
- package/dist/bin.js +0 -0
- package/dist/cli.js +2 -7
- package/dist/headless/init-phase2.js +1 -1
- package/dist/headless/setup.js +2 -2
- package/dist/launch/agent.js +1 -3
- package/dist/mcp/clients/claude-code.js +1 -1
- package/dist/mcp/clients/codex.js +1 -1
- package/dist/mcp/writer.js +1 -3
- package/dist/ui/intro/LogoView.js +2 -7
- package/dist/ui/tui/App.js +1 -1
- package/dist/ui/tui/hooks/useKeyBindings.js +1 -1
- package/dist/ui/tui/hooks/useStdoutDimensions.js +1 -4
- package/dist/ui/tui/primitives/PickerMenu.js +3 -5
- package/dist/ui/tui/screens/EnvScreen.js +2 -2
- package/dist/ui/tui/steps/AccountStep.js +1 -4
- package/dist/ui/tui/steps/ApiKeyStep.js +1 -1
- package/dist/ui/tui/steps/ClientsStep.js +1 -3
- package/dist/ui/tui/steps/SummaryStep.js +1 -3
- package/package.json +9 -10
- package/dist/api/client.d.ts +0 -6
- package/dist/api/format-key.d.ts +0 -7
- package/dist/api/graphql-client.d.ts +0 -5
- package/dist/api/operations.d.ts +0 -65
- package/dist/api/types.d.ts +0 -18
- package/dist/auth/callback-server.d.ts +0 -14
- package/dist/auth/config.d.ts +0 -2
- package/dist/auth/oauth.d.ts +0 -17
- package/dist/auth/storage.d.ts +0 -6
- package/dist/bin.d.ts +0 -2
- package/dist/cli.d.ts +0 -1
- package/dist/commands/dash.d.ts +0 -1
- package/dist/commands/debug.d.ts +0 -1
- package/dist/commands/debug.js +0 -53
- package/dist/commands/env.d.ts +0 -1
- package/dist/commands/init.d.ts +0 -13
- package/dist/commands/mcp.d.ts +0 -7
- package/dist/commands/skills.d.ts +0 -6
- package/dist/headless/host-agent.d.ts +0 -19
- package/dist/headless/init-phase1.d.ts +0 -9
- package/dist/headless/init-phase2.d.ts +0 -36
- package/dist/headless/next-step-prompt.d.ts +0 -7
- package/dist/headless/options.d.ts +0 -30
- package/dist/headless/reporter.d.ts +0 -16
- package/dist/headless/setup.d.ts +0 -29
- package/dist/launch/agent.d.ts +0 -55
- package/dist/mcp/clients/base.d.ts +0 -49
- package/dist/mcp/clients/claude-code.d.ts +0 -22
- package/dist/mcp/clients/claude-desktop.d.ts +0 -9
- package/dist/mcp/clients/codex.d.ts +0 -13
- package/dist/mcp/clients/cursor.d.ts +0 -9
- package/dist/mcp/clients/index.d.ts +0 -7
- package/dist/mcp/clients/mcp-remote.d.ts +0 -11
- package/dist/mcp/clients/vscode.d.ts +0 -17
- package/dist/mcp/clients.d.ts +0 -4
- package/dist/mcp/clients.js +0 -50
- package/dist/mcp/config-merge.d.ts +0 -9
- package/dist/mcp/writer.d.ts +0 -6
- package/dist/setup/storage.d.ts +0 -21
- package/dist/skills/install.d.ts +0 -19
- package/dist/types.d.ts +0 -35
- package/dist/ui/components/Card.d.ts +0 -11
- package/dist/ui/components/Card.js +0 -19
- package/dist/ui/components/ContextRow.d.ts +0 -11
- package/dist/ui/components/ContextRow.js +0 -8
- package/dist/ui/components/Footer.d.ts +0 -10
- package/dist/ui/components/Footer.js +0 -9
- package/dist/ui/components/Header.d.ts +0 -11
- package/dist/ui/components/Header.js +0 -6
- package/dist/ui/components/JsonPreview.d.ts +0 -13
- package/dist/ui/components/JsonPreview.js +0 -25
- package/dist/ui/components/SectionTitle.d.ts +0 -6
- package/dist/ui/components/SectionTitle.js +0 -5
- package/dist/ui/hooks/useAsyncEffect.d.ts +0 -3
- package/dist/ui/hooks/useResize.d.ts +0 -4
- package/dist/ui/hooks/useResize.js +0 -20
- package/dist/ui/hud.d.ts +0 -15
- package/dist/ui/ink-theme.d.ts +0 -2
- package/dist/ui/ink-theme.js +0 -34
- package/dist/ui/intro/LogoView.d.ts +0 -12
- package/dist/ui/intro/MatrixIntro.d.ts +0 -6
- package/dist/ui/intro/MatrixIntro.js +0 -80
- package/dist/ui/intro/logo.d.ts +0 -6
- package/dist/ui/messages.d.ts +0 -5
- package/dist/ui/screens/DashScreen.d.ts +0 -6
- package/dist/ui/screens/DashScreen.js +0 -27
- package/dist/ui/screens/DebugScreen.d.ts +0 -6
- package/dist/ui/screens/DebugScreen.js +0 -39
- package/dist/ui/screens/InitScreen.d.ts +0 -6
- package/dist/ui/screens/InitScreen.js +0 -138
- package/dist/ui/screens/MenuScreen.d.ts +0 -7
- package/dist/ui/screens/MenuScreen.js +0 -38
- package/dist/ui/state.d.ts +0 -72
- package/dist/ui/steps/AccountStep.d.ts +0 -8
- package/dist/ui/steps/AccountStep.js +0 -42
- package/dist/ui/steps/ApiKeyStep.d.ts +0 -8
- package/dist/ui/steps/ApiKeyStep.js +0 -91
- package/dist/ui/steps/ClientsStep.d.ts +0 -10
- package/dist/ui/steps/ClientsStep.js +0 -69
- package/dist/ui/steps/CredentialKindStep.d.ts +0 -7
- package/dist/ui/steps/CredentialKindStep.js +0 -18
- package/dist/ui/steps/EnvironmentStep.d.ts +0 -8
- package/dist/ui/steps/EnvironmentStep.js +0 -37
- package/dist/ui/steps/LoginStep.d.ts +0 -7
- package/dist/ui/steps/LoginStep.js +0 -56
- package/dist/ui/steps/SkillsStep.d.ts +0 -7
- package/dist/ui/steps/SkillsStep.js +0 -7
- package/dist/ui/steps/SummaryStep.d.ts +0 -8
- package/dist/ui/steps/SummaryStep.js +0 -41
- package/dist/ui/steps/WritingStep.d.ts +0 -10
- package/dist/ui/steps/WritingStep.js +0 -96
- package/dist/ui/theme.d.ts +0 -53
- package/dist/ui/tui/App.d.ts +0 -10
- package/dist/ui/tui/components/ContextStrip.d.ts +0 -11
- package/dist/ui/tui/components/TitleBar.d.ts +0 -6
- package/dist/ui/tui/components/WizardChecklist.d.ts +0 -7
- package/dist/ui/tui/hooks/keyboard-hints-utils.d.ts +0 -26
- package/dist/ui/tui/hooks/useKeyBindings.d.ts +0 -14
- package/dist/ui/tui/hooks/useKeyboardHints.d.ts +0 -13
- package/dist/ui/tui/hooks/useStdoutDimensions.d.ts +0 -8
- package/dist/ui/tui/primitives/BlinkingLabel.d.ts +0 -19
- package/dist/ui/tui/primitives/ConfirmPrompt.d.ts +0 -16
- package/dist/ui/tui/primitives/KeyboardHintsBar.d.ts +0 -2
- package/dist/ui/tui/primitives/PickerMenu.d.ts +0 -38
- package/dist/ui/tui/primitives/PromptLabel.d.ts +0 -6
- package/dist/ui/tui/primitives/ScreenContainer.d.ts +0 -39
- package/dist/ui/tui/primitives/Spinner.d.ts +0 -7
- package/dist/ui/tui/screens/DashScreen.d.ts +0 -6
- package/dist/ui/tui/screens/DebugScreen.d.ts +0 -6
- package/dist/ui/tui/screens/DebugScreen.js +0 -48
- package/dist/ui/tui/screens/EnvScreen.d.ts +0 -6
- package/dist/ui/tui/screens/InitScreen.d.ts +0 -9
- package/dist/ui/tui/screens/MenuScreen.d.ts +0 -7
- package/dist/ui/tui/start-tui.d.ts +0 -11
- package/dist/ui/tui/steps/AccountStep.d.ts +0 -8
- package/dist/ui/tui/steps/ApiKeyStep.d.ts +0 -8
- package/dist/ui/tui/steps/ClientsStep.d.ts +0 -10
- package/dist/ui/tui/steps/CredentialKindStep.d.ts +0 -7
- package/dist/ui/tui/steps/CredentialKindStep.js +0 -18
- package/dist/ui/tui/steps/EnvironmentStep.d.ts +0 -8
- package/dist/ui/tui/steps/LoginStep.d.ts +0 -8
- package/dist/ui/tui/steps/SkillsStep.d.ts +0 -7
- package/dist/ui/tui/steps/SummaryStep.d.ts +0 -10
- package/dist/ui/tui/steps/WritingStep.d.ts +0 -10
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Select, Spinner } from "@inkjs/ui";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { useState } from "react";
|
|
5
|
-
import { createScopedApiKey, listApiKeys } from "../../api/client.js";
|
|
6
|
-
import { SectionTitle } from "../components/SectionTitle.js";
|
|
7
|
-
import { useAsyncEffect } from "../hooks/useAsyncEffect.js";
|
|
8
|
-
const CREATE_NEW = "__create_new__";
|
|
9
|
-
function timeAgo(iso) {
|
|
10
|
-
const ms = Date.now() - new Date(iso).getTime();
|
|
11
|
-
const days = Math.floor(ms / (1000 * 60 * 60 * 24));
|
|
12
|
-
if (days < 1)
|
|
13
|
-
return "today";
|
|
14
|
-
if (days < 7)
|
|
15
|
-
return `${days}d ago`;
|
|
16
|
-
if (days < 30)
|
|
17
|
-
return `${Math.floor(days / 7)}w ago`;
|
|
18
|
-
if (days < 365)
|
|
19
|
-
return `${Math.floor(days / 30)}mo ago`;
|
|
20
|
-
return `${Math.floor(days / 365)}y ago`;
|
|
21
|
-
}
|
|
22
|
-
export function ApiKeyStep({ state, dispatch }) {
|
|
23
|
-
const [minting, setMinting] = useState(false);
|
|
24
|
-
useAsyncEffect(async (signal) => {
|
|
25
|
-
if (state.apiKeys ||
|
|
26
|
-
!state.session ||
|
|
27
|
-
!state.environment ||
|
|
28
|
-
!state.account) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
const keys = await listApiKeys(state.session.accessToken, state.account.id, state.environment.id);
|
|
32
|
-
if (signal.cancelled)
|
|
33
|
-
return;
|
|
34
|
-
dispatch({ type: "KEYS_LOADED", apiKeys: keys });
|
|
35
|
-
}, [
|
|
36
|
-
state.session?.accessToken,
|
|
37
|
-
state.account?.id,
|
|
38
|
-
state.environment?.id,
|
|
39
|
-
], (err) => dispatch({
|
|
40
|
-
type: "ERROR",
|
|
41
|
-
message: err instanceof Error ? err.message : String(err),
|
|
42
|
-
}));
|
|
43
|
-
if (!state.apiKeys) {
|
|
44
|
-
return _jsx(Spinner, { label: `Loading API keys for ${state.environment?.name}…` });
|
|
45
|
-
}
|
|
46
|
-
if (minting) {
|
|
47
|
-
return _jsx(Spinner, { label: "Minting new key\u2026" });
|
|
48
|
-
}
|
|
49
|
-
const handleSelect = async (value) => {
|
|
50
|
-
if (value === CREATE_NEW) {
|
|
51
|
-
setMinting(true);
|
|
52
|
-
try {
|
|
53
|
-
const newKey = await createScopedApiKey(state.session.accessToken, state.account.id, state.environment.id, { name: "cyberdeck-mcp" });
|
|
54
|
-
const minted = {
|
|
55
|
-
id: `key_${Date.now().toString(36)}`,
|
|
56
|
-
name: "cyberdeck-mcp",
|
|
57
|
-
lastFour: newKey.slice(-4),
|
|
58
|
-
scopes: ["read", "write"],
|
|
59
|
-
createdAt: new Date().toISOString(),
|
|
60
|
-
value: newKey,
|
|
61
|
-
};
|
|
62
|
-
dispatch({
|
|
63
|
-
type: "PICK_KEY",
|
|
64
|
-
key: minted,
|
|
65
|
-
credentialValue: newKey,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
dispatch({
|
|
70
|
-
type: "ERROR",
|
|
71
|
-
message: err instanceof Error ? err.message : String(err),
|
|
72
|
-
});
|
|
73
|
-
setMinting(false);
|
|
74
|
-
}
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
const key = state.apiKeys?.find((k) => k.id === value);
|
|
78
|
-
if (!key || !key.value)
|
|
79
|
-
return;
|
|
80
|
-
dispatch({ type: "PICK_KEY", key, credentialValue: key.value });
|
|
81
|
-
};
|
|
82
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionTitle, { children: "Pick an existing key, or create a new one" }), _jsx(Select, { options: [
|
|
83
|
-
...state.apiKeys.map((k) => ({
|
|
84
|
-
label: `${k.name.padEnd(20)} sk_…${k.lastFour} ${k.scopes.join(", ").padEnd(14)} ${timeAgo(k.createdAt)}`,
|
|
85
|
-
value: k.id,
|
|
86
|
-
})),
|
|
87
|
-
{ label: "+ Create new key", value: CREATE_NEW },
|
|
88
|
-
], onChange: (v) => {
|
|
89
|
-
void handleSelect(v);
|
|
90
|
-
} }), state.apiKeys.length === 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["No keys yet for ", state.environment?.name, ". Pick \"Create new\" to mint one."] }) }))] }));
|
|
91
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { ClientId, McpClientHandler } from "../../types.js";
|
|
3
|
-
import type { Action, WizardState } from "../state.js";
|
|
4
|
-
interface Props {
|
|
5
|
-
state: WizardState;
|
|
6
|
-
dispatch: React.Dispatch<Action>;
|
|
7
|
-
handlers: Record<ClientId, McpClientHandler>;
|
|
8
|
-
}
|
|
9
|
-
export declare function ClientsStep({ state, dispatch, handlers, }: Props): React.ReactElement;
|
|
10
|
-
export {};
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { MultiSelect, Spinner } from "@inkjs/ui";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { useState } from "react";
|
|
5
|
-
import { buildMcpEntry } from "../../mcp/writer.js";
|
|
6
|
-
import { SectionTitle } from "../components/SectionTitle.js";
|
|
7
|
-
import { useAsyncEffect } from "../hooks/useAsyncEffect.js";
|
|
8
|
-
const ALL_CLIENTS = [
|
|
9
|
-
{ id: "claude-code", label: "Claude Code", configPath: "~/.claude.json" },
|
|
10
|
-
{ id: "cursor", label: "Cursor", configPath: "~/.cursor/mcp.json" },
|
|
11
|
-
];
|
|
12
|
-
const MCP_URL = "https://mcp.stigg.io";
|
|
13
|
-
function maskValue(v, keep = 4) {
|
|
14
|
-
if (v.length <= keep + 4)
|
|
15
|
-
return v;
|
|
16
|
-
return `${v.slice(0, 6)}…${v.slice(-keep)}`;
|
|
17
|
-
}
|
|
18
|
-
function maskedEntry(credential) {
|
|
19
|
-
if (!credential)
|
|
20
|
-
return null;
|
|
21
|
-
const entry = buildMcpEntry(credential, MCP_URL);
|
|
22
|
-
const maskedHeaders = Object.fromEntries(Object.entries(entry.headers).map(([k, v]) => {
|
|
23
|
-
if (k === "X-Environment")
|
|
24
|
-
return [k, v];
|
|
25
|
-
return [k, maskValue(v)];
|
|
26
|
-
}));
|
|
27
|
-
return { entry: { ...entry, headers: maskedHeaders } };
|
|
28
|
-
}
|
|
29
|
-
export function ClientsStep({ state, dispatch, handlers, }) {
|
|
30
|
-
useAsyncEffect(async (signal) => {
|
|
31
|
-
if (state.detectedClients)
|
|
32
|
-
return;
|
|
33
|
-
const detected = [];
|
|
34
|
-
for (const id of ALL_CLIENTS.map((c) => c.id)) {
|
|
35
|
-
if (await handlers[id].isInstalled()) {
|
|
36
|
-
detected.push(id);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (signal.cancelled)
|
|
40
|
-
return;
|
|
41
|
-
dispatch({ type: "DETECT_OK", clients: detected });
|
|
42
|
-
}, [], (err) => dispatch({
|
|
43
|
-
type: "ERROR",
|
|
44
|
-
message: err instanceof Error ? err.message : String(err),
|
|
45
|
-
}));
|
|
46
|
-
const initial = state.selectedClients ??
|
|
47
|
-
(state.detectedClients && state.detectedClients.length > 0
|
|
48
|
-
? state.detectedClients
|
|
49
|
-
: ["claude-code"]);
|
|
50
|
-
const [, setSelected] = useState(initial);
|
|
51
|
-
if (!state.detectedClients) {
|
|
52
|
-
return _jsx(Spinner, { label: "Detecting installed AI clients\u2026" });
|
|
53
|
-
}
|
|
54
|
-
const masked = maskedEntry(state.credential);
|
|
55
|
-
const previewLines = masked
|
|
56
|
-
? JSON.stringify({ stigg: masked.entry }, null, 2).split("\n")
|
|
57
|
-
: [];
|
|
58
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionTitle, { children: "Which clients should we configure?" }), _jsxs(Box, { flexDirection: "row", gap: 4, children: [_jsx(Box, { flexDirection: "column", minWidth: 42, children: _jsx(MultiSelect, { options: ALL_CLIENTS.map((c) => {
|
|
59
|
-
const detected = state.detectedClients?.includes(c.id);
|
|
60
|
-
const suffix = detected ? " (detected)" : " (not installed)";
|
|
61
|
-
return {
|
|
62
|
-
label: `${c.label.padEnd(13)} ${c.configPath.padEnd(22)}${suffix}`,
|
|
63
|
-
value: c.id,
|
|
64
|
-
};
|
|
65
|
-
}), defaultValue: initial, onChange: (values) => setSelected(values), onSubmit: (values) => dispatch({
|
|
66
|
-
type: "PICK_CLIENTS",
|
|
67
|
-
clients: values,
|
|
68
|
-
}) }) }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsx(Text, { dimColor: true, children: "Preview \u00B7 mcpServers.stigg" }), previewLines.length === 0 ? (_jsx(Text, { dimColor: true, children: "(no credential yet)" })) : (previewLines.map((line, i) => (_jsx(Text, { color: "green", children: line.trim() === "" ? "" : `+ ${line}` }, i))))] })] })] }));
|
|
69
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Select } from "@inkjs/ui";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { SectionTitle } from "../components/SectionTitle.js";
|
|
5
|
-
export function CredentialKindStep({ dispatch, }) {
|
|
6
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionTitle, { children: "Which credential should the MCP use?" }), _jsx(Select, { options: [
|
|
7
|
-
{
|
|
8
|
-
label: "User JWT · your user identity, broad access across envs",
|
|
9
|
-
value: "jwt",
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
label: "API key · single env, limited permissions (recommended)",
|
|
13
|
-
value: "scoped",
|
|
14
|
-
},
|
|
15
|
-
], onChange: (v) => {
|
|
16
|
-
dispatch({ type: "PICK_CRED_KIND", kind: v });
|
|
17
|
-
} }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Scoped keys are safer (smaller blast radius if leaked)." }), _jsx(Text, { dimColor: true, children: "JWT is your full user identity and follows your role across envs." })] })] }));
|
|
18
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { Action, WizardState } from "../state.js";
|
|
3
|
-
interface Props {
|
|
4
|
-
state: WizardState;
|
|
5
|
-
dispatch: React.Dispatch<Action>;
|
|
6
|
-
}
|
|
7
|
-
export declare function EnvironmentStep({ state, dispatch, }: Props): React.ReactElement;
|
|
8
|
-
export {};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Select, Spinner } from "@inkjs/ui";
|
|
3
|
-
import { Box } from "ink";
|
|
4
|
-
import { listEnvironments } from "../../api/client.js";
|
|
5
|
-
import { SectionTitle } from "../components/SectionTitle.js";
|
|
6
|
-
import { useAsyncEffect } from "../hooks/useAsyncEffect.js";
|
|
7
|
-
export function EnvironmentStep({ state, dispatch, }) {
|
|
8
|
-
useAsyncEffect(async (signal) => {
|
|
9
|
-
if (state.environments || !state.session || !state.account)
|
|
10
|
-
return;
|
|
11
|
-
const envs = await listEnvironments(state.session.accessToken, state.account.id);
|
|
12
|
-
if (signal.cancelled)
|
|
13
|
-
return;
|
|
14
|
-
dispatch({
|
|
15
|
-
type: "ENVS_LOADED",
|
|
16
|
-
environments: envs.map((e) => ({
|
|
17
|
-
id: e.id,
|
|
18
|
-
name: e.name,
|
|
19
|
-
slug: e.slug,
|
|
20
|
-
})),
|
|
21
|
-
});
|
|
22
|
-
}, [state.session?.accessToken, state.account?.id], (err) => dispatch({
|
|
23
|
-
type: "ERROR",
|
|
24
|
-
message: err instanceof Error ? err.message : String(err),
|
|
25
|
-
}));
|
|
26
|
-
if (!state.environments) {
|
|
27
|
-
return _jsx(Spinner, { label: "Loading environments\u2026" });
|
|
28
|
-
}
|
|
29
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionTitle, { children: "Which environment?" }), _jsx(Select, { options: state.environments.map((e) => ({
|
|
30
|
-
label: e.name,
|
|
31
|
-
value: e.id,
|
|
32
|
-
})), onChange: (v) => {
|
|
33
|
-
const env = state.environments?.find((e) => e.id === v);
|
|
34
|
-
if (env)
|
|
35
|
-
dispatch({ type: "PICK_ENV", environment: env });
|
|
36
|
-
} })] }));
|
|
37
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Spinner } from "@inkjs/ui";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { useState } from "react";
|
|
5
|
-
import { authenticate } from "../../auth/oauth.js";
|
|
6
|
-
import { saveSession } from "../../auth/storage.js";
|
|
7
|
-
import { SectionTitle } from "../components/SectionTitle.js";
|
|
8
|
-
import { useAsyncEffect } from "../hooks/useAsyncEffect.js";
|
|
9
|
-
export function LoginStep({ dispatch }) {
|
|
10
|
-
const [started, setStarted] = useState(false);
|
|
11
|
-
const [message, setMessage] = useState("Opening browser to log in…");
|
|
12
|
-
const [errored, setErrored] = useState(null);
|
|
13
|
-
useInput((_input, key) => {
|
|
14
|
-
if (key.return)
|
|
15
|
-
setStarted(true);
|
|
16
|
-
}, { isActive: !started && !errored });
|
|
17
|
-
useAsyncEffect(async (signal) => {
|
|
18
|
-
if (!started)
|
|
19
|
-
return;
|
|
20
|
-
try {
|
|
21
|
-
const session = await authenticate({
|
|
22
|
-
onAuthUrlReady: (_url, port) => {
|
|
23
|
-
if (!signal.cancelled) {
|
|
24
|
-
setMessage(`Waiting for callback on http://127.0.0.1:${port}`);
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
await saveSession(session);
|
|
29
|
-
if (signal.cancelled)
|
|
30
|
-
return;
|
|
31
|
-
dispatch({
|
|
32
|
-
type: "LOGIN_OK",
|
|
33
|
-
session: {
|
|
34
|
-
email: session.email,
|
|
35
|
-
accessToken: session.access_token,
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
if (signal.cancelled)
|
|
41
|
-
return;
|
|
42
|
-
setErrored(err instanceof Error ? err.message : String(err));
|
|
43
|
-
dispatch({
|
|
44
|
-
type: "ERROR",
|
|
45
|
-
message: err instanceof Error ? err.message : String(err),
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}, [started]);
|
|
49
|
-
if (errored) {
|
|
50
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: "\u2717 Login failed" }), _jsx(Text, { dimColor: true, children: errored })] }));
|
|
51
|
-
}
|
|
52
|
-
if (!started) {
|
|
53
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionTitle, { children: "Sign in to Stigg" }), _jsx(Text, { dimColor: true, children: "We'll open your browser to complete the OAuth flow." }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Press ", _jsx(Text, { color: "cyan", children: "enter" }), " to continue."] }) })] }));
|
|
54
|
-
}
|
|
55
|
-
return _jsx(Spinner, { label: message });
|
|
56
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ConfirmInput } from "@inkjs/ui";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { SectionTitle } from "../components/SectionTitle.js";
|
|
5
|
-
export function SkillsStep({ dispatch }) {
|
|
6
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionTitle, { children: "Install Stigg skills for Claude Code?" }), _jsx(Text, { dimColor: true, children: "Clones stiggio/skills into ~/.claude/plugins/marketplaces/ \u2014 works as a Claude Code marketplace plugin." }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "Install? " }), _jsx(ConfirmInput, { onConfirm: () => dispatch({ type: "SKILLS_CHOICE", install: true }), onCancel: () => dispatch({ type: "SKILLS_CHOICE", install: false }) })] })] }));
|
|
7
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text, useInput } from "ink";
|
|
3
|
-
import { ContextRow } from "../components/ContextRow.js";
|
|
4
|
-
import { SectionTitle } from "../components/SectionTitle.js";
|
|
5
|
-
function credentialLabel(state) {
|
|
6
|
-
if (!state.credential)
|
|
7
|
-
return "?";
|
|
8
|
-
if (state.credential.kind === "scoped") {
|
|
9
|
-
const name = state.selectedKey?.name ?? "scoped";
|
|
10
|
-
const last4 = state.selectedKey?.lastFour ?? "????";
|
|
11
|
-
return `API key ${name} (sk_…${last4})`;
|
|
12
|
-
}
|
|
13
|
-
return `User JWT (broad access, env: ${state.environment?.name ?? "?"})`;
|
|
14
|
-
}
|
|
15
|
-
export function SummaryStep({ state, onDone }) {
|
|
16
|
-
useInput(() => onDone());
|
|
17
|
-
const entries = [
|
|
18
|
-
{ label: "Account", value: state.session?.email ?? "?" },
|
|
19
|
-
{ label: "Credential", value: credentialLabel(state) },
|
|
20
|
-
{ label: "Environment", value: state.environment?.name ?? "?" },
|
|
21
|
-
];
|
|
22
|
-
for (const w of state.writes) {
|
|
23
|
-
entries.push({
|
|
24
|
-
label: entries.find((e) => e.label === "Wrote to") ? "" : "Wrote to",
|
|
25
|
-
value: w.path,
|
|
26
|
-
hint: w.backedUpTo ? `backup: ${w.backedUpTo}` : undefined,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
if (state.installedSkills) {
|
|
30
|
-
entries.push({
|
|
31
|
-
label: "Skills",
|
|
32
|
-
value: state.installedSkills.ok
|
|
33
|
-
? `cloned to ${state.installedSkills.installedPath ?? "~/.claude/plugins/marketplaces/stiggio-skills"}`
|
|
34
|
-
: `skipped (${state.installedSkills.reason ?? "see logs"})`,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
else if (state.installSkills === false) {
|
|
38
|
-
entries.push({ label: "Skills", value: "not installed (declined)" });
|
|
39
|
-
}
|
|
40
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionTitle, { children: "Setup complete" }), _jsx(ContextRow, { entries: entries }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { children: "Next:" }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/stigg help" }), " ", "in Claude Code"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "@stigg" }), " ", "in Cursor (after restart)"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "cyberdeck dash" }), " ", "to open the Stigg dashboard"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "cyberdeck debug" }), " ", "to stream audit + usage logs"] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "press any key to return to menu" }) })] }));
|
|
41
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { ClientId, McpClientHandler } from "../../types.js";
|
|
3
|
-
import type { Action, WizardState } from "../state.js";
|
|
4
|
-
interface Props {
|
|
5
|
-
state: WizardState;
|
|
6
|
-
dispatch: React.Dispatch<Action>;
|
|
7
|
-
handlers: Record<ClientId, McpClientHandler>;
|
|
8
|
-
}
|
|
9
|
-
export declare function WritingStep({ state, dispatch, handlers, }: Props): React.ReactElement;
|
|
10
|
-
export {};
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ConfirmInput, Spinner } from "@inkjs/ui";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { useEffect, useState } from "react";
|
|
5
|
-
import { installStiggSkills } from "../../skills/install.js";
|
|
6
|
-
import { SectionTitle } from "../components/SectionTitle.js";
|
|
7
|
-
import { useAsyncEffect } from "../hooks/useAsyncEffect.js";
|
|
8
|
-
export function WritingStep({ state, dispatch, handlers, }) {
|
|
9
|
-
const [phase, setPhase] = useState({ kind: "init" });
|
|
10
|
-
const [currentClient, setCurrentClient] = useState(null);
|
|
11
|
-
const [skipped, setSkipped] = useState([]);
|
|
12
|
-
useAsyncEffect(async (signal) => {
|
|
13
|
-
if (phase.kind !== "init")
|
|
14
|
-
return;
|
|
15
|
-
const clients = state.selectedClients ?? [];
|
|
16
|
-
const existing = [];
|
|
17
|
-
for (const c of clients) {
|
|
18
|
-
if (await handlers[c].hasExistingEntry())
|
|
19
|
-
existing.push(c);
|
|
20
|
-
}
|
|
21
|
-
if (signal.cancelled)
|
|
22
|
-
return;
|
|
23
|
-
if (existing.length > 0) {
|
|
24
|
-
setPhase({ kind: "needs-confirm", existing });
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
setPhase({ kind: "writing" });
|
|
28
|
-
}
|
|
29
|
-
}, [phase.kind], (err) => dispatch({
|
|
30
|
-
type: "ERROR",
|
|
31
|
-
message: err instanceof Error ? err.message : String(err),
|
|
32
|
-
}));
|
|
33
|
-
useAsyncEffect(async (signal) => {
|
|
34
|
-
if (phase.kind !== "writing")
|
|
35
|
-
return;
|
|
36
|
-
const clients = (state.selectedClients ?? []).filter((c) => !skipped.includes(c));
|
|
37
|
-
for (const c of clients) {
|
|
38
|
-
if (signal.cancelled)
|
|
39
|
-
return;
|
|
40
|
-
setCurrentClient(c);
|
|
41
|
-
try {
|
|
42
|
-
const result = await handlers[c].write(state.credential);
|
|
43
|
-
const decorated = { ...result, client: c };
|
|
44
|
-
dispatch({ type: "WRITE_OK", result: decorated });
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
dispatch({
|
|
48
|
-
type: "ERROR",
|
|
49
|
-
message: err instanceof Error ? err.message : String(err),
|
|
50
|
-
});
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
setCurrentClient(null);
|
|
55
|
-
if (signal.cancelled)
|
|
56
|
-
return;
|
|
57
|
-
if (state.installSkills) {
|
|
58
|
-
setPhase({ kind: "skills" });
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
setPhase({ kind: "advancing" });
|
|
62
|
-
}
|
|
63
|
-
}, [phase.kind]);
|
|
64
|
-
useAsyncEffect(async (signal) => {
|
|
65
|
-
if (phase.kind !== "skills")
|
|
66
|
-
return;
|
|
67
|
-
const result = await installStiggSkills();
|
|
68
|
-
if (signal.cancelled)
|
|
69
|
-
return;
|
|
70
|
-
dispatch({ type: "SKILLS_INSTALL_OK", result });
|
|
71
|
-
}, [phase.kind], (err) => dispatch({
|
|
72
|
-
type: "ERROR",
|
|
73
|
-
message: err instanceof Error ? err.message : String(err),
|
|
74
|
-
}));
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
if (phase.kind === "advancing") {
|
|
77
|
-
dispatch({ type: "ADVANCE" });
|
|
78
|
-
}
|
|
79
|
-
}, [phase.kind, dispatch]);
|
|
80
|
-
if (phase.kind === "needs-confirm") {
|
|
81
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SectionTitle, { children: "Existing stigg entry found" }), _jsx(Text, { children: "The following clients already have a stigg MCP entry:" }), _jsx(Box, { flexDirection: "column", marginY: 1, children: phase.existing.map((c) => (_jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "\u2022" }), " ", handlers[c].label] }, c))) }), _jsx(Text, { children: "Overwrite? Existing entries will be backed up." }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "Overwrite? " }), _jsx(ConfirmInput, { onConfirm: () => setPhase({ kind: "writing" }), onCancel: () => {
|
|
82
|
-
setSkipped(phase.existing);
|
|
83
|
-
setPhase({ kind: "writing" });
|
|
84
|
-
} })] }), skipped.length > 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: ["Will skip: ", skipped.map((c) => handlers[c].label).join(", ")] }) }))] }));
|
|
85
|
-
}
|
|
86
|
-
if (phase.kind === "writing") {
|
|
87
|
-
const label = currentClient
|
|
88
|
-
? `Writing ${handlers[currentClient].label}…`
|
|
89
|
-
: "Writing config files…";
|
|
90
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Spinner, { label: label }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: state.writes.map((w, i) => (_jsxs(Text, { color: "green", children: [" ✓ ", w.path, w.backedUpTo ? (_jsxs(Text, { dimColor: true, children: [" (backup: ", w.backedUpTo, ")"] })) : null] }, i))) })] }));
|
|
91
|
-
}
|
|
92
|
-
if (phase.kind === "skills") {
|
|
93
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Spinner, { label: "Cloning stiggio/skills\u2026" }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: state.writes.map((w, i) => (_jsxs(Text, { color: "green", children: [" ✓ ", w.path] }, i))) })] }));
|
|
94
|
-
}
|
|
95
|
-
return _jsx(Spinner, { label: "Preparing\u2026" });
|
|
96
|
-
}
|
package/dist/ui/theme.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stigg brand palette — dark background, electric lime accent.
|
|
3
|
-
* Matches the May-2026 website theme.
|
|
4
|
-
*/
|
|
5
|
-
export declare const BRAND_LIME: {
|
|
6
|
-
readonly brightest: "#c8ff3c";
|
|
7
|
-
readonly primary: "#9eff00";
|
|
8
|
-
readonly mid: "#7dd83a";
|
|
9
|
-
readonly forest: "#4a9e1f";
|
|
10
|
-
readonly deep: "#235a14";
|
|
11
|
-
};
|
|
12
|
-
export declare const COLORS: {
|
|
13
|
-
readonly primary: "#9eff00";
|
|
14
|
-
readonly accent: "cyan";
|
|
15
|
-
readonly success: "#9eff00";
|
|
16
|
-
readonly warning: "yellow";
|
|
17
|
-
readonly error: "#ff4d4d";
|
|
18
|
-
readonly muted: "gray";
|
|
19
|
-
};
|
|
20
|
-
export declare const GLYPHS: {
|
|
21
|
-
readonly check: "✓";
|
|
22
|
-
readonly cross: "✗";
|
|
23
|
-
readonly bullet: "·";
|
|
24
|
-
readonly arrow: "▸";
|
|
25
|
-
readonly filled: "■";
|
|
26
|
-
readonly empty: "□";
|
|
27
|
-
readonly dot: "●";
|
|
28
|
-
readonly ring: "○";
|
|
29
|
-
};
|
|
30
|
-
/** Shell palette used by the new TUI (TitleBar, PickerMenu, hints bar). */
|
|
31
|
-
export declare const Colors: {
|
|
32
|
-
readonly primary: "#c8ff3c";
|
|
33
|
-
readonly accent: "#9eff00";
|
|
34
|
-
readonly titleColor: "#0a0a0a";
|
|
35
|
-
readonly success: "#9eff00";
|
|
36
|
-
readonly error: "#ff4d4d";
|
|
37
|
-
readonly muted: "gray";
|
|
38
|
-
};
|
|
39
|
-
/** RGB triplet painted into the terminal's alt-screen background via ANSI 48;2;r;g;b. */
|
|
40
|
-
export declare const SHELL_BG_RGB: readonly [10, 10, 10];
|
|
41
|
-
export declare const Icons: {
|
|
42
|
-
readonly triangleSmallRight: "▸";
|
|
43
|
-
readonly squareFilled: "◼";
|
|
44
|
-
readonly squareOpen: "◻";
|
|
45
|
-
readonly check: "✓";
|
|
46
|
-
readonly cross: "✗";
|
|
47
|
-
readonly bullet: "·";
|
|
48
|
-
};
|
|
49
|
-
export declare const MIN_SHELL_WIDTH = 80;
|
|
50
|
-
export declare const MAX_SHELL_WIDTH = 120;
|
|
51
|
-
export declare const MIN_CARD_WIDTH = 78;
|
|
52
|
-
export declare function shouldRenderBorder(): boolean;
|
|
53
|
-
export declare function shouldRenderAnimation(): boolean;
|
package/dist/ui/tui/App.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { LaunchRequest } from '../../launch/agent.js';
|
|
3
|
-
export type AppScreen = 'menu' | 'init' | 'dash' | 'env';
|
|
4
|
-
interface AppProps {
|
|
5
|
-
initialScreen?: AppScreen;
|
|
6
|
-
callbackPort?: number;
|
|
7
|
-
onLaunchAgent?: (req: LaunchRequest) => void;
|
|
8
|
-
}
|
|
9
|
-
export declare function App(props: AppProps): React.ReactElement;
|
|
10
|
-
export {};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
export interface ContextEntry {
|
|
3
|
-
label: string;
|
|
4
|
-
value: string;
|
|
5
|
-
hint?: string;
|
|
6
|
-
}
|
|
7
|
-
interface ContextStripProps {
|
|
8
|
-
entries: ContextEntry[];
|
|
9
|
-
}
|
|
10
|
-
export declare function ContextStrip({ entries }: ContextStripProps): React.ReactElement | null;
|
|
11
|
-
export {};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Key } from 'ink';
|
|
2
|
-
export declare enum KeyMatch {
|
|
3
|
-
UpArrow = 0,
|
|
4
|
-
DownArrow = 1,
|
|
5
|
-
LeftArrow = 2,
|
|
6
|
-
RightArrow = 3,
|
|
7
|
-
Return = 4,
|
|
8
|
-
Escape = 5,
|
|
9
|
-
Space = 6,
|
|
10
|
-
Tab = 7,
|
|
11
|
-
AnyChar = 8
|
|
12
|
-
}
|
|
13
|
-
export type KeyMatchOrChar = KeyMatch | string;
|
|
14
|
-
export interface KeyHint {
|
|
15
|
-
label: string;
|
|
16
|
-
action: string;
|
|
17
|
-
priority?: number;
|
|
18
|
-
}
|
|
19
|
-
export interface KeyBinding extends KeyHint {
|
|
20
|
-
match: KeyMatchOrChar | KeyMatchOrChar[];
|
|
21
|
-
handler: (input: string, key: Key) => void;
|
|
22
|
-
}
|
|
23
|
-
export declare const DEFAULT_HINT_PRIORITY = 50;
|
|
24
|
-
export declare function defaultPriorityFor(m: KeyMatchOrChar): number;
|
|
25
|
-
export declare function matchesKey(m: KeyMatchOrChar, input: string, key: Key): boolean;
|
|
26
|
-
export declare function dedupeAndSortHints(bag: Map<string, KeyHint[]>): KeyHint[];
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type KeyBinding } from './keyboard-hints-utils.js';
|
|
2
|
-
interface UseKeyBindingsOptions {
|
|
3
|
-
isActive?: boolean;
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Declarative key bindings + automatic hint registration.
|
|
7
|
-
*
|
|
8
|
-
* Each binding declares `{match, label, action, handler}`. We wire `useInput`
|
|
9
|
-
* to dispatch the matching binding's handler, AND register `{label, action,
|
|
10
|
-
* priority}` with the KeyboardHintsProvider so the bottom hints bar updates
|
|
11
|
-
* automatically when this component mounts/unmounts.
|
|
12
|
-
*/
|
|
13
|
-
export declare function useKeyBindings(id: string, bindings: KeyBinding[], opts?: UseKeyBindingsOptions): void;
|
|
14
|
-
export {};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { type KeyHint } from './keyboard-hints-utils.js';
|
|
3
|
-
interface KeyboardHintsContextValue {
|
|
4
|
-
register: (id: string, hints: KeyHint[]) => void;
|
|
5
|
-
unregister: (id: string) => void;
|
|
6
|
-
hints: KeyHint[];
|
|
7
|
-
}
|
|
8
|
-
interface ProviderProps {
|
|
9
|
-
children: React.ReactNode;
|
|
10
|
-
}
|
|
11
|
-
export declare function KeyboardHintsProvider({ children }: ProviderProps): React.ReactElement;
|
|
12
|
-
export declare function useKeyboardHintsContext(): KeyboardHintsContextValue;
|
|
13
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns the terminal's [columns, rows] and re-renders on resize.
|
|
3
|
-
*
|
|
4
|
-
* Ink's built-in `useStdout` doesn't trigger re-renders on resize — this hook
|
|
5
|
-
* subscribes to the `resize` event on the underlying stream and forces a state
|
|
6
|
-
* update so the entire layout reflows.
|
|
7
|
-
*/
|
|
8
|
-
export declare function useStdoutDimensions(): readonly [number, number];
|