@root-signals/scorable-cli 0.13.0 → 0.15.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 (97) hide show
  1. package/README.md +113 -0
  2. package/dist/client.d.ts +1 -0
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +1 -0
  5. package/dist/commands/annotation/index.d.ts +3 -0
  6. package/dist/commands/annotation/index.d.ts.map +1 -0
  7. package/dist/commands/annotation/index.js +145 -0
  8. package/dist/commands/auth/index.d.ts.map +1 -1
  9. package/dist/commands/auth/index.js +68 -1
  10. package/dist/commands/calibration-run/index.d.ts +3 -0
  11. package/dist/commands/calibration-run/index.d.ts.map +1 -0
  12. package/dist/commands/calibration-run/index.js +83 -0
  13. package/dist/commands/dataset-item/index.d.ts +3 -0
  14. package/dist/commands/dataset-item/index.d.ts.map +1 -0
  15. package/dist/commands/dataset-item/index.js +160 -0
  16. package/dist/commands/evaluator/calibrate.d.ts +3 -0
  17. package/dist/commands/evaluator/calibrate.d.ts.map +1 -0
  18. package/dist/commands/evaluator/calibrate.js +29 -0
  19. package/dist/commands/evaluator/create.d.ts.map +1 -1
  20. package/dist/commands/evaluator/create.js +8 -0
  21. package/dist/commands/evaluator/duplicate.d.ts.map +1 -1
  22. package/dist/commands/evaluator/duplicate.js +5 -2
  23. package/dist/commands/evaluator/execute-by-name.d.ts +1 -0
  24. package/dist/commands/evaluator/execute-by-name.d.ts.map +1 -1
  25. package/dist/commands/evaluator/execute-by-name.js +5 -0
  26. package/dist/commands/evaluator/execute.d.ts +1 -0
  27. package/dist/commands/evaluator/execute.d.ts.map +1 -1
  28. package/dist/commands/evaluator/execute.js +5 -0
  29. package/dist/commands/evaluator/export-yaml.d.ts.map +1 -1
  30. package/dist/commands/evaluator/export-yaml.js +10 -1
  31. package/dist/commands/evaluator/import-yaml.d.ts.map +1 -1
  32. package/dist/commands/evaluator/import-yaml.js +10 -1
  33. package/dist/commands/evaluator/index.d.ts.map +1 -1
  34. package/dist/commands/evaluator/index.js +2 -0
  35. package/dist/commands/evaluator/list.d.ts.map +1 -1
  36. package/dist/commands/evaluator/list.js +5 -0
  37. package/dist/commands/evaluator/update.d.ts.map +1 -1
  38. package/dist/commands/evaluator/update.js +8 -0
  39. package/dist/commands/execution-log/list.d.ts.map +1 -1
  40. package/dist/commands/execution-log/list.js +5 -0
  41. package/dist/commands/judge/create.d.ts.map +1 -1
  42. package/dist/commands/judge/create.js +5 -0
  43. package/dist/commands/judge/duplicate.d.ts.map +1 -1
  44. package/dist/commands/judge/duplicate.js +5 -2
  45. package/dist/commands/judge/exec-openai-generic.d.ts.map +1 -1
  46. package/dist/commands/judge/exec-openai-generic.js +5 -0
  47. package/dist/commands/judge/exec-openai.d.ts.map +1 -1
  48. package/dist/commands/judge/exec-openai.js +5 -0
  49. package/dist/commands/judge/execute-by-name.d.ts +1 -0
  50. package/dist/commands/judge/execute-by-name.d.ts.map +1 -1
  51. package/dist/commands/judge/execute-by-name.js +5 -0
  52. package/dist/commands/judge/execute.d.ts +1 -0
  53. package/dist/commands/judge/execute.d.ts.map +1 -1
  54. package/dist/commands/judge/execute.js +5 -0
  55. package/dist/commands/judge/generate.d.ts.map +1 -1
  56. package/dist/commands/judge/generate.js +4 -0
  57. package/dist/commands/judge/list.d.ts.map +1 -1
  58. package/dist/commands/judge/list.js +5 -0
  59. package/dist/commands/judge/update.d.ts.map +1 -1
  60. package/dist/commands/judge/update.js +5 -0
  61. package/dist/commands/project/create.d.ts +3 -0
  62. package/dist/commands/project/create.d.ts.map +1 -0
  63. package/dist/commands/project/create.js +31 -0
  64. package/dist/commands/project/delete.d.ts +3 -0
  65. package/dist/commands/project/delete.d.ts.map +1 -0
  66. package/dist/commands/project/delete.js +37 -0
  67. package/dist/commands/project/get.d.ts +3 -0
  68. package/dist/commands/project/get.d.ts.map +1 -0
  69. package/dist/commands/project/get.js +23 -0
  70. package/dist/commands/project/index.d.ts +3 -0
  71. package/dist/commands/project/index.d.ts.map +1 -0
  72. package/dist/commands/project/index.js +17 -0
  73. package/dist/commands/project/list.d.ts +3 -0
  74. package/dist/commands/project/list.d.ts.map +1 -0
  75. package/dist/commands/project/list.js +39 -0
  76. package/dist/commands/project/set-default.d.ts +3 -0
  77. package/dist/commands/project/set-default.d.ts.map +1 -0
  78. package/dist/commands/project/set-default.js +23 -0
  79. package/dist/commands/project/update.d.ts +3 -0
  80. package/dist/commands/project/update.d.ts.map +1 -0
  81. package/dist/commands/project/update.js +37 -0
  82. package/dist/commands/prompt-test/init.d.ts.map +1 -1
  83. package/dist/commands/prompt-test/init.js +9 -2
  84. package/dist/commands/prompt-test/run.d.ts +1 -1
  85. package/dist/commands/prompt-test/run.d.ts.map +1 -1
  86. package/dist/commands/prompt-test/run.js +9 -2
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +8 -0
  89. package/dist/lib/project-id.d.ts +9 -0
  90. package/dist/lib/project-id.d.ts.map +1 -0
  91. package/dist/lib/project-id.js +23 -0
  92. package/dist/output.d.ts +2 -1
  93. package/dist/output.d.ts.map +1 -1
  94. package/dist/output.js +71 -12
  95. package/dist/types.d.ts +1 -0
  96. package/dist/types.d.ts.map +1 -1
  97. package/package.json +4 -4
