outrank-cli 0.5.0 → 0.6.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.
- package/README.md +317 -20
- package/SKILL.md +20 -2
- package/bin/outrank-mcp.js +3 -0
- package/package.json +21 -5
- package/src/adapters/cli/jsonInput.js +42 -0
- package/src/adapters/cli/parse.js +124 -0
- package/src/adapters/cli/run.js +139 -0
- package/src/adapters/mcp/constants.js +49 -0
- package/src/adapters/mcp/descriptions.js +87 -0
- package/src/adapters/mcp/help.js +34 -0
- package/src/adapters/mcp/input.js +195 -0
- package/src/adapters/mcp/instructions.js +139 -0
- package/src/adapters/mcp/logger.js +45 -0
- package/src/adapters/mcp/main.js +36 -0
- package/src/adapters/mcp/options.js +118 -0
- package/src/adapters/mcp/result.js +33 -0
- package/src/adapters/mcp/server.js +174 -0
- package/src/adapters/mcp/session.js +274 -0
- package/src/adapters/mcp/toolNotes.js +426 -0
- package/src/adapters/mcp/toolsets.js +106 -0
- package/src/commands/articles.js +285 -301
- package/src/commands/auth.js +204 -86
- package/src/commands/billing.js +102 -104
- package/src/commands/improvements.js +319 -211
- package/src/commands/index.js +22 -0
- package/src/commands/keywords.js +266 -249
- package/src/commands/marketplace/buyer.js +386 -0
- package/src/commands/marketplace/index.js +83 -0
- package/src/commands/marketplace/notifications.js +60 -0
- package/src/commands/marketplace/seller.js +595 -0
- package/src/commands/marketplace/shared.js +27 -0
- package/src/commands/products/backlinks.js +181 -0
- package/src/commands/products/core.js +149 -0
- package/src/commands/products/gsc.js +250 -0
- package/src/commands/products/index.js +174 -0
- package/src/commands/products/integrations.js +343 -0
- package/src/commands/products/linking.js +192 -0
- package/src/commands/products/shared.js +8 -0
- package/src/commands/registry.js +272 -0
- package/src/commands/subscription.js +20 -30
- package/src/commands/usage.js +17 -30
- package/src/core/config.js +243 -62
- package/src/core/constants.js +101 -0
- package/src/core/context.js +311 -0
- package/src/core/errors.js +39 -0
- package/src/core/execute.js +71 -0
- package/src/core/files.js +186 -0
- package/src/core/http.js +393 -0
- package/src/core/profileSelection.js +7 -0
- package/src/core/query.js +11 -0
- package/src/core/redact.js +27 -0
- package/src/core/schema.js +222 -0
- package/src/core/version.js +12 -0
- package/src/index.js +30 -58
- package/src/commands/marketplace.js +0 -740
- package/src/commands/products.js +0 -1185
- package/src/core/api.js +0 -82
- package/src/core/args.js +0 -144
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { IMPROVEMENTS_CANDIDATES_MAX_LIMIT, LIST_MAX_LIMIT, LIST_MIN_LIMIT, MIN_OFFSET } from '../core/constants.js';
|
|
2
|
+
import { BoolSerialize, bool, int, string, uuid } from '../core/schema.js';
|
|
3
|
+
import { BodyMode, CommandKind, Toolset, defineCommand, defineGroup } from './registry.js';
|
|
4
4
|
|
|
5
5
|
export const IMPROVEMENTS_HELP = `Usage:
|
|
6
6
|
outrank-cli improvements settings get <product-id>
|
|
@@ -46,232 +46,340 @@ Examples:
|
|
|
46
46
|
outrank-cli improvements executions push 00000000-0000-0000-0000-000000000000 --json '{"decisions":{"para-3":"rejected"}}'
|
|
47
47
|
`;
|
|
48
48
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
const SETTINGS_HELP = `Usage:
|
|
50
|
+
outrank-cli improvements settings get <product-id>
|
|
51
|
+
outrank-cli improvements settings update <product-id> --json <object>
|
|
52
|
+
`;
|
|
53
|
+
const CANDIDATES_HELP = `Usage:
|
|
54
|
+
outrank-cli improvements candidates list <product-id> [--type outsider|ctr_gap|declining|content_gap|thin_content] [--limit <n>] [--offset <n>]
|
|
55
|
+
outrank-cli improvements candidates brief <candidate-id> [--task <task-id>]
|
|
56
|
+
outrank-cli improvements candidates edit-brief <candidate-id> --json <object>
|
|
57
|
+
outrank-cli improvements candidates schedule <candidate-id> --scheduled-for <iso-date>
|
|
58
|
+
`;
|
|
59
|
+
const TASKS_HELP = `Usage:
|
|
60
|
+
outrank-cli improvements tasks list <product-id>
|
|
61
|
+
outrank-cli improvements tasks reschedule <task-id> --scheduled-for <iso-date>
|
|
62
|
+
outrank-cli improvements tasks cancel <task-id>
|
|
63
|
+
outrank-cli improvements tasks edit-brief <task-id> --json <object>
|
|
64
|
+
outrank-cli improvements tasks execute <task-id> [--improve-images true|false]
|
|
65
|
+
`;
|
|
66
|
+
const EXECUTIONS_HELP = `Usage:
|
|
67
|
+
outrank-cli improvements executions list <product-id> [--review-status awaiting_review|pushed|auto_pushed|rejected|all] [--limit <n>] [--offset <n>]
|
|
68
|
+
outrank-cli improvements executions get <execution-id>
|
|
69
|
+
outrank-cli improvements executions decisions <execution-id> --json <object>
|
|
70
|
+
outrank-cli improvements executions push <execution-id> [--json <object>]
|
|
71
|
+
`;
|
|
54
72
|
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
73
|
+
const TOOLSETS = [Toolset.IMPROVEMENTS];
|
|
74
|
+
const PRODUCT_CLI = { positionals: ['productId'] };
|
|
75
|
+
const CANDIDATE_CLI = { positionals: ['candidateId'] };
|
|
76
|
+
const TASK_CLI = { positionals: ['taskId'] };
|
|
77
|
+
const EXECUTION_CLI = { positionals: ['executionId'] };
|
|
78
|
+
const SCHEDULED_FOR_PLACEHOLDERS = { scheduledFor: '<iso-date>' };
|
|
79
|
+
const PRODUCT_SETTINGS_PATH = '/products/{productId}/improvements/settings';
|
|
80
|
+
const CANDIDATE_BRIEF_PATH = '/improvements/candidates/{candidateId}/brief';
|
|
81
|
+
const TASK_PATH = '/improvements/tasks/{taskId}';
|
|
82
|
+
const EXECUTION_PATH = '/improvements/executions/{executionId}';
|
|
83
|
+
const POLL_EXECUTIONS_LIST = 'improvements.executions.list';
|
|
84
|
+
const POLL_CANDIDATES_LIST = 'improvements.candidates.list';
|
|
85
|
+
const POLL_EXECUTIONS_GET = 'improvements.executions.get';
|
|
64
86
|
|
|
65
|
-
const
|
|
66
|
-
|
|
87
|
+
const SCHEDULED_FOR_REQUIRED = { guidance: 'Pass a date or ISO timestamp, e.g. `--scheduled-for 2026-06-01`.' };
|
|
88
|
+
const IMPROVE_IMAGES_GUIDANCE =
|
|
89
|
+
'Pass `--improve-images true` or `--improve-images false`, or omit it to use the default (images are regenerated).';
|
|
67
90
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
if (raw === undefined) return undefined;
|
|
71
|
-
if (raw === 'true') return true;
|
|
72
|
-
if (raw === 'false') return false;
|
|
73
|
-
throw invalidUsage('--improve-images must be true or false.', 'Pass `--improve-images true` or `--improve-images false`, or omit it to use the default (images are regenerated).');
|
|
74
|
-
};
|
|
91
|
+
const productInput = () => ({ productId: uuid().required() });
|
|
92
|
+
const productParams = (input) => ({ productId: input.productId });
|
|
75
93
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
94
|
+
const settingsGet = defineCommand({
|
|
95
|
+
id: 'improvements.settings.get',
|
|
96
|
+
summary: 'Get the article improvement settings of a product.',
|
|
97
|
+
kind: CommandKind.READ,
|
|
98
|
+
toolsets: TOOLSETS,
|
|
99
|
+
input: productInput(),
|
|
100
|
+
cli: PRODUCT_CLI,
|
|
101
|
+
run: (input, ctx) => ctx.http({ method: 'GET', path: PRODUCT_SETTINGS_PATH, pathParams: productParams(input) }),
|
|
102
|
+
});
|
|
83
103
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
const settingsUpdate = defineCommand({
|
|
105
|
+
id: 'improvements.settings.update',
|
|
106
|
+
summary: 'Update the article improvement settings of a product from a JSON body.',
|
|
107
|
+
kind: CommandKind.WRITE,
|
|
108
|
+
toolsets: TOOLSETS,
|
|
109
|
+
input: productInput(),
|
|
110
|
+
cli: PRODUCT_CLI,
|
|
111
|
+
body: BodyMode.JSON,
|
|
112
|
+
run: (input, ctx) =>
|
|
113
|
+
ctx.http({ method: 'PATCH', path: PRODUCT_SETTINGS_PATH, pathParams: productParams(input), body: input.body }),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const analyze = defineCommand({
|
|
117
|
+
id: 'improvements.analyze',
|
|
118
|
+
summary: 'Run improvement opportunity discovery for a product (multi-minute).',
|
|
119
|
+
kind: CommandKind.WRITE,
|
|
120
|
+
toolsets: TOOLSETS,
|
|
121
|
+
input: productInput(),
|
|
122
|
+
cli: PRODUCT_CLI,
|
|
123
|
+
longRunning: { pollTool: POLL_EXECUTIONS_LIST },
|
|
124
|
+
run: (input, ctx) =>
|
|
125
|
+
ctx.http({ method: 'POST', path: '/products/{productId}/improvements/analyze', pathParams: productParams(input) }),
|
|
126
|
+
});
|
|
92
127
|
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
128
|
+
const candidatesList = defineCommand({
|
|
129
|
+
id: 'improvements.candidates.list',
|
|
130
|
+
summary: 'List improvement candidates for a product.',
|
|
131
|
+
kind: CommandKind.READ,
|
|
132
|
+
toolsets: TOOLSETS,
|
|
133
|
+
input: {
|
|
134
|
+
...productInput(),
|
|
135
|
+
type: string(),
|
|
136
|
+
limit: int({ min: LIST_MIN_LIMIT, max: IMPROVEMENTS_CANDIDATES_MAX_LIMIT }),
|
|
137
|
+
offset: int({ min: MIN_OFFSET }),
|
|
138
|
+
},
|
|
139
|
+
cli: PRODUCT_CLI,
|
|
140
|
+
run: (input, ctx) =>
|
|
141
|
+
ctx.http({
|
|
97
142
|
method: 'GET',
|
|
98
|
-
path:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const body = await readJsonInput(parsed);
|
|
104
|
-
const response = await requestAgentApi(parsed, {
|
|
105
|
-
method: 'PATCH',
|
|
106
|
-
path: `/products/${productId}/improvements/settings`,
|
|
107
|
-
body,
|
|
108
|
-
});
|
|
109
|
-
return response.payload;
|
|
110
|
-
}
|
|
111
|
-
throw invalidUsage(`Unknown settings action: ${action ?? '(none)'}.`, 'Use: improvements settings get|update <product-id>.');
|
|
112
|
-
};
|
|
143
|
+
path: '/products/{productId}/improvements/candidates',
|
|
144
|
+
pathParams: productParams(input),
|
|
145
|
+
query: { type: input.type, limit: input.limit, offset: input.offset },
|
|
146
|
+
}),
|
|
147
|
+
});
|
|
113
148
|
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
if (action === 'brief') {
|
|
126
|
-
const candidateId = getRequiredPositional(parsed, 0, '<candidate-id>');
|
|
127
|
-
const taskId = getOption(parsed, 'task');
|
|
128
|
-
const response = await requestAgentApi(parsed, {
|
|
149
|
+
const candidatesBrief = defineCommand({
|
|
150
|
+
id: 'improvements.candidates.brief',
|
|
151
|
+
summary: 'Generate the improvement brief for a candidate (multi-minute).',
|
|
152
|
+
kind: CommandKind.WRITE,
|
|
153
|
+
toolsets: TOOLSETS,
|
|
154
|
+
input: { candidateId: uuid().required(), taskId: uuid() },
|
|
155
|
+
cli: { ...CANDIDATE_CLI, options: { task: 'taskId' } },
|
|
156
|
+
longRunning: { pollTool: POLL_CANDIDATES_LIST },
|
|
157
|
+
run: (input, ctx) =>
|
|
158
|
+
ctx.http({
|
|
129
159
|
method: 'POST',
|
|
130
|
-
path:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (action === 'edit-brief') {
|
|
136
|
-
const candidateId = getRequiredPositional(parsed, 0, '<candidate-id>');
|
|
137
|
-
const body = await readJsonInput(parsed);
|
|
138
|
-
const response = await requestAgentApi(parsed, {
|
|
139
|
-
method: 'PATCH',
|
|
140
|
-
path: `/improvements/candidates/${candidateId}/brief`,
|
|
141
|
-
body,
|
|
142
|
-
});
|
|
143
|
-
return response.payload;
|
|
144
|
-
}
|
|
145
|
-
if (action === 'schedule') {
|
|
146
|
-
const candidateId = getRequiredPositional(parsed, 0, '<candidate-id>');
|
|
147
|
-
const scheduledFor = requireScheduledFor(parsed);
|
|
148
|
-
const response = await requestAgentApi(parsed, {
|
|
149
|
-
method: 'POST',
|
|
150
|
-
path: `/improvements/candidates/${candidateId}/schedule`,
|
|
151
|
-
body: { scheduled_for: scheduledFor },
|
|
152
|
-
});
|
|
153
|
-
return response.payload;
|
|
154
|
-
}
|
|
155
|
-
throw invalidUsage(`Unknown candidates action: ${action ?? '(none)'}.`, 'Use: improvements candidates list|brief|edit-brief|schedule.');
|
|
156
|
-
};
|
|
160
|
+
path: CANDIDATE_BRIEF_PATH,
|
|
161
|
+
pathParams: { candidateId: input.candidateId },
|
|
162
|
+
body: input.taskId ? { task_id: input.taskId } : {},
|
|
163
|
+
}),
|
|
164
|
+
});
|
|
157
165
|
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const taskId = getRequiredPositional(parsed, 0, '<task-id>');
|
|
169
|
-
const scheduledFor = requireScheduledFor(parsed);
|
|
170
|
-
const response = await requestAgentApi(parsed, {
|
|
166
|
+
const candidatesEditBrief = defineCommand({
|
|
167
|
+
id: 'improvements.candidates.edit-brief',
|
|
168
|
+
summary: 'Edit the improvement brief of a candidate from a JSON body.',
|
|
169
|
+
kind: CommandKind.WRITE,
|
|
170
|
+
toolsets: TOOLSETS,
|
|
171
|
+
input: { candidateId: uuid().required() },
|
|
172
|
+
cli: CANDIDATE_CLI,
|
|
173
|
+
body: BodyMode.JSON,
|
|
174
|
+
run: (input, ctx) =>
|
|
175
|
+
ctx.http({
|
|
171
176
|
method: 'PATCH',
|
|
172
|
-
path:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const body = await readJsonInput(parsed);
|
|
188
|
-
const response = await requestAgentApi(parsed, {
|
|
189
|
-
method: 'PATCH',
|
|
190
|
-
path: `/improvements/tasks/${taskId}/brief`,
|
|
191
|
-
body,
|
|
192
|
-
});
|
|
193
|
-
return response.payload;
|
|
194
|
-
}
|
|
195
|
-
if (action === 'execute') {
|
|
196
|
-
const taskId = getRequiredPositional(parsed, 0, '<task-id>');
|
|
197
|
-
const improveImages = parseImproveImages(parsed);
|
|
198
|
-
const response = await requestAgentApi(parsed, {
|
|
177
|
+
path: CANDIDATE_BRIEF_PATH,
|
|
178
|
+
pathParams: { candidateId: input.candidateId },
|
|
179
|
+
body: input.body,
|
|
180
|
+
}),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const candidatesSchedule = defineCommand({
|
|
184
|
+
id: 'improvements.candidates.schedule',
|
|
185
|
+
summary: 'Schedule an improvement task for a candidate.',
|
|
186
|
+
kind: CommandKind.WRITE,
|
|
187
|
+
toolsets: TOOLSETS,
|
|
188
|
+
input: { candidateId: uuid().required(), scheduledFor: string().required(SCHEDULED_FOR_REQUIRED) },
|
|
189
|
+
cli: { ...CANDIDATE_CLI, placeholders: SCHEDULED_FOR_PLACEHOLDERS },
|
|
190
|
+
run: (input, ctx) =>
|
|
191
|
+
ctx.http({
|
|
199
192
|
method: 'POST',
|
|
200
|
-
path:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
throw invalidUsage(`Unknown tasks action: ${action ?? '(none)'}.`, 'Use: improvements tasks list|reschedule|cancel|edit-brief|execute.');
|
|
206
|
-
};
|
|
193
|
+
path: '/improvements/candidates/{candidateId}/schedule',
|
|
194
|
+
pathParams: { candidateId: input.candidateId },
|
|
195
|
+
body: { scheduled_for: input.scheduledFor },
|
|
196
|
+
}),
|
|
197
|
+
});
|
|
207
198
|
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const executionId = getRequiredPositional(parsed, 0, '<execution-id>');
|
|
229
|
-
const body = await readJsonInput(parsed);
|
|
230
|
-
const response = await requestAgentApi(parsed, {
|
|
199
|
+
const tasksList = defineCommand({
|
|
200
|
+
id: 'improvements.tasks.list',
|
|
201
|
+
summary: 'List scheduled improvement tasks for a product.',
|
|
202
|
+
kind: CommandKind.READ,
|
|
203
|
+
toolsets: TOOLSETS,
|
|
204
|
+
input: productInput(),
|
|
205
|
+
cli: PRODUCT_CLI,
|
|
206
|
+
run: (input, ctx) =>
|
|
207
|
+
ctx.http({ method: 'GET', path: '/products/{productId}/improvements/tasks', pathParams: productParams(input) }),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const tasksReschedule = defineCommand({
|
|
211
|
+
id: 'improvements.tasks.reschedule',
|
|
212
|
+
summary: 'Reschedule an improvement task.',
|
|
213
|
+
kind: CommandKind.WRITE,
|
|
214
|
+
toolsets: TOOLSETS,
|
|
215
|
+
input: { taskId: uuid().required(), scheduledFor: string().required(SCHEDULED_FOR_REQUIRED) },
|
|
216
|
+
cli: { ...TASK_CLI, placeholders: SCHEDULED_FOR_PLACEHOLDERS },
|
|
217
|
+
run: (input, ctx) =>
|
|
218
|
+
ctx.http({
|
|
231
219
|
method: 'PATCH',
|
|
232
|
-
path:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
220
|
+
path: TASK_PATH,
|
|
221
|
+
pathParams: { taskId: input.taskId },
|
|
222
|
+
body: { scheduled_for: input.scheduledFor },
|
|
223
|
+
}),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const tasksCancel = defineCommand({
|
|
227
|
+
id: 'improvements.tasks.cancel',
|
|
228
|
+
summary: 'Cancel an improvement task.',
|
|
229
|
+
kind: CommandKind.DESTRUCTIVE,
|
|
230
|
+
toolsets: TOOLSETS,
|
|
231
|
+
input: { taskId: uuid().required() },
|
|
232
|
+
cli: TASK_CLI,
|
|
233
|
+
run: (input, ctx) => ctx.http({ method: 'DELETE', path: TASK_PATH, pathParams: { taskId: input.taskId } }),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const tasksEditBrief = defineCommand({
|
|
237
|
+
id: 'improvements.tasks.edit-brief',
|
|
238
|
+
summary: 'Edit the brief of an improvement task from a JSON body.',
|
|
239
|
+
kind: CommandKind.WRITE,
|
|
240
|
+
toolsets: TOOLSETS,
|
|
241
|
+
input: { taskId: uuid().required() },
|
|
242
|
+
cli: TASK_CLI,
|
|
243
|
+
body: BodyMode.JSON,
|
|
244
|
+
run: (input, ctx) =>
|
|
245
|
+
ctx.http({ method: 'PATCH', path: `${TASK_PATH}/brief`, pathParams: { taskId: input.taskId }, body: input.body }),
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const tasksExecute = defineCommand({
|
|
249
|
+
id: 'improvements.tasks.execute',
|
|
250
|
+
summary: 'Execute an improvement task now (multi-minute).',
|
|
251
|
+
kind: CommandKind.WRITE,
|
|
252
|
+
toolsets: TOOLSETS,
|
|
253
|
+
input: {
|
|
254
|
+
taskId: uuid().required(),
|
|
255
|
+
improveImages: bool({ serialize: BoolSerialize.ALWAYS }).guidance(IMPROVE_IMAGES_GUIDANCE),
|
|
256
|
+
},
|
|
257
|
+
cli: { ...TASK_CLI, options: { 'improve-images': { field: 'improveImages', takesValue: true } } },
|
|
258
|
+
longRunning: { pollTool: POLL_EXECUTIONS_GET },
|
|
259
|
+
run: (input, ctx) =>
|
|
260
|
+
ctx.http({
|
|
241
261
|
method: 'POST',
|
|
242
|
-
path:
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
throw invalidUsage(`Unknown executions action: ${action ?? '(none)'}.`, 'Use: improvements executions list|get|decisions|push.');
|
|
248
|
-
};
|
|
262
|
+
path: `${TASK_PATH}/execute`,
|
|
263
|
+
pathParams: { taskId: input.taskId },
|
|
264
|
+
body: input.improveImages === undefined ? {} : { improve_images: input.improveImages },
|
|
265
|
+
}),
|
|
266
|
+
});
|
|
249
267
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
268
|
+
const executionsList = defineCommand({
|
|
269
|
+
id: 'improvements.executions.list',
|
|
270
|
+
summary: 'List improvement executions for a product.',
|
|
271
|
+
kind: CommandKind.READ,
|
|
272
|
+
toolsets: TOOLSETS,
|
|
273
|
+
input: {
|
|
274
|
+
...productInput(),
|
|
275
|
+
reviewStatus: string(),
|
|
276
|
+
limit: int({ min: LIST_MIN_LIMIT, max: LIST_MAX_LIMIT }),
|
|
277
|
+
offset: int({ min: MIN_OFFSET }),
|
|
278
|
+
},
|
|
279
|
+
cli: PRODUCT_CLI,
|
|
280
|
+
run: (input, ctx) =>
|
|
281
|
+
ctx.http({
|
|
282
|
+
method: 'GET',
|
|
283
|
+
path: '/products/{productId}/improvements/executions',
|
|
284
|
+
pathParams: productParams(input),
|
|
285
|
+
query: { review_status: input.reviewStatus, limit: input.limit, offset: input.offset },
|
|
286
|
+
}),
|
|
287
|
+
});
|
|
254
288
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
289
|
+
const executionsGet = defineCommand({
|
|
290
|
+
id: 'improvements.executions.get',
|
|
291
|
+
summary: 'Get one improvement execution with its proposed changes.',
|
|
292
|
+
kind: CommandKind.READ,
|
|
293
|
+
toolsets: TOOLSETS,
|
|
294
|
+
input: { executionId: uuid().required() },
|
|
295
|
+
cli: EXECUTION_CLI,
|
|
296
|
+
run: (input, ctx) =>
|
|
297
|
+
ctx.http({ method: 'GET', path: EXECUTION_PATH, pathParams: { executionId: input.executionId } }),
|
|
298
|
+
});
|
|
263
299
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
300
|
+
const executionsDecisions = defineCommand({
|
|
301
|
+
id: 'improvements.executions.decisions',
|
|
302
|
+
summary: 'Record review decisions for an execution from a JSON body.',
|
|
303
|
+
kind: CommandKind.WRITE,
|
|
304
|
+
toolsets: TOOLSETS,
|
|
305
|
+
input: { executionId: uuid().required() },
|
|
306
|
+
cli: EXECUTION_CLI,
|
|
307
|
+
body: BodyMode.JSON,
|
|
308
|
+
run: (input, ctx) =>
|
|
309
|
+
ctx.http({
|
|
310
|
+
method: 'PATCH',
|
|
311
|
+
path: `${EXECUTION_PATH}/decisions`,
|
|
312
|
+
pathParams: { executionId: input.executionId },
|
|
313
|
+
body: input.body,
|
|
314
|
+
}),
|
|
315
|
+
});
|
|
267
316
|
|
|
268
|
-
|
|
269
|
-
|
|
317
|
+
const executionsPush = defineCommand({
|
|
318
|
+
id: 'improvements.executions.push',
|
|
319
|
+
summary: 'Push an execution to the CMS, optionally with decisions in a JSON body.',
|
|
320
|
+
kind: CommandKind.WRITE,
|
|
321
|
+
toolsets: TOOLSETS,
|
|
322
|
+
input: { executionId: uuid().required() },
|
|
323
|
+
cli: EXECUTION_CLI,
|
|
324
|
+
body: BodyMode.OPTIONAL_JSON_OR_EMPTY_OBJECT,
|
|
325
|
+
longRunning: { pollTool: POLL_EXECUTIONS_GET },
|
|
326
|
+
run: (input, ctx) =>
|
|
327
|
+
ctx.http({
|
|
328
|
+
method: 'POST',
|
|
329
|
+
path: `${EXECUTION_PATH}/push`,
|
|
330
|
+
pathParams: { executionId: input.executionId },
|
|
331
|
+
body: input.body,
|
|
332
|
+
}),
|
|
333
|
+
});
|
|
270
334
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
335
|
+
const subGroup = ({ id, usage, actions, children }) =>
|
|
336
|
+
defineGroup({
|
|
337
|
+
id,
|
|
338
|
+
help: { usage, guidance: `Use: improvements ${id.slice(id.indexOf('.') + 1)} ${actions}.` },
|
|
339
|
+
unknown: (word) => ({
|
|
340
|
+
message: `Unknown ${id.slice(id.indexOf('.') + 1)} action: ${word}.`,
|
|
341
|
+
guidance: `Use: improvements ${id.slice(id.indexOf('.') + 1)} ${actions}.`,
|
|
342
|
+
}),
|
|
343
|
+
children,
|
|
344
|
+
});
|
|
275
345
|
|
|
276
|
-
|
|
277
|
-
|
|
346
|
+
export const improvementsGroup = defineGroup({
|
|
347
|
+
id: 'improvements',
|
|
348
|
+
help: {
|
|
349
|
+
usage: IMPROVEMENTS_HELP,
|
|
350
|
+
guidance:
|
|
351
|
+
'Choose a sub-noun: settings, analyze, candidates, tasks, or executions. The typical flow is analyze -> ' +
|
|
352
|
+
'candidates brief -> candidates schedule -> tasks execute -> executions push.',
|
|
353
|
+
},
|
|
354
|
+
unknown: (word) => ({
|
|
355
|
+
message: `Unknown improvements sub-noun: ${word}.`,
|
|
356
|
+
guidance: 'Run `outrank-cli improvements --help` to see available improvement commands.',
|
|
357
|
+
}),
|
|
358
|
+
children: [
|
|
359
|
+
subGroup({
|
|
360
|
+
id: 'improvements.settings',
|
|
361
|
+
usage: SETTINGS_HELP,
|
|
362
|
+
actions: 'get|update <product-id>',
|
|
363
|
+
children: [settingsGet, settingsUpdate],
|
|
364
|
+
}),
|
|
365
|
+
analyze,
|
|
366
|
+
subGroup({
|
|
367
|
+
id: 'improvements.candidates',
|
|
368
|
+
usage: CANDIDATES_HELP,
|
|
369
|
+
actions: 'list|brief|edit-brief|schedule',
|
|
370
|
+
children: [candidatesList, candidatesBrief, candidatesEditBrief, candidatesSchedule],
|
|
371
|
+
}),
|
|
372
|
+
subGroup({
|
|
373
|
+
id: 'improvements.tasks',
|
|
374
|
+
usage: TASKS_HELP,
|
|
375
|
+
actions: 'list|reschedule|cancel|edit-brief|execute',
|
|
376
|
+
children: [tasksList, tasksReschedule, tasksCancel, tasksEditBrief, tasksExecute],
|
|
377
|
+
}),
|
|
378
|
+
subGroup({
|
|
379
|
+
id: 'improvements.executions',
|
|
380
|
+
usage: EXECUTIONS_HELP,
|
|
381
|
+
actions: 'list|get|decisions|push',
|
|
382
|
+
children: [executionsList, executionsGet, executionsDecisions, executionsPush],
|
|
383
|
+
}),
|
|
384
|
+
],
|
|
385
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { articlesGroup } from './articles.js';
|
|
2
|
+
import { authGroup } from './auth.js';
|
|
3
|
+
import { billingGroup } from './billing.js';
|
|
4
|
+
import { improvementsGroup } from './improvements.js';
|
|
5
|
+
import { keywordsGroup } from './keywords.js';
|
|
6
|
+
import { marketplaceGroup } from './marketplace/index.js';
|
|
7
|
+
import { productsGroup } from './products/index.js';
|
|
8
|
+
import { createRegistry } from './registry.js';
|
|
9
|
+
import { subscriptionGroup } from './subscription.js';
|
|
10
|
+
import { usageGroup } from './usage.js';
|
|
11
|
+
|
|
12
|
+
export const registry = createRegistry([
|
|
13
|
+
authGroup,
|
|
14
|
+
usageGroup,
|
|
15
|
+
subscriptionGroup,
|
|
16
|
+
billingGroup,
|
|
17
|
+
keywordsGroup,
|
|
18
|
+
articlesGroup,
|
|
19
|
+
improvementsGroup,
|
|
20
|
+
productsGroup,
|
|
21
|
+
marketplaceGroup,
|
|
22
|
+
]);
|