@series-a/cli 0.24.0 → 1.1.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 +33 -148
- package/README.md +79 -260
- package/bin/setu.mjs +587 -0
- package/lib/api.mjs +84 -0
- package/lib/config.mjs +42 -0
- package/lib/ui.mjs +68 -0
- package/package.json +15 -50
- package/LICENSE +0 -7
- package/SKILLS.md +0 -325
- package/bin/advisoros.mjs +0 -2
- package/src/api.mjs +0 -102
- package/src/commands/auth.mjs +0 -193
- package/src/commands/brand.mjs +0 -439
- package/src/commands/flow.mjs +0 -175
- package/src/commands/insights.mjs +0 -1758
- package/src/commands/knowledge-sync.mjs +0 -519
- package/src/commands/resources.mjs +0 -2151
- package/src/commands/strategies.mjs +0 -242
- package/src/commands/voice.mjs +0 -212
- package/src/config.mjs +0 -82
- package/src/index.mjs +0 -76
- package/src/ui.mjs +0 -104
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { call } from "../api.mjs";
|
|
2
|
-
import { emit, fail, ctxFrom, withCommonOpts, table, truncate, confirmDestructive } from "../ui.mjs";
|
|
3
|
-
|
|
4
|
-
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
5
|
-
|
|
6
|
-
export function registerStrategies(program) {
|
|
7
|
-
const s = program
|
|
8
|
-
.command("strategy")
|
|
9
|
-
.alias("strategies")
|
|
10
|
-
.description("Build and manage AI content strategies (multi-week content arcs)");
|
|
11
|
-
|
|
12
|
-
withCommonOpts(s.command("ideate"))
|
|
13
|
-
.description("Propose 3 grounded strategy directions from KB + signals")
|
|
14
|
-
.option("--hint <text>", "steer the ideation (theme, audience, launch…)")
|
|
15
|
-
.option("--no-tone", "do not apply the workspace tone of voice")
|
|
16
|
-
.action(async function () {
|
|
17
|
-
try {
|
|
18
|
-
const o = this.optsWithGlobals();
|
|
19
|
-
const r = await call("strategies", "ideate", {
|
|
20
|
-
hint: o.hint, apply_tone_of_voice: o.tone !== false,
|
|
21
|
-
}, ctxFrom(this));
|
|
22
|
-
emit(this, r, (d) => {
|
|
23
|
-
(d.strategies || []).forEach((st, i) => {
|
|
24
|
-
process.stdout.write(
|
|
25
|
-
`\n${i + 1}. ${st.name}\n audience: ${st.audience}\n outcome: ${st.outcome}\n pillars: ${(st.pillars || []).join(", ")}\n ${st.narrative}\n`,
|
|
26
|
-
);
|
|
27
|
-
});
|
|
28
|
-
process.stdout.write("\n");
|
|
29
|
-
});
|
|
30
|
-
} catch (e) { fail(e); }
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
withCommonOpts(s.command("create"))
|
|
34
|
-
.description("Build a full strategy: plans the arc and queues every post for drafting")
|
|
35
|
-
.requiredOption("--name <name>", "strategy name")
|
|
36
|
-
.option("--narrative <text>", "the story arc")
|
|
37
|
-
.option("--audience <text>", "who it targets")
|
|
38
|
-
.option("--outcome <text>", "what it should achieve")
|
|
39
|
-
.option("--pillars <list>", "comma-separated content pillars")
|
|
40
|
-
.option("--months <n>", "duration in months", "1")
|
|
41
|
-
.option("--per-week <n>", "posts per week (1-5)", "3")
|
|
42
|
-
.option("--format <f>", "linkedin | blog | mixed", "linkedin")
|
|
43
|
-
.option("--no-tone", "do not apply the workspace tone of voice")
|
|
44
|
-
.option("--wait", "poll resume until every post is drafted")
|
|
45
|
-
.action(async function (opts) {
|
|
46
|
-
try {
|
|
47
|
-
const ctx = ctxFrom(this);
|
|
48
|
-
const r = await call("strategies", "create", {
|
|
49
|
-
strategy: {
|
|
50
|
-
name: opts.name, narrative: opts.narrative, audience: opts.audience,
|
|
51
|
-
outcome: opts.outcome,
|
|
52
|
-
pillars: opts.pillars ? String(opts.pillars).split(",").map((p) => p.trim()) : [],
|
|
53
|
-
},
|
|
54
|
-
duration_months: Number(opts.months),
|
|
55
|
-
posts_per_week: Number(opts.perWeek),
|
|
56
|
-
format_mix: opts.format,
|
|
57
|
-
apply_tone_of_voice: opts.tone !== false,
|
|
58
|
-
}, ctx);
|
|
59
|
-
const id = r?.data?.strategy?.id ?? r?.strategy?.id;
|
|
60
|
-
if (opts.wait && id) {
|
|
61
|
-
for (let i = 0; i < 90; i++) {
|
|
62
|
-
await sleep(8000);
|
|
63
|
-
const p = await call("strategies", "resume", { id }, ctx);
|
|
64
|
-
const d = p?.data ?? p;
|
|
65
|
-
process.stderr.write(` … ${d.progress?.done ?? 0}/${d.progress?.total ?? "?"} done\n`);
|
|
66
|
-
if (d.status === "ready" || d.status === "failed") break;
|
|
67
|
-
}
|
|
68
|
-
const final = await call("strategies", "get", { id, include_posts: false }, ctx);
|
|
69
|
-
return emit(this, final, (d) => process.stdout.write(`✓ ${d.strategy?.name} — ${d.strategy?.status}\n`));
|
|
70
|
-
}
|
|
71
|
-
emit(this, r, (d) => process.stdout.write(
|
|
72
|
-
`✓ Created strategy ${d.strategy?.id} (${d.total_posts ?? "?"} posts queued)\n Run: advisoros strategy resume ${d.strategy?.id}\n`,
|
|
73
|
-
));
|
|
74
|
-
} catch (e) { fail(e); }
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
withCommonOpts(s.command("list"))
|
|
78
|
-
.description("List content strategies")
|
|
79
|
-
.option("--status <s>", "planning | generating | ready | failed | archived")
|
|
80
|
-
.option("--search <q>", "search by name")
|
|
81
|
-
.option("--limit <n>", "max rows", "25")
|
|
82
|
-
.action(async function () {
|
|
83
|
-
try {
|
|
84
|
-
const o = this.optsWithGlobals();
|
|
85
|
-
const r = await call("strategies", "list", {
|
|
86
|
-
status: o.status, search: o.search, limit: Number(o.limit),
|
|
87
|
-
}, ctxFrom(this));
|
|
88
|
-
emit(this, r, (d) => {
|
|
89
|
-
process.stdout.write(table(
|
|
90
|
-
["id", "status", "posts", "wk", "name"],
|
|
91
|
-
(d.strategies || []).map((st) => [
|
|
92
|
-
truncate(st.id, 8), st.status, st.total_posts ?? "", st.posts_per_week ?? "",
|
|
93
|
-
truncate(st.name, 46),
|
|
94
|
-
]),
|
|
95
|
-
) + `\n${d.strategies?.length ?? 0} rows\n`);
|
|
96
|
-
});
|
|
97
|
-
} catch (e) { fail(e); }
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
withCommonOpts(s.command("show <id>"))
|
|
101
|
-
.description("Show a strategy with its planned posts")
|
|
102
|
-
.option("--no-posts", "omit the post list")
|
|
103
|
-
.action(async function (id, opts) {
|
|
104
|
-
try {
|
|
105
|
-
const r = await call("strategies", "get", { id, include_posts: opts.posts !== false }, ctxFrom(this));
|
|
106
|
-
emit(this, r, (d) => {
|
|
107
|
-
const st = d.strategy || {};
|
|
108
|
-
process.stdout.write(`${st.name} [${st.status}]\n${st.narrative ?? ""}\n\n`);
|
|
109
|
-
if (d.posts?.length) {
|
|
110
|
-
process.stdout.write(table(
|
|
111
|
-
["#", "wk", "status", "format", "date", "hook"],
|
|
112
|
-
d.posts.map((p) => [p.position, p.week_no, p.status, p.format, p.planned_date ?? "", truncate(p.hook, 44)]),
|
|
113
|
-
) + "\n");
|
|
114
|
-
}
|
|
115
|
-
if (d.progress) process.stdout.write(`\n${JSON.stringify(d.progress)}\n`);
|
|
116
|
-
});
|
|
117
|
-
} catch (e) { fail(e); }
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
withCommonOpts(s.command("resume <id>"))
|
|
121
|
-
.description("Push the drafting queue along (repeat until status is ready)")
|
|
122
|
-
.option("--wait", "keep polling until done")
|
|
123
|
-
.action(async function (id, opts) {
|
|
124
|
-
try {
|
|
125
|
-
const ctx = ctxFrom(this);
|
|
126
|
-
let r = await call("strategies", "resume", { id }, ctx);
|
|
127
|
-
if (opts.wait) {
|
|
128
|
-
for (let i = 0; i < 90; i++) {
|
|
129
|
-
const d = r?.data ?? r;
|
|
130
|
-
if (d.status === "ready" || d.status === "failed") break;
|
|
131
|
-
process.stderr.write(` … ${d.progress?.done ?? 0}/${d.progress?.total ?? "?"} done\n`);
|
|
132
|
-
await sleep(8000);
|
|
133
|
-
r = await call("strategies", "resume", { id }, ctx);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
emit(this, r, (d) => process.stdout.write(`${d.status} — ${JSON.stringify(d.progress)}\n`));
|
|
137
|
-
} catch (e) { fail(e); }
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
withCommonOpts(s.command("update <id>"))
|
|
141
|
-
.description("Patch a strategy")
|
|
142
|
-
.option("--name <n>")
|
|
143
|
-
.option("--narrative <text>")
|
|
144
|
-
.option("--audience <text>")
|
|
145
|
-
.option("--outcome <text>")
|
|
146
|
-
.option("--pillars <list>", "comma-separated")
|
|
147
|
-
.option("--status <s>", "planning | generating | ready | failed | archived")
|
|
148
|
-
.option("--campaign <id>", "link to a campaign")
|
|
149
|
-
.action(async function (id, opts) {
|
|
150
|
-
try {
|
|
151
|
-
const r = await call("strategies", "update", {
|
|
152
|
-
id, name: opts.name, narrative: opts.narrative, audience: opts.audience,
|
|
153
|
-
outcome: opts.outcome, status: opts.status, campaign_id: opts.campaign,
|
|
154
|
-
pillars: opts.pillars ? String(opts.pillars).split(",").map((p) => p.trim()) : undefined,
|
|
155
|
-
}, ctxFrom(this));
|
|
156
|
-
emit(this, r, (d) => process.stdout.write(`✓ Updated ${d.strategy?.id}\n`));
|
|
157
|
-
} catch (e) { fail(e); }
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
withCommonOpts(s.command("delete <id>"))
|
|
161
|
-
.description("Delete a strategy and its planned posts")
|
|
162
|
-
.option("-y, --yes", "skip the confirmation prompt")
|
|
163
|
-
.action(async function (id) {
|
|
164
|
-
try {
|
|
165
|
-
await confirmDestructive(this, `Delete strategy ${id} and every planned post. This cannot be undone.`);
|
|
166
|
-
const r = await call("strategies", "delete", { id }, ctxFrom(this));
|
|
167
|
-
emit(this, r, (d) => process.stdout.write(`✓ Deleted ${d.deleted}\n`));
|
|
168
|
-
} catch (e) { fail(e); }
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
withCommonOpts(s.command("posts <id>"))
|
|
172
|
-
.description("List the planned posts of a strategy")
|
|
173
|
-
.option("--status <s>", "queued | claimed | done | failed | skipped")
|
|
174
|
-
.option("--limit <n>", "max rows", "200")
|
|
175
|
-
.action(async function (id) {
|
|
176
|
-
try {
|
|
177
|
-
const o = this.optsWithGlobals();
|
|
178
|
-
const r = await call("strategies", "posts", { id, status: o.status, limit: Number(o.limit) }, ctxFrom(this));
|
|
179
|
-
emit(this, r, (d) => {
|
|
180
|
-
process.stdout.write(table(
|
|
181
|
-
["post_id", "#", "wk", "status", "format", "date", "hook"],
|
|
182
|
-
(d.posts || []).map((p) => [
|
|
183
|
-
truncate(p.id, 8), p.position, p.week_no, p.status, p.format,
|
|
184
|
-
p.planned_date ?? "", truncate(p.hook, 38),
|
|
185
|
-
]),
|
|
186
|
-
) + `\n${JSON.stringify(d.progress)}\n`);
|
|
187
|
-
});
|
|
188
|
-
} catch (e) { fail(e); }
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
withCommonOpts(s.command("post <postId>"))
|
|
192
|
-
.description("Show one planned post")
|
|
193
|
-
.action(async function (postId) {
|
|
194
|
-
try {
|
|
195
|
-
const r = await call("strategies", "get_post", { post_id: postId }, ctxFrom(this));
|
|
196
|
-
emit(this, r, (d) => process.stdout.write(JSON.stringify(d.post, null, 2) + "\n"));
|
|
197
|
-
} catch (e) { fail(e); }
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
withCommonOpts(s.command("update-post <postId>"))
|
|
201
|
-
.description("Patch a planned post before it is drafted")
|
|
202
|
-
.option("--pillar <p>")
|
|
203
|
-
.option("--hook <text>")
|
|
204
|
-
.option("--objective <text>")
|
|
205
|
-
.option("--title <text>", "title_seed")
|
|
206
|
-
.option("--brief <text>")
|
|
207
|
-
.option("--format <f>", "linkedin | blog")
|
|
208
|
-
.option("--date <YYYY-MM-DD>", "planned_date")
|
|
209
|
-
.option("--week <n>", "week_no")
|
|
210
|
-
.option("--status <s>", "queued | claimed | done | failed | skipped")
|
|
211
|
-
.action(async function (postId, opts) {
|
|
212
|
-
try {
|
|
213
|
-
const r = await call("strategies", "update_post", {
|
|
214
|
-
post_id: postId, pillar: opts.pillar, hook: opts.hook, objective: opts.objective,
|
|
215
|
-
title_seed: opts.title, brief: opts.brief, format: opts.format,
|
|
216
|
-
planned_date: opts.date, week_no: opts.week ? Number(opts.week) : undefined,
|
|
217
|
-
status: opts.status,
|
|
218
|
-
}, ctxFrom(this));
|
|
219
|
-
emit(this, r, (d) => process.stdout.write(`✓ Updated post ${d.post?.id}\n`));
|
|
220
|
-
} catch (e) { fail(e); }
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
withCommonOpts(s.command("retry-post <postId>"))
|
|
224
|
-
.description("Re-queue a failed post for drafting")
|
|
225
|
-
.action(async function (postId) {
|
|
226
|
-
try {
|
|
227
|
-
const r = await call("strategies", "retry_post", { post_id: postId }, ctxFrom(this));
|
|
228
|
-
emit(this, r, (d) => process.stdout.write(`✓ Re-queued ${d.post?.id}\n`));
|
|
229
|
-
} catch (e) { fail(e); }
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
withCommonOpts(s.command("delete-post <postId>"))
|
|
233
|
-
.description("Remove a planned post")
|
|
234
|
-
.option("-y, --yes", "skip the confirmation prompt")
|
|
235
|
-
.action(async function (postId) {
|
|
236
|
-
try {
|
|
237
|
-
await confirmDestructive(this, `Delete planned post ${postId}.`);
|
|
238
|
-
const r = await call("strategies", "delete_post", { post_id: postId }, ctxFrom(this));
|
|
239
|
-
emit(this, r, (d) => process.stdout.write(`✓ Deleted ${d.deleted}\n`));
|
|
240
|
-
} catch (e) { fail(e); }
|
|
241
|
-
});
|
|
242
|
-
}
|
package/src/commands/voice.mjs
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { call } from "../api.mjs";
|
|
2
|
-
import { emit, fail, ctxFrom, withCommonOpts, table, truncate, confirmDestructive } from "../ui.mjs";
|
|
3
|
-
|
|
4
|
-
export function registerVoice(program) {
|
|
5
|
-
const v = program
|
|
6
|
-
.command("voice")
|
|
7
|
-
.alias("tone")
|
|
8
|
-
.description("Read, write and delete the workspace Tone of Voice (directive, samples, scores)");
|
|
9
|
-
|
|
10
|
-
withCommonOpts(v.command("show"))
|
|
11
|
-
.alias("get")
|
|
12
|
-
.description("Show the workspace tone of voice configuration")
|
|
13
|
-
.action(async function () {
|
|
14
|
-
try {
|
|
15
|
-
const r = await call("voice", "get", {}, ctxFrom(this));
|
|
16
|
-
emit(this, r, (d) => {
|
|
17
|
-
const t = d.voice || {};
|
|
18
|
-
process.stdout.write(
|
|
19
|
-
`Directive: ${t.has_directive ? "set" : "(none)"}${t.source ? ` [source: ${t.source}]` : ""}\n` +
|
|
20
|
-
`Applied by default: ${t.apply_by_default ? "yes" : "no"}\n` +
|
|
21
|
-
`Writing samples: ${t.style_reference_count}${t.primary_style_reference_id ? ` (pinned: ${t.primary_style_reference_id})` : ""}\n` +
|
|
22
|
-
(t.synced_at ? `Last synced: ${t.synced_at}\n` : "") +
|
|
23
|
-
(t.directive ? `\n${t.directive}\n` : ""),
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
} catch (e) { fail(e); }
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
withCommonOpts(v.command("set"))
|
|
30
|
-
.description("Write the tone of voice directive and/or the apply-by-default toggle")
|
|
31
|
-
.option("--directive <text>", "the tone of voice directive")
|
|
32
|
-
.option("--source <text>", "where the directive came from", undefined)
|
|
33
|
-
.option("--apply-default <yes|no>", "apply tone of voice to new content by default")
|
|
34
|
-
.action(async function (opts) {
|
|
35
|
-
try {
|
|
36
|
-
const params = { directive: opts.directive, source: opts.source };
|
|
37
|
-
if (opts.applyDefault !== undefined) {
|
|
38
|
-
params.apply_by_default = /^(y|yes|true|1|on)$/i.test(String(opts.applyDefault));
|
|
39
|
-
}
|
|
40
|
-
const r = await call("voice", "set", params, ctxFrom(this));
|
|
41
|
-
emit(this, r, (d) => process.stdout.write(
|
|
42
|
-
`✓ Tone of voice updated (directive ${d.voice?.has_directive ? "set" : "empty"}, default ${d.voice?.apply_by_default ? "on" : "off"})\n`,
|
|
43
|
-
));
|
|
44
|
-
} catch (e) { fail(e); }
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
withCommonOpts(v.command("delete"))
|
|
48
|
-
.alias("clear")
|
|
49
|
-
.description("Delete the tone of voice directive")
|
|
50
|
-
.option("--with-references", "also unmark every writing sample")
|
|
51
|
-
.option("-y, --yes", "skip the confirmation prompt")
|
|
52
|
-
.action(async function (opts) {
|
|
53
|
-
try {
|
|
54
|
-
await confirmDestructive(this, "Delete this workspace's tone of voice directive.");
|
|
55
|
-
const r = await call("voice", "delete", { clear_references: !!opts.withReferences }, ctxFrom(this));
|
|
56
|
-
emit(this, r, () => process.stdout.write("✓ Tone of voice cleared\n"));
|
|
57
|
-
} catch (e) { fail(e); }
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
withCommonOpts(v.command("sync"))
|
|
61
|
-
.description("Re-pull the directive from Business Build")
|
|
62
|
-
.option("--email <email>", "identity to resolve the client by")
|
|
63
|
-
.action(async function (opts) {
|
|
64
|
-
try {
|
|
65
|
-
const r = await call("voice", "sync", { email: opts.email }, ctxFrom(this));
|
|
66
|
-
emit(this, r, (d) => process.stdout.write(
|
|
67
|
-
`${d.voice?.has_directive ? "✓ Directive synced" : "No directive found"}\n`,
|
|
68
|
-
));
|
|
69
|
-
} catch (e) { fail(e); }
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// ── writing samples (benchmark corpus) ──
|
|
73
|
-
withCommonOpts(v.command("references"))
|
|
74
|
-
.alias("samples")
|
|
75
|
-
.description("List the knowledge base items used as writing samples")
|
|
76
|
-
.option("--limit <n>", "max rows", "50")
|
|
77
|
-
.action(async function (opts) {
|
|
78
|
-
try {
|
|
79
|
-
const r = await call("voice", "references", { limit: Number(opts.limit) }, ctxFrom(this));
|
|
80
|
-
emit(this, r, (d) => process.stdout.write(
|
|
81
|
-
table(
|
|
82
|
-
["id", "primary", "name", "category"],
|
|
83
|
-
(d.references || []).map((x) => [truncate(x.id, 8), x.is_primary ? "★" : "", truncate(x.name, 44), x.category ?? ""]),
|
|
84
|
-
) + `\n${d.references?.length ?? 0} rows\n`,
|
|
85
|
-
));
|
|
86
|
-
} catch (e) { fail(e); }
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
withCommonOpts(v.command("add-reference <knowledgeItemId>"))
|
|
90
|
-
.description("Mark a knowledge base item as a writing sample")
|
|
91
|
-
.option("--primary", "also pin it as the benchmark sample")
|
|
92
|
-
.action(async function (id, opts) {
|
|
93
|
-
try {
|
|
94
|
-
const r = await call("voice", "add_reference", { knowledge_item_id: id, set_primary: !!opts.primary }, ctxFrom(this));
|
|
95
|
-
emit(this, r, () => process.stdout.write(`✓ ${id} is now a writing sample\n`));
|
|
96
|
-
} catch (e) { fail(e); }
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
withCommonOpts(v.command("remove-reference <knowledgeItemId>"))
|
|
100
|
-
.description("Unmark a writing sample")
|
|
101
|
-
.action(async function (id) {
|
|
102
|
-
try {
|
|
103
|
-
const r = await call("voice", "remove_reference", { knowledge_item_id: id }, ctxFrom(this));
|
|
104
|
-
emit(this, r, () => process.stdout.write(`✓ ${id} removed from the writing samples\n`));
|
|
105
|
-
} catch (e) { fail(e); }
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
withCommonOpts(v.command("set-primary [knowledgeItemId]"))
|
|
109
|
-
.description("Pin (or clear, when no id is given) the benchmark writing sample")
|
|
110
|
-
.action(async function (id) {
|
|
111
|
-
try {
|
|
112
|
-
const r = await call("voice", "set_primary", { knowledge_item_id: id ?? null }, ctxFrom(this));
|
|
113
|
-
emit(this, r, (d) => process.stdout.write(
|
|
114
|
-
d.primary_style_reference_id ? `✓ Pinned ${d.primary_style_reference_id}\n` : "✓ Benchmark unpinned\n",
|
|
115
|
-
));
|
|
116
|
-
} catch (e) { fail(e); }
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// ── derived card + scoring ──
|
|
120
|
-
withCommonOpts(v.command("card"))
|
|
121
|
-
.description("Show the measured voice card (house rules + stylometric targets)")
|
|
122
|
-
.option("--rebuild", "rebuild it from the writing samples")
|
|
123
|
-
.action(async function (opts) {
|
|
124
|
-
try {
|
|
125
|
-
const r = await call("voice", "card", { rebuild: !!opts.rebuild }, ctxFrom(this));
|
|
126
|
-
emit(this, r, (d) => {
|
|
127
|
-
if (!d.card) {
|
|
128
|
-
process.stdout.write(
|
|
129
|
-
`✖ ${d.error || "No voice card — add a writing sample first."}\n` +
|
|
130
|
-
` workspace: ${d.workspace_id || "?"} status: ${d.status || "error"}\n`,
|
|
131
|
-
);
|
|
132
|
-
process.exitCode = 1;
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
process.stdout.write(
|
|
136
|
-
`Built: ${d.card.built_at}\nReferences: ${(d.card.reference_titles || []).join(", ")}\n\nRules:\n` +
|
|
137
|
-
(d.card.rules || []).map((x) => ` - ${x}`).join("\n") +
|
|
138
|
-
`\n\nTargets:\n` + (d.targets || []).map((x) => ` - ${x}`).join("\n") +
|
|
139
|
-
`\n\nWorkspace: ${d.workspace_id || "?"} ${d.rebuilt ? "rebuilt" : "cached"} status: ${d.status || "ok"}` +
|
|
140
|
-
`\nReference ids: ${(d.reference_item_ids || []).join(", ") || "(none recorded)"}` +
|
|
141
|
-
(d.primary_reference_id ? `\nPrimary reference: ${d.primary_reference_id}` : "") + "\n",
|
|
142
|
-
);
|
|
143
|
-
});
|
|
144
|
-
} catch (e) { fail(e); }
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
withCommonOpts(v.command("score"))
|
|
148
|
-
.description("Score a piece of writing against the workspace voice")
|
|
149
|
-
.option("--text <text>", "text to score")
|
|
150
|
-
.option("--content <id>", "content item to score")
|
|
151
|
-
.option("--reference <id>", "knowledge item to score against (defaults to the pinned sample)")
|
|
152
|
-
.option("--no-persist", "do not stamp the score onto the content item")
|
|
153
|
-
.action(async function (opts) {
|
|
154
|
-
try {
|
|
155
|
-
const r = await call("voice", "score", {
|
|
156
|
-
text: opts.text, content_item_id: opts.content,
|
|
157
|
-
reference_item_id: opts.reference, persist: opts.persist !== false,
|
|
158
|
-
}, ctxFrom(this));
|
|
159
|
-
emit(this, r, (d) => process.stdout.write(
|
|
160
|
-
`Match: ${d.report?.overall_score ?? d.overall_score ?? "?"}%\n${d.report?.rationale ?? d.rationale ?? ""}\n`,
|
|
161
|
-
));
|
|
162
|
-
} catch (e) { fail(e); }
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
withCommonOpts(v.command("redraft"))
|
|
166
|
-
.description("Rewrite a piece in the author's voice (returns text, saves nothing)")
|
|
167
|
-
.option("--text <text>", "text to rewrite")
|
|
168
|
-
.option("--content <id>", "content item to rewrite")
|
|
169
|
-
.action(async function (opts) {
|
|
170
|
-
try {
|
|
171
|
-
const r = await call("voice", "redraft", { text: opts.text, content_item_id: opts.content }, ctxFrom(this));
|
|
172
|
-
emit(this, r, (d) => process.stdout.write(`${d.text ?? d.redraft ?? JSON.stringify(d)}\n`));
|
|
173
|
-
} catch (e) { fail(e); }
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// ── reports ──
|
|
177
|
-
withCommonOpts(v.command("reports"))
|
|
178
|
-
.description("List voice match reports")
|
|
179
|
-
.option("--content <id>", "only reports for this content item")
|
|
180
|
-
.option("--limit <n>", "max rows", "25")
|
|
181
|
-
.action(async function (opts) {
|
|
182
|
-
try {
|
|
183
|
-
const r = await call("voice", "reports", { content_item_id: opts.content, limit: Number(opts.limit) }, ctxFrom(this));
|
|
184
|
-
emit(this, r, (d) => process.stdout.write(
|
|
185
|
-
table(
|
|
186
|
-
["id", "score", "created", "subject"],
|
|
187
|
-
(d.reports || []).map((x) => [truncate(x.id, 8), x.overall_score, (x.created_at || "").slice(0, 16), truncate(x.subject_title, 40)]),
|
|
188
|
-
) + `\n${d.reports?.length ?? 0} rows\n`,
|
|
189
|
-
));
|
|
190
|
-
} catch (e) { fail(e); }
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
withCommonOpts(v.command("report <id>"))
|
|
194
|
-
.description("Show one voice match report")
|
|
195
|
-
.action(async function (id) {
|
|
196
|
-
try {
|
|
197
|
-
const r = await call("voice", "get_report", { report_id: id }, ctxFrom(this));
|
|
198
|
-
emit(this, r, (d) => process.stdout.write(JSON.stringify(d.report, null, 2) + "\n"));
|
|
199
|
-
} catch (e) { fail(e); }
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
withCommonOpts(v.command("delete-report <id>"))
|
|
203
|
-
.description("Delete a voice match report")
|
|
204
|
-
.option("-y, --yes", "skip the confirmation prompt")
|
|
205
|
-
.action(async function (id) {
|
|
206
|
-
try {
|
|
207
|
-
await confirmDestructive(this, `Delete voice match report ${id}. This cannot be undone.`);
|
|
208
|
-
const r = await call("voice", "delete_report", { report_id: id }, ctxFrom(this));
|
|
209
|
-
emit(this, r, (d) => process.stdout.write(`✓ Deleted ${d.deleted}\n`));
|
|
210
|
-
} catch (e) { fail(e); }
|
|
211
|
-
});
|
|
212
|
-
}
|
package/src/config.mjs
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { homedir } from "node:os";
|
|
2
|
-
import { join, dirname } from "node:path";
|
|
3
|
-
import { mkdir, readFile, writeFile, chmod } from "node:fs/promises";
|
|
4
|
-
|
|
5
|
-
const CONFIG_DIR = join(homedir(), ".advisoros");
|
|
6
|
-
const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
7
|
-
|
|
8
|
-
const DEFAULT_BASE_URL =
|
|
9
|
-
"https://iwcwydcxbzoenmqcqkcv.supabase.co/functions/v1/agent-api";
|
|
10
|
-
|
|
11
|
-
export const DEFAULTS = { baseUrl: DEFAULT_BASE_URL };
|
|
12
|
-
|
|
13
|
-
async function readConfig() {
|
|
14
|
-
try {
|
|
15
|
-
const raw = await readFile(CONFIG_PATH, "utf8");
|
|
16
|
-
return JSON.parse(raw);
|
|
17
|
-
} catch {
|
|
18
|
-
return { profiles: {} };
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function writeConfig(cfg) {
|
|
23
|
-
await mkdir(dirname(CONFIG_PATH), { recursive: true });
|
|
24
|
-
await writeFile(CONFIG_PATH, JSON.stringify(cfg, null, 2), "utf8");
|
|
25
|
-
try { await chmod(CONFIG_PATH, 0o600); } catch {}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function getProfile(name = "default") {
|
|
29
|
-
const cfg = await readConfig();
|
|
30
|
-
return cfg.profiles?.[name] ?? null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function setProfile(name, data) {
|
|
34
|
-
const cfg = await readConfig();
|
|
35
|
-
cfg.profiles = cfg.profiles ?? {};
|
|
36
|
-
cfg.profiles[name] = data;
|
|
37
|
-
cfg.currentProfile = name;
|
|
38
|
-
await writeConfig(cfg);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** Save several profiles in one write (e.g. "default" plus a workspace alias). */
|
|
42
|
-
export async function setProfiles(entries, currentProfile) {
|
|
43
|
-
const cfg = await readConfig();
|
|
44
|
-
cfg.profiles = cfg.profiles ?? {};
|
|
45
|
-
for (const [name, data] of Object.entries(entries)) cfg.profiles[name] = data;
|
|
46
|
-
if (currentProfile) cfg.currentProfile = currentProfile;
|
|
47
|
-
await writeConfig(cfg);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** All saved profiles with their data — used to detect overwrite collisions. */
|
|
51
|
-
export async function allProfiles() {
|
|
52
|
-
const cfg = await readConfig();
|
|
53
|
-
return cfg.profiles ?? {};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** The saved profile already pointing at this workspace, if any. */
|
|
57
|
-
export async function findProfileByWorkspace(workspaceId) {
|
|
58
|
-
if (!workspaceId) return null;
|
|
59
|
-
const profiles = await allProfiles();
|
|
60
|
-
for (const [name, p] of Object.entries(profiles)) {
|
|
61
|
-
if (p?.workspaceId === workspaceId) return { name, profile: p };
|
|
62
|
-
}
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
export async function listProfiles() {
|
|
68
|
-
const cfg = await readConfig();
|
|
69
|
-
return Object.keys(cfg.profiles ?? {});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export async function deleteProfile(name) {
|
|
73
|
-
const cfg = await readConfig();
|
|
74
|
-
if (cfg.profiles?.[name]) {
|
|
75
|
-
delete cfg.profiles[name];
|
|
76
|
-
await writeConfig(cfg);
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export { CONFIG_PATH };
|
package/src/index.mjs
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { registerStrategies } from "./commands/strategies.mjs";
|
|
2
|
-
import { registerVoice } from "./commands/voice.mjs";
|
|
3
|
-
import { registerBrand } from "./commands/brand.mjs";
|
|
4
|
-
import { Command } from "commander";
|
|
5
|
-
import { readFileSync } from "node:fs";
|
|
6
|
-
import { registerAuth } from "./commands/auth.mjs";
|
|
7
|
-
import {
|
|
8
|
-
registerLeads, registerCampaigns, registerSequences,
|
|
9
|
-
registerInbox, registerContent, registerAgents, registerKnowledge,
|
|
10
|
-
registerCalendar, registerSignals, registerPipelines, registerAuthority,
|
|
11
|
-
registerBriefs,
|
|
12
|
-
} from "./commands/resources.mjs";
|
|
13
|
-
import {
|
|
14
|
-
registerCampaignAnalytics, registerAnalytics, registerSafety, registerCtas,
|
|
15
|
-
registerNotifications, registerAudiences, registerNewsletter, registerVideo,
|
|
16
|
-
registerWatchlist, registerIntelligencePrompts, registerMeetings, registerActivity, registerWorkspacesExtras,
|
|
17
|
-
registerExport, registerIntegrations, registerAudit, registerReports,
|
|
18
|
-
} from "./commands/insights.mjs";
|
|
19
|
-
import { registerFlow } from "./commands/flow.mjs";
|
|
20
|
-
import { registerVaultSync } from "./commands/knowledge-sync.mjs";
|
|
21
|
-
|
|
22
|
-
const program = new Command();
|
|
23
|
-
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
24
|
-
|
|
25
|
-
program
|
|
26
|
-
.name("advisoros")
|
|
27
|
-
.description("AdvisorPro CLI — drive leads, campaigns, sequences and agents from your terminal.")
|
|
28
|
-
.version(pkg.version)
|
|
29
|
-
.option("--json", "machine-readable JSON output (applies to all subcommands)")
|
|
30
|
-
.option("--as-agent <name>", "caller identity sent as agent_name (audit label only)");
|
|
31
|
-
|
|
32
|
-
registerAuth(program);
|
|
33
|
-
registerLeads(program);
|
|
34
|
-
registerCampaigns(program);
|
|
35
|
-
registerSequences(program);
|
|
36
|
-
registerInbox(program);
|
|
37
|
-
registerContent(program);
|
|
38
|
-
registerCalendar(program);
|
|
39
|
-
registerKnowledge(program);
|
|
40
|
-
registerSignals(program);
|
|
41
|
-
registerPipelines(program);
|
|
42
|
-
registerStrategies(program);
|
|
43
|
-
registerVoice(program);
|
|
44
|
-
registerBrand(program);
|
|
45
|
-
registerAuthority(program);
|
|
46
|
-
registerBriefs(program);
|
|
47
|
-
registerAgents(program);
|
|
48
|
-
registerIntegrations(program);
|
|
49
|
-
|
|
50
|
-
// Analytics, safety guardrails and the remaining resource surface.
|
|
51
|
-
registerCampaignAnalytics(program);
|
|
52
|
-
registerAnalytics(program);
|
|
53
|
-
registerSafety(program);
|
|
54
|
-
registerCtas(program);
|
|
55
|
-
registerNotifications(program);
|
|
56
|
-
registerAudiences(program);
|
|
57
|
-
registerNewsletter(program);
|
|
58
|
-
registerVideo(program);
|
|
59
|
-
registerWatchlist(program);
|
|
60
|
-
registerIntelligencePrompts(program);
|
|
61
|
-
registerMeetings(program);
|
|
62
|
-
registerActivity(program);
|
|
63
|
-
registerAudit(program);
|
|
64
|
-
registerWorkspacesExtras(program);
|
|
65
|
-
registerExport(program);
|
|
66
|
-
|
|
67
|
-
registerVaultSync(program);
|
|
68
|
-
registerReports(program);
|
|
69
|
-
|
|
70
|
-
registerFlow(program);
|
|
71
|
-
|
|
72
|
-
program.parseAsync(process.argv).catch((e) => {
|
|
73
|
-
process.stderr.write(`✖ ${e?.message ?? e}\n`);
|
|
74
|
-
process.exit(1);
|
|
75
|
-
});
|
|
76
|
-
|