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