@stigg/terminal 0.0.1-alpha

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 (199) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +47 -0
  3. package/dist/api/client.d.ts +6 -0
  4. package/dist/api/client.js +48 -0
  5. package/dist/api/format-key.d.ts +7 -0
  6. package/dist/api/format-key.js +12 -0
  7. package/dist/api/graphql-client.d.ts +5 -0
  8. package/dist/api/graphql-client.js +44 -0
  9. package/dist/api/operations.d.ts +65 -0
  10. package/dist/api/operations.js +77 -0
  11. package/dist/api/types.d.ts +18 -0
  12. package/dist/api/types.js +1 -0
  13. package/dist/auth/callback-server.d.ts +14 -0
  14. package/dist/auth/callback-server.js +145 -0
  15. package/dist/auth/config.d.ts +2 -0
  16. package/dist/auth/config.js +24 -0
  17. package/dist/auth/oauth.d.ts +17 -0
  18. package/dist/auth/oauth.js +94 -0
  19. package/dist/auth/storage.d.ts +6 -0
  20. package/dist/auth/storage.js +34 -0
  21. package/dist/bin.d.ts +2 -0
  22. package/dist/bin.js +3 -0
  23. package/dist/cli.d.ts +1 -0
  24. package/dist/cli.js +79 -0
  25. package/dist/commands/dash.d.ts +1 -0
  26. package/dist/commands/dash.js +24 -0
  27. package/dist/commands/debug.d.ts +1 -0
  28. package/dist/commands/debug.js +53 -0
  29. package/dist/commands/env.d.ts +1 -0
  30. package/dist/commands/env.js +15 -0
  31. package/dist/commands/init.d.ts +13 -0
  32. package/dist/commands/init.js +59 -0
  33. package/dist/commands/mcp.d.ts +7 -0
  34. package/dist/commands/mcp.js +37 -0
  35. package/dist/commands/skills.d.ts +6 -0
  36. package/dist/commands/skills.js +48 -0
  37. package/dist/headless/host-agent.d.ts +19 -0
  38. package/dist/headless/host-agent.js +64 -0
  39. package/dist/headless/init-phase1.d.ts +9 -0
  40. package/dist/headless/init-phase1.js +173 -0
  41. package/dist/headless/init-phase2.d.ts +36 -0
  42. package/dist/headless/init-phase2.js +150 -0
  43. package/dist/headless/next-step-prompt.d.ts +7 -0
  44. package/dist/headless/next-step-prompt.js +25 -0
  45. package/dist/headless/options.d.ts +30 -0
  46. package/dist/headless/options.js +77 -0
  47. package/dist/headless/reporter.d.ts +16 -0
  48. package/dist/headless/reporter.js +41 -0
  49. package/dist/headless/setup.d.ts +29 -0
  50. package/dist/headless/setup.js +80 -0
  51. package/dist/launch/agent.d.ts +55 -0
  52. package/dist/launch/agent.js +134 -0
  53. package/dist/mcp/clients/base.d.ts +49 -0
  54. package/dist/mcp/clients/base.js +66 -0
  55. package/dist/mcp/clients/claude-code.d.ts +22 -0
  56. package/dist/mcp/clients/claude-code.js +120 -0
  57. package/dist/mcp/clients/claude-desktop.d.ts +9 -0
  58. package/dist/mcp/clients/claude-desktop.js +35 -0
  59. package/dist/mcp/clients/codex.d.ts +13 -0
  60. package/dist/mcp/clients/codex.js +113 -0
  61. package/dist/mcp/clients/cursor.d.ts +9 -0
  62. package/dist/mcp/clients/cursor.js +26 -0
  63. package/dist/mcp/clients/index.d.ts +7 -0
  64. package/dist/mcp/clients/index.js +27 -0
  65. package/dist/mcp/clients/mcp-remote.d.ts +11 -0
  66. package/dist/mcp/clients/mcp-remote.js +13 -0
  67. package/dist/mcp/clients/vscode.d.ts +17 -0
  68. package/dist/mcp/clients/vscode.js +84 -0
  69. package/dist/mcp/clients.d.ts +4 -0
  70. package/dist/mcp/clients.js +50 -0
  71. package/dist/mcp/config-merge.d.ts +9 -0
  72. package/dist/mcp/config-merge.js +51 -0
  73. package/dist/mcp/writer.d.ts +6 -0
  74. package/dist/mcp/writer.js +65 -0
  75. package/dist/setup/storage.d.ts +21 -0
  76. package/dist/setup/storage.js +34 -0
  77. package/dist/skills/install.d.ts +19 -0
  78. package/dist/skills/install.js +64 -0
  79. package/dist/types.d.ts +35 -0
  80. package/dist/types.js +1 -0
  81. package/dist/ui/components/Card.d.ts +11 -0
  82. package/dist/ui/components/Card.js +19 -0
  83. package/dist/ui/components/ContextRow.d.ts +11 -0
  84. package/dist/ui/components/ContextRow.js +8 -0
  85. package/dist/ui/components/Footer.d.ts +10 -0
  86. package/dist/ui/components/Footer.js +9 -0
  87. package/dist/ui/components/Header.d.ts +11 -0
  88. package/dist/ui/components/Header.js +6 -0
  89. package/dist/ui/components/JsonPreview.d.ts +13 -0
  90. package/dist/ui/components/JsonPreview.js +25 -0
  91. package/dist/ui/components/SectionTitle.d.ts +6 -0
  92. package/dist/ui/components/SectionTitle.js +5 -0
  93. package/dist/ui/hooks/useAsyncEffect.d.ts +3 -0
  94. package/dist/ui/hooks/useAsyncEffect.js +20 -0
  95. package/dist/ui/hooks/useResize.d.ts +4 -0
  96. package/dist/ui/hooks/useResize.js +20 -0
  97. package/dist/ui/hud.d.ts +15 -0
  98. package/dist/ui/hud.js +30 -0
  99. package/dist/ui/ink-theme.d.ts +2 -0
  100. package/dist/ui/ink-theme.js +34 -0
  101. package/dist/ui/intro/LogoView.d.ts +12 -0
  102. package/dist/ui/intro/LogoView.js +226 -0
  103. package/dist/ui/intro/MatrixIntro.d.ts +6 -0
  104. package/dist/ui/intro/MatrixIntro.js +80 -0
  105. package/dist/ui/intro/logo.d.ts +6 -0
  106. package/dist/ui/intro/logo.js +21 -0
  107. package/dist/ui/messages.d.ts +5 -0
  108. package/dist/ui/messages.js +5 -0
  109. package/dist/ui/screens/DashScreen.d.ts +6 -0
  110. package/dist/ui/screens/DashScreen.js +27 -0
  111. package/dist/ui/screens/DebugScreen.d.ts +6 -0
  112. package/dist/ui/screens/DebugScreen.js +39 -0
  113. package/dist/ui/screens/InitScreen.d.ts +6 -0
  114. package/dist/ui/screens/InitScreen.js +138 -0
  115. package/dist/ui/screens/MenuScreen.d.ts +7 -0
  116. package/dist/ui/screens/MenuScreen.js +38 -0
  117. package/dist/ui/state.d.ts +72 -0
  118. package/dist/ui/state.js +107 -0
  119. package/dist/ui/steps/AccountStep.d.ts +8 -0
  120. package/dist/ui/steps/AccountStep.js +42 -0
  121. package/dist/ui/steps/ApiKeyStep.d.ts +8 -0
  122. package/dist/ui/steps/ApiKeyStep.js +91 -0
  123. package/dist/ui/steps/ClientsStep.d.ts +10 -0
  124. package/dist/ui/steps/ClientsStep.js +69 -0
  125. package/dist/ui/steps/CredentialKindStep.d.ts +7 -0
  126. package/dist/ui/steps/CredentialKindStep.js +18 -0
  127. package/dist/ui/steps/EnvironmentStep.d.ts +8 -0
  128. package/dist/ui/steps/EnvironmentStep.js +37 -0
  129. package/dist/ui/steps/LoginStep.d.ts +7 -0
  130. package/dist/ui/steps/LoginStep.js +56 -0
  131. package/dist/ui/steps/SkillsStep.d.ts +7 -0
  132. package/dist/ui/steps/SkillsStep.js +7 -0
  133. package/dist/ui/steps/SummaryStep.d.ts +8 -0
  134. package/dist/ui/steps/SummaryStep.js +41 -0
  135. package/dist/ui/steps/WritingStep.d.ts +10 -0
  136. package/dist/ui/steps/WritingStep.js +96 -0
  137. package/dist/ui/theme.d.ts +53 -0
  138. package/dist/ui/theme.js +66 -0
  139. package/dist/ui/tui/App.d.ts +10 -0
  140. package/dist/ui/tui/App.js +51 -0
  141. package/dist/ui/tui/components/ContextStrip.d.ts +11 -0
  142. package/dist/ui/tui/components/ContextStrip.js +8 -0
  143. package/dist/ui/tui/components/TitleBar.d.ts +6 -0
  144. package/dist/ui/tui/components/TitleBar.js +18 -0
  145. package/dist/ui/tui/components/WizardChecklist.d.ts +7 -0
  146. package/dist/ui/tui/components/WizardChecklist.js +69 -0
  147. package/dist/ui/tui/hooks/keyboard-hints-utils.d.ts +26 -0
  148. package/dist/ui/tui/hooks/keyboard-hints-utils.js +69 -0
  149. package/dist/ui/tui/hooks/useKeyBindings.d.ts +14 -0
  150. package/dist/ui/tui/hooks/useKeyBindings.js +44 -0
  151. package/dist/ui/tui/hooks/useKeyboardHints.d.ts +13 -0
  152. package/dist/ui/tui/hooks/useKeyboardHints.js +38 -0
  153. package/dist/ui/tui/hooks/useStdoutDimensions.d.ts +8 -0
  154. package/dist/ui/tui/hooks/useStdoutDimensions.js +28 -0
  155. package/dist/ui/tui/primitives/BlinkingLabel.d.ts +19 -0
  156. package/dist/ui/tui/primitives/BlinkingLabel.js +25 -0
  157. package/dist/ui/tui/primitives/ConfirmPrompt.d.ts +16 -0
  158. package/dist/ui/tui/primitives/ConfirmPrompt.js +36 -0
  159. package/dist/ui/tui/primitives/KeyboardHintsBar.d.ts +2 -0
  160. package/dist/ui/tui/primitives/KeyboardHintsBar.js +8 -0
  161. package/dist/ui/tui/primitives/PickerMenu.d.ts +38 -0
  162. package/dist/ui/tui/primitives/PickerMenu.js +162 -0
  163. package/dist/ui/tui/primitives/PromptLabel.d.ts +6 -0
  164. package/dist/ui/tui/primitives/PromptLabel.js +6 -0
  165. package/dist/ui/tui/primitives/ScreenContainer.d.ts +39 -0
  166. package/dist/ui/tui/primitives/ScreenContainer.js +39 -0
  167. package/dist/ui/tui/primitives/Spinner.d.ts +7 -0
  168. package/dist/ui/tui/primitives/Spinner.js +18 -0
  169. package/dist/ui/tui/screens/DashScreen.d.ts +6 -0
  170. package/dist/ui/tui/screens/DashScreen.js +37 -0
  171. package/dist/ui/tui/screens/DebugScreen.d.ts +6 -0
  172. package/dist/ui/tui/screens/DebugScreen.js +48 -0
  173. package/dist/ui/tui/screens/EnvScreen.d.ts +6 -0
  174. package/dist/ui/tui/screens/EnvScreen.js +192 -0
  175. package/dist/ui/tui/screens/InitScreen.d.ts +9 -0
  176. package/dist/ui/tui/screens/InitScreen.js +102 -0
  177. package/dist/ui/tui/screens/MenuScreen.d.ts +7 -0
  178. package/dist/ui/tui/screens/MenuScreen.js +84 -0
  179. package/dist/ui/tui/start-tui.d.ts +11 -0
  180. package/dist/ui/tui/start-tui.js +72 -0
  181. package/dist/ui/tui/steps/AccountStep.d.ts +8 -0
  182. package/dist/ui/tui/steps/AccountStep.js +42 -0
  183. package/dist/ui/tui/steps/ApiKeyStep.d.ts +8 -0
  184. package/dist/ui/tui/steps/ApiKeyStep.js +53 -0
  185. package/dist/ui/tui/steps/ClientsStep.d.ts +10 -0
  186. package/dist/ui/tui/steps/ClientsStep.js +52 -0
  187. package/dist/ui/tui/steps/CredentialKindStep.d.ts +7 -0
  188. package/dist/ui/tui/steps/CredentialKindStep.js +18 -0
  189. package/dist/ui/tui/steps/EnvironmentStep.d.ts +8 -0
  190. package/dist/ui/tui/steps/EnvironmentStep.js +38 -0
  191. package/dist/ui/tui/steps/LoginStep.d.ts +8 -0
  192. package/dist/ui/tui/steps/LoginStep.js +79 -0
  193. package/dist/ui/tui/steps/SkillsStep.d.ts +7 -0
  194. package/dist/ui/tui/steps/SkillsStep.js +7 -0
  195. package/dist/ui/tui/steps/SummaryStep.d.ts +10 -0
  196. package/dist/ui/tui/steps/SummaryStep.js +133 -0
  197. package/dist/ui/tui/steps/WritingStep.d.ts +10 -0
  198. package/dist/ui/tui/steps/WritingStep.js +101 -0
  199. package/package.json +62 -0