package/README.md CHANGED
@@ -78,6 +78,66 @@ export SCORABLE_API_KEY="sk-your-api-key"
78
78
 
79
79
  The key lookup order is: `SCORABLE_API_KEY` env var → `api_key` in `~/.scorable/settings.json` → `temporary_api_key` in `~/.scorable/settings.json`.
80
80
 
81
+ ## Projects
82
+
83
+ A **project** is a workspace inside your organization that groups related judges, evaluators, datasets, and execution logs. Every resource belongs to a project; omitting the project at create/execute time files things under the org's default project.
84
+
85
+ ### Manage projects
86
+
87
+ ```bash
88
+ scorable project list # list all projects (default marked)
89
+ scorable project get <project_id> # show a single project
90
+ scorable project create --name "Production" # create a project
91
+ scorable project create --name "Production" --is-default
92
+ scorable project update <project_id> --name "Renamed"
93
+ scorable project update <project_id> --is-default # promote to default
94
+ scorable project set-default <project_id> # convenience for `update --is-default`
95
+ scorable project delete <project_id>
96
+ ```
97
+
98
+ ### `--project-id` on every project-aware command
99
+
100
+ Every command that creates, executes, lists, or filters a project-scoped resource accepts `--project-id <uuid>`:
101
+
102
+ ```bash
103
+ # Filter list endpoints
104
+ scorable judge list --project-id <project_id>
105
+ scorable evaluator list --project-id <project_id>
106
+ scorable execution-log list --project-id <project_id>
107
+
108
+ # Route an execution log to a project
109
+ scorable judge execute <judge_id> --project-id <project_id>
110
+ scorable evaluator execute <evaluator_id> --project-id <project_id>
111
+
112
+ # Pin a resource to a project at creation
113
+ scorable judge create --name X --intent Y --project-id <project_id>
114
+ scorable evaluator import-yaml --file evaluator.yaml --project-id <project_id>
115
+
116
+ # Move a resource between projects
117
+ scorable judge update <judge_id> --project-id <other_project_id>
118
+
119
+ # OpenAI-compat (translated to X-Project-Id header)
120
+ scorable judge exec-openai <judge_id> --project-id <project_id>
121
+ ```
122
+
123
+ ### Setting a default project for your shell
124
+
125
+ To avoid passing `--project-id` on every command, set an env var or persist a per-machine default:
126
+
127
+ ```bash
128
+ # Environment variable (great for CI)
129
+ export SCORABLE_PROJECT_ID=<project_id>
130
+
131
+ # Persistent default written to ~/.scorable/settings.json
132
+ scorable auth set-project <project_id>
133
+ scorable auth show-project # see what's resolved and from where
134
+ scorable auth unset-project # remove the saved default
135
+ ```
136
+
137
+ Resolution order: `--project-id` flag → `SCORABLE_PROJECT_ID` env var → `project_id` in `~/.scorable/settings.json` → omitted (backend resolves to org default). Pass `--project-id ""` to explicitly opt out of an inherited default for a single invocation.
138
+
139
+ `scorable auth logout` clears the entire auth section of `~/.scorable/settings.json`, including the saved project_id.
140
+
81
141
  ## Scorable Skills for AI Coding Agents
