@respan/cli 0.10.0 → 0.12.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.
Files changed (47) hide show
  1. package/dist/commands/demo/clear.d.ts +23 -0
  2. package/dist/commands/demo/clear.js +114 -0
  3. package/dist/commands/demo/index.d.ts +15 -0
  4. package/dist/commands/demo/index.js +81 -0
  5. package/dist/commands/setup/doctor.d.ts +0 -1
  6. package/dist/commands/setup/doctor.js +25 -40
  7. package/dist/commands/setup/gateway.d.ts +16 -0
  8. package/dist/commands/setup/gateway.js +33 -0
  9. package/dist/commands/setup/index.d.ts +4 -33
  10. package/dist/commands/setup/index.js +11 -762
  11. package/dist/commands/setup/tracing.d.ts +16 -0
  12. package/dist/commands/setup/tracing.js +33 -0
  13. package/dist/lib/agents.d.ts +16 -0
  14. package/dist/lib/agents.js +75 -0
  15. package/dist/lib/auth.js +24 -0
  16. package/dist/lib/colors.d.ts +7 -0
  17. package/dist/lib/colors.js +10 -0
  18. package/dist/lib/demo/dataset-fixtures.d.ts +32 -0
  19. package/dist/lib/demo/dataset-fixtures.js +194 -0
  20. package/dist/lib/demo/evaluator-fixtures.d.ts +41 -0
  21. package/dist/lib/demo/evaluator-fixtures.js +251 -0
  22. package/dist/lib/demo/prompt-fixtures.d.ts +54 -0
  23. package/dist/lib/demo/prompt-fixtures.js +395 -0
  24. package/dist/lib/demo/seed-datasets.d.ts +15 -0
  25. package/dist/lib/demo/seed-datasets.js +107 -0
  26. package/dist/lib/demo/seed-evaluators.d.ts +22 -0
  27. package/dist/lib/demo/seed-evaluators.js +180 -0
  28. package/dist/lib/demo/seed-prompts.d.ts +10 -0
  29. package/dist/lib/demo/seed-prompts.js +111 -0
  30. package/dist/lib/demo/seed-traces.d.ts +27 -0
  31. package/dist/lib/demo/seed-traces.js +158 -0
  32. package/dist/lib/demo/seeders.d.ts +8 -0
  33. package/dist/lib/demo/seeders.js +11 -0
  34. package/dist/lib/demo/trace-fixtures.d.ts +31 -0
  35. package/dist/lib/demo/trace-fixtures.js +79 -0
  36. package/dist/lib/demo/types.d.ts +57 -0
  37. package/dist/lib/demo/types.js +9 -0
  38. package/dist/lib/integrate.d.ts +6 -0
  39. package/dist/lib/integrate.js +11 -0
  40. package/dist/lib/setup-base-command.d.ts +84 -0
  41. package/dist/lib/setup-base-command.js +649 -0
  42. package/dist/lib/skill-content.d.ts +1 -0
  43. package/dist/lib/skill-content.js +16 -0
  44. package/dist/lib/skill-refs.generated.d.ts +3 -2
  45. package/dist/lib/skill-refs.generated.js +423 -102
  46. package/oclif.manifest.json +945 -642
  47. package/package.json +2 -1
