@series-a/cli 1.4.1 → 1.5.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/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/src/commands/references.mjs +76 -0
- package/src/index.mjs +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ All notable changes to this package are documented here. This project follows
|
|
|
4
4
|
[Semantic Versioning](https://semver.org/) and uses
|
|
5
5
|
[Changesets](https://github.com/changesets/changesets) to manage releases.
|
|
6
6
|
|
|
7
|
+
## 1.5.0 — Calendar control, references, analytics report, safer campaign holds
|
|
8
|
+
|
|
9
|
+
Version follows 1.4.1, the latest release on npm (it was published without a changelog entry).
|
|
10
|
+
|
|
11
|
+
- Calendar: `calendar schedule <id> --at <iso>` moves or reschedules a post, `calendar unschedule <id>` cancels it and keeps the content as a draft, and `calendar delete <id>` removes it. All three cancel on Taplio first when Taplio owns the post. `content unschedule <id>` does the same from the content side.
|
|
12
|
+
- Links: `references list|show|library|verify` shows the published links stored for each post and checks they still resolve.
|
|
13
|
+
- Reports: `advisoros analytics report [--days n] [--format md|json] [--out file]` writes a full branded performance report (summary, outreach funnel, campaigns, content, revenue impact).
|
|
14
|
+
- Campaigns (server-side, no CLI change needed): LinkedIn holds now last only until the time Madnion gives; with no time given the campaign retries within 5 minutes and asks Madnion again. "If accepted" always checks LinkedIn at send time, so someone who just accepted is no longer sent down the "No" path. Slow-setup campaigns always send at least one action per run. Wrong-name checks no longer block normal greetings such as "Hi, thanks for connecting".
|
|
15
|
+
- Agents run Monday to Friday (UTC); manual runs still work on weekends.
|
|
16
|
+
- Blog generation is white-label: no platform name or platform links in workspace content.
|
|
17
|
+
|
|
7
18
|
## 1.4.0 — Company news, brand imagery fix, API reliability
|
|
8
19
|
|
|
9
20
|
Version jumps from 0.28.0 to 1.4.0 because npm already has releases up to 1.3.2.
|
package/package.json
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { call } from "../api.mjs";
|
|
2
|
+
import { emit, fail, ctxFrom, withCommonOpts } from "../ui.mjs";
|
|
3
|
+
|
|
4
|
+
const ok = (v) => (v === null || v === undefined ? "" : v ? "" : " (dead)");
|
|
5
|
+
|
|
6
|
+
function printList(d) {
|
|
7
|
+
for (const r of d.references || []) {
|
|
8
|
+
const date = r.published_at ? String(r.published_at).slice(0, 10) : "----------";
|
|
9
|
+
process.stdout.write(`${date} ${r.id} ${r.title || "(untitled)"}\n`);
|
|
10
|
+
if (r.blog_url) process.stdout.write(` blog: ${r.blog_url}${ok(r.blog_ok)}\n`);
|
|
11
|
+
if (r.linkedin_url) process.stdout.write(` linkedin: ${r.linkedin_url}${ok(r.linkedin_ok)}\n`);
|
|
12
|
+
if (r.missing_link) process.stdout.write(` MISSING LINK — published but no address saved\n`);
|
|
13
|
+
}
|
|
14
|
+
for (const v of d.videos || []) process.stdout.write(`video ${v.id} ${v.title}\n ${v.video_url}\n`);
|
|
15
|
+
process.stdout.write(`\n${d.total ?? 0} published post(s), ${d.missing_link_count ?? 0} without a saved link in this page.\n`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function registerReferences(program) {
|
|
19
|
+
const r = program
|
|
20
|
+
.command("references")
|
|
21
|
+
.alias("refs")
|
|
22
|
+
.description("Published links (blog, LinkedIn, video) that actually went out — the same list AI writers and replies use");
|
|
23
|
+
|
|
24
|
+
withCommonOpts(r.command("list"))
|
|
25
|
+
.description("List published links")
|
|
26
|
+
.option("--channel <c>", "blog | linkedin | video | all", "all")
|
|
27
|
+
.option("--since <date>", "only posts published on/after this date (YYYY-MM-DD)")
|
|
28
|
+
.option("--search <text>", "filter by title")
|
|
29
|
+
.option("--missing", "only published posts with no saved link")
|
|
30
|
+
.option("--limit <n>", "max rows (default 100, max 500)")
|
|
31
|
+
.action(async function (o) {
|
|
32
|
+
try {
|
|
33
|
+
const res = await call("references", "list", {
|
|
34
|
+
channel: o.channel, since: o.since, search: o.search, missing: !!o.missing,
|
|
35
|
+
limit: o.limit ? Number(o.limit) : undefined,
|
|
36
|
+
}, ctxFrom(this));
|
|
37
|
+
emit(this, res, printList);
|
|
38
|
+
} catch (e) { fail(e); }
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
withCommonOpts(r.command("show <id>"))
|
|
42
|
+
.alias("get")
|
|
43
|
+
.description("Show one published post's links and publishing records")
|
|
44
|
+
.action(async function (id) {
|
|
45
|
+
try {
|
|
46
|
+
const res = await call("references", "show", { id }, ctxFrom(this));
|
|
47
|
+
emit(this, res, (d) => {
|
|
48
|
+
printList({ references: [d.reference], total: 1, missing_link_count: d.reference?.missing_link ? 1 : 0 });
|
|
49
|
+
for (const x of d.distributions || []) process.stdout.write(` ${x.platform} ${x.status} ${x.platform_url || "-"}\n`);
|
|
50
|
+
});
|
|
51
|
+
} catch (e) { fail(e); }
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
withCommonOpts(r.command("library"))
|
|
55
|
+
.description("Show exactly what the AI writers see, ranked for a topic")
|
|
56
|
+
.option("--topic <text>", "topic to rank by")
|
|
57
|
+
.option("--limit <n>", "how many (default 15)")
|
|
58
|
+
.action(async function (o) {
|
|
59
|
+
try {
|
|
60
|
+
const res = await call("references", "library", { topic: o.topic, limit: o.limit ? Number(o.limit) : undefined }, ctxFrom(this));
|
|
61
|
+
emit(this, res, (d) => {
|
|
62
|
+
for (const i of d.library || []) process.stdout.write(`${i.kind.padEnd(8)} ${i.title}\n ${i.canonical_url || i.linkedin_url || i.video_url || ""}\n`);
|
|
63
|
+
});
|
|
64
|
+
} catch (e) { fail(e); }
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
withCommonOpts(r.command("verify"))
|
|
68
|
+
.description("Re-check that published links still work")
|
|
69
|
+
.option("--dry-run", "check without saving results")
|
|
70
|
+
.action(async function (o) {
|
|
71
|
+
try {
|
|
72
|
+
const res = await call("references", "verify", { dry_run: !!o.dryRun }, ctxFrom(this));
|
|
73
|
+
emit(this, res, (d) => process.stdout.write(JSON.stringify(d.verify, null, 2) + "\n"));
|
|
74
|
+
} catch (e) { fail(e); }
|
|
75
|
+
});
|
|
76
|
+
}
|
package/src/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerStrategies } from "./commands/strategies.mjs";
|
|
2
2
|
import { registerVoice } from "./commands/voice.mjs";
|
|
3
3
|
import { registerBrand } from "./commands/brand.mjs";
|
|
4
|
+
import { registerReferences } from "./commands/references.mjs";
|
|
4
5
|
import { registerResearch } from "./commands/research.mjs";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
import { readFileSync } from "node:fs";
|
|
@@ -45,6 +46,7 @@ registerPipelines(program);
|
|
|
45
46
|
registerStrategies(program);
|
|
46
47
|
registerVoice(program);
|
|
47
48
|
registerBrand(program);
|
|
49
|
+
registerReferences(program);
|
|
48
50
|
registerAuthority(program);
|
|
49
51
|
registerEmail(program);
|
|
50
52
|
registerBriefs(program);
|