@respan/cli 0.9.0 → 0.11.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 (62) hide show
  1. package/dist/commands/datasets/create-span.js +5 -3
  2. package/dist/commands/datasets/create.js +5 -4
  3. package/dist/commands/datasets/get-span.js +5 -1
  4. package/dist/commands/datasets/get.js +1 -1
  5. package/dist/commands/datasets/list.js +5 -1
  6. package/dist/commands/datasets/spans.js +1 -1
  7. package/dist/commands/datasets/update.js +3 -6
  8. package/dist/commands/{datasets/add-spans.d.ts → eval/index.d.ts} +2 -3
  9. package/dist/commands/eval/index.js +26 -0
  10. package/dist/commands/evaluators/create.js +10 -7
  11. package/dist/commands/evaluators/get.js +1 -1
  12. package/dist/commands/evaluators/list.js +1 -1
  13. package/dist/commands/evaluators/run.js +8 -7
  14. package/dist/commands/evaluators/update.js +6 -7
  15. package/dist/commands/experiments/create.js +9 -8
  16. package/dist/commands/experiments/get.js +1 -1
  17. package/dist/commands/experiments/list.js +1 -1
  18. package/dist/commands/logs/create.js +9 -7
  19. package/dist/commands/logs/get.js +1 -1
  20. package/dist/commands/logs/list.js +4 -3
  21. package/dist/commands/logs/summary.js +3 -2
  22. package/dist/commands/prompts/create-version.js +9 -9
  23. package/dist/commands/prompts/create.js +5 -4
  24. package/dist/commands/prompts/get.js +1 -1
  25. package/dist/commands/prompts/list.js +1 -1
  26. package/dist/commands/prompts/update.js +3 -6
  27. package/dist/commands/prompts/versions.js +1 -1
  28. package/dist/commands/setup/doctor.d.ts +0 -1
  29. package/dist/commands/setup/doctor.js +25 -40
  30. package/dist/commands/setup/gateway.d.ts +16 -0
  31. package/dist/commands/setup/gateway.js +33 -0
  32. package/dist/commands/setup/index.d.ts +4 -33
  33. package/dist/commands/setup/index.js +11 -907
  34. package/dist/commands/setup/tracing.d.ts +16 -0
  35. package/dist/commands/setup/tracing.js +33 -0
  36. package/dist/commands/traces/get.js +1 -1
  37. package/dist/commands/traces/list.js +8 -10
  38. package/dist/commands/traces/summary.js +6 -2
  39. package/dist/commands/users/get.js +1 -1
  40. package/dist/commands/users/list.js +5 -7
  41. package/dist/lib/agents.d.ts +16 -0
  42. package/dist/lib/agents.js +75 -0
  43. package/dist/lib/auth.js +24 -0
  44. package/dist/lib/base-command.d.ts +2 -0
  45. package/dist/lib/base-command.js +11 -1
  46. package/dist/lib/colors.d.ts +7 -0
  47. package/dist/lib/colors.js +10 -0
  48. package/dist/lib/eval/runner.d.ts +15 -0
  49. package/dist/lib/eval/runner.js +292 -0
  50. package/dist/lib/eval/schema.d.ts +67 -0
  51. package/dist/lib/eval/schema.js +22 -0
  52. package/dist/lib/integrate.d.ts +6 -0
  53. package/dist/lib/integrate.js +11 -0
  54. package/dist/lib/setup-base-command.d.ts +84 -0
  55. package/dist/lib/setup-base-command.js +649 -0
  56. package/dist/lib/skill-content.d.ts +1 -0
  57. package/dist/lib/skill-content.js +16 -0
  58. package/dist/lib/skill-refs.generated.d.ts +6 -0
  59. package/dist/lib/skill-refs.generated.js +1489 -0
  60. package/oclif.manifest.json +385 -230
  61. package/package.json +8 -3
  62. package/dist/commands/datasets/add-spans.js +0 -24
@@ -14,10 +14,12 @@ class DatasetsCreateSpan extends BaseCommand {
14
14
  this.error('Invalid JSON for --body');
15
15
  }
