@toloka-platform/sdk 0.2.0-preview.2 → 0.2.0-preview.4

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 (110) hide show
  1. package/README.md +10 -4
  2. package/dist/cli/toloka.js +162 -154
  3. package/dist/cli/toloka.js.jsc +0 -0
  4. package/dist/cli/toloka.js.jsc.sha256 +1 -1
  5. package/dist/cli/toloka.js.sha256 +1 -1
  6. package/docs/authoring.md +18 -1
  7. package/docs/cli-v2.md +6 -4
  8. package/docs/cli.md +58 -11
  9. package/docs/getting-started.md +3 -3
  10. package/docs/limitations.md +1 -1
  11. package/docs/testing.md +1 -1
  12. package/docs/troubleshooting.md +1 -1
  13. package/examples/face-image-collection/README.md +2 -2
  14. package/openapi/gen/api.ts +78 -0
  15. package/openapi/gen/models/baseModel.ts +1 -0
  16. package/openapi/gen/models/checkReport.ts +2 -1
  17. package/openapi/gen/models/checkReportAnyOfTwoseven.ts +5 -0
  18. package/openapi/gen/models/checkReportAnyOfTwosevenResultsItem.ts +6 -0
  19. package/openapi/gen/models/checkReportAnyOfTwosevenResultsItemVerdict.ts +2 -0
  20. package/openapi/gen/models/currentUser.ts +3 -0
  21. package/openapi/gen/models/currentUserTeamsItem.ts +6 -0
  22. package/openapi/gen/models/deliveryOrder.ts +9 -0
  23. package/openapi/gen/models/deliveryOrderClientName.ts +2 -0
  24. package/openapi/gen/models/getTrainingRunMetricHistoryParams.ts +4 -0
  25. package/openapi/gen/models/gistingTrainingConfiguration.ts +6 -2
  26. package/openapi/gen/models/gistingTrainingConfigurationBatchSize.ts +2 -0
  27. package/openapi/gen/models/gistingTrainingConfigurationGistTokens.ts +2 -0
  28. package/openapi/gen/models/gistingTrainingConfigurationInput.ts +6 -2
  29. package/openapi/gen/models/gistingTrainingConfigurationInputBatchSize.ts +2 -0
  30. package/openapi/gen/models/gistingTrainingConfigurationInputGistTokens.ts +2 -0
  31. package/openapi/gen/models/index.ts +28 -4
  32. package/openapi/gen/models/listDeliveryOrders200.ts +5 -0
  33. package/openapi/gen/models/sftTrainingConfiguration.ts +6 -3
  34. package/openapi/gen/models/sftTrainingConfigurationBatchSize.ts +2 -0
  35. package/openapi/gen/models/sftTrainingConfigurationInput.ts +6 -3
  36. package/openapi/gen/models/sftTrainingConfigurationInputBatchSize.ts +2 -0
  37. package/openapi/gen/models/sftTrainingConfigurationInputLoraRank.ts +2 -0
  38. package/openapi/gen/models/sftTrainingConfigurationLoraRank.ts +2 -0
  39. package/openapi/gen/models/trainingRunMetricHistory.ts +9 -0
  40. package/openapi/gen/models/trainingRunMetricHistoryMetric.ts +2 -0
  41. package/openapi/gen/models/trainingRunMetricHistoryPointsItem.ts +9 -0
  42. package/openapi/gen/models/trainingRunMetricHistoryPointsItemNonFinite.ts +2 -0
  43. package/openapi/gen/models/trainingRunMetricHistoryPointsItemValue.ts +2 -0
  44. package/openapi/gen/models/trainingRunMetrics.ts +9 -0
  45. package/openapi/gen/models/trainingRunMetricsMetricsItem.ts +8 -0
  46. package/openapi/gen/models/trainingRunMetricsMetricsItemLatest.ts +9 -0
  47. package/openapi/gen/models/trainingRunMetricsMetricsItemLatestNonFinite.ts +2 -0
  48. package/openapi/gen/models/trainingRunMetricsMetricsItemLatestValue.ts +2 -0
  49. package/openapi/gen/models/trainingRunMetricsMetricsItemMetric.ts +2 -0
  50. package/openapi/gen/models/trainingRunMetricsUnavailableReason.ts +2 -0
  51. package/package.json +2 -2
  52. package/skills/catalog.json +55 -7
  53. package/skills/toloka-build/SKILL.md +35 -21
  54. package/skills/toloka-build/references/node-semantics.md +13 -11
  55. package/skills/toloka-build/references/workflow-and-cli.md +31 -20
  56. package/skills/toloka-fine-tuning/SKILL.md +155 -0
  57. package/skills/toloka-get-started/SKILL.md +70 -0
  58. package/skills/toloka-gisting/SKILL.md +166 -0
  59. package/skills/toloka-report-issue/references/report-template.md +1 -1
  60. package/src/authoring/index.ts +14 -0
  61. package/src/checks/task-ui-typecheck.ts +12 -10
  62. package/src/cli/analytics.ts +88 -15
  63. package/src/cli/auth.ts +93 -21
  64. package/src/cli/auto-update.ts +36 -39
  65. package/src/cli/check.ts +88 -39
  66. package/src/cli/cli-entry.ts +3 -2
  67. package/src/cli/cli-error.ts +43 -0
  68. package/src/cli/commands/auth.ts +89 -0
  69. package/src/cli/commands/config.ts +28 -0
  70. package/src/cli/commands/dataset.ts +85 -0
  71. package/src/cli/commands/delivery-order.ts +18 -0
  72. package/src/cli/commands/models.ts +121 -0
  73. package/src/cli/commands/pipeline.ts +131 -0
  74. package/src/cli/commands/project.ts +168 -0
  75. package/src/cli/commands/report.ts +43 -0
  76. package/src/cli/commands/secret.ts +40 -0
  77. package/src/cli/commands/skill.ts +36 -0
  78. package/src/cli/commands/source.ts +204 -0
  79. package/src/cli/commands/status.ts +17 -0
  80. package/src/cli/commands/training.ts +261 -0
  81. package/src/cli/commands/version.ts +14 -0
  82. package/src/cli/config.ts +7 -8
  83. package/src/cli/context.ts +251 -0
  84. package/src/cli/credentials.ts +12 -4
  85. package/src/cli/data.ts +96 -34
  86. package/src/cli/delivery-orders.ts +47 -0
  87. package/src/cli/environment.ts +26 -0
  88. package/src/cli/file-system.ts +6 -2
  89. package/src/cli/format-error.ts +45 -2
  90. package/src/cli/init.ts +14 -11
  91. package/src/cli/models.ts +43 -12
  92. package/src/cli/program.ts +120 -1347
  93. package/src/cli/project-context.ts +126 -43
  94. package/src/cli/project.ts +80 -28
  95. package/src/cli/report.ts +24 -9
  96. package/src/cli/runs.ts +33 -8
  97. package/src/cli/sdk-version.ts +38 -0
  98. package/src/cli/settings.ts +13 -5
  99. package/src/cli/skill.ts +67 -24
  100. package/src/cli/source.ts +3 -2
  101. package/src/cli/terminal-io.ts +110 -0
  102. package/src/cli/trainings.ts +242 -57
  103. package/src/cli/version.ts +3 -3
  104. package/src/client.ts +21 -9
  105. package/src/importer.ts +32 -2
  106. package/src/transport.ts +13 -1
  107. package/openapi/gen/models/gistingTrainingConfigurationInputRegime.ts +0 -2
  108. package/openapi/gen/models/gistingTrainingConfigurationRegime.ts +0 -2
  109. package/openapi/gen/models/sftTrainingConfigurationInputRegime.ts +0 -2
  110. package/openapi/gen/models/sftTrainingConfigurationRegime.ts +0 -2