82
142
 
83
143
  Install Scorable skills into your project so your AI coding agent (Claude Code, Cursor, etc.) can integrate evaluators automatically:
@@ -276,6 +336,59 @@ scorable evaluator execute-by-name "My Evaluator" --request "What is 2+2?" --res
276
336
 
277
337
  Accepts the same options as `execute`, including `--variables`.
278
338
 
339
+ ## Labelling & Calibration
340
+
341
+ Build a labelled dataset, then calibrate a saved evaluator against it to measure how well it agrees with your expected scores.
342
+
343
+ ### Dataset items
344
+
345
+ Populate a `test`-type dataset with request/response items.
346
+
347
+ ```bash
348
+ scorable dataset-item add <dataset_id> --response "Paris" --request "Capital of France?"
349
+ scorable dataset-item add-bulk <dataset_id> --items '[{"response":"Paris","request":"Capital of France?"}]'
350
+ scorable dataset-item list <dataset_id> # latest-version items (with embedded annotations)
351
+ scorable dataset-item list <dataset_id> --include-archived
352
+ scorable dataset-item get <dataset_id> <item_id>
353
+ scorable dataset-item update <dataset_id> <item_id> --response "Paris, France"
354
+ scorable dataset-item archive <dataset_id> <item_id>
355
+ ```
356
+
357
+ ### Annotations
358
+
359
+ Label a dataset item (or execution log) with an expected score. Omitting `--score-config-id` uses the global identity "Score" config, so a raw expected score can be set with just `--value`.
360
+
361
+ ```bash
362
+ scorable annotation create --dataset-item-id <item_id> --value 0.9
363
+ scorable annotation create --dataset-item-id <item_id> --category "👍" --score-config-id <config_id>
364
+ scorable annotation list --dataset <dataset_id>
365
+ scorable annotation get <annotation_id>
366
+ scorable annotation update <annotation_id> --value 0.8
367
+ scorable annotation delete <annotation_id>
368
+ ```
369
+
370
+ ### Calibration runs
371
+
372
+ Start a calibration run against a labelled dataset and read its per-example results (human vs. evaluator score, disagreement, and the request/response that was scored).
373
+
374
+ ```bash
375
+ scorable evaluator calibrate <evaluator_id> --dataset-id <dataset_id>
376
+ # ...or the equivalent calibration-run command:
377
+ scorable calibration-run create --evaluator-id <evaluator_id> --dataset-id <dataset_id>
378
+ scorable calibration-run get <run_id> # poll for status + metrics
379
+ scorable calibration-run list --evaluator-id <evaluator_id>
380
+ scorable calibration-run items <run_id> # per-example results
381
+ ```
382
+
383
+ ### Demonstrations
384
+
385
+ Attach a labelled dataset as few-shot demonstrations on an evaluator.
386
+
387
+ ```bash
388
+ scorable evaluator create --name "My Evaluator" ... --demonstration-dataset <dataset_id>
389
+ scorable evaluator update <evaluator_id> --demonstration-dataset <dataset_id>
390
+ ```
391
+
279
392
  ## Custom Model Management
280
393
 