16
16
  const spanData = parsed;
17
- const data = await this.spin('Creating dataset span', () => client.datasets.createDatasetSpan({
17
+ const data = await this.spin('Creating dataset span', () => client.datasets.createDatasetLog({
18
+ Authorization: this.getAuthHeader(),
18
19
  dataset_id: args['dataset-id'],
19
- input: String(spanData.input || ''),
20
- output: String(spanData.output || ''),
20
+ input: spanData.input,
21
+ output: spanData.output,
22
+ ...(spanData.expected_output !== undefined ? { expected_output: spanData.expected_output } : {}),
21
23
  ...(spanData.metadata ? { metadata: spanData.metadata } : {}),
22
24
  }));
23
25
  this.log(JSON.stringify(data, null, 2));
@@ -6,10 +6,11 @@ class DatasetsCreate extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const body = { name: flags.name };
10
- if (flags.description)
11
- body.description = flags.description;
12
- const data = await this.spin('Creating dataset', () => client.datasets.createDataset(body));
9
+ const data = await this.spin('Creating dataset', () => client.datasets.createDataset({
10
+ Authorization: this.getAuthHeader(),
11
+ name: flags.name,
12
+ ...(flags.description ? { description: flags.description } : {}),
13
+ }));
13
14
  this.log(JSON.stringify(data, null, 2));
14
15
  }
15
16
  catch (error) {
@@ -6,7 +6,11 @@ class DatasetsGetSpan extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching dataset span', () => client.datasets.retrievespan({ dataset_id: args['dataset-id'], log_id: args['span-id'] }));
9
+ const data = await this.spin('Fetching dataset span', () => client.datasets.retrieveDatasetLog({
10
+ Authorization: this.getAuthHeader(),
11
+ dataset_id: args['dataset-id'],
12
+ unique_id: args['span-id'],
13
+ }));
10
14
  this.log(JSON.stringify(data, null, 2));
11
15
  }
12
16
  catch (error) {
@@ -6,7 +6,7 @@ class DatasetsGet extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching dataset', () => client.datasets.retrieveDataset({ dataset_id: args.id }));
9
+ const data = await this.spin('Fetching dataset', () => client.datasets.retrieveDataset({ Authorization: this.getAuthHeader(), dataset_id: args.id }));
10
10
  this.log(JSON.stringify(data, null, 2));
11
11
  }
12
12
  catch (error) {
@@ -6,7 +6,11 @@ class DatasetsList extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching datasets', () => client.datasets.listDatasets());
9
+ const data = await this.spin('Fetching datasets', () => client.datasets.listDatasets({
10
+ Authorization: this.getAuthHeader(),
11
+ page: flags.page,
12
+ page_size: flags.limit,
13
+ }));
10
14
  this.outputResult(data, ['id', 'name', 'description', 'created_at']);
11
15
  }
12
16
  catch (error) {
@@ -6,7 +6,7 @@ class DatasetsSpans extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching dataset spans', () => client.datasets.listspans({ dataset_id: args['dataset-id'] }));
9
+ const data = await this.spin('Fetching dataset spans', () => client.datasets.listDatasetLogs({ Authorization: this.getAuthHeader(), dataset_id: args['dataset-id'] }));
10
10
  this.outputResult(data, ['id', 'input', 'output', 'created_at']);
11
11
  }
12
12
  catch (error) {
@@ -6,14 +6,11 @@ class DatasetsUpdate extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const updateBody = {};
10
- if (flags.name)
11
- updateBody.name = flags.name;
12
- if (flags.description)
13
- updateBody.description = flags.description;
14
9
  const data = await this.spin('Updating dataset', () => client.datasets.updateDataset({
10
+ Authorization: this.getAuthHeader(),
15
11
  dataset_id: args.id,
16
- body: updateBody,
12
+ ...(flags.name ? { name: flags.name } : {}),
13
+ ...(flags.description ? { description: flags.description } : {}),
17
14
  }));
18
15
  this.log(JSON.stringify(data, null, 2));
19
16
  }
@@ -1,11 +1,10 @@
1
1
  import { BaseCommand } from '../../lib/base-command.js';
2
- export default class DatasetsAddSpans extends BaseCommand {
2
+ export default class EvalRun extends BaseCommand {
3
3
  static description: string;
4
4
  static args: {
5
- 'dataset-id': import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ file: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
6
6
  };
7
7
  static flags: {
8
- 'span-ids': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
8
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
9
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
10
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -0,0 +1,26 @@
1
+ import { Args } from '@oclif/core';
2
+ import { resolve } from 'node:path';
3
+ import { BaseCommand } from '../../lib/base-command.js';
4
+ import { runEval } from '../../lib/eval/runner.js';
5
+ class EvalRun extends BaseCommand {
6
+ async run() {
7
+ const { args, flags } = await this.parse(EvalRun);
8
+ this.globalFlags = flags;
9
+ try {
10
+ const client = this.getClient();
11
+ const filePath = resolve(args.file);
12
+ const result = await runEval(filePath, client, this.getAuthHeader(), this.getBaseUrl(), (msg) => this.log(msg));
13
+ this.log('');
14
+ this.log(JSON.stringify(result, null, 2));
15
+ }
16
+ catch (error) {
17
+ this.handleError(error);
18
+ }
19
+ }
20
+ }
21
+ EvalRun.description = 'Run an eval defined in a JSON file (creates prompt + dataset on the platform)';
22
+ EvalRun.args = {
23
+ file: Args.string({ description: 'Path to eval JSON file', required: true }),
24
+ };
25
+ EvalRun.flags = { ...BaseCommand.baseFlags };
26
+ export default EvalRun;
@@ -6,20 +6,23 @@ class EvaluatorsCreate extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const body = { name: flags.name };
10
- if (flags.type)
11
- body.type = flags.type;
12
- if (flags.description)
13
- body.description = flags.description;
9
+ let extra = {};
14
10
  if (flags.config) {
15
11
  try {
16
- body.config = JSON.parse(flags.config);
12
+ extra = JSON.parse(flags.config);
17
13
  }
18
14
  catch {
19
15
  this.error('Invalid JSON for --config');
20
16
  }
21
17
  }
22
- const data = await this.spin('Creating evaluator', () => client.evaluators.createEvaluator(body));
18
+ const data = await this.spin('Creating evaluator', () => client.evaluators.createEvaluator({
19
+ Authorization: this.getAuthHeader(),
20
+ ...extra,
21
+ name: flags.name,
22
+ type: (flags.type ?? extra.type ?? 'llm'),
23
+ score_value_type: (extra.score_value_type ?? 'numerical'),
24
+ ...(flags.description ? { description: flags.description } : {}),
25
+ }));
23
26
  this.log(JSON.stringify(data, null, 2));
24
27
  }
25
28
  catch (error) {
@@ -6,7 +6,7 @@ class EvaluatorsGet extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching evaluator', () => client.evaluators.retrieveEvaluator({ evaluator_id: args.id }));
9
+ const data = await this.spin('Fetching evaluator', () => client.evaluators.retrieveEvaluator({ Authorization: this.getAuthHeader(), evaluator_id: args.id }));
10
10
  this.log(JSON.stringify(data, null, 2));
11
11
  }
12
12
  catch (error) {
@@ -7,7 +7,7 @@ class EvaluatorsList extends BaseCommand {
7
7
  this.globalFlags = flags;
8
8
  try {
9
9
  const client = this.getClient();
10
- const data = await this.spin('Fetching evaluators', () => client.evaluators.listEvaluators());
10
+ const data = await this.spin('Fetching evaluators', () => client.evaluators.listEvaluators({ Authorization: this.getAuthHeader() }));
11
11
  this.outputResult(data, ['id', 'name', 'type', 'is_active', 'created_at']);
12
12
  const pagination = extractPagination(data, flags.page);
13
13
  this.log(formatPaginationInfo(pagination));
@@ -6,22 +6,23 @@ class EvaluatorsRun extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const runBody = {};
10
- if (flags['dataset-id'])
11
- runBody.dataset_id = flags['dataset-id'];
12
- if (flags['log-ids'])
13
- runBody.log_ids = flags['log-ids'].split(',').map((s) => s.trim());
9
+ let extra = {};
14
10
  if (flags.params) {
15
11
  try {
16
- Object.assign(runBody, JSON.parse(flags.params));
12
+ extra = JSON.parse(flags.params);
17
13
  }
18
14
  catch {
19
15
  this.error('Invalid JSON for --params');
20
16
  }
21
17
  }
22
18
  const data = await this.spin('Running evaluator', () => client.evaluators.runEvaluator({
19
+ Authorization: this.getAuthHeader(),
20
+ ...extra,
23
21
  evaluator_id: args.id,
24
- body: runBody,
22
+ ...(flags['dataset-id'] ? { dataset_id: flags['dataset-id'] } : {}),
23
+ ...(flags['log-ids']
24
+ ? { log_ids: flags['log-ids'].split(',').map((s) => s.trim()) }
25
+ : {}),
25
26
  }));
26
27
  this.log(JSON.stringify(data, null, 2));
27
28
  }
@@ -6,22 +6,21 @@ class EvaluatorsUpdate extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const updateBody = {};
10
- if (flags.name)
11
- updateBody.name = flags.name;
12
- if (flags.description)
13
- updateBody.description = flags.description;
9
+ let extra = {};
14
10
  if (flags.config) {
15
11
  try {
16
- Object.assign(updateBody, JSON.parse(flags.config));
12
+ extra = JSON.parse(flags.config);
17
13
  }
18
14
  catch {
19
15
  this.error('Invalid JSON for --config');
20
16
  }
21
17
  }
22
18
  const data = await this.spin('Updating evaluator', () => client.evaluators.updateEvaluator({
19
+ Authorization: this.getAuthHeader(),
20
+ ...extra,
23
21
  evaluator_id: args.id,
24
- body: updateBody,
22
+ ...(flags.name ? { name: flags.name } : {}),
23
+ ...(flags.description ? { description: flags.description } : {}),
25
24
  }));
26
25
  this.log(JSON.stringify(data, null, 2));
27
26
  }
@@ -6,21 +6,22 @@ class ExperimentsCreate extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const body = {
10
- name: flags.name,
11
- dataset_id: flags['dataset-id'],
12
- };
13
- if (flags.description)
14
- body.description = flags.description;
9
+ let workflows = undefined;
15
10
  if (flags.workflows) {
16
11
  try {
17
- body.workflows = JSON.parse(flags.workflows);
12
+ workflows = JSON.parse(flags.workflows);
18
13
  }
19
14
  catch {
20
15
  this.error('Invalid JSON for --workflows');
21
16
  }
22
17
  }
23
- const data = await this.spin('Creating experiment', () => client.experiments.createExperiment(body));
18
+ const data = await this.spin('Creating experiment', () => client.experiments.createExperiment({
19
+ Authorization: this.getAuthHeader(),
20
+ name: flags.name,
21
+ dataset_id: flags['dataset-id'],
22
+ ...(flags.description ? { description: flags.description } : {}),
23
+ ...(workflows ? { workflows: workflows } : {}),
24
+ }));
24
25
  this.log(JSON.stringify(data, null, 2));
25
26
  }
26
27
  catch (error) {
@@ -6,7 +6,7 @@ class ExperimentsGet extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching experiment', () => client.experiments.retrieveExperiment({ experiment_id: args.id }));
9
+ const data = await this.spin('Fetching experiment', () => client.experiments.retrieveExperiment({ Authorization: this.getAuthHeader(), experiment_id: args.id }));
10
10
  this.log(JSON.stringify(data, null, 2));
11
11
  }
12
12
  catch (error) {
@@ -6,7 +6,7 @@ class ExperimentsList extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching experiments', () => client.experiments.listExperiments());
9
+ const data = await this.spin('Fetching experiments', () => client.experiments.listExperiments({ Authorization: this.getAuthHeader() }));
10
10
  this.outputResult(data, ['id', 'name', 'dataset_id', 'status', 'created_at']);
11
11
  }
12
12
  catch (error) {
@@ -6,20 +6,22 @@ class LogsCreate extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const body = { input: flags.input };
10
- if (flags.output)
11
- body.output = flags.output;
12
- if (flags.model)
13
- body.model = flags.model;
9
+ let metadata;
14
10
  if (flags.metadata) {
15
11
  try {
16
- body.metadata = JSON.parse(flags.metadata);
12
+ metadata = JSON.parse(flags.metadata);
17
13
  }
18
14
  catch {
19
15
  this.error('Invalid JSON for --metadata');
20
16
  }
21
17
  }
22
- const data = await this.spin('Creating span', () => client.logs.createSpan(body));
18
+ const data = await this.spin('Creating span', () => client.spans.createSpan({
19
+ Authorization: this.getAuthHeader(),
20
+ prompt: flags.input,
21
+ ...(flags.output ? { completion: flags.output } : {}),
22
+ ...(flags.model ? { model: flags.model } : {}),
23
+ ...(metadata ? { metadata } : {}),
24
+ }));
23
25
  this.log(JSON.stringify(data, null, 2));
24
26
  }
25
27
  catch (error) {
@@ -6,7 +6,7 @@ class LogsGet extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching span', () => client.logs.retrieveSpan({ unique_id: args.id }));
9
+ const data = await this.spin('Fetching span', () => client.spans.retrieveSpan({ Authorization: this.getAuthHeader(), unique_id: args.id }));
10
10
  this.log(JSON.stringify(data, null, 2));
11
11
  }
12
12
  catch (error) {
@@ -13,18 +13,19 @@ class LogsList extends BaseCommand {
13
13
  filters = parseFilters(flags.filter);
14
14
  }
15
15
  const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString();
16
- const data = await this.spin('Fetching logs', () => client.logs.listSpans({
16
+ const data = await this.spin('Fetching logs', () => client.spans.listSpans({
17
+ Authorization: this.getAuthHeader(),
17
18
  start_time: flags['start-time'] || oneHourAgo,
18
19
  end_time: flags['end-time'] || new Date().toISOString(),
19
20
  sort_by: flags['sort-by'] || '-id',
20
- operator: '',
21
+ operator: 'AND',
21
22
  page_size: flags.limit,
22
23
  page: flags.page,
23
24
  is_test: flags['is-test'],
24
25
  all_envs: flags['all-envs'],
25
26
  fetch_filters: 'false',
26
27
  include_fields: flags['include-fields'],
27
- filters,
28
+ filters: filters,
28
29
  }));
29
30
  this.outputResult(data, ['id', 'model', 'prompt_tokens', 'completion_tokens', 'cost', 'latency', 'timestamp']);
30
31
  const pagination = extractPagination(data, flags.page);
@@ -11,12 +11,13 @@ class LogsSummary extends BaseCommand {
11
11
  if (flags.filter && flags.filter.length > 0) {
12
12
  filters = parseFilters(flags.filter);
13
13
  }
14
- const data = await this.spin('Fetching summary', () => client.logs.getSpansSummary({
14
+ const data = await this.spin('Fetching summary', () => client.spans.getSpansSummary({
15
+ Authorization: this.getAuthHeader(),
15
16
  start_time: flags['start-time'],
16
17
  end_time: flags['end-time'],
17
18
  is_test: flags['is-test'],
18
19
  all_envs: flags['all-envs'],
19
- filters,
20
+ filters: filters,
20
21
  }));
21
22
  this.log(JSON.stringify(data, null, 2));
22
23
  }
@@ -14,17 +14,17 @@ class PromptsCreateVersion extends BaseCommand {
14
14
  this.error('Invalid JSON for --messages');
15
15
  }
16
16
  // createVersion requires prompt_id, messages (string[]), and model (required)
17
- const messagesStr = Array.isArray(messages) ? messages.map((m) => typeof m === 'string' ? m : JSON.stringify(m)) : [String(messages)];
18
- const createBody = {
17
+ const messageList = Array.isArray(messages)
18
+ ? messages
19
+ : [{ role: 'user', content: String(messages) }];
20
+ const data = await this.spin('Creating prompt version', () => client.prompts.createPromptVersion({
21
+ Authorization: this.getAuthHeader(),
19
22
  prompt_id: args['prompt-id'],
20
- messages: messagesStr,
23
+ messages: messageList,
21
24
  model: flags.model || 'gpt-4o',
22
- };
23
- if (flags.temperature)
24
- createBody.temperature = parseFloat(flags.temperature);
25
- if (flags['max-tokens'])
26
- createBody.max_tokens = flags['max-tokens'];
27
- const data = await this.spin('Creating prompt version', () => client.prompts.createVersion(createBody));
25
+ ...(flags.temperature ? { temperature: parseFloat(flags.temperature) } : {}),
26
+ ...(flags['max-tokens'] !== undefined ? { max_tokens: flags['max-tokens'] } : {}),
27
+ }));
28
28
  this.log(JSON.stringify(data, null, 2));
29
29
  }
30
30
  catch (error) {
@@ -6,10 +6,11 @@ class PromptsCreate extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const body = { name: flags.name };
10
- if (flags.description)
11
- body.description = flags.description;
12
- const data = await this.spin('Creating prompt', () => client.prompts.createPrompt(body));
9
+ const data = await this.spin('Creating prompt', () => client.prompts.createPrompt({
10
+ Authorization: this.getAuthHeader(),
11
+ name: flags.name,
12
+ ...(flags.description ? { description: flags.description } : {}),
13
+ }));
13
14
  this.log(JSON.stringify(data, null, 2));
14
15
  }
15
16
  catch (error) {
@@ -6,7 +6,7 @@ class PromptsGet extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching prompt', () => client.prompts.retrievePrompts({ prompt_id: args.id }));
9
+ const data = await this.spin('Fetching prompt', () => client.prompts.retrievePrompt({ Authorization: this.getAuthHeader(), prompt_id: args.id }));
10
10
  this.log(JSON.stringify(data, null, 2));
11
11
  }
12
12
  catch (error) {
@@ -6,7 +6,7 @@ class PromptsList extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching prompts', () => client.prompts.retrievePrompts());
9
+ const data = await this.spin('Fetching prompts', () => client.prompts.listPrompts({ Authorization: this.getAuthHeader(), page_size: flags.limit }));
10
10
  this.outputResult(data, ['id', 'name', 'description', 'is_active', 'current_version', 'updated_at']);
11
11
  }
12
12
  catch (error) {
@@ -6,14 +6,11 @@ class PromptsUpdate extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const updateBody = {};
10
- if (flags.name)
11
- updateBody.name = flags.name;
12
- if (flags.description)
13
- updateBody.description = flags.description;
14
9
  const data = await this.spin('Updating prompt', () => client.prompts.updatePrompt({
10
+ Authorization: this.getAuthHeader(),
15
11
  prompt_id: args.id,
16
- body: updateBody,
12
+ ...(flags.name ? { name: flags.name } : {}),
13
+ ...(flags.description ? { description: flags.description } : {}),
17
14
  }));
18
15
  this.log(JSON.stringify(data, null, 2));
19
16
  }
@@ -6,7 +6,7 @@ class PromptsVersions extends BaseCommand {
6
6
  this.globalFlags = flags;
7
7
  try {
8
8
  const client = this.getClient();
9
- const data = await this.spin('Fetching prompt versions', () => client.prompts.retrieveVersions({ prompt_id: args['prompt-id'] }));
9
+ const data = await this.spin('Fetching prompt versions', () => client.prompts.listPromptVersions({ Authorization: this.getAuthHeader(), prompt_id: args['prompt-id'] }));
10
10
  this.outputResult(data, ['id', 'version', 'is_active', 'created_at']);
11
11
  }
12
12
  catch (error) {
@@ -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 = [