@@ -0,0 +1,23 @@
1
+ import { BaseCommand } from '../../lib/base-command.js';
2
+ /**
3
+ * Tear down what `respan demo` created. Each seeder owns how it identifies its own
4
+ * demo resources — prompts by exact fixture name, traces by the `demo` workflow —
5
+ * so a resource that was manually renamed/relabeled may not be matched, the same
6
+ * identity contract used when seeding.
7
+ */
8
+ export default class DemoClear extends BaseCommand {
9
+ static description: string;
10
+ static examples: string[];
11
+ static flags: {
12
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ 'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ 'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
+ csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
+ };
20
+ run(): Promise<void>;
21
+ private previewDeletions;
22
+ private printSummary;
23
+ }
@@ -0,0 +1,114 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { confirm } from '@inquirer/prompts';
3
+ import { BaseCommand } from '../../lib/base-command.js';
4
+ import { getActiveProfile, getCredential } from '../../lib/config.js';
5
+ import { GREEN, DIM, BOLD, RESET } from '../../lib/colors.js';
6
+ import { SEEDERS } from '../../lib/demo/seeders.js';
7
+ /**
8
+ * Tear down what `respan demo` created. Each seeder owns how it identifies its own
9
+ * demo resources — prompts by exact fixture name, traces by the `demo` workflow —
10
+ * so a resource that was manually renamed/relabeled may not be matched, the same
11
+ * identity contract used when seeding.
12
+ */
13
+ class DemoClear extends BaseCommand {
14
+ async run() {
15
+ const { flags } = await this.parse(DemoClear);
16
+ this.globalFlags = flags;
17
+ const profile = flags.profile || getActiveProfile();
18
+ if (!getCredential(profile) && !flags['api-key']) {
19
+ this.error('Not authenticated. Run `respan auth login` (or set RESPAN_API_KEY) before running `respan demo clear`.', { exit: 1 });
20
+ }
21
+ try {
22
+ const client = this.getClient();
23
+ const ctx = {
24
+ client,
25
+ authHeader: this.getAuthHeader(),
26
+ baseUrl: this.getBaseUrl(),
27
+ };
28
+ // Preview what exists before deleting anything.
29
+ const existing = [];
30
+ for (const seeder of SEEDERS) {
31
+ const matches = await this.spin(`Finding ${seeder.label}`, () => seeder.findExisting(ctx));
32
+ existing.push({ label: seeder.label, matches });
33
+ }
34
+ const total = existing.reduce((n, e) => n + e.matches.length, 0);
35
+ if (total === 0) {
36
+ this.log('');
37
+ this.log(`Nothing to clear in account ${DIM}(${profile})${RESET}.`);
38
+ this.log('');
39
+ return;
40
+ }
41
+ if (!flags.yes && !flags.json) {
42
+ this.previewDeletions(profile, existing);
43
+ if (!process.stdin.isTTY) {
44
+ this.error('Refusing to delete without confirmation. Re-run with --yes.', { exit: 1 });
45
+ }
46
+ const proceed = await confirm({
47
+ message: `Delete ${total} demo resource(s) from account "${profile}"?`,
48
+ default: false,
49
+ });
50
+ if (!proceed) {
51
+ this.log('Aborted. Nothing was deleted.');
52
+ return;
53
+ }
54
+ }
55
+ const results = [];
56
+ for (const seeder of SEEDERS) {
57
+ const result = await this.spin(`Clearing ${seeder.label}`, () => seeder.clear(ctx));
58
+ results.push(result);
59
+ }
60
+ this.printSummary(profile, results);
61
+ }
62
+ catch (error) {
63
+ this.handleError(error);
64
+ }
65
+ }
66
+ previewDeletions(profile, existing) {
67
+ this.log('');
68
+ this.log(`${BOLD}respan demo clear${RESET} will delete from account ${DIM}(${profile})${RESET}:`);
69
+ for (const { label, matches } of existing) {
70
+ if (matches.length === 0)
71
+ continue;
72
+ this.log('');
73
+ this.log(` ${BOLD}${label}${RESET}`);
74
+ for (const m of matches) {
75
+ this.log(` ${DIM}- ${m.name} (id: ${m.id})${RESET}`);
76
+ }
77
+ }
78
+ this.log('');
79
+ }
80
+ printSummary(profile, results) {
81
+ if (this.globalFlags.json) {
82
+ this.outputResult(results);
83
+ return;
84
+ }
85
+ this.log('');
86
+ this.log(`${GREEN}✓${RESET} ${BOLD}respan demo clear${RESET} — account ${DIM}(${profile})${RESET}`);
87
+ for (const result of results) {
88
+ if (result.items.length === 0)
89
+ continue; // e.g. traces, which are never deleted
90
+ this.log('');
91
+ this.log(` ${BOLD}${result.label}${RESET}`);
92
+ for (const item of result.items) {
93
+ if (item.status === 'deleted') {
94
+ this.log(` ${GREEN}Deleted${RESET} ${item.name} ${DIM}(id: ${item.id})${RESET}`);
95
+ }
96
+ else {
97
+ this.log(` ${DIM}Skipped ${item.name} (${item.reason})${RESET}`);
98
+ }
99
+ }
100
+ }
101
+ const deletedCount = results.reduce((n, r) => n + r.items.filter((i) => i.status === 'deleted').length, 0);
102
+ const skippedCount = results.reduce((n, r) => n + r.items.filter((i) => i.status === 'skipped').length, 0);
103
+ this.log('');
104
+ this.log(` ${DIM}${deletedCount} deleted, ${skippedCount} not found${RESET}`);
105
+ this.log('');
106
+ }
107
+ }
108
+ DemoClear.description = 'Delete the sample prompts, datasets, and evaluators created by `respan demo`. Demo traces are left in place (each run is timestamped history). Idempotent — safe to re-run.';
109
+ DemoClear.examples = ['<%= config.bin %> demo clear', '<%= config.bin %> demo clear --yes'];
110
+ DemoClear.flags = {
111
+ ...BaseCommand.baseFlags,
112
+ yes: Flags.boolean({ char: 'y', description: 'Skip the confirmation prompt', default: false }),
113
+ };
114
+ export default DemoClear;
@@ -0,0 +1,15 @@
1
+ import { BaseCommand } from '../../lib/base-command.js';
2
+ export default class Demo extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ 'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ 'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ };
13
+ run(): Promise<void>;
14
+ private printSummary;
15
+ }
@@ -0,0 +1,81 @@
1
+ import { BaseCommand } from '../../lib/base-command.js';
2
+ import { getActiveProfile, getCredential } from '../../lib/config.js';
3
+ import { GREEN, DIM, BOLD, RESET } from '../../lib/colors.js';
4
+ import { SEEDERS } from '../../lib/demo/seeders.js';
5
+ const PLATFORM_BASE = 'https://platform.respan.ai/platform';
6
+ /** Dashboard link for a seeded service, deep-linked/filtered where possible so the
7
+ * user lands directly on what was just created. Traces are pre-filtered to the
8
+ * `demo` workflow so they're isolated from any existing traffic. */
9
+ function viewLink(service) {
10
+ switch (service) {
11
+ case 'prompts':
12
+ return `${PLATFORM_BASE}/prompts`;
13
+ case 'datasets':
14
+ return `${PLATFORM_BASE}/datasets`;
15
+ case 'evaluators':
16
+ return `${PLATFORM_BASE}/evaluators`;
17
+ case 'traces':
18
+ return `${PLATFORM_BASE}/traces?span_workflow_name=demo`;
19
+ default:
20
+ return undefined;
21
+ }
22
+ }
23
+ class Demo extends BaseCommand {
24
+ async run() {
25
+ const { flags } = await this.parse(Demo);
26
+ this.globalFlags = flags;
27
+ const profile = flags.profile || getActiveProfile();
28
+ if (!getCredential(profile) && !flags['api-key']) {
29
+ this.error('Not authenticated. Run `respan auth login` (or set RESPAN_API_KEY) before running `respan demo`.', { exit: 1 });
30
+ }
31
+ try {
32
+ const client = this.getClient();
33
+ const ctx = {
34
+ client,
35
+ authHeader: this.getAuthHeader(),
36
+ baseUrl: this.getBaseUrl(),
37
+ };
38
+ const results = [];
39
+ for (const seeder of SEEDERS) {
40
+ const result = await this.spin(`Seeding ${seeder.label}`, () => seeder.run(ctx));
41
+ results.push(result);
42
+ }
43
+ this.printSummary(profile, results);
44
+ }
45
+ catch (error) {
46
+ this.handleError(error);
47
+ }
48
+ }
49
+ printSummary(profile, results) {
50
+ if (this.globalFlags.json) {
51
+ this.outputResult(results);
52
+ return;
53
+ }
54
+ this.log('');
55
+ this.log(`${GREEN}✓${RESET} ${BOLD}respan demo${RESET} — seeded into account ${DIM}(${profile})${RESET}`);
56
+ for (const result of results) {
57
+ this.log('');
58
+ this.log(` ${BOLD}${result.label}${RESET}`);
59
+ for (const item of result.items) {
60
+ if (item.status === 'created') {
61
+ this.log(` ${GREEN}Created${RESET} ${item.name} ${DIM}(id: ${item.id})${RESET}`);
62
+ }
63
+ else {
64
+ this.log(` ${DIM}Skipped ${item.name} (${item.reason})${RESET}`);
65
+ }
66
+ }
67
+ const link = viewLink(result.service);
68
+ if (link)
69
+ this.log(` ${DIM}View:${RESET} ${link}`);
70
+ }
71
+ const createdCount = results.reduce((n, r) => n + r.items.filter((i) => i.status === 'created').length, 0);
72
+ const skippedCount = results.reduce((n, r) => n + r.items.filter((i) => i.status === 'skipped').length, 0);
73
+ this.log('');
74
+ this.log(` ${DIM}${createdCount} created, ${skippedCount} skipped${RESET}`);
75
+ this.log('');
76
+ }
77
+ }
78
+ Demo.description = 'Seed your account with sample data (prompts and traces) so you have something to explore. Idempotent — safe to re-run.';
79
+ Demo.examples = ['<%= config.bin %> demo'];
80
+ Demo.flags = { ...BaseCommand.baseFlags };
81
+ export default Demo;
@@ -13,5 +13,4 @@ export default class SetupDoctor extends BaseCommand {
13
13
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
14
  };
