@rolino/cli 0.6.0 → 0.7.1
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/CHANGELOG.md +29 -0
- package/README.md +43 -21
- package/dist/bin.cjs +213 -47
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-3WBZCTM5.js → chunk-KSPZKKBG.js} +198 -31
- package/dist/chunk-KSPZKKBG.js.map +1 -0
- package/dist/index.cjs +213 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -10
- package/dist/index.d.ts +21 -10
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-3WBZCTM5.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -123,12 +123,18 @@ function removeExistingCodexEntry(source, newline) {
|
|
|
123
123
|
return kept.join(newline).trimEnd();
|
|
124
124
|
}
|
|
125
125
|
function codexBlock(server, newline) {
|
|
126
|
+
const configuration = server.transport === "http" ? [
|
|
127
|
+
`url = ${tomlString(server.url)}`,
|
|
128
|
+
`auth = ${tomlString(server.auth)}`
|
|
129
|
+
] : [
|
|
130
|
+
`command = ${tomlString(server.command)}`,
|
|
131
|
+
`args = [${server.args.map(tomlString).join(", ")}]`,
|
|
132
|
+
`env = { ROLINO_URL = ${tomlString(server.env.ROLINO_URL)} }`
|
|
133
|
+
];
|
|
126
134
|
return [
|
|
127
135
|
CODEX_BEGIN,
|
|
128
136
|
"[mcp_servers.rolino]",
|
|
129
|
-
|
|
130
|
-
`args = [${server.args.map(tomlString).join(", ")}]`,
|
|
131
|
-
`env = { ROLINO_URL = ${tomlString(server.env.ROLINO_URL)} }`,
|
|
137
|
+
...configuration,
|
|
132
138
|
CODEX_END
|
|
133
139
|
].join(newline);
|
|
134
140
|
}
|
|
@@ -137,13 +143,12 @@ function updateCodexConfig(source, server) {
|
|
|
137
143
|
const block = codexBlock(server, newline);
|
|
138
144
|
const begin = source.indexOf(CODEX_BEGIN);
|
|
139
145
|
const end = source.indexOf(CODEX_END);
|
|
140
|
-
if (begin === -1 !== (end === -1) || begin !== -1 && end < begin) {
|
|
141
|
-
throw new TypeError("Codex config contains an incomplete Rolino-managed block.");
|
|
142
|
-
}
|
|
143
146
|
let unmanagedSource = source;
|
|
144
|
-
if (begin !== -1) {
|
|
147
|
+
if (begin !== -1 && end !== -1 && end > begin) {
|
|
145
148
|
const after = end + CODEX_END.length;
|
|
146
149
|
unmanagedSource = `${source.slice(0, begin)}${source.slice(after)}`;
|
|
150
|
+
} else if (begin !== -1 || end !== -1) {
|
|
151
|
+
unmanagedSource = source.split(/\r?\n/).filter((line) => line.trim() !== CODEX_BEGIN && line.trim() !== CODEX_END).join(newline);
|
|
147
152
|
}
|
|
148
153
|
const withoutRolino = removeExistingCodexEntry(unmanagedSource, newline);
|
|
149
154
|
return `${withoutRolino ? `${withoutRolino}${newline}${newline}` : ""}${block}${newline}`;
|
|
@@ -168,7 +173,12 @@ function updateClaudeProjectConfig(source, server) {
|
|
|
168
173
|
...parsed,
|
|
169
174
|
mcpServers: {
|
|
170
175
|
...currentServers,
|
|
171
|
-
rolino: { type: "
|
|
176
|
+
rolino: server.transport === "http" ? { type: "http", url: server.url } : {
|
|
177
|
+
type: "stdio",
|
|
178
|
+
command: server.command,
|
|
179
|
+
args: server.args,
|
|
180
|
+
env: server.env
|
|
181
|
+
}
|
|
172
182
|
}
|
|
173
183
|
}, null, 2)}
|
|
174
184
|
`;
|
|
@@ -200,6 +210,7 @@ async function setupCodex(options, server) {
|
|
|
200
210
|
backupPath,
|
|
201
211
|
changed,
|
|
202
212
|
dryRun: options.dryRun ?? false,
|
|
213
|
+
transport: server.transport,
|
|
203
214
|
server
|
|
204
215
|
};
|
|
205
216
|
}
|
|
@@ -220,6 +231,7 @@ async function setupClaudeCode(options, server) {
|
|
|
220
231
|
backupPath,
|
|
221
232
|
changed,
|
|
222
233
|
dryRun: options.dryRun ?? false,
|
|
234
|
+
transport: server.transport,
|
|
223
235
|
server
|
|
224
236
|
};
|
|
225
237
|
}
|
|
@@ -232,6 +244,7 @@ async function setupClaudeCode(options, server) {
|
|
|
232
244
|
backupPath: null,
|
|
233
245
|
changed: true,
|
|
234
246
|
dryRun: true,
|
|
247
|
+
transport: server.transport,
|
|
235
248
|
server
|
|
236
249
|
};
|
|
237
250
|
}
|
|
@@ -245,7 +258,12 @@ async function setupClaudeCode(options, server) {
|
|
|
245
258
|
"mcp",
|
|
246
259
|
"add-json",
|
|
247
260
|
"rolino",
|
|
248
|
-
JSON.stringify({ type: "
|
|
261
|
+
JSON.stringify(server.transport === "http" ? { type: "http", url: server.url } : {
|
|
262
|
+
type: "stdio",
|
|
263
|
+
command: server.command,
|
|
264
|
+
args: server.args,
|
|
265
|
+
env: server.env
|
|
266
|
+
}),
|
|
249
267
|
"--scope",
|
|
250
268
|
"user"
|
|
251
269
|
], options);
|
|
@@ -261,14 +279,51 @@ async function setupClaudeCode(options, server) {
|
|
|
261
279
|
backupPath: null,
|
|
262
280
|
changed: true,
|
|
263
281
|
dryRun: false,
|
|
282
|
+
transport: server.transport,
|
|
264
283
|
server
|
|
265
284
|
};
|
|
266
285
|
}
|
|
286
|
+
function remoteMcpUrl(baseUrl) {
|
|
287
|
+
return new URL("mcp", `${baseUrl.replace(/\/$/, "")}/`).toString();
|
|
288
|
+
}
|
|
289
|
+
async function advertisedRemoteMcp(options) {
|
|
290
|
+
const fetchImplementation = options.fetch ?? globalThis.fetch;
|
|
291
|
+
try {
|
|
292
|
+
const response = await fetchImplementation(
|
|
293
|
+
new URL("api/v1/meta", `${options.baseUrl.replace(/\/$/, "")}/`),
|
|
294
|
+
{
|
|
295
|
+
headers: { accept: "application/json" },
|
|
296
|
+
signal: AbortSignal.timeout(5e3)
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
if (!response.ok) return false;
|
|
300
|
+
const payload = await response.json();
|
|
301
|
+
return payload.data?.mcp?.streamableHttp === true;
|
|
302
|
+
} catch {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async function resolveTransport(options) {
|
|
307
|
+
const requested = options.transport ?? "stdio";
|
|
308
|
+
if (requested === "stdio") return "stdio";
|
|
309
|
+
if (await advertisedRemoteMcp(options)) return "http";
|
|
310
|
+
if (requested === "http") {
|
|
311
|
+
throw new TypeError(
|
|
312
|
+
"This Rolino instance does not advertise Streamable HTTP MCP. Use --transport stdio, or enable and verify remote MCP on the server."
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
return "stdio";
|
|
316
|
+
}
|
|
267
317
|
async function setupMcp(options) {
|
|
268
|
-
const
|
|
269
|
-
const server = {
|
|
318
|
+
const transport = await resolveTransport(options);
|
|
319
|
+
const server = transport === "http" ? {
|
|
320
|
+
transport: "http",
|
|
321
|
+
url: remoteMcpUrl(options.baseUrl),
|
|
322
|
+
auth: "oauth"
|
|
323
|
+
} : {
|
|
324
|
+
transport: "stdio",
|
|
270
325
|
command: options.nodePath,
|
|
271
|
-
args: [
|
|
326
|
+
args: [await resolveServerPath(options)],
|
|
272
327
|
env: { ROLINO_URL: options.baseUrl }
|
|
273
328
|
};
|
|
274
329
|
return options.client === "codex" ? setupCodex(options, server) : setupClaudeCode(options, server);
|
|
@@ -285,7 +340,7 @@ import { Command, CommanderError, InvalidArgumentError } from "commander";
|
|
|
285
340
|
// package.json
|
|
286
341
|
var package_default = {
|
|
287
342
|
name: "@rolino/cli",
|
|
288
|
-
version: "0.
|
|
343
|
+
version: "0.7.1",
|
|
289
344
|
description: "Agent-friendly command-line interface for Rolino",
|
|
290
345
|
type: "module",
|
|
291
346
|
license: "MIT",
|
|
@@ -342,9 +397,9 @@ var package_default = {
|
|
|
342
397
|
dev: "tsx src/bin.ts"
|
|
343
398
|
},
|
|
344
399
|
dependencies: {
|
|
345
|
-
"@rolino/contracts": "0.
|
|
346
|
-
"@rolino/local-auth": "0.
|
|
347
|
-
"@rolino/sdk": "0.
|
|
400
|
+
"@rolino/contracts": "0.7.1",
|
|
401
|
+
"@rolino/local-auth": "0.7.1",
|
|
402
|
+
"@rolino/sdk": "0.7.1",
|
|
348
403
|
commander: "^15.0.0",
|
|
349
404
|
open: "^11.0.0"
|
|
350
405
|
},
|
|
@@ -360,6 +415,7 @@ var package_default = {
|
|
|
360
415
|
import {
|
|
361
416
|
PostStatusSchema,
|
|
362
417
|
AgentBlogDraftUpdateSchema,
|
|
418
|
+
BacklinkProspectStageSchema,
|
|
363
419
|
ProjectCreateInputSchema,
|
|
364
420
|
ProjectTypeSchema,
|
|
365
421
|
ProviderDeliveryOptionsProviderSchema,
|
|
@@ -381,6 +437,7 @@ import {
|
|
|
381
437
|
// src/browser-login.ts
|
|
382
438
|
import { createHash, randomBytes, timingSafeEqual } from "crypto";
|
|
383
439
|
import { createServer } from "http";
|
|
440
|
+
import { AGENT_CAPABILITIES } from "@rolino/contracts";
|
|
384
441
|
import {
|
|
385
442
|
oauthConfiguration
|
|
386
443
|
} from "@rolino/local-auth";
|
|
@@ -388,13 +445,9 @@ import open from "open";
|
|
|
388
445
|
var OAUTH_CALLBACK_PORT = 48391;
|
|
389
446
|
var OAUTH_CALLBACK_PATH = "/oauth/callback";
|
|
390
447
|
var OAUTH_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
391
|
-
var
|
|
448
|
+
var AUTHORIZATION_REQUEST_SCOPES = [
|
|
392
449
|
"offline_access",
|
|
393
|
-
|
|
394
|
-
"projects:read",
|
|
395
|
-
"posts:read",
|
|
396
|
-
"integrations:read",
|
|
397
|
-
"calendar:read"
|
|
450
|
+
...AGENT_CAPABILITIES
|
|
398
451
|
];
|
|
399
452
|
function escapeHtml(value) {
|
|
400
453
|
return value.replace(/[&<>"']/g, (character) => ({
|
|
@@ -434,7 +487,7 @@ function createBrowserAuthorizationRequest(baseUrl) {
|
|
|
434
487
|
url.searchParams.set("response_type", "code");
|
|
435
488
|
url.searchParams.set("client_id", configuration.clientId);
|
|
436
489
|
url.searchParams.set("redirect_uri", redirectUri);
|
|
437
|
-
url.searchParams.set("scope",
|
|
490
|
+
url.searchParams.set("scope", AUTHORIZATION_REQUEST_SCOPES.join(" "));
|
|
438
491
|
url.searchParams.set("resource", configuration.resource);
|
|
439
492
|
url.searchParams.set("state", state);
|
|
440
493
|
url.searchParams.set("code_challenge", codeChallenge);
|
|
@@ -473,7 +526,7 @@ async function exchangeAuthorizationCode(options) {
|
|
|
473
526
|
accessTokenExpiresAt: new Date(Date.now() + expiresIn * 1e3).toISOString(),
|
|
474
527
|
refreshToken: payload.refresh_token,
|
|
475
528
|
refreshTokenExpiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1e3).toISOString(),
|
|
476
|
-
scopes: typeof payload.scope === "string" ? payload.scope.split(/\s+/).filter(Boolean) : [...
|
|
529
|
+
scopes: typeof payload.scope === "string" ? payload.scope.split(/\s+/).filter(Boolean) : [...AUTHORIZATION_REQUEST_SCOPES]
|
|
477
530
|
};
|
|
478
531
|
}
|
|
479
532
|
async function loginWithBrowser(options) {
|
|
@@ -943,6 +996,10 @@ function mcpScope(value) {
|
|
|
943
996
|
if (value === "user" || value === "project") return value;
|
|
944
997
|
throw new InvalidArgumentError("MCP setup scope must be user or project.");
|
|
945
998
|
}
|
|
999
|
+
function mcpTransport(value) {
|
|
1000
|
+
if (value === "auto" || value === "http" || value === "stdio") return value;
|
|
1001
|
+
throw new InvalidArgumentError("MCP transport must be auto, http, or stdio.");
|
|
1002
|
+
}
|
|
946
1003
|
function isoDateTime(value) {
|
|
947
1004
|
const date = new Date(value);
|
|
948
1005
|
if (Number.isNaN(date.getTime())) {
|
|
@@ -1003,13 +1060,21 @@ function requireBlogExecutionConsent(options) {
|
|
|
1003
1060
|
throw new TypeError("This Blog execute command requires explicit consent. Review the confirmed operation and pass --yes.");
|
|
1004
1061
|
}
|
|
1005
1062
|
function formatMcpSetupPreview(result) {
|
|
1063
|
+
const connection = result.server.transport === "http" ? [
|
|
1064
|
+
`Transport: Streamable HTTP`,
|
|
1065
|
+
`Endpoint: ${result.server.url}`,
|
|
1066
|
+
"Authentication: OAuth in the MCP client"
|
|
1067
|
+
] : [
|
|
1068
|
+
"Transport: local STDIO",
|
|
1069
|
+
`Command: ${result.server.command}`,
|
|
1070
|
+
`Arguments: ${result.server.args.join(" ")}`,
|
|
1071
|
+
`Rolino URL: ${result.server.env.ROLINO_URL}`
|
|
1072
|
+
];
|
|
1006
1073
|
return [
|
|
1007
1074
|
`Client: ${result.client === "codex" ? "Codex" : "Claude Code"}`,
|
|
1008
1075
|
`Scope: ${result.scope}`,
|
|
1009
1076
|
`Target: ${result.target}`,
|
|
1010
|
-
|
|
1011
|
-
`Arguments: ${result.server.args.join(" ")}`,
|
|
1012
|
-
`Rolino URL: ${result.server.env.ROLINO_URL}`,
|
|
1077
|
+
...connection,
|
|
1013
1078
|
"No token will be written to MCP configuration."
|
|
1014
1079
|
].join("\n");
|
|
1015
1080
|
}
|
|
@@ -1472,7 +1537,7 @@ async function runCli(argv = process.argv, overrides = {}) {
|
|
|
1472
1537
|
});
|
|
1473
1538
|
});
|
|
1474
1539
|
const setup = program.command("setup").description("Configure local agent tools for Rolino");
|
|
1475
|
-
setup.command("mcp").description("Configure
|
|
1540
|
+
setup.command("mcp").description("Configure Rolino MCP with Streamable HTTP or local STDIO").requiredOption("--client <client>", "codex or claude-code", mcpClient).option("--scope <scope>", "user or project", mcpScope, "user").option("--transport <transport>", "auto, http, or stdio", mcpTransport, "auto").option("--server-path <path>", "absolute or working-directory-relative MCP server path").option("--dry-run", "show the intended configuration without writing it").option("--yes", "apply without an interactive confirmation").option("--force", "replace an existing Claude Code user-scoped Rolino server").action(async (local) => {
|
|
1476
1541
|
const global = program.opts();
|
|
1477
1542
|
commandExitCode = await execute({
|
|
1478
1543
|
command: "setup mcp",
|
|
@@ -1485,7 +1550,8 @@ async function runCli(argv = process.argv, overrides = {}) {
|
|
|
1485
1550
|
cwd: runtime.cwd,
|
|
1486
1551
|
env: runtime.env,
|
|
1487
1552
|
nodePath: runtime.nodePath,
|
|
1488
|
-
cliEntryPath: runtime.cliEntryPath
|
|
1553
|
+
cliEntryPath: runtime.cliEntryPath,
|
|
1554
|
+
fetch: runtime.fetch
|
|
1489
1555
|
};
|
|
1490
1556
|
const preview = await setupMcp({ ...setupOptions, dryRun: true });
|
|
1491
1557
|
let result = preview;
|
|
@@ -1512,11 +1578,12 @@ async function runCli(argv = process.argv, overrides = {}) {
|
|
|
1512
1578
|
`${state} Rolino MCP for ${clientLabel}.`,
|
|
1513
1579
|
`Scope: ${result.scope}`,
|
|
1514
1580
|
`Target: ${result.target}`,
|
|
1581
|
+
`Transport: ${result.transport === "http" ? "Streamable HTTP" : "local STDIO"}`,
|
|
1515
1582
|
...result.backupPath && !result.dryRun ? [`Backup: ${result.backupPath}`] : [],
|
|
1516
1583
|
`Rolino URL: ${client.baseUrl}`,
|
|
1517
1584
|
"No token was written to MCP configuration."
|
|
1518
1585
|
].join("\n"),
|
|
1519
|
-
result.client === "codex" ? ["codex mcp
|
|
1586
|
+
result.client === "codex" ? result.transport === "http" ? ["codex mcp login rolino", "codex mcp list"] : ["rolino auth login", "codex mcp list"] : result.transport === "http" ? ["claude mcp get rolino", "Complete OAuth when Claude prompts you"] : ["rolino auth login", "claude mcp get rolino"]
|
|
1520
1587
|
);
|
|
1521
1588
|
}
|
|
1522
1589
|
});
|
|
@@ -2255,6 +2322,106 @@ Revision: ${local.revision}` });
|
|
|
2255
2322
|
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2256
2323
|
} });
|
|
2257
2324
|
});
|
|
2325
|
+
const backlinks = program.command("backlinks").description("Review backlink prospects and public contact drafts. Rolino never sends email.");
|
|
2326
|
+
const backlinkTargets = backlinks.command("targets");
|
|
2327
|
+
backlinkTargets.command("list").requiredOption("--project <project-id>").action(async (local) => {
|
|
2328
|
+
const global = program.opts();
|
|
2329
|
+
commandExitCode = await execute({ command: "backlinks targets list", global, runtime, async action(context, client) {
|
|
2330
|
+
const data = await client.backlinks.targets.list(local.project, { requestId: context.requestId });
|
|
2331
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2332
|
+
} });
|
|
2333
|
+
});
|
|
2334
|
+
backlinkTargets.command("add").requiredOption("--project <project-id>").requiredOption("--url <url>").requiredOption("--label <label>").action(async (local) => {
|
|
2335
|
+
const global = program.opts();
|
|
2336
|
+
commandExitCode = await execute({ command: "backlinks targets add", global, runtime, async action(context, client) {
|
|
2337
|
+
const data = await client.backlinks.targets.add(local.project, { url: local.url, label: local.label }, context.requestId, { requestId: context.requestId });
|
|
2338
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2339
|
+
} });
|
|
2340
|
+
});
|
|
2341
|
+
backlinks.command("discover").requiredOption("--project <project-id>").option("--limit <number>", "maximum saved prospects", Number, 20).option("--idempotency-key <key>").action(async (local) => {
|
|
2342
|
+
const global = program.opts();
|
|
2343
|
+
commandExitCode = await execute({ command: "backlinks discover", global, runtime, async action(context, client) {
|
|
2344
|
+
const data = await client.backlinks.discoveries.start(local.project, { limit: local.limit }, local.idempotencyKey ?? context.requestId, { requestId: context.requestId });
|
|
2345
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2346
|
+
} });
|
|
2347
|
+
});
|
|
2348
|
+
const backlinkRuns = backlinks.command("runs");
|
|
2349
|
+
backlinkRuns.command("get").requiredOption("--project <project-id>").requiredOption("--run <run-id>").action(async (local) => {
|
|
2350
|
+
const global = program.opts();
|
|
2351
|
+
commandExitCode = await execute({ command: "backlinks runs get", global, runtime, async action(context, client) {
|
|
2352
|
+
const data = await client.backlinks.discoveries.get(local.project, local.run, { requestId: context.requestId });
|
|
2353
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2354
|
+
} });
|
|
2355
|
+
});
|
|
2356
|
+
const backlinkProspects = backlinks.command("prospects");
|
|
2357
|
+
backlinkProspects.command("list").requiredOption("--project <project-id>").option("--stage <stage>").action(async (local) => {
|
|
2358
|
+
const global = program.opts();
|
|
2359
|
+
commandExitCode = await execute({ command: "backlinks prospects list", global, runtime, async action(context, client) {
|
|
2360
|
+
const stage = local.stage ? BacklinkProspectStageSchema.parse(local.stage.toUpperCase()) : void 0;
|
|
2361
|
+
const data = await client.backlinks.prospects.list(local.project, { stage }, { requestId: context.requestId });
|
|
2362
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2363
|
+
} });
|
|
2364
|
+
});
|
|
2365
|
+
backlinkProspects.command("get").requiredOption("--project <project-id>").requiredOption("--prospect <prospect-id>").action(async (local) => {
|
|
2366
|
+
const global = program.opts();
|
|
2367
|
+
commandExitCode = await execute({ command: "backlinks prospects get", global, runtime, async action(context, client) {
|
|
2368
|
+
const data = await client.backlinks.prospects.get(local.project, local.prospect, { requestId: context.requestId });
|
|
2369
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2370
|
+
} });
|
|
2371
|
+
});
|
|
2372
|
+
backlinkProspects.command("approve").requiredOption("--project <project-id>").requiredOption("--prospect <prospect-id>").requiredOption("--expected-version <number>", "current optimistic version", Number).action(async (local) => {
|
|
2373
|
+
const global = program.opts();
|
|
2374
|
+
commandExitCode = await execute({ command: "backlinks prospects approve", global, runtime, async action(context, client) {
|
|
2375
|
+
const data = await client.backlinks.prospects.updateStage(local.project, local.prospect, { stage: "APPROVED", expectedVersion: local.expectedVersion }, context.requestId, { requestId: context.requestId });
|
|
2376
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2377
|
+
} });
|
|
2378
|
+
});
|
|
2379
|
+
const backlinkContacts = backlinks.command("contacts");
|
|
2380
|
+
backlinkContacts.command("research").requiredOption("--project <project-id>").requiredOption("--prospect <prospect-id>").action(async (local) => {
|
|
2381
|
+
const global = program.opts();
|
|
2382
|
+
commandExitCode = await execute({ command: "backlinks contacts research", global, runtime, async action(context, client) {
|
|
2383
|
+
const data = await client.backlinks.prospects.researchContact(local.project, local.prospect, context.requestId, { requestId: context.requestId });
|
|
2384
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2385
|
+
} });
|
|
2386
|
+
});
|
|
2387
|
+
backlinkContacts.command("list").requiredOption("--project <project-id>").action(async (local) => {
|
|
2388
|
+
const global = program.opts();
|
|
2389
|
+
commandExitCode = await execute({ command: "backlinks contacts list", global, runtime, async action(context, client) {
|
|
2390
|
+
const data = await client.backlinks.contacts.list(local.project, { limit: 50 }, { requestId: context.requestId });
|
|
2391
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2392
|
+
} });
|
|
2393
|
+
});
|
|
2394
|
+
backlinkContacts.command("export").requiredOption("--project <project-id>").option("--format <format>", "json or csv", "csv").action(async (local) => {
|
|
2395
|
+
const global = program.opts();
|
|
2396
|
+
commandExitCode = await execute({ command: "backlinks contacts export", global, runtime, async action(context, client) {
|
|
2397
|
+
const data = await client.backlinks.contacts.list(local.project, { limit: 50 }, { requestId: context.requestId });
|
|
2398
|
+
if (local.format !== "csv") return writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2399
|
+
const cell = (value) => {
|
|
2400
|
+
let text = String(value ?? "").replace(/[\r\n]+/g, " ");
|
|
2401
|
+
if (/^[=+\-@\t]/.test(text)) text = `'${text}`;
|
|
2402
|
+
return `"${text.replaceAll('"', '""')}"`;
|
|
2403
|
+
};
|
|
2404
|
+
const csv = ["prospectId,name,role,email,sourceUrl,checkedAt", ...data.items.map((item) => [item.prospectId, item.name, item.role, item.email, item.sourceUrl, item.checkedAt].map(cell).join(","))].join("\n");
|
|
2405
|
+
context.stdout.write(`${csv}
|
|
2406
|
+
`);
|
|
2407
|
+
} });
|
|
2408
|
+
});
|
|
2409
|
+
const backlinkOutreach = backlinks.command("outreach");
|
|
2410
|
+
backlinkOutreach.command("update").requiredOption("--project <project-id>").requiredOption("--prospect <prospect-id>").requiredOption("--file <file>").requiredOption("--expected-version <number>", "current draft version", Number).action(async (local) => {
|
|
2411
|
+
const global = program.opts();
|
|
2412
|
+
commandExitCode = await execute({ command: "backlinks outreach update", global, runtime, async action(context, client) {
|
|
2413
|
+
const payload = JSON.parse(await readFile2(resolve2(runtime.cwd, local.file), "utf8"));
|
|
2414
|
+
const data = await client.backlinks.prospects.updateOutreach(local.project, local.prospect, { ...payload, expectedVersion: local.expectedVersion }, context.requestId, { requestId: context.requestId });
|
|
2415
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2416
|
+
} });
|
|
2417
|
+
});
|
|
2418
|
+
backlinks.command("verify").requiredOption("--project <project-id>").requiredOption("--prospect <prospect-id>").requiredOption("--url <url>").requiredOption("--expected-version <number>", "current prospect version", Number).action(async (local) => {
|
|
2419
|
+
const global = program.opts();
|
|
2420
|
+
commandExitCode = await execute({ command: "backlinks verify", global, runtime, async action(context, client) {
|
|
2421
|
+
const data = await client.backlinks.prospects.verify(local.project, local.prospect, { url: local.url, expectedVersion: local.expectedVersion }, context.requestId, { requestId: context.requestId });
|
|
2422
|
+
writeSuccess(context, data, JSON.stringify(data, null, 2));
|
|
2423
|
+
} });
|
|
2424
|
+
});
|
|
2258
2425
|
const seo = program.command("seo").description("Read authorized SEO opportunities and weekly reports");
|
|
2259
2426
|
const seoOpportunities = seo.command("opportunities").description("Read accepted SEO opportunities");
|
|
2260
2427
|
seoOpportunities.command("list").description("List bounded SEO opportunities").requiredOption("--project <project-id>", "exact Rolino project ID").option("--limit <number>", "maximum opportunities to return", (value) => {
|
|
@@ -2420,4 +2587,4 @@ export {
|
|
|
2420
2587
|
ROLINO_CLI_VERSION,
|
|
2421
2588
|
runCli
|
|
2422
2589
|
};
|
|
2423
|
-
//# sourceMappingURL=chunk-
|
|
2590
|
+
//# sourceMappingURL=chunk-KSPZKKBG.js.map
|