281
394
  Bring your own LLM (BYO-LLM) — register a custom or self-hosted model, then reference it from evaluators and judges.
package/dist/client.d.ts CHANGED
@@ -3,6 +3,7 @@ interface RequestOptions {
3
3
  params?: Record<string, unknown>;
4
4
  apiKey?: string;
5
5
  baseUrl?: string;
6
+ headers?: Record<string, string>;
6
7
  }
7
8
  export interface ApiRequestResult {
8
9
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAQD,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAoD3B;AAKD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,CAAC,CAGlB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAQD,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAqD3B;AAKD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,CAAC,CAGlB"}
package/dist/client.js CHANGED
@@ -15,6 +15,7 @@ export async function apiRequestStatus(method, endpoint, options) {
15
15
  }
16
16
  }
17
17
  const headers = {
18
+ ...options?.headers,
18
19
  Authorization: `Api-Key ${apiKey}`,
19
20
  "Content-Type": "application/json",
20
21
  Accept: "application/json",
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerAnnotationCommands(program: Command): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/annotation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiKjE"}
@@ -0,0 +1,145 @@
1
+ import { Command } from "commander";
2
+ import ora from "ora";
3
+ import { requireApiKey, getSdkClient } from "../../auth.js";
4
+ import { printSuccess, printError, printJson, handleSdkError } from "../../output.js";
5
+ export function registerAnnotationCommands(program) {
6
+ const annotation = new Command("annotation").description("Annotation (labelling) commands");
7
+ annotation
8
+ .command("create")
9
+ .description("Create an annotation on a dataset item or execution log")
10
+ .option("--dataset-item-id <id>", "Dataset item to annotate (mutually exclusive with --execution-log-id)")
11
+ .option("--execution-log-id <id>", "Execution log to annotate (mutually exclusive with --dataset-item-id)")
12
+ .option("--value <number>", "Score for continuous configs", parseFloat)
13
+ .option("--category <label>", "Label for binary/categorical configs")
14
+ .option("--rationale <text>", "Optional free-text justification")
15
+ .option("--status <status>", "draft or published (default published)")
16
+ .option("--score-config-id <id>", "Score config; defaults to the global identity 'Score' config")
17
+ .action(async (opts) => {
18
+ if (!opts.datasetItemId === !opts.executionLogId) {
19
+ printError("Exactly one of --dataset-item-id or --execution-log-id must be provided.");
20
+ return;
21
+ }
22
+ const payload = {};
23
+ if (opts.datasetItemId)
24
+ payload.datasetItemId = opts.datasetItemId;
25
+ if (opts.executionLogId)
26
+ payload.executionLogId = opts.executionLogId;
27
+ if (opts.value !== undefined)
28
+ payload.value = opts.value;
29
+ if (opts.category !== undefined)
30
+ payload.category = opts.category;
31
+ if (opts.rationale !== undefined)
32
+ payload.rationale = opts.rationale;
33
+ if (opts.status !== undefined)
34
+ payload.status = opts.status;
35
+ if (opts.scoreConfigId)
36
+ payload.scoreConfigId = opts.scoreConfigId;
37
+ const spinner = ora("Creating annotation...").start();
38
+ try {
39
+ const client = getSdkClient(await requireApiKey());
40
+ const result = await client.annotations.create(payload);
41
+ spinner.stop();
42
+ printSuccess("Annotation created!");
43
+ printJson(result);
44
+ }
45
+ catch (e) {
46
+ spinner.stop();
47
+ handleSdkError(e);
48
+ }
49
+ });
50
+ annotation
51
+ .command("list")
52
+ .description("List annotations")
53
+ .option("--dataset <id>", "Filter by the dataset the annotated items belong to")
54
+ .option("--score-config <id>", "Filter by score config id")
55
+ .option("--status <status>", "Filter by draft or published")
56
+ .option("--dataset-item <id>", "Filter by dataset item id")
57
+ .option("--execution-log <id>", "Filter by execution log id")
58
+ .action(async (opts) => {
59
+ const params = {};
60
+ if (opts.dataset)
61
+ params.dataset = opts.dataset;
62
+ if (opts.scoreConfig)
63
+ params.score_config = opts.scoreConfig;
64
+ if (opts.status)
65
+ params.status = opts.status;
66
+ if (opts.datasetItem)
67
+ params.dataset_item = opts.datasetItem;
68
+ if (opts.executionLog)
69
+ params.execution_log = opts.executionLog;
70
+ const spinner = ora("Listing annotations...").start();
71
+ try {
72
+ const client = getSdkClient(await requireApiKey());
73
+ const result = await client.annotations.list(params);
74
+ spinner.stop();
75
+ printJson(result.results);
76
+ }
77
+ catch (e) {
78
+ spinner.stop();
79
+ handleSdkError(e);
80
+ }
81
+ });
82
+ annotation
83
+ .command("get <id>")
84
+ .description("Get an annotation by ID")
85
+ .action(async (id) => {
86
+ const spinner = ora("Fetching annotation...").start();
87
+ try {
88
+ const client = getSdkClient(await requireApiKey());
89
+ const result = await client.annotations.get(id);
90
+ spinner.stop();
91
+ printJson(result);
92
+ }
93
+ catch (e) {
94
+ spinner.stop();
95
+ handleSdkError(e);
96
+ }
97
+ });
98
+ annotation
99
+ .command("update <id>")
100
+ .description("Update an annotation (target is immutable)")
101
+ .option("--value <number>", "New score for continuous configs", parseFloat)
102
+ .option("--category <label>", "New label for binary/categorical configs")
103
+ .option("--rationale <text>", "New rationale")
104
+ .option("--status <status>", "draft or published")
105
+ .action(async (id, opts) => {
106
+ const payload = {};
107
+ if (opts.value !== undefined)
108
+ payload.value = opts.value;
109
+ if (opts.category !== undefined)
110
+ payload.category = opts.category;
111
+ if (opts.rationale !== undefined)
112
+ payload.rationale = opts.rationale;
113
+ if (opts.status !== undefined)
114
+ payload.status = opts.status;
115
+ const spinner = ora("Updating annotation...").start();
116
+ try {
117
+ const client = getSdkClient(await requireApiKey());
118
+ const result = await client.annotations.update(id, payload);
119
+ spinner.stop();
120
+ printSuccess("Annotation updated!");
121
+ printJson(result);
122
+ }
123
+ catch (e) {
124
+ spinner.stop();
125
+ handleSdkError(e);
126
+ }
127
+ });
128
+ annotation
129
+ .command("delete <id>")
130
+ .description("Delete an annotation")
131
+ .action(async (id) => {
132
+ const spinner = ora("Deleting annotation...").start();
133
+ try {
134
+ const client = getSdkClient(await requireApiKey());
135
+ await client.annotations.delete(id);
136
+ spinner.stop();
137
+ printSuccess(`Annotation ${id} deleted.`);
138
+ }
139
+ catch (e) {
140
+ spinner.stop();
141
+ handleSdkError(e);
142
+ }
143
+ });
144
+ program.addCommand(annotation);
145
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgE3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsI3D"}
@@ -1,7 +1,9 @@
1
1
  import ora from "ora";
2
2
  import { loadSettings, saveSettings, createDemoKey } from "../../auth.js";
3
- import { printSuccess, printError } from "../../output.js";
3
+ import { printSuccess, printError, printInfo, printMessage } from "../../output.js";
4
+ import { resolveProjectId } from "../../lib/project-id.js";
4
5
  import { CliError } from "../../types.js";
6
+ const AUTH_SETTINGS_KEYS = ["api_key", "temporary_api_key", "project_id"];
5
7
  export function registerAuthCommands(program) {
6
8
  const auth = program.command("auth").description("Manage authentication");
7
9
  auth
@@ -39,6 +41,71 @@ export function registerAuthCommands(program) {
39
41
  }
40
42
  printSuccess("API key saved to ~/.scorable/settings.json");
41
43
  });
44
+ auth
45
+ .command("set-project <projectId>")
46
+ .description("Persist a project_id to ~/.scorable/settings.json")
47
+ .action((projectId) => {
48
+ if (!projectId.trim()) {
49
+ printError("Project ID must not be empty.");
50
+ throw new CliError(1, "Empty project id");
51
+ }
52
+ const settings = loadSettings();
53
+ settings["project_id"] = projectId.trim();
54
+ if (!saveSettings(settings)) {
55
+ printError("Failed to save project_id to ~/.scorable/settings.json");
56
+ throw new CliError(1, "Failed to save project_id");
57
+ }
58
+ printSuccess(`project_id saved to ~/.scorable/settings.json`);
59
+ });
60
+ auth
61
+ .command("unset-project")
62
+ .description("Remove the persisted project_id from ~/.scorable/settings.json")
63
+ .action(() => {
64
+ const settings = loadSettings();
65
+ if (!("project_id" in settings)) {
66
+ printInfo("No project_id was set.");
67
+ return;
68
+ }
69
+ delete settings["project_id"];
70
+ if (!saveSettings(settings)) {
71
+ printError("Failed to update ~/.scorable/settings.json");
72
+ throw new CliError(1, "Failed to update settings");
73
+ }
74
+ printSuccess("project_id removed from ~/.scorable/settings.json");
75
+ });
76
+ auth
77
+ .command("show-project")
78
+ .description("Print the resolved project_id and its source (flag/env/settings/none)")
79
+ .action(() => {
80
+ const resolved = resolveProjectId(undefined);
81
+ if (resolved.value === undefined) {
82
+ printMessage("project_id: <none> (source: none)");
83
+ return;
84
+ }
85
+ printMessage(`project_id: ${resolved.value} (source: ${resolved.source})`);
86
+ });
87
+ auth
88
+ .command("logout")
89
+ .description("Clear the auth section of ~/.scorable/settings.json (api keys + project_id)")
90
+ .action(() => {
91
+ const settings = loadSettings();
92
+ let touched = false;
93
+ for (const k of AUTH_SETTINGS_KEYS) {
94
+ if (k in settings) {
95
+ delete settings[k];
96
+ touched = true;
97
+ }
98
+ }
99
+ if (!touched) {
100
+ printInfo("Already logged out.");
101
+ return;
102
+ }
103
+ if (!saveSettings(settings)) {
104
+ printError("Failed to update ~/.scorable/settings.json");
105
+ throw new CliError(1, "Failed to update settings");
106
+ }
107
+ printSuccess("Logged out — cleared api_key, temporary_api_key, and project_id.");
108
+ });
42
109
  auth
43
110
  .command("demo-key")
44
111
  .description("Create a free demo API key and save it to ~/.scorable/settings.json")
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerCalibrationRunCommands(program: Command): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/calibration-run/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiFrE"}
@@ -0,0 +1,83 @@
1
+ import { Command } from "commander";
2
+ import ora from "ora";
3
+ import { requireApiKey, getSdkClient } from "../../auth.js";
4
+ import { printSuccess, printJson, handleSdkError } from "../../output.js";
5
+ export function registerCalibrationRunCommands(program) {
6
+ const run = new Command("calibration-run").description("Calibration run commands");
7
+ run
8
+ .command("create")
9
+ .description("Start a calibration run against a labelled dataset")
10
+ .requiredOption("--evaluator-id <id>", "The saved evaluator to calibrate")
11
+ .requiredOption("--dataset-id <id>", "Dataset whose published annotations to calibrate against")
12
+ .option("--score-config-id <id>", "Score config (defaults to the dataset's continuous scores)")
13
+ .action(async (opts) => {
14
+ const payload = {
15
+ evaluatorId: opts.evaluatorId,
16
+ datasetId: opts.datasetId,
17
+ };
18
+ if (opts.scoreConfigId)
19
+ payload.scoreConfigId = opts.scoreConfigId;
20
+ const spinner = ora("Starting calibration run...").start();
21
+ try {
22
+ const client = getSdkClient(await requireApiKey());
23
+ const result = await client.calibrationRuns.create(payload);
24
+ spinner.stop();
25
+ printSuccess(`Calibration run ${result.id} started (status: ${result.status}).`);
26
+ printJson(result);
27
+ }
28
+ catch (e) {
29
+ spinner.stop();
30
+ handleSdkError(e);
31
+ }
32
+ });
33
+ run
34
+ .command("get <id>")
35
+ .description("Get a calibration run (poll for status and metrics)")
36
+ .action(async (id) => {
37
+ const spinner = ora("Fetching calibration run...").start();
38
+ try {
39
+ const client = getSdkClient(await requireApiKey());
40
+ const result = await client.calibrationRuns.get(id);
41
+ spinner.stop();
42
+ printJson(result);
43
+ }
44
+ catch (e) {
45
+ spinner.stop();
46
+ handleSdkError(e);
47
+ }
48
+ });
49
+ run
50
+ .command("list")
51
+ .description("List calibration runs")
52
+ .option("--evaluator-id <id>", "Filter by evaluator external id")
53
+ .action(async (opts) => {
54
+ const spinner = ora("Listing calibration runs...").start();
55
+ try {
56
+ const client = getSdkClient(await requireApiKey());
57
+ const result = await client.calibrationRuns.list(opts.evaluatorId ? { evaluatorId: opts.evaluatorId } : {});
58
+ spinner.stop();
59
+ printJson(result.results);
60
+ }
61
+ catch (e) {
62
+ spinner.stop();
63
+ handleSdkError(e);
64
+ }
65
+ });
66
+ run
67
+ .command("items <id>")
68
+ .description("List the per-example results of a calibration run")
69
+ .action(async (id) => {
70
+ const spinner = ora("Fetching calibration run items...").start();
71
+ try {
72
+ const client = getSdkClient(await requireApiKey());
73
+ const result = await client.calibrationRuns.listItems(id);
74
+ spinner.stop();
75
+ printJson(result.results);
76
+ }
77
+ catch (e) {
78
+ spinner.stop();
79
+ handleSdkError(e);
80
+ }
81
+ });
82
+ program.addCommand(run);
83
+ }
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerDatasetItemCommands(program: Command): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/dataset-item/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4KlE"}
@@ -0,0 +1,160 @@
1
+ import { Command } from "commander";
2
+ import ora from "ora";
3
+ import { z } from "zod";
4
+ import { requireApiKey, getSdkClient } from "../../auth.js";
5
+ import { printSuccess, printError, printJson, handleSdkError } from "../../output.js";
6
+ import { parseJsonArg } from "../../utils.js";
7
+ export function registerDatasetItemCommands(program) {
8
+ const item = new Command("dataset-item").description("Dataset item commands");
9
+ item
10
+ .command("add <datasetId>")
11
+ .description("Add a single item to a dataset")
12
+ .requiredOption("--response <text>", "The response text")
13
+ .option("--request <text>", "The request/prompt text")
14
+ .option("--expected-output <text>", "The expected output")
15
+ .option("--metadata <json>", "Metadata JSON object")
16
+ .option("--change-note <text>", "Change note for this version")
17
+ .action(async (datasetId, opts) => {
18
+ const body = { response: opts.response };
19
+ if (opts.request !== undefined)
20
+ body.request = opts.request;
21
+ if (opts.expectedOutput !== undefined)
22
+ body.expected_output = opts.expectedOutput;
23
+ if (opts.changeNote !== undefined)
24
+ body.change_note = opts.changeNote;
25
+ if (opts.metadata !== undefined) {
26
+ const r = parseJsonArg(opts.metadata, z.record(z.string(), z.unknown()));
27
+ if (!r.ok) {
28
+ printError("Invalid JSON for --metadata. Expected an object.");
29
+ return;
30
+ }
31
+ body.metadata = r.value;
32
+ }
33
+ const spinner = ora("Adding item...").start();
34
+ try {
35
+ const client = getSdkClient(await requireApiKey());
36
+ const result = await client.datasets.addItem(datasetId, body);
37
+ spinner.stop();
38
+ printSuccess("Dataset item added!");
39
+ printJson(result);
40
+ }
41
+ catch (e) {
42
+ spinner.stop();
43
+ handleSdkError(e);
44
+ }
45
+ });
46
+ item
47
+ .command("add-bulk <datasetId>")
48
+ .description("Bulk add items to a dataset (at most 5000)")
49
+ .requiredOption("--items <json>", "JSON array of item objects")
50
+ .action(async (datasetId, opts) => {
51
+ const r = parseJsonArg(opts.items, z.array(z.record(z.string(), z.unknown())));
52
+ if (!r.ok) {
53
+ printError("Invalid JSON for --items. Expected an array of item objects.");
54
+ return;
55
+ }
56
+ const spinner = ora("Bulk adding items...").start();
57
+ try {
58
+ const client = getSdkClient(await requireApiKey());
59
+ const result = await client.datasets.addItems(datasetId, r.value);
60
+ spinner.stop();
61
+ printSuccess(`Added ${result.length} dataset items.`);
62
+ printJson(result);
63
+ }
64
+ catch (e) {
65
+ spinner.stop();
66
+ handleSdkError(e);
67
+ }
68
+ });
69
+ item
70
+ .command("list <datasetId>")
71
+ .description("List the latest-version items of a dataset (with embedded annotations)")
72
+ .option("--include-archived", "Include archived items", false)
73
+ .action(async (datasetId, opts) => {
74
+ const spinner = ora("Listing items...").start();
75
+ try {
76
+ const client = getSdkClient(await requireApiKey());
77
+ const result = await client.datasets.listItems(datasetId, {
78
+ includeArchived: opts.includeArchived ?? false,
79
+ });
80
+ spinner.stop();
81
+ printJson(result.results);
82
+ }
83
+ catch (e) {
84
+ spinner.stop();
85
+ handleSdkError(e);
86
+ }
87
+ });
88
+ item
89
+ .command("get <datasetId> <itemId>")
90
+ .description("Get a single dataset item")
91
+ .action(async (datasetId, itemId) => {
92
+ const spinner = ora("Fetching item...").start();
93
+ try {
94
+ const client = getSdkClient(await requireApiKey());
95
+ const result = await client.datasets.getItem(datasetId, itemId);
96
+ spinner.stop();
97
+ printJson(result);
98
+ }
99
+ catch (e) {
100
+ spinner.stop();
101
+ handleSdkError(e);
102
+ }
103
+ });
104
+ item
105
+ .command("update <datasetId> <itemId>")
106
+ .description("Edit a dataset item (creates a new version)")
107
+ .option("--response <text>", "The response text")
108
+ .option("--request <text>", "The request/prompt text")
109
+ .option("--expected-output <text>", "The expected output")
110
+ .option("--metadata <json>", "Metadata JSON object")
111
+ .option("--change-note <text>", "Change note for this version")
112
+ .action(async (datasetId, itemId, opts) => {
113
+ const body = {};
114
+ if (opts.response !== undefined)
115
+ body.response = opts.response;
116
+ if (opts.request !== undefined)
117
+ body.request = opts.request;
118
+ if (opts.expectedOutput !== undefined)
119
+ body.expected_output = opts.expectedOutput;
120
+ if (opts.changeNote !== undefined)
121
+ body.change_note = opts.changeNote;
122
+ if (opts.metadata !== undefined) {
123
+ const r = parseJsonArg(opts.metadata, z.record(z.string(), z.unknown()));
124
+ if (!r.ok) {
125
+ printError("Invalid JSON for --metadata. Expected an object.");
126
+ return;
127
+ }
128
+ body.metadata = r.value;
129
+ }
130
+ const spinner = ora("Updating item...").start();
131
+ try {
132
+ const client = getSdkClient(await requireApiKey());
133
+ const result = await client.datasets.updateItem(datasetId, itemId, body);
134
+ spinner.stop();
135
+ printSuccess("Dataset item updated!");
136
+ printJson(result);
137
+ }
138
+ catch (e) {
139
+ spinner.stop();
140
+ handleSdkError(e);
141
+ }
142
+ });
143
+ item
144
+ .command("archive <datasetId> <itemId>")
145
+ .description("Archive (soft-delete) a dataset item")
146
+ .action(async (datasetId, itemId) => {
147
+ const spinner = ora("Archiving item...").start();
148
+ try {
149
+ const client = getSdkClient(await requireApiKey());
150
+ await client.datasets.archiveItem(datasetId, itemId);
151
+ spinner.stop();
152
+ printSuccess(`Dataset item ${itemId} archived.`);
153
+ }
154
+ catch (e) {
155
+ spinner.stop();
156
+ handleSdkError(e);
157
+ }
158
+ });
159
+ program.addCommand(item);
160
+ }
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerCalibrateCommand(evaluator: Command): void;
3
+ //# sourceMappingURL=calibrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calibrate.d.ts","sourceRoot":"","sources":["../../../src/commands/evaluator/calibrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CA6BjE"}