15
15
  run(): Promise<void>;
16
- private isBinaryInstalled;
17
16
  }
@@ -5,12 +5,8 @@ import { execSync } from 'node:child_process';
5
5
  import { Flags } from '@oclif/core';
6
6
  import { BaseCommand } from '../../lib/base-command.js';
7
7
  import { findProjectRoot, expandHome, readTextFile } from '../../lib/integrate.js';
8
- const GREEN = '\x1b[32m';
9
- const RED = '\x1b[31m';
10
- const YELLOW = '\x1b[33m';
11
- const DIM = '\x1b[2m';
12
- const BOLD = '\x1b[1m';
13
- const RESET = '\x1b[0m';
8
+ import { GREEN, RED, YELLOW, DIM, BOLD, RESET } from '../../lib/colors.js';
9
+ import { isBinaryInstalled } from '../../lib/agents.js';
14
10
  class SetupDoctor extends BaseCommand {
15
11
  async run() {
16
12
  const { flags } = await this.parse(SetupDoctor);
@@ -43,7 +39,7 @@ class SetupDoctor extends BaseCommand {
43
39
  this.log('');
44
40
  // ── 2. Respan CLI ──────────────────────────────────────────────
45
41
  this.log(` ${BOLD}Respan CLI${RESET}`);
46
- const respanInstalled = this.isBinaryInstalled('respan');
42
+ const respanInstalled = isBinaryInstalled('respan');
47
43
  if (respanInstalled) {
48
44
  try {
49
45
  const version = execSync('respan --version', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
@@ -66,44 +62,44 @@ class SetupDoctor extends BaseCommand {
66
62
  name: 'Claude Code',
67
63
  globalConfigs: ['~/.claude/settings.json'],
68
64
  localConfigs: ['.claude/settings.local.json'],
69
- globalSkills: ['~/.claude/skills/respan/SKILL.md', '~/.agents/skills/respan/SKILL.md'],
70
- localSkills: ['.claude/skills/respan/SKILL.md', '.agents/skills/respan/SKILL.md'],
65
+ globalSkills: ['~/.claude/skills/respan/SKILL.md'],
66
+ localSkills: ['.claude/skills/respan/SKILL.md'],
71
67
  },
72
68
  'cursor': {
73
69
  binary: 'cursor',
74
70
  name: 'Cursor',
75
71
  globalConfigs: ['~/.cursor/rules'],
76
72
  localConfigs: ['.cursor/rules'],
77
- globalSkills: ['~/.cursor/skills/respan/SKILL.md', '~/.agents/skills/respan/SKILL.md'],
78
- localSkills: ['.cursor/skills/respan/SKILL.md', '.agents/skills/respan/SKILL.md'],
73
+ globalSkills: ['~/.agents/skills/respan/SKILL.md', '~/.cursor/skills/respan/SKILL.md'],
74
+ localSkills: ['.agents/skills/respan/SKILL.md', '.cursor/skills/respan/SKILL.md'],
79
75
  },
80
76
  'codex-cli': {
81
77
  binary: 'codex',
82
78
  name: 'Codex CLI',
83
79
  globalConfigs: ['~/.codex/config.toml'],
84
80
  localConfigs: ['.codex/respan.json'],
85
- globalSkills: ['~/.codex/skills/respan/SKILL.md', '~/.agents/skills/respan/SKILL.md'],
86
- localSkills: ['.codex/skills/respan/SKILL.md', '.agents/skills/respan/SKILL.md'],
81
+ globalSkills: ['~/.agents/skills/respan/SKILL.md', '~/.codex/skills/respan/SKILL.md'],
82
+ localSkills: ['.agents/skills/respan/SKILL.md', '.codex/skills/respan/SKILL.md'],
87
83
  },
88
84
  'gemini-cli': {
89
85
  binary: 'gemini',
90
86
  name: 'Gemini CLI',
91
87
  globalConfigs: ['~/.gemini/settings.json'],
92
88
  localConfigs: ['.gemini/settings.json'],
93
- globalSkills: ['~/.gemini/skills/respan/SKILL.md', '~/.agents/skills/respan/SKILL.md'],
94
- localSkills: ['.gemini/skills/respan/SKILL.md', '.agents/skills/respan/SKILL.md'],
89
+ globalSkills: ['~/.agents/skills/respan/SKILL.md', '~/.gemini/skills/respan/SKILL.md'],
90
+ localSkills: ['.agents/skills/respan/SKILL.md', '.gemini/skills/respan/SKILL.md'],
95
91
  },
96
92
  'opencode': {
97
93
  binary: 'opencode',
98
94
  name: 'OpenCode',
99
95
  globalConfigs: ['~/.config/opencode'],
100
96
  localConfigs: ['.opencode'],
101
- globalSkills: ['~/.config/opencode/skills/respan/SKILL.md', '~/.agents/skills/respan/SKILL.md'],
102
- localSkills: ['.opencode/skills/respan/SKILL.md', '.agents/skills/respan/SKILL.md'],
97
+ globalSkills: ['~/.agents/skills/respan/SKILL.md', '~/.config/opencode/skills/respan/SKILL.md'],
98
+ localSkills: ['.agents/skills/respan/SKILL.md', '.opencode/skills/respan/SKILL.md'],
103
99
  },
104
100
  };
105
101
  for (const [id, tool] of Object.entries(tools)) {
106
- const binaryFound = this.isBinaryInstalled(tool.binary);
102
+ const binaryFound = isBinaryInstalled(tool.binary);
107
103
  this.log(` ${BOLD}${tool.name}${RESET} ${DIM}(${tool.binary})${RESET}`);
108
104
  // Binary
109
105
  if (binaryFound) {
@@ -129,24 +125,22 @@ class SetupDoctor extends BaseCommand {
129
125
  }
130
126
  }
131
127
  }
132
- // Skills
128
+ // Skills \u2014 each tool only lists dirs it actually reads (the shared
129
+ // ~/.agents, or ~/.claude for Claude Code) plus its own dir as a
130
+ // fallback. Report the first match.
133
131
  let hasSkill = false;
134
132
  if (checkGlobal) {
135
- for (const skill of tool.globalSkills) {
136
- const resolved = expandHome(skill);
137
- if (fs.existsSync(resolved)) {
138
- this.log(` ${GREEN}\u2713${RESET} Global skill: ${DIM}${skill}${RESET}`);
139
- hasSkill = true;
140
- }
133
+ const found = tool.globalSkills.find((skill) => fs.existsSync(expandHome(skill)));
134
+ if (found) {
135
+ this.log(` ${GREEN}\u2713${RESET} Global skill: ${DIM}${found}${RESET}`);
136
+ hasSkill = true;
141
137
  }
142
138
  }
143
139
  if (checkLocal) {
144
- for (const skill of tool.localSkills) {
145
- const resolved = path.join(projectRoot, skill);
146
- if (fs.existsSync(resolved)) {
147
- this.log(` ${GREEN}\u2713${RESET} Local skill: ${DIM}${skill}${RESET}`);
148
- hasSkill = true;
149
- }
140
+ const found = tool.localSkills.find((skill) => fs.existsSync(path.join(projectRoot, skill)));
141
+ if (found) {
142
+ this.log(` ${GREEN}\u2713${RESET} Local skill: ${DIM}${found}${RESET}`);
143
+ hasSkill = true;
150
144
  }
151
145
  }
152
146
  if (binaryFound && !hasSkill) {
@@ -193,15 +187,6 @@ class SetupDoctor extends BaseCommand {
193
187
  }
194
188
  this.log('');
195
189
  }
196
- isBinaryInstalled(binary) {
197
- try {
198
- execSync(`command -v ${binary}`, { stdio: 'pipe' });
199
- return true;
200
- }
201
- catch {
202
- return false;
203
- }
204
- }
205
190
  }
206
191
  SetupDoctor.description = 'Diagnose coding-agent setup for Respan';
207
192
  SetupDoctor.examples = [
@@ -0,0 +1,16 @@
1
+ import { SetupBaseCommand } from '../../lib/setup-base-command.js';
2
+ export default class SetupGateway extends SetupBaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ agent: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ 'no-instrument': import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ 'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ };
15
+ run(): Promise<void>;
16
+ }
@@ -0,0 +1,33 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { SetupBaseCommand } from '../../lib/setup-base-command.js';
3
+ class SetupGateway extends SetupBaseCommand {
4
+ async run() {
5
+ const { flags } = await this.parse(SetupGateway);
6
+ this.globalFlags = flags;
7
+ await this.runSetup('gateway', {
8
+ agent: flags.agent,
9
+ noInstrument: flags['no-instrument'],
10
+ });
11
+ }
12
+ }
13
+ SetupGateway.description = `Set up Respan gateway routing in this project.
14
+
15
+ Runs the gateway setup flow directly (skips the "Tracing or Gateway?"
16
+ question). Sets up your API key, installs the Respan skill, and optionally
17
+ opens your coding agent to route the detected framework through the gateway.`;
18
+ SetupGateway.examples = [
19
+ 'respan setup gateway',
20
+ 'respan setup gateway --agent claude-code',
21
+ 'respan setup gateway --no-instrument',
22
+ ];
23
+ SetupGateway.flags = {
24
+ ...SetupBaseCommand.baseFlags,
25
+ agent: Flags.string({
26
+ description: 'Agent to configure (claude-code, cursor, codex-cli, gemini-cli, opencode)',
27
+ }),
28
+ 'no-instrument': Flags.boolean({
29
+ description: 'Skip opening the agent after setup',
30
+ default: false,
31
+ }),
32
+ };
33
+ export default SetupGateway;
@@ -1,45 +1,16 @@
1
- import { BaseCommand } from '../../lib/base-command.js';
2
- export default class Setup extends BaseCommand {
1
+ import { SetupBaseCommand } from '../../lib/setup-base-command.js';
2
+ export default class Setup extends SetupBaseCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
6
6
  agent: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
7
  'no-instrument': import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
10
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
11
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
12
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
- json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
- csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
13
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
14
  };
15
15
  run(): Promise<void>;
16
- private askApiKey;
17
- private verifyApiKey;
18
- /**
19
- * Build a rich demo OTLP trace that mimics a customer support agent workflow:
20
- * workflow: customer_support_pipeline
21
- * └── agent: support_agent
22
- * ├── tool: lookup_order
23
- * ├── chat: openai.chat (classify intent)
24
- * ├── tool: process_refund
25
- * ├── chat: openai.chat (generate response)
26
- * └── task: log_resolution
27
- */
28
- private buildDemoTrace;
29
- private detectAgents;
30
- private selectAgent;
31
- private installSkill;
32
- private runInstrumentAgent;
33
- private getSkillMd;
34
- private logStep;
35
- private isBinaryInstalled;
36
- private extractEnvVar;
37
- private saveToEnv;
38
- private getGitEmail;
39
- /**
40
- * Send a lightweight setup notification (email only).
41
- * This helps the team know when new users set up Respan so we can
42
- * reach out and help with onboarding.
43
- */
44
- private notifySetup;
45
16
  }