@@ -0,0 +1,34 @@
1
+ import { chmod, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ export function configDir() {
5
+ const xdg = process.env.XDG_CONFIG_HOME;
6
+ if (xdg)
7
+ return join(xdg, 'stigg');
8
+ return join(homedir(), '.config', 'stigg');
9
+ }
10
+ export function credentialsPath() {
11
+ return join(configDir(), 'credentials.json');
12
+ }
13
+ export async function saveSession(session) {
14
+ const dir = configDir();
15
+ const path = credentialsPath();
16
+ await mkdir(dir, { recursive: true });
17
+ await writeFile(path, JSON.stringify(session, null, 2), 'utf8');
18
+ await chmod(path, 0o600);
19
+ return path;
20
+ }
21
+ export async function loadSession() {
22
+ try {
23
+ const raw = await readFile(credentialsPath(), 'utf8');
24
+ return JSON.parse(raw);
25
+ }
26
+ catch (e) {
27
+ if (e.code === 'ENOENT')
28
+ return null;
29
+ throw e;
30
+ }
31
+ }
32
+ export async function clearSession() {
33
+ await rm(credentialsPath(), { force: true });
34
+ }
package/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { cli } from './cli.js';
3
+ cli();
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function cli(argv?: string[]): void;
package/dist/cli.js ADDED
@@ -0,0 +1,79 @@
1
+ import { Command } from 'commander';
2
+ import pc from 'picocolors';
3
+ import { dashCommand } from './commands/dash.js';
4
+ import { envCommand } from './commands/env.js';
5
+ import { initCommand } from './commands/init.js';
6
+ import { mcpAddCommand } from './commands/mcp.js';
7
+ import { skillsAddCommand } from './commands/skills.js';
8
+ import { ConfigParseError } from './mcp/config-merge.js';
9
+ import { runHudThenMaybeLaunch } from './ui/hud.js';
10
+ import { messages } from './ui/messages.js';
11
+ // Keep in sync with `version` in package.json.
12
+ const VERSION = '0.0.1-alpha';
13
+ function collectClient(value, prev) {
14
+ return [...prev, value];
15
+ }
16
+ export function cli(argv = process.argv) {
17
+ const program = new Command()
18
+ .name('stiggt')
19
+ .description('Stigg terminal — interactive setup TUI for AI coding assistants')
20
+ .version(VERSION)
21
+ .action(async () => {
22
+ if (!process.stdin.isTTY) {
23
+ program.outputHelp();
24
+ return;
25
+ }
26
+ await runHudThenMaybeLaunch();
27
+ });
28
+ program
29
+ .command('init')
30
+ .description('Set up Stigg in this project — auth, MCP, skills')
31
+ .option('--headless', 'Run without the interactive TUI')
32
+ .option('--force-login', 'Re-authenticate even if a valid session is cached')
33
+ .option('--callback-port <port>', 'Loopback port for the OAuth callback (overrides STIGG_CALLBACK_PORT)')
34
+ .option('--account-id <id>', 'phase 2: account ID from phase 1 listing')
35
+ .option('--environment-id <id>', 'phase 2: environment ID from phase 1 listing')
36
+ .option('--api-key-id <id>', 'phase 2: API key ID from phase 1 listing')
37
+ .option('-c, --client <id>', 'phase 2: limit to specific client(s); repeatable; default: host agent if detected, else --all', collectClient, [])
38
+ .option('--all', 'phase 2: target every detected client (overrides host-agent default)')
39
+ .option('--no-skills', 'phase 2: skip skill install (default: install)')
40
+ .option('--json', 'Emit a single JSON object on stdout instead of human-readable text')
41
+ .action(initCommand);
42
+ const mcp = program.command('mcp').description('Manage Stigg MCP entries in AI client configs');
43
+ mcp
44
+ .command('add')
45
+ .description('Write the Stigg MCP entry to one or more AI client configs (non-interactive)')
46
+ .option('--api-key <value>', 'Stigg API key (or set STIGG_API_KEY)')
47
+ .option('-c, --client <id>', 'target client (repeatable)', collectClient, [])
48
+ .option('--all', 'target every detected client')
49
+ .option('--json', 'JSON output')
50
+ .action(mcpAddCommand);
51
+ const skills = program
52
+ .command('skills')
53
+ .description('Manage Stigg skills install for AI clients');
54
+ skills
55
+ .command('add')
56
+ .description('Install Stigg skills for one or more AI clients (non-interactive)')
57
+ .option('-c, --client <id>', 'target client (repeatable)', collectClient, [])
58
+ .option('--all', 'target every detected client')
59
+ .option('--json', 'JSON output')
60
+ .action(skillsAddCommand);
61
+ program.command('env').description('Switch the active Stigg environment').action(envCommand);
62
+ program
63
+ .command('dash')
64
+ .description('Open the Stigg dashboard in your browser')
65
+ .action(dashCommand);
66
+ program.parseAsync(argv).catch((err) => {
67
+ if (err instanceof ConfigParseError) {
68
+ console.error(pc.red(`\n✗ ${messages.writes.abortMalformed(err.path)}`));
69
+ process.exit(2);
70
+ }
71
+ if (err instanceof Error) {
72
+ console.error(pc.red(`\n✗ ${err.message}`));
73
+ }
74
+ else {
75
+ console.error(err);
76
+ }
77
+ process.exit(1);
78
+ });
79
+ }
@@ -0,0 +1 @@
1
+ export declare function dashCommand(): Promise<void>;
@@ -0,0 +1,24 @@
1
+ import open from 'open';
2
+ import pc from 'picocolors';
3
+ import { runHud } from '../ui/hud.js';
4
+ const DASHBOARD_URL = 'https://app.stigg.io';
5
+ export async function dashCommand() {
6
+ if (process.stdin.isTTY) {
7
+ await runHud({ initialScreen: 'dash' });
8
+ return;
9
+ }
10
+ // Non-TTY fallback (CI / pipe) — plain console output.
11
+ console.log();
12
+ console.log(pc.greenBright(pc.bold(' stigg · terminal · dash')));
13
+ console.log(pc.dim(' ─────────────────────────'));
14
+ console.log();
15
+ console.log(` Opening ${pc.cyan(DASHBOARD_URL)}…`);
16
+ console.log();
17
+ try {
18
+ await open(DASHBOARD_URL);
19
+ }
20
+ catch {
21
+ console.log(` Could not launch a browser automatically. Open manually: ${pc.cyan(DASHBOARD_URL)}`);
22
+ console.log();
23
+ }
24
+ }
@@ -0,0 +1 @@
1
+ export declare function debugCommand(): Promise<void>;
@@ -0,0 +1,53 @@
1
+ import pc from "picocolors";
2
+ import { runHud } from "../ui/hud.js";
3
+ const SAMPLE_LOGS = [
4
+ {
5
+ time: "16:42:13.221",
6
+ level: "INFO",
7
+ source: "feature.access",
8
+ message: "customer=acme_corp has_access=true plan=growth feature=ai_credits",
9
+ },
10
+ {
11
+ time: "16:42:14.034",
12
+ level: "INFO",
13
+ source: "usage.report",
14
+ message: "customer=acme_corp feature=api_calls value=1 source=mcp",
15
+ },
16
+ {
17
+ time: "16:42:18.512",
18
+ level: "WARN",
19
+ source: "entitlement.exceeded",
20
+ message: "customer=acme_corp feature=api_calls usage=1001 limit=1000 reset_at=2026-07-01",
21
+ },
22
+ {
23
+ time: "16:42:21.118",
24
+ level: "INFO",
25
+ source: "subscription.updated",
26
+ message: "customer=acme_corp from=growth to=growth_v2 status=active",
27
+ },
28
+ ];
29
+ const LEVEL_COLOR = {
30
+ INFO: pc.green,
31
+ WARN: pc.yellow,
32
+ ERROR: pc.red,
33
+ };
34
+ export async function debugCommand() {
35
+ if (process.stdin.isTTY) {
36
+ await runHud({ initialScreen: "debug" });
37
+ return;
38
+ }
39
+ // Non-TTY fallback (CI / pipe) — plain console output.
40
+ console.log();
41
+ console.log(pc.greenBright(pc.bold(" stigg · terminal · debug")));
42
+ console.log(pc.dim(" ──────────────────────────"));
43
+ console.log();
44
+ console.log(pc.dim(" Streaming audit + usage logs (placeholder, sample output)…"));
45
+ console.log();
46
+ for (const log of SAMPLE_LOGS) {
47
+ const colorFn = LEVEL_COLOR[log.level];
48
+ console.log(` ${pc.dim(log.time)} ${colorFn(log.level.padEnd(5))} ${pc.cyan(log.source.padEnd(22))} ${log.message}`);
49
+ }
50
+ console.log();
51
+ console.log(pc.dim(" (placeholder — the real command will live-tail audit + usage events for the active env, with `--since`, `--follow`, and `--filter` flags.)"));
52
+ console.log();
53
+ }
@@ -0,0 +1 @@
1
+ export declare function envCommand(): Promise<void>;
@@ -0,0 +1,15 @@
1
+ import pc from 'picocolors';
2
+ import { runHud } from '../ui/hud.js';
3
+ export async function envCommand() {
4
+ if (process.stdin.isTTY) {
5
+ await runHud({ initialScreen: 'env' });
6
+ return;
7
+ }
8
+ // Non-TTY fallback (CI / pipe) — plain console output.
9
+ console.log();
10
+ console.log(pc.greenBright(pc.bold(' stigg · terminal · env')));
11
+ console.log(pc.dim(' ──────────────────────────'));
12
+ console.log();
13
+ console.log(pc.dim(' Switch environments interactively by running `terminal env` from a real terminal.'));
14
+ console.log();
15
+ }
@@ -0,0 +1,13 @@
1
+ export interface InitOptions {
2
+ headless?: boolean;
3
+ forceLogin?: boolean;
4
+ callbackPort?: string;
5
+ accountId?: string;
6
+ environmentId?: string;
7
+ apiKeyId?: string;
8
+ client?: string[];
9
+ all?: boolean;
10
+ skills?: boolean;
11
+ json?: boolean;
12
+ }
13
+ export declare function initCommand(opts?: InitOptions): Promise<void>;
@@ -0,0 +1,59 @@
1
+ import pc from 'picocolors';
2
+ import { runInitPhase1 } from '../headless/init-phase1.js';
3
+ import { runInitPhase2 } from '../headless/init-phase2.js';
4
+ import { HeadlessOptionsError } from '../headless/options.js';
5
+ import { runHudThenMaybeLaunch } from '../ui/hud.js';
6
+ function parseCallbackPort(raw) {
7
+ if (raw === undefined)
8
+ return undefined;
9
+ const port = Number(raw);
10
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
11
+ throw new HeadlessOptionsError(`--callback-port must be an integer between 1 and 65535 (got "${raw}")`);
12
+ }
13
+ return port;
14
+ }
15
+ export async function initCommand(opts = {}) {
16
+ try {
17
+ const callbackPort = parseCallbackPort(opts.callbackPort);
18
+ if (!opts.headless) {
19
+ if (!process.stdin.isTTY) {
20
+ process.stderr.write('\nterminal init needs an interactive terminal (TTY).\n' +
21
+ 'Pass --headless to run non-interactively, or run from a shell directly.\n\n');
22
+ process.exit(1);
23
+ }
24
+ await runHudThenMaybeLaunch({ initialScreen: 'init', callbackPort });
25
+ return;
26
+ }
27
+ const anyId = opts.accountId || opts.environmentId || opts.apiKeyId;
28
+ if (!anyId) {
29
+ await runInitPhase1({
30
+ forceLogin: opts.forceLogin,
31
+ callbackPort,
32
+ client: opts.client,
33
+ all: opts.all,
34
+ installSkills: opts.skills !== false,
35
+ json: opts.json,
36
+ });
37
+ return;
38
+ }
39
+ if (!opts.accountId || !opts.environmentId || !opts.apiKeyId) {
40
+ throw new HeadlessOptionsError('phase 2 requires all three: --account-id, --environment-id, --api-key-id');
41
+ }
42
+ await runInitPhase2({
43
+ accountId: opts.accountId,
44
+ environmentId: opts.environmentId,
45
+ apiKeyId: opts.apiKeyId,
46
+ client: opts.client,
47
+ all: opts.all,
48
+ installSkills: opts.skills !== false,
49
+ json: opts.json,
50
+ });
51
+ }
52
+ catch (e) {
53
+ if (e instanceof HeadlessOptionsError) {
54
+ process.stderr.write(`${pc.red('✗')} ${e.message}\n`);
55
+ process.exit(2);
56
+ }
57
+ throw e;
58
+ }
59
+ }
@@ -0,0 +1,7 @@
1
+ export interface McpAddOptions {
2
+ apiKey?: string;
3
+ client?: string[];
4
+ all?: boolean;
5
+ json?: boolean;
6
+ }
7
+ export declare function mcpAddCommand(opts?: McpAddOptions): Promise<void>;
@@ -0,0 +1,37 @@
1
+ import pc from 'picocolors';
2
+ import { HeadlessOptionsError, parseClientSelection, requireApiKey } from '../headless/options.js';
3
+ import { createReporter, fmt } from '../headless/reporter.js';
4
+ import { runHeadlessSetup } from '../headless/setup.js';
5
+ export async function mcpAddCommand(opts = {}) {
6
+ try {
7
+ const apiKey = requireApiKey(opts.apiKey);
8
+ const clients = parseClientSelection({ client: opts.client, all: opts.all }, { required: true });
9
+ const reporter = createReporter({ json: opts.json });
10
+ if (!opts.json)
11
+ reporter.human(fmt.heading('mcp · add'));
12
+ const result = await runHeadlessSetup({ apiKey, clients, installSkills: false }, {
13
+ onClientResult: (write, { name }) => {
14
+ if (!opts.json)
15
+ reporter.human(fmt.ok(name, write.path));
16
+ },
17
+ onClientFail: (_id, name, reason) => {
18
+ reporter.stderr(fmt.fail(name, reason));
19
+ },
20
+ });
21
+ if (!opts.json && result.ok)
22
+ reporter.human('Done.');
23
+ reporter.emit({
24
+ ok: result.ok,
25
+ writes: result.writes,
26
+ skipped: result.skipped,
27
+ });
28
+ process.exit(result.ok ? 0 : 1);
29
+ }
30
+ catch (e) {
31
+ if (e instanceof HeadlessOptionsError) {
32
+ process.stderr.write(`${pc.red('✗')} ${e.message}\n`);
33
+ process.exit(2);
34
+ }
35
+ throw e;
36
+ }
37
+ }
@@ -0,0 +1,6 @@
1
+ export interface SkillsAddOptions {
2
+ client?: string[];
3
+ all?: boolean;
4
+ json?: boolean;
5
+ }
6
+ export declare function skillsAddCommand(opts?: SkillsAddOptions): Promise<void>;
@@ -0,0 +1,48 @@
1
+ import pc from 'picocolors';
2
+ import { HeadlessOptionsError, parseClientSelection } from '../headless/options.js';
3
+ import { createReporter, fmt } from '../headless/reporter.js';
4
+ import { runHeadlessSetup } from '../headless/setup.js';
5
+ export async function skillsAddCommand(opts = {}) {
6
+ try {
7
+ const clients = parseClientSelection({ client: opts.client, all: opts.all }, { required: true });
8
+ const reporter = createReporter({ json: opts.json });
9
+ if (!opts.json)
10
+ reporter.human(fmt.heading('skills · add'));
11
+ const result = await runHeadlessSetup({ apiKey: '', clients, installSkills: true, skipMcp: true }, {
12
+ onSkillsResult: (skillsResult) => {
13
+ if (skillsResult.claudeCode) {
14
+ if (skillsResult.claudeCode.ok) {
15
+ if (!opts.json)
16
+ reporter.human(fmt.ok('Claude Code plugin', 'stigg@stigg-marketplace'));
17
+ }
18
+ else {
19
+ reporter.stderr(fmt.fail('Claude Code plugin', skillsResult.claudeCode.reason));
20
+ }
21
+ }
22
+ if (skillsResult.agentSkills) {
23
+ if (skillsResult.agentSkills.ok) {
24
+ if (!opts.json)
25
+ reporter.human(fmt.ok('Agent skills', 'stiggio/skills'));
26
+ }
27
+ else {
28
+ reporter.stderr(fmt.fail('Agent skills', skillsResult.agentSkills.reason));
29
+ }
30
+ }
31
+ },
32
+ });
33
+ if (!opts.json && result.ok)
34
+ reporter.human('Done.');
35
+ reporter.emit({
36
+ ok: result.ok,
37
+ skillsInstall: result.skillsInstall,
38
+ });
39
+ process.exit(result.ok ? 0 : 1);
40
+ }
41
+ catch (e) {
42
+ if (e instanceof HeadlessOptionsError) {
43
+ process.stderr.write(`${pc.red('✗')} ${e.message}\n`);
44
+ process.exit(2);
45
+ }
46
+ throw e;
47
+ }
48
+ }
@@ -0,0 +1,19 @@
1
+ import type { ClientId } from '../types.js';
2
+ export interface HostAgent {
3
+ /** The MCP client ID this agent corresponds to. */
4
+ id: ClientId;
5
+ /** Human-readable display name. */
6
+ name: string;
7
+ /** Agent-specific one-line restart instruction (without the leading ⚠ marker). */
8
+ restartHint: string;
9
+ }
10
+ /**
11
+ * Detect which AI agent (if any) is hosting this CLI invocation, based on
12
+ * env vars that each agent sets when it spawns shell commands.
13
+ *
14
+ * Priority: STIGG_HOST_AGENT override > Claude Code > Cursor > Codex > VS Code > null.
15
+ *
16
+ * Detection is best-effort — a false negative just falls back to the generic
17
+ * restart line and `--all` client default.
18
+ */
19
+ export declare function detectHostAgent(): HostAgent | null;
@@ -0,0 +1,64 @@
1
+ const CLAUDE_CODE = {
2
+ id: 'claude-code',
3
+ name: 'Claude Code',
4
+ restartHint: 'Restart Claude Code (/exit + run `claude` again) to load Stigg MCP into your next session.',
5
+ };
6
+ const CURSOR = {
7
+ id: 'cursor',
8
+ name: 'Cursor',
9
+ restartHint: 'Restart Cursor (close and reopen the window) to load Stigg MCP.',
10
+ };
11
+ const VSCODE = {
12
+ id: 'vscode',
13
+ name: 'VS Code',
14
+ restartHint: 'Restart VS Code (close and reopen the window) to load Stigg MCP.',
15
+ };
16
+ const CODEX = {
17
+ id: 'codex',
18
+ name: 'Codex',
19
+ restartHint: 'Restart Codex (exit and run `codex` again) to load Stigg MCP.',
20
+ };
21
+ const CLAUDE_DESKTOP = {
22
+ id: 'claude-desktop',
23
+ name: 'Claude Desktop',
24
+ restartHint: 'Restart Claude Desktop (quit and reopen the app) to load Stigg MCP.',
25
+ };
26
+ const KNOWN_AGENTS = {
27
+ 'claude-code': CLAUDE_CODE,
28
+ cursor: CURSOR,
29
+ vscode: VSCODE,
30
+ codex: CODEX,
31
+ 'claude-desktop': CLAUDE_DESKTOP,
32
+ };
33
+ /**
34
+ * Detect which AI agent (if any) is hosting this CLI invocation, based on
35
+ * env vars that each agent sets when it spawns shell commands.
36
+ *
37
+ * Priority: STIGG_HOST_AGENT override > Claude Code > Cursor > Codex > VS Code > null.
38
+ *
39
+ * Detection is best-effort — a false negative just falls back to the generic
40
+ * restart line and `--all` client default.
41
+ */
42
+ export function detectHostAgent() {
43
+ const override = process.env.STIGG_HOST_AGENT;
44
+ if (override !== undefined) {
45
+ const trimmed = override.trim();
46
+ if (trimmed === 'none')
47
+ return null;
48
+ if (trimmed !== '') {
49
+ const known = KNOWN_AGENTS[trimmed];
50
+ if (known)
51
+ return known;
52
+ process.stderr.write(`⚠ STIGG_HOST_AGENT="${trimmed}" is not a known client id; ignoring.\n`);
53
+ }
54
+ }
55
+ if (process.env.CLAUDECODE === '1')
56
+ return CLAUDE_CODE;
57
+ if (process.env.CURSOR_TRACE_ID || process.env.TERM_PROGRAM === 'cursor')
58
+ return CURSOR;
59
+ if (process.env.CODEX_SESSION_ID || process.env.CODEX_CLI === '1')
60
+ return CODEX;
61
+ if (process.env.TERM_PROGRAM === 'vscode')
62
+ return VSCODE;
63
+ return null;
64
+ }
@@ -0,0 +1,9 @@
1
+ export interface PhaseOneOptions {
2
+ forceLogin?: boolean;
3
+ callbackPort?: number;
4
+ client?: string[];
5
+ all?: boolean;
6
+ installSkills?: boolean;
7
+ json?: boolean;
8
+ }
9
+ export declare function runInitPhase1(opts?: PhaseOneOptions): Promise<void>;