@@ -0,0 +1,121 @@
1
+ import type { Command } from "commander";
2
+ import { resolveContext, type CommandHost } from "../context";
3
+ import {
4
+ archiveModel,
5
+ createModel,
6
+ downloadModelVersion,
7
+ getBaseModel,
8
+ getModel,
9
+ listBaseModels,
10
+ listModels,
11
+ listModelVersions,
12
+ parseBaseModelId,
13
+ } from "../models";
14
+ import { assertProjectSelected } from "../project-context";
15
+
16
+ export const registerModelCommands = (program: Command, host: CommandHost): void => {
17
+ const { context, globals } = host;
18
+
19
+ const baseModel = program
20
+ .command("base-model")
21
+ .description("inspect the global base model catalog");
22
+ baseModel
23
+ .command("list")
24
+ .option("--json", "print JSON", false)
25
+ .description("list base models")
26
+ .action(async (options: { json: boolean }) => {
27
+ const { client } = await resolveContext(globals(), context);
28
+ await listBaseModels(client, { json: options.json }, context.io);
29
+ });
30
+ baseModel
31
+ .command("get")
32
+ .argument("<id>", "base model ID")
33
+ .option("--json", "print JSON", false)
34
+ .description("show one base model")
35
+ .action(async (id: string, options: { json: boolean }) => {
36
+ const { client } = await resolveContext(globals(), context);
37
+ await getBaseModel(client, { id: parseBaseModelId(id), json: options.json }, context.io);
38
+ });
39
+
40
+ const model = program
41
+ .command("model")
42
+ .description("manage project Models and immutable versions");
43
+ model
44
+ .command("list")
45
+ .option("--json", "print JSON", false)
46
+ .description("list Models owned by the selected project")
47
+ .action(async (options: { json: boolean }) => {
48
+ const { client, projectId } = await resolveContext(globals(), context);
49
+ assertProjectSelected(projectId);
50
+ await listModels(client, { projectId, json: options.json }, context.io);
51
+ });
52
+ model
53
+ .command("get")
54
+ .argument("<name-or-id>", "project Model name or ID")
55
+ .option("--json", "print JSON", false)
56
+ .description("show one project Model")
57
+ .action(async (nameOrId: string, options: { json: boolean }) => {
58
+ const { client, projectId } = await resolveContext(globals(), context);
59
+ assertProjectSelected(projectId);
60
+ await getModel(client, { projectId, nameOrId, json: options.json }, context.io);
61
+ });
62
+ model
63
+ .command("versions")
64
+ .argument("<name-or-id>", "project Model name or ID")
65
+ .option("--json", "print JSON", false)
66
+ .description("list immutable versions of a model")
67
+ .action(async (nameOrId: string, options: { json: boolean }) => {
68
+ const { client, projectId } = await resolveContext(globals(), context);
69
+ assertProjectSelected(projectId);
70
+ await listModelVersions(client, { projectId, nameOrId, json: options.json }, context.io);
71
+ });
72
+ model
73
+ .command("create")
74
+ .argument("<name>", "new Model name")
75
+ .requiredOption("--base <id>", "base model ID")
76
+ .option("--description <text>", "Model description")
77
+ .option("--json", "print JSON", false)
78
+ .description("create project Model metadata without a Model Version")
79
+ .action(
80
+ async (name: string, options: { base: string; description?: string; json: boolean }) => {
81
+ const { client, projectId } = await resolveContext(globals(), context);
82
+ assertProjectSelected(projectId);
83
+ await createModel(
84
+ client,
85
+ {
86
+ projectId,
87
+ name,
88
+ description: options.description,
89
+ baseModelId: parseBaseModelId(options.base),
90
+ json: options.json,
91
+ },
92
+ context.io,
93
+ );
94
+ },
95
+ );
96
+ model
97
+ .command("archive")
98
+ .option("--json", "print JSON", false)
99
+ .argument("<name-or-id>", "project Model name or ID")
100
+ .description("archive a project Model")
101
+ .action(async (nameOrId: string, options: { json: boolean }) => {
102
+ const { client, projectId } = await resolveContext(globals(), context);
103
+ assertProjectSelected(projectId);
104
+ await archiveModel(client, { projectId, nameOrId, json: options.json }, context.io);
105
+ });
106
+
107
+ const modelVersion = model.command("version").description("manage one immutable Model Version");
108
+ modelVersion
109
+ .command("download")
110
+ .argument("<model-version>", "Model Version ID or Model@name")
111
+ .requiredOption("--out <directory>", "output directory")
112
+ .description("download and verify Model Version content")
113
+ .action(async (modelVersionId: string, options: { out: string }) => {
114
+ const { client, projectId } = await resolveContext(globals(), context);
115
+ await downloadModelVersion(
116
+ client,
117
+ { projectId, modelVersionId, out: options.out },
118
+ context.io,
119
+ );
120
+ });
121
+ };
@@ -0,0 +1,131 @@
1
+ import type { Command } from "commander";
2
+ import { estimatePipelineCost } from "../cost";
3
+ import { exitCodeForOutcome, positiveInteger, resolveContext, type CommandHost } from "../context";
4
+ import { assertProjectSelected } from "../project-context";
5
+ import {
6
+ cancelPipelineRun,
7
+ listLivePipelines,
8
+ listPipelineRuns,
9
+ pipelineRunResults,
10
+ pipelineRunStatus,
11
+ startPipelineRun,
12
+ } from "../runs";
13
+
14
+ export const registerPipelineCommands = (program: Command, host: CommandHost): void => {
15
+ const { context, exitCode, globals } = host;
16
+ const pipelineNameHelp =
17
+ "pipeline name or id; required unless a TTY picker can choose among several";
18
+ const pipeline = program
19
+ .command("pipeline")
20
+ .description("operate on a live pipeline in the selected project");
21
+ pipeline
22
+ .command("list")
23
+ .option("--limit <n>", "maximum pipelines to list", positiveInteger)
24
+ .description("list live pipelines in the selected project")
25
+ .action(async (options: { limit?: number }) => {
26
+ const { client, projectId, state } = await resolveContext(globals(), context);
27
+ assertProjectSelected(projectId);
28
+ const result = await listLivePipelines({
29
+ client,
30
+ projectId,
31
+ state,
32
+ ...(options.limit === undefined ? {} : { limit: options.limit }),
33
+ });
34
+ context.io.stdout(result.output);
35
+ });
36
+ pipeline
37
+ .command("run")
38
+ .argument("[name]", pipelineNameHelp)
39
+ .option("--wait", "wait for the run to reach a terminal state", false)
40
+ .option("--timeout <ms>", "how long to wait", positiveInteger)
41
+ .description("start a run on a deployed pipeline")
42
+ .action(async (name: string | undefined, options: { wait: boolean; timeout?: number }) => {
43
+ const { client, state, projectId } = await resolveContext(globals(), context);
44
+ assertProjectSelected(projectId);
45
+ const result = await startPipelineRun(client, {
46
+ projectId,
47
+ state,
48
+ ...(name === undefined ? {} : { pipeline: name }),
49
+ wait: options.wait,
50
+ ...(options.timeout === undefined ? {} : { timeoutMs: options.timeout }),
51
+ ...(context.io.select === undefined ? {} : { select: context.io.select }),
52
+ });
53
+ context.io.stdout(result.output);
54
+ exitCode.value = exitCodeForOutcome(result.outcome);
55
+ });
56
+ pipeline
57
+ .command("status")
58
+ .argument("[name]", pipelineNameHelp)
59
+ .description("report the latest run's state and item counts")
60
+ .action(async (name: string | undefined) => {
61
+ const { client, state, projectId } = await resolveContext(globals(), context);
62
+ assertProjectSelected(projectId);
63
+ const result = await pipelineRunStatus(client, {
64
+ projectId,
65
+ state,
66
+ ...(name === undefined ? {} : { pipeline: name }),
67
+ ...(context.io.select === undefined ? {} : { select: context.io.select }),
68
+ });
69
+ context.io.stdout(result.output);
70
+ exitCode.value = exitCodeForOutcome(result.outcome);
71
+ });
72
+ pipeline
73
+ .command("runs")
74
+ .argument("[name]", pipelineNameHelp)
75
+ .option("--limit <n>", "how many runs to list", positiveInteger)
76
+ .description("list recent runs")
77
+ .action(async (name: string | undefined, options: { limit?: number }) => {
78
+ const { client, state, projectId } = await resolveContext(globals(), context);
79
+ assertProjectSelected(projectId);
80
+ const result = await listPipelineRuns(client, {
81
+ projectId,
82
+ state,
83
+ ...(name === undefined ? {} : { pipeline: name }),
84
+ ...(options.limit === undefined ? {} : { limit: options.limit }),
85
+ ...(context.io.select === undefined ? {} : { select: context.io.select }),
86
+ });
87
+ context.io.stdout(result.output);
88
+ });
89
+ pipeline
90
+ .command("cost")
91
+ .argument("[name]", pipelineNameHelp)
92
+ .option("--item-limit <n>", "cap how many items to price", positiveInteger)
93
+ .description("forecast what a run of this pipeline would bill")
94
+ .action(async (name: string | undefined, options: { itemLimit?: number }) => {
95
+ const { client, state, projectId } = await resolveContext(globals(), context);
96
+ assertProjectSelected(projectId);
97
+ const result = await estimatePipelineCost(client, {
98
+ projectId,
99
+ state,
100
+ ...(name === undefined ? {} : { pipeline: name }),
101
+ ...(options.itemLimit === undefined ? {} : { itemLimit: options.itemLimit }),
102
+ ...(context.io.select === undefined ? {} : { select: context.io.select }),
103
+ });
104
+ context.io.stdout(result.output);
105
+ });
106
+ pipeline
107
+ .command("cancel")
108
+ .argument("<runId>", "run to cancel")
109
+ .description("request cancellation of a run")
110
+ .action(async (runId: string) => {
111
+ const { client } = await resolveContext(globals(), context);
112
+ const result = await cancelPipelineRun(client, { runId });
113
+ context.io.stdout(result.output);
114
+ });
115
+ pipeline
116
+ .command("results")
117
+ .argument("<runId>", "run to read")
118
+ .option("--limit <n>", "how many items to scan", positiveInteger)
119
+ .option("--failed", "only report failed items", false)
120
+ .description("report a run's items")
121
+ .action(async (runId: string, options: { limit?: number; failed: boolean }) => {
122
+ const { client } = await resolveContext(globals(), context);
123
+ const result = await pipelineRunResults(client, {
124
+ runId,
125
+ failedOnly: options.failed,
126
+ ...(options.limit === undefined ? {} : { limit: options.limit }),
127
+ });
128
+ context.io.stdout(result.output);
129
+ exitCode.value = exitCodeForOutcome(result.outcome);
130
+ });
131
+ };
@@ -0,0 +1,168 @@
1
+ import type { Command } from "commander";
2
+ import { createClient } from "../../client";
3
+ import {
4
+ identifyClientUser,
5
+ positiveInteger,
6
+ readCommandCredentials,
7
+ resolveContext,
8
+ resolveSelectedProject,
9
+ resolveSourceRoot,
10
+ type CommandHost,
11
+ } from "../context";
12
+ import { requireStoredCredentials } from "../credentials";
13
+ import { addProject, assertProjectSelected, createProject, currentProject, listRemoteProjects, removeProject, switchProject, untrackProjectResource } from "../project-context";
14
+ import { readTolokaState } from "../../state";
15
+ import { assertCli } from "../cli-error";
16
+
17
+ export const registerProjectCommands = (program: Command, host: CommandHost): void => {
18
+ const { context, exitCode, globals } = host;
19
+ const project = program
20
+ .command("project")
21
+ .description("select and manage the current platform project");
22
+ project
23
+ .command("list")
24
+ .option("--limit <n>", "maximum projects to list", positiveInteger)
25
+ .description("list remote projects this key can see")
26
+ .action(async (options: { limit?: number }) => {
27
+ const flags = globals();
28
+ const { client, stored, state } = await resolveContext(flags, context);
29
+ const selected = resolveSelectedProject(flags, context, stored, state);
30
+ await listRemoteProjects({
31
+ client,
32
+ io: context.io,
33
+ ...(selected === undefined ? {} : { context: selected }),
34
+ ...(options.limit === undefined ? {} : { limit: options.limit }),
35
+ });
36
+ });
37
+ project
38
+ .command("add")
39
+ .argument("[alias]", "local name for this project")
40
+ .argument("[projectId]", "platform project id")
41
+ .description("register a live project and select it")
42
+ .action(async (alias?: string, projectId?: string) => {
43
+ const flags = globals();
44
+ const found = await requireStoredCredentials(context.environment);
45
+ const client = context.injectedClient ?? createClient(found.credentials);
46
+ await addProject({
47
+ environment: context.environment,
48
+ flags,
49
+ client,
50
+ io: context.io,
51
+ afterPreflight: async () => identifyClientUser(client, context.analytics),
52
+ ...(alias === undefined ? {} : { alias }),
53
+ ...(projectId === undefined ? {} : { projectId }),
54
+ });
55
+ });
56
+
57
+ project
58
+ .command("switch")
59
+ .argument("<alias>", "local project alias")
60
+ .description("select a registered project")
61
+ .action(async (alias: string) => {
62
+ await switchProject({
63
+ environment: context.environment,
64
+ flags: globals(),
65
+ alias,
66
+ io: context.io,
67
+ });
68
+ });
69
+ project
70
+ .command("current")
71
+ .description("show the project this command would use")
72
+ .action(async () => {
73
+ const flags = globals();
74
+ const stored = await readCommandCredentials(flags, context);
75
+ const sourceRoot = await resolveSourceRoot(flags, context.io);
76
+ const state = await readTolokaState(sourceRoot);
77
+ const result = currentProject({
78
+ flags,
79
+ environment: context.environment,
80
+ stored,
81
+ ...(state === undefined ? {} : { state }),
82
+ io: context.io,
83
+ });
84
+ if (result.project === undefined) exitCode.value = 1;
85
+ });
86
+ project
87
+ .command("url")
88
+ .description("print the current project URL")
89
+ .action(async () => {
90
+ const { baseUrl, client, projectId } = await resolveContext(globals(), context);
91
+ assertProjectSelected(projectId);
92
+ const live = await client.projects.get({ projectId });
93
+ const url = new URL(
94
+ `/teams/${encodeURIComponent(live.teamId)}/projects/${encodeURIComponent(live.id)}`,
95
+ baseUrl,
96
+ );
97
+ context.io.stdout(url.href);
98
+ });
99
+
100
+ project
101
+ .command("remove")
102
+ .argument("<alias>", "local project alias")
103
+ .description("forget a local project alias")
104
+ .action(async (alias: string) => {
105
+ await removeProject({
106
+ environment: context.environment,
107
+ flags: globals(),
108
+ alias,
109
+ io: context.io,
110
+ });
111
+ });
112
+ project
113
+ .command("untrack")
114
+ .argument("<type>", "pipeline or dataset")
115
+ .argument("<name>", "tracked resource name")
116
+ .option("--confirm", "confirm untracking in a non-interactive environment", false)
117
+ .description("remove a pipeline or dataset from local tracking without deleting it")
118
+ .action(async (type: string, name: string, options: { confirm: boolean }) => {
119
+ assertCli(
120
+ type === "pipeline" || type === "dataset",
121
+ "Resource type must be pipeline or dataset.",
122
+ { hint: { description: "Run toloka project untrack pipeline <name> or toloka project untrack dataset <name>." } },
123
+ );
124
+ const sourceRoot = await resolveSourceRoot(globals(), context.io);
125
+ await untrackProjectResource({
126
+ sourceRoot,
127
+ type,
128
+ name,
129
+ confirm: options.confirm,
130
+ io: context.io,
131
+ });
132
+ });
133
+ const create = project
134
+ .command("create")
135
+ .argument("[alias]", "local name for the new project")
136
+ .option("--name <name>", "platform project name")
137
+ .option("--team-id <id>", "team that owns the project")
138
+ .description("create a live project and select it");
139
+ create.option(
140
+ "--delivery-order-id <id>",
141
+ "Sunday delivery order id (required when the owning team is internal)",
142
+ );
143
+ create.action(
144
+ async (
145
+ alias: string | undefined,
146
+ options: { name?: string; teamId?: string; deliveryOrderId?: string },
147
+ ) => {
148
+ const flags = globals();
149
+ const found = await requireStoredCredentials(context.environment);
150
+ const client = context.injectedClient ?? createClient(found.credentials);
151
+ const sourceRoot = await resolveSourceRoot(flags, context.io);
152
+ await createProject({
153
+ environment: context.environment,
154
+ flags,
155
+ client,
156
+ io: context.io,
157
+ sourceRoot,
158
+ afterPreflight: async () => identifyClientUser(client, context.analytics),
159
+ ...(alias === undefined ? {} : { alias }),
160
+ ...(options.name === undefined ? {} : { name: options.name }),
161
+ ...(options.teamId === undefined ? {} : { teamId: options.teamId }),
162
+ ...(options.deliveryOrderId === undefined
163
+ ? {}
164
+ : { deliveryOrderId: options.deliveryOrderId }),
165
+ });
166
+ },
167
+ );
168
+ };
@@ -0,0 +1,43 @@
1
+ import type { Command } from "commander";
2
+ import { authoredByOption, resolveInitRoot, type CommandHost } from "../context";
3
+ import { PRODUCTION_BASE_URL, resolveInternalBaseUrl } from "../config";
4
+ import { submitIssueReport, type IssueReportAuthor } from "../report";
5
+ import { assertCli } from "../cli-error";
6
+
7
+ export const registerReportCommand = (program: Command, host: CommandHost): void => {
8
+ const { context, exitCode, globals } = host;
9
+ program
10
+ .command("report")
11
+ .argument("<markdownPath>", "path to a UTF-8 Markdown report")
12
+ .option("--authored-by <who>", "human or agent", authoredByOption, "human")
13
+ .option("--confirm", "confirm submission in a non-interactive environment", false)
14
+ .description("preview and send an issue report to Toloka through PostHog")
15
+ .action(
16
+ async (
17
+ markdownPath: string,
18
+ options: { authoredBy: IssueReportAuthor; confirm: boolean },
19
+ ) => {
20
+ assertCli(
21
+ context.analytics,
22
+ "Issue reporting requires CLI analytics.",
23
+ { hint: { description: "Set TOLOKA_TELEMETRY=1 to enable analytics, then re-run toloka report." } },
24
+ );
25
+ const sourceRoot = resolveInitRoot(globals());
26
+ const baseUrl =
27
+ globals().baseUrl ??
28
+ context.environment.TOLOKA_BASE_URL ??
29
+ resolveInternalBaseUrl(context.environment) ??
30
+ PRODUCTION_BASE_URL;
31
+ exitCode.value = await submitIssueReport({
32
+ path: markdownPath,
33
+ authoredBy: options.authoredBy,
34
+ platform: new URL(baseUrl).origin,
35
+ confirm: options.confirm,
36
+ sourceRoot,
37
+ cwd: process.cwd(),
38
+ analytics: context.analytics,
39
+ io: context.io,
40
+ });
41
+ },
42
+ );
43
+ };
@@ -0,0 +1,40 @@
1
+ import type { Command } from "commander";
2
+ import { resolveContext, type CommandHost } from "../context";
3
+ import { setProjectSecret } from "../data";
4
+ import { assertProjectSelected } from "../project-context";
5
+ import { assertCli } from "../cli-error";
6
+
7
+ export const registerSecretCommands = (program: Command, host: CommandHost): void => {
8
+ const { context, exitCode, globals } = host;
9
+ const secret = program.command("secret").description("manage project secrets");
10
+ secret
11
+ .command("set")
12
+ .argument("<name>", "secret name referenced by a code node")
13
+ .option(
14
+ "--from-env <variable>",
15
+ "read the value from this environment variable instead of stdin",
16
+ )
17
+ .description("set a secret value without writing it to disk")
18
+ .action(async (name: string, options: { fromEnv?: string }) => {
19
+ const { client, projectId } = await resolveContext(globals(), context);
20
+ assertProjectSelected(projectId);
21
+
22
+ const value =
23
+ options.fromEnv === undefined
24
+ ? (await context.io.readStdin()).replace(/\r?\n$/u, "")
25
+ : context.environment[options.fromEnv];
26
+ assertCli(
27
+ value !== undefined,
28
+ `Missing secret value. Set ${options.fromEnv ?? "the named environment variable"} or pipe it to stdin.`,
29
+ { hint: { disabled: true } },
30
+ );
31
+
32
+ try {
33
+ const result = await setProjectSecret(client, { projectId, name, value });
34
+ context.io.stdout(result.output);
35
+ } catch {
36
+ context.io.stderr(`Failed to set secret ${name}.`);
37
+ exitCode.value = 1;
38
+ }
39
+ });
40
+ };
@@ -0,0 +1,36 @@
1
+ import type { Command } from "commander";
2
+ import { resolveSourceRoot, type CommandHost } from "../context";
3
+ import { skillInstallCommand, skillListCommand, skillSearchCommand } from "../skill";
4
+
5
+ export const registerSkillCommands = (program: Command, host: CommandHost): void => {
6
+ const { context, globals } = host;
7
+ const skill = program
8
+ .command("skill")
9
+ .description("discover bundled agent skills and install them into .agents/skills");
10
+ skill
11
+ .command("list")
12
+ .option("--json", "print Skill Descriptors with their status as JSON", false)
13
+ .description("list bundled skills as not-installed, current, or stale")
14
+ .action(async (options: { json: boolean }) => {
15
+ const sourceRoot = await resolveSourceRoot(globals(), context.io);
16
+ await skillListCommand({ sourceRoot, json: options.json, io: context.io });
17
+ });
18
+ skill
19
+ .command("search")
20
+ .argument("<query>", "text matched case-insensitively against id, name, description, and tags")
21
+ .option("--json", "print matching Skill Descriptors with their status as JSON", false)
22
+ .description("find bundled skills for a task")
23
+ .action(async (query: string, options: { json: boolean }) => {
24
+ const sourceRoot = await resolveSourceRoot(globals(), context.io);
25
+ await skillSearchCommand({ sourceRoot, query, json: options.json, io: context.io });
26
+ });
27
+ skill
28
+ .command("install")
29
+ .argument("<skillId>", "skill id from toloka skill list")
30
+ .option("-f, --force", "replace an existing .agents/skills/<skillId> directory", false)
31
+ .description("copy one bundled skill into .agents/skills/<skillId>")
32
+ .action(async (skillId: string, options: { force: boolean }) => {
33
+ const sourceRoot = await resolveSourceRoot(globals(), context.io);
34
+ await skillInstallCommand({ sourceRoot, skillId, force: options.force, io: context.io });
35
+ });
36
+ };