@todoforai/cli 0.1.50 → 0.1.52
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/dist/todoforai-cli.js +152 -107
- package/package.json +1 -1
package/dist/todoforai-cli.js
CHANGED
|
@@ -42884,29 +42884,26 @@ class ApiClient {
|
|
|
42884
42884
|
setDeviceWallpaperMode(id, mode) {
|
|
42885
42885
|
return this.request("POST", `/api/v1/devices/${id}/wallpaper-mode`, { id, mode });
|
|
42886
42886
|
}
|
|
42887
|
-
|
|
42888
|
-
return this.request("GET",
|
|
42887
|
+
getBusinessContext(projectId) {
|
|
42888
|
+
return this.request("GET", `/api/v1/projects/${projectId}/business-context`);
|
|
42889
42889
|
}
|
|
42890
|
-
createBusinessContext(name) {
|
|
42891
|
-
return this.request("POST",
|
|
42890
|
+
createBusinessContext(projectId, name) {
|
|
42891
|
+
return this.request("POST", `/api/v1/projects/${projectId}/business-context`, { projectId, name });
|
|
42892
42892
|
}
|
|
42893
|
-
renameBusinessContext(
|
|
42894
|
-
return this.request("PUT", `/api/v1/business-context
|
|
42893
|
+
renameBusinessContext(projectId, name) {
|
|
42894
|
+
return this.request("PUT", `/api/v1/projects/${projectId}/business-context`, { projectId, name });
|
|
42895
42895
|
}
|
|
42896
|
-
|
|
42897
|
-
return this.request("
|
|
42896
|
+
listVoiceSources(projectId) {
|
|
42897
|
+
return this.request("GET", `/api/v1/projects/${projectId}/voice-sources`);
|
|
42898
42898
|
}
|
|
42899
|
-
|
|
42900
|
-
return this.request("
|
|
42899
|
+
collectVoiceSource(projectId, channel, opts) {
|
|
42900
|
+
return this.request("POST", "/api/v1/business-context/collect-voice-source", { projectId, channel, ...opts });
|
|
42901
42901
|
}
|
|
42902
|
-
|
|
42903
|
-
return this.request("POST", "/api/v1/business-context/
|
|
42902
|
+
removeVoiceSource(projectId, channel, opts = {}) {
|
|
42903
|
+
return this.request("POST", "/api/v1/business-context/remove-voice-source", { projectId, channel, ...opts });
|
|
42904
42904
|
}
|
|
42905
|
-
|
|
42906
|
-
return this.request("POST", "/api/v1/business-context/
|
|
42907
|
-
}
|
|
42908
|
-
refineBrandVoice(businessContextId, answers, source, correction) {
|
|
42909
|
-
return this.request("POST", "/api/v1/business-context/refine-brand-voice", { businessContextId, answers, ...source && { source }, ...correction && { correction } });
|
|
42905
|
+
refineBrandVoice(projectId, source, correction) {
|
|
42906
|
+
return this.request("POST", "/api/v1/business-context/refine-brand-voice", { projectId, ...source && { source }, ...correction && { correction } });
|
|
42910
42907
|
}
|
|
42911
42908
|
getProfile() {
|
|
42912
42909
|
return this.request("GET", "/api/v1/users/profile");
|
|
@@ -42926,6 +42923,15 @@ class ApiClient {
|
|
|
42926
42923
|
upsertProjectGroup(projectId, slug, fields) {
|
|
42927
42924
|
return this.request("PUT", `/api/v1/projects/${projectId}/groups/${encodeURIComponent(slug)}`, { projectId, slug, ...fields });
|
|
42928
42925
|
}
|
|
42926
|
+
listProjectSurfaces(projectId) {
|
|
42927
|
+
return this.request("GET", `/api/v1/projects/${projectId}/surfaces`);
|
|
42928
|
+
}
|
|
42929
|
+
upsertProjectSurface(projectId, surfaceId, fields) {
|
|
42930
|
+
return this.request("PUT", `/api/v1/projects/${projectId}/surfaces/${encodeURIComponent(surfaceId)}`, { projectId, surfaceId, ...fields });
|
|
42931
|
+
}
|
|
42932
|
+
deleteProjectSurface(projectId, surfaceId) {
|
|
42933
|
+
return this.request("DELETE", `/api/v1/projects/${projectId}/surfaces/${encodeURIComponent(surfaceId)}`, { projectId, surfaceId });
|
|
42934
|
+
}
|
|
42929
42935
|
reorderProjectGroups(projectId, slugs) {
|
|
42930
42936
|
return this.request("PUT", `/api/v1/projects/${projectId}/groups-order`, { projectId, slugs });
|
|
42931
42937
|
}
|
|
@@ -43441,7 +43447,7 @@ var TodoStatus;
|
|
|
43441
43447
|
TodoStatus2["DELETED"] = "DELETED";
|
|
43442
43448
|
})(TodoStatus ||= {});
|
|
43443
43449
|
// ../packages/shared-fbe/src/models.ts
|
|
43444
|
-
var DEFAULT_MODEL = "anthropic:anthropic/claude-opus-5";
|
|
43450
|
+
var DEFAULT_MODEL = "anthropic:anthropic/claude-opus-5.5";
|
|
43445
43451
|
var MODEL_ALIASES = {
|
|
43446
43452
|
claude: DEFAULT_MODEL
|
|
43447
43453
|
};
|
|
@@ -43729,8 +43735,11 @@ var SERVER_TO_FRONTENDS = {
|
|
|
43729
43735
|
hexGrid: {
|
|
43730
43736
|
updated: (projectId) => `${"hexgrid:updated" /* HEXGRID_UPDATED */}:${projectId}`
|
|
43731
43737
|
},
|
|
43738
|
+
surfaces: {
|
|
43739
|
+
updated: (projectId) => `${"project:surfaces_updated" /* PROJECT_SURFACES_UPDATED */}:${projectId}`
|
|
43740
|
+
},
|
|
43732
43741
|
killSwitch: {
|
|
43733
|
-
changed: (projectId) => `${"project:kill_switch" /* KILL_SWITCH */}:${projectId}`
|
|
43742
|
+
changed: (projectId, userId) => `${"project:kill_switch" /* KILL_SWITCH */}:${projectId}${privateSuffix(userId)}`
|
|
43734
43743
|
},
|
|
43735
43744
|
sandbox: {
|
|
43736
43745
|
state: (userId) => `${"sandbox:state" /* SANDBOX_STATE */}:${userId}`
|
|
@@ -44342,6 +44351,8 @@ var model_promos_default = {
|
|
|
44342
44351
|
{ family: "gpt-5-5(-pro)?", rate: 0.8, starts: "2026-09-14", ends: "2026-11-21" },
|
|
44343
44352
|
{ family: "gpt-5-6-sol", rate: 0.85, starts: "2026-08-26", ends: "2026-09-13" },
|
|
44344
44353
|
{ family: "gpt-5-6-sol", rate: 0.8, starts: "2026-09-14", ends: "2026-11-21" },
|
|
44354
|
+
{ family: "gpt-6-sol", rate: 0.8, starts: "2026-09-22", ends: "2026-11-21" },
|
|
44355
|
+
{ family: "gpt-6-luna", rate: 0.8, starts: "2026-09-22", ends: "2026-11-21" },
|
|
44345
44356
|
{ family: "gpt-6-astra", rate: 0.85, starts: "2026-09-05", ends: "2026-09-13", boostable: false },
|
|
44346
44357
|
{ family: "gpt-6-astra", rate: 0.8, starts: "2026-09-14", ends: "2026-11-21", boostable: false },
|
|
44347
44358
|
{ family: "gpt-5-6-terra", rate: 0.85, starts: "2026-06-29", ends: "2026-09-13" },
|
|
@@ -44393,8 +44404,12 @@ var TOPICS = {
|
|
|
44393
44404
|
channel: (p) => SERVER_TO_FRONTENDS.hexGrid.updated(p.projectId),
|
|
44394
44405
|
audience: "frontend"
|
|
44395
44406
|
},
|
|
44407
|
+
["project:surfaces_updated" /* PROJECT_SURFACES_UPDATED */]: {
|
|
44408
|
+
channel: (p) => SERVER_TO_FRONTENDS.surfaces.updated(p.projectId),
|
|
44409
|
+
audience: "frontend"
|
|
44410
|
+
},
|
|
44396
44411
|
["project:kill_switch" /* KILL_SWITCH */]: {
|
|
44397
|
-
channel: (p) => SERVER_TO_FRONTENDS.killSwitch.changed(p.projectId),
|
|
44412
|
+
channel: (p) => SERVER_TO_FRONTENDS.killSwitch.changed(p.projectId, p.userId),
|
|
44398
44413
|
audience: "frontend"
|
|
44399
44414
|
},
|
|
44400
44415
|
["sandbox:state" /* SANDBOX_STATE */]: {
|
|
@@ -44533,7 +44548,7 @@ import { parseArgs } from "util";
|
|
|
44533
44548
|
// package.json
|
|
44534
44549
|
var package_default = {
|
|
44535
44550
|
name: "@todoforai/cli",
|
|
44536
|
-
version: "0.1.
|
|
44551
|
+
version: "0.1.52",
|
|
44537
44552
|
type: "module",
|
|
44538
44553
|
bin: {
|
|
44539
44554
|
"todoforai-cli": "bin/todoforai-cli.js",
|
|
@@ -44591,7 +44606,7 @@ Examples:
|
|
|
44591
44606
|
tfa-cli agent list|get|update|create … # Agents (update <agent> model=…)
|
|
44592
44607
|
tfa-cli todo set <todo-id|-> title=… group=… star=true # Edit a todo's fields
|
|
44593
44608
|
tfa-cli project list|set|settings|groups|default|agent … # Projects; edit the current one
|
|
44594
|
-
tfa-cli brand
|
|
44609
|
+
tfa-cli brand [show|create|rename|voice …] # The project's brand page + voice learning
|
|
44595
44610
|
tfa-cli device list|rename|wallpaper … # Paired machines
|
|
44596
44611
|
tfa-cli list [-n 30] [--cursor N] [--all] [--status S] # List todos (paginated)
|
|
44597
44612
|
tfa-cli status <todo-id> <STATUS> # Update a todo's status
|
|
@@ -44708,8 +44723,6 @@ function parseCliArgs() {
|
|
|
44708
44723
|
card: { type: "string" },
|
|
44709
44724
|
link: { type: "boolean", default: false },
|
|
44710
44725
|
direction: { type: "string" },
|
|
44711
|
-
"business-context": { type: "string" },
|
|
44712
|
-
brand: { type: "string" },
|
|
44713
44726
|
url: { type: "string" },
|
|
44714
44727
|
"pasted-file": { type: "string" },
|
|
44715
44728
|
"from-company": { type: "boolean", default: false },
|
|
@@ -47823,7 +47836,6 @@ Fields (PUT /todos/{id}):
|
|
|
47823
47836
|
star true|false (starredAt now / 0)
|
|
47824
47837
|
schedule unix ms timestamp, 0 = immediate (alias: scheduledTimestamp)
|
|
47825
47838
|
agent agentSettingsId (alias: agentSettingsId)
|
|
47826
|
-
brand businessContextId (alias: businessContextId)
|
|
47827
47839
|
public true|false — refused from an agent shell (isPublic)
|
|
47828
47840
|
|
|
47829
47841
|
tfa-cli todo message <todo-id|-> <message-id> <field=value>…
|
|
@@ -47845,7 +47857,7 @@ tfa-cli project — edit the current project
|
|
|
47845
47857
|
|
|
47846
47858
|
Usage:
|
|
47847
47859
|
tfa-cli project list Projects you can access (* = default)
|
|
47848
|
-
tfa-cli project set <field=value>… name=… description=…
|
|
47860
|
+
tfa-cli project set <field=value>… name=… description=…
|
|
47849
47861
|
(isPublic refused from an agent shell)
|
|
47850
47862
|
tfa-cli project default Make it the project you land on at /
|
|
47851
47863
|
tfa-cli project agent <agent> Default agent for new todos in this project
|
|
@@ -47853,11 +47865,18 @@ Usage:
|
|
|
47853
47865
|
tfa-cli project groups List todo groups
|
|
47854
47866
|
tfa-cli project groups set <slug> <field=value>… Create/update a group: name description pinned archived order
|
|
47855
47867
|
tfa-cli project groups reorder <slug>… Set wall order
|
|
47868
|
+
tfa-cli project surfaces List the board's card surfaces (live refs shown as cards)
|
|
47869
|
+
tfa-cli project surfaces set <id> ref=<ref> [title=…] [group=<slug>] [order=N]
|
|
47870
|
+
Show a ref on the board: a todo id, <todoId>:<alias>
|
|
47871
|
+
(shown artifact) or an http(s) url. group= puts it
|
|
47872
|
+
inside that group's card; group="" makes it standalone.
|
|
47873
|
+
tfa-cli project surfaces rm <id> Take it off the board
|
|
47856
47874
|
|
|
47857
47875
|
Examples:
|
|
47858
47876
|
tfa-cli project set name="Q4 launch"
|
|
47859
47877
|
tfa-cli project groups set marketing name=Marketing description="Top-of-funnel work"
|
|
47860
47878
|
tfa-cli project groups reorder marketing sales ops
|
|
47879
|
+
tfa-cli project surfaces set weekly-kpis ref=$TODOFORAI_TODO_ID:kpi title="Weekly KPIs" group=marketing
|
|
47861
47880
|
`);
|
|
47862
47881
|
}
|
|
47863
47882
|
var TODO_ALIASES = {
|
|
@@ -47865,10 +47884,9 @@ var TODO_ALIASES = {
|
|
|
47865
47884
|
group: "groupTag",
|
|
47866
47885
|
schedule: "scheduledTimestamp",
|
|
47867
47886
|
agent: "agentSettingsId",
|
|
47868
|
-
brand: "businessContextId",
|
|
47869
47887
|
public: "isPublic"
|
|
47870
47888
|
};
|
|
47871
|
-
var PROJECT_ALIASES = {
|
|
47889
|
+
var PROJECT_ALIASES = {};
|
|
47872
47890
|
function fail(msg) {
|
|
47873
47891
|
process.stderr.write(`${RED}${msg}${RESET}
|
|
47874
47892
|
`);
|
|
@@ -48010,22 +48028,58 @@ async function projectCommand(api, positionals, args) {
|
|
|
48010
48028
|
}
|
|
48011
48029
|
fail(`Unknown 'project groups' verb: ${verb}`);
|
|
48012
48030
|
}
|
|
48031
|
+
if (sub === "surfaces") {
|
|
48032
|
+
const [verb, ...sargs] = rest;
|
|
48033
|
+
if (!verb) {
|
|
48034
|
+
const surfaces = await api.listProjectSurfaces(projectId);
|
|
48035
|
+
if (args.json) {
|
|
48036
|
+
console.log(JSON.stringify(surfaces, null, 2));
|
|
48037
|
+
return;
|
|
48038
|
+
}
|
|
48039
|
+
for (const s of surfaces)
|
|
48040
|
+
process.stderr.write(`${s.id} ${s.ref} ${DIM}${[s.title, s.group && `in ${s.group}`].filter(Boolean).join(" ")}${RESET}
|
|
48041
|
+
`);
|
|
48042
|
+
return;
|
|
48043
|
+
}
|
|
48044
|
+
if (verb === "set") {
|
|
48045
|
+
const [id, ...fields] = sargs;
|
|
48046
|
+
if (!id)
|
|
48047
|
+
fail("Usage: tfa-cli project surfaces set <id> ref=<ref> [title=…] [group=<slug>] [order=N]");
|
|
48048
|
+
const surface = await api.upsertProjectSurface(projectId, id, parseAssignments2(fields));
|
|
48049
|
+
if (args.json) {
|
|
48050
|
+
console.log(JSON.stringify(surface, null, 2));
|
|
48051
|
+
return;
|
|
48052
|
+
}
|
|
48053
|
+
process.stderr.write(`${GREEN}✅ surface ${id} shows ${surface.ref}${surface.group ? ` in ${surface.group}` : ""}${RESET}
|
|
48054
|
+
`);
|
|
48055
|
+
return;
|
|
48056
|
+
}
|
|
48057
|
+
if (verb === "rm") {
|
|
48058
|
+
const [id] = sargs;
|
|
48059
|
+
if (!id)
|
|
48060
|
+
fail("Usage: tfa-cli project surfaces rm <id>");
|
|
48061
|
+
await api.deleteProjectSurface(projectId, id);
|
|
48062
|
+
process.stderr.write(`${GREEN}✅ surface ${id} removed${RESET}
|
|
48063
|
+
`);
|
|
48064
|
+
return;
|
|
48065
|
+
}
|
|
48066
|
+
fail(`Unknown 'project surfaces' verb: ${verb}`);
|
|
48067
|
+
}
|
|
48013
48068
|
fail(`Unknown 'project' subcommand: ${sub}`);
|
|
48014
48069
|
}
|
|
48015
48070
|
function printBrandHelp() {
|
|
48016
48071
|
process.stderr.write(`
|
|
48017
|
-
tfa-cli brand —
|
|
48072
|
+
tfa-cli brand — the project's brand page and its learned writing voice
|
|
48018
48073
|
|
|
48074
|
+
The project IS the brand. --project <id> or $TODOFORAI_PROJECT_ID selects it.
|
|
48019
48075
|
The brand page text itself is a file: read/write todoforai:business-context.
|
|
48020
|
-
These commands manage the contexts and the voice learned for them.
|
|
48021
48076
|
|
|
48022
48077
|
Usage:
|
|
48023
|
-
tfa-cli brand
|
|
48024
|
-
tfa-cli brand create <name>
|
|
48025
|
-
tfa-cli brand rename <
|
|
48026
|
-
tfa-cli brand select <brand|none> Active brand for the account
|
|
48078
|
+
tfa-cli brand [show] This project's brand (none = personal board)
|
|
48079
|
+
tfa-cli brand create <name> Give the project a brand page (empty .md); the board turns business
|
|
48080
|
+
tfa-cli brand rename <name>
|
|
48027
48081
|
tfa-cli brand voice Learned profile + sources
|
|
48028
|
-
tfa-cli brand voice answers [<q>=<a>…] Show / set the
|
|
48082
|
+
tfa-cli brand voice answers [<q>=<a>…] Show / set the Manual source: answers to the style questions
|
|
48029
48083
|
tfa-cli brand voice collect <channel> [--url U | --pasted-file <F|-> | --max N]
|
|
48030
48084
|
Add a writing sample source.
|
|
48031
48085
|
On this device (signed-in CLI, reply pairs):
|
|
@@ -48039,9 +48093,7 @@ Usage:
|
|
|
48039
48093
|
tfa-cli brand voice correct "<what is off>" Tell the learner what it got wrong; profile is updated
|
|
48040
48094
|
in one pass and the correction is kept for every re-learn
|
|
48041
48095
|
|
|
48042
|
-
|
|
48043
|
-
selected brand unless --brand <id|name> is given (--pasted-file - reads stdin).
|
|
48044
|
-
Delete / reset are UI-only.
|
|
48096
|
+
--pasted-file - reads stdin. Delete is UI-only.
|
|
48045
48097
|
|
|
48046
48098
|
Questions the UI asks (keys for 'answers'):
|
|
48047
48099
|
"What makes you different from competitors?"
|
|
@@ -48049,43 +48101,30 @@ Questions the UI asks (keys for 'answers'):
|
|
|
48049
48101
|
"A frustrated customer says things aren't working. How do you reply?"
|
|
48050
48102
|
`);
|
|
48051
48103
|
}
|
|
48052
|
-
|
|
48053
|
-
const
|
|
48054
|
-
if (!
|
|
48055
|
-
|
|
48056
|
-
|
|
48057
|
-
return sel;
|
|
48058
|
-
if (contexts.length === 1)
|
|
48059
|
-
return contexts[0];
|
|
48060
|
-
fail("No brand selected — pass --brand <id|name> or 'tfa-cli brand select'");
|
|
48061
|
-
}
|
|
48062
|
-
const q = query.toLowerCase();
|
|
48063
|
-
const exact = contexts.find((c3) => c3.id === query || c3.name.toLowerCase() === q);
|
|
48064
|
-
if (exact)
|
|
48065
|
-
return exact;
|
|
48066
|
-
const partial = contexts.filter((c3) => c3.id.startsWith(query) || c3.name.toLowerCase().includes(q));
|
|
48067
|
-
if (partial.length === 1)
|
|
48068
|
-
return partial[0];
|
|
48069
|
-
fail(partial.length ? `Ambiguous brand '${query}'` : `No brand matching '${query}'`);
|
|
48104
|
+
function requireProject(args) {
|
|
48105
|
+
const projectId = args.project || getEnv2("PROJECT_ID");
|
|
48106
|
+
if (!projectId)
|
|
48107
|
+
fail("No project — pass --project <id> or set TODOFORAI_PROJECT_ID");
|
|
48108
|
+
return projectId;
|
|
48070
48109
|
}
|
|
48071
48110
|
async function brandCommand(api, positionals, args) {
|
|
48072
48111
|
const [, sub, ...rest] = positionals;
|
|
48073
|
-
|
|
48074
|
-
|
|
48075
|
-
const
|
|
48112
|
+
const projectId = requireProject(args);
|
|
48113
|
+
if (!sub || sub === "show") {
|
|
48114
|
+
const brand = await api.getBusinessContext(projectId);
|
|
48076
48115
|
if (args.json) {
|
|
48077
|
-
console.log(JSON.stringify(
|
|
48116
|
+
console.log(JSON.stringify(brand, null, 2));
|
|
48078
48117
|
return;
|
|
48079
48118
|
}
|
|
48080
|
-
|
|
48081
|
-
|
|
48119
|
+
process.stderr.write(brand ? `${brand.name} ${DIM}${brand.id}${RESET}
|
|
48120
|
+
` : `${DIM}(personal board — no brand)${RESET}
|
|
48082
48121
|
`);
|
|
48083
48122
|
return;
|
|
48084
48123
|
}
|
|
48085
48124
|
if (sub === "create") {
|
|
48086
48125
|
if (!rest[0])
|
|
48087
48126
|
fail("Usage: tfa-cli brand create <name>");
|
|
48088
|
-
const c3 = await api.createBusinessContext(rest[0]);
|
|
48127
|
+
const c3 = await api.createBusinessContext(projectId, rest[0]);
|
|
48089
48128
|
if (args.json) {
|
|
48090
48129
|
console.log(JSON.stringify(c3, null, 2));
|
|
48091
48130
|
return;
|
|
@@ -48095,25 +48134,15 @@ async function brandCommand(api, positionals, args) {
|
|
|
48095
48134
|
return;
|
|
48096
48135
|
}
|
|
48097
48136
|
if (sub === "rename") {
|
|
48098
|
-
if (!rest[1])
|
|
48099
|
-
fail("Usage: tfa-cli brand rename <brand> <name>");
|
|
48100
|
-
const c3 = await resolveBrand(api, rest[0]);
|
|
48101
|
-
await api.renameBusinessContext(c3.id, rest[1]);
|
|
48102
|
-
process.stderr.write(`${GREEN}✅ renamed to ${rest[1]}${RESET}
|
|
48103
|
-
`);
|
|
48104
|
-
return;
|
|
48105
|
-
}
|
|
48106
|
-
if (sub === "select") {
|
|
48107
48137
|
if (!rest[0])
|
|
48108
|
-
fail("Usage: tfa-cli brand
|
|
48109
|
-
|
|
48110
|
-
|
|
48111
|
-
process.stderr.write(`${GREEN}✅ selected brand: ${id ?? "none"}${RESET}
|
|
48138
|
+
fail("Usage: tfa-cli brand rename <name>");
|
|
48139
|
+
await api.renameBusinessContext(projectId, rest[0]);
|
|
48140
|
+
process.stderr.write(`${GREEN}✅ renamed to ${rest[0]}${RESET}
|
|
48112
48141
|
`);
|
|
48113
48142
|
return;
|
|
48114
48143
|
}
|
|
48115
48144
|
if (sub === "voice")
|
|
48116
|
-
return voiceCommand(api, rest, args);
|
|
48145
|
+
return voiceCommand(api, projectId, rest, args);
|
|
48117
48146
|
fail(`Unknown 'brand' subcommand: ${sub}`);
|
|
48118
48147
|
}
|
|
48119
48148
|
function dryCollect(channel, max) {
|
|
@@ -48167,26 +48196,30 @@ async function voiceDeviceCommand(rest, args) {
|
|
|
48167
48196
|
}
|
|
48168
48197
|
return false;
|
|
48169
48198
|
}
|
|
48170
|
-
async function voiceCommand(api, rest, args) {
|
|
48199
|
+
async function voiceCommand(api, projectId, rest, args) {
|
|
48171
48200
|
const [verb, ...vargs] = rest;
|
|
48172
48201
|
if (verb === "collect" && !vargs[0])
|
|
48173
|
-
fail("Usage: tfa-cli brand voice collect <channel> [--url U | --pasted-file F|- | --max N] [--dry-run]");
|
|
48174
|
-
const
|
|
48202
|
+
fail("Usage: tfa-cli brand voice collect <channel> [--url U | --pasted-file F|- | --account <page-id> | --max N] [--dry-run]");
|
|
48203
|
+
const brand = await api.getBusinessContext(projectId);
|
|
48204
|
+
if (!brand)
|
|
48205
|
+
fail("This project has no brand — 'tfa-cli brand create <name>' first");
|
|
48175
48206
|
if (verb === "answers") {
|
|
48207
|
+
const { sources } = await api.listVoiceSources(projectId);
|
|
48208
|
+
const manual = sources.find((s) => s.channel === "Manual");
|
|
48209
|
+
const answers = Object.fromEntries((manual?.items ?? []).filter((x) => x?.prompt).map((x) => [x.prompt, x.text]));
|
|
48176
48210
|
if (vargs.length) {
|
|
48177
|
-
const
|
|
48211
|
+
for (const a of vargs) {
|
|
48178
48212
|
const i = a.indexOf("=");
|
|
48179
48213
|
if (i < 1)
|
|
48180
48214
|
fail(`Expected question=answer, got '${a}'`);
|
|
48181
|
-
|
|
48182
|
-
}
|
|
48183
|
-
const
|
|
48184
|
-
await api.
|
|
48215
|
+
answers[a.slice(0, i)] = a.slice(i + 1);
|
|
48216
|
+
}
|
|
48217
|
+
const samples = Object.entries(answers).filter(([, t]) => t.trim()).map(([prompt, text]) => ({ prompt, text }));
|
|
48218
|
+
await api.collectVoiceSource(projectId, "Manual", { samples });
|
|
48185
48219
|
process.stderr.write(`${GREEN}✅ ${vargs.length} answer(s) saved${RESET}
|
|
48186
48220
|
`);
|
|
48187
48221
|
return;
|
|
48188
48222
|
}
|
|
48189
|
-
const answers = onboarding.styleAnswers ?? {};
|
|
48190
48223
|
if (args.json) {
|
|
48191
48224
|
console.log(JSON.stringify(answers, null, 2));
|
|
48192
48225
|
return;
|
|
@@ -48197,10 +48230,8 @@ async function voiceCommand(api, rest, args) {
|
|
|
48197
48230
|
`);
|
|
48198
48231
|
return;
|
|
48199
48232
|
}
|
|
48200
|
-
const brand = await resolveBrand(api, args.brand, (await api.getProfile()).user?.selectedBusinessContextId);
|
|
48201
48233
|
if (!verb || verb === "show") {
|
|
48202
|
-
const profile =
|
|
48203
|
-
const { sources } = await api.listVoiceSources(brand.id);
|
|
48234
|
+
const { sources, profile } = await api.listVoiceSources(projectId);
|
|
48204
48235
|
if (args.json) {
|
|
48205
48236
|
console.log(JSON.stringify({ brand, profile, sources }, null, 2));
|
|
48206
48237
|
return;
|
|
@@ -48213,7 +48244,7 @@ ${DIM}match ${profile.match}/100 · source ${profile.source}${RESET}
|
|
|
48213
48244
|
` : `${DIM}(no voice learned yet)${RESET}
|
|
48214
48245
|
`);
|
|
48215
48246
|
for (const s of sources)
|
|
48216
|
-
process.stderr.write(` ${s.channel} ${DIM}${s.posts ?? "?"} posts · ${s.chars ?? "?"} chars${RESET}
|
|
48247
|
+
process.stderr.write(` ${s.channel}${s.account ? ` ${s.label} ${DIM}(${s.account})${RESET}` : ""} ${DIM}${s.posts ?? "?"} posts · ${s.chars ?? "?"} chars${RESET}
|
|
48217
48248
|
`);
|
|
48218
48249
|
return;
|
|
48219
48250
|
}
|
|
@@ -48234,20 +48265,20 @@ ${DIM}match ${profile.match}/100 · source ${profile.source}${RESET}
|
|
|
48234
48265
|
const { samples, note } = collectChannel(channel, Number(args.max ?? 40));
|
|
48235
48266
|
if (!samples.length)
|
|
48236
48267
|
fail(`${channel}: nothing usable came back${note ? ` (${note})` : ""}`);
|
|
48237
|
-
const { sources: sources2 } = await api.collectVoiceSource(
|
|
48268
|
+
const { sources: sources2 } = await api.collectVoiceSource(projectId, channel, { samples });
|
|
48238
48269
|
process.stderr.write(`${GREEN}✅ ${channel}: ${samples.length} reply pairs stored (${sources2.length} source(s))${RESET}
|
|
48239
48270
|
`);
|
|
48240
48271
|
return;
|
|
48241
48272
|
}
|
|
48242
|
-
const { sources } = await api.collectVoiceSource(
|
|
48273
|
+
const { sources } = await api.collectVoiceSource(projectId, channel, { url: args.url, pasted, account: args.account });
|
|
48243
48274
|
process.stderr.write(`${GREEN}✅ ${channel} collected (${sources.length} source(s))${RESET}
|
|
48244
48275
|
`);
|
|
48245
48276
|
return;
|
|
48246
48277
|
}
|
|
48247
48278
|
if (verb === "remove") {
|
|
48248
48279
|
if (!vargs[0])
|
|
48249
|
-
fail("Usage: tfa-cli brand voice remove <channel>");
|
|
48250
|
-
await api.removeVoiceSource(
|
|
48280
|
+
fail("Usage: tfa-cli brand voice remove <channel> [--account <id>] (no --account: every source of the channel)");
|
|
48281
|
+
await api.removeVoiceSource(projectId, vargs[0], args.account ? { account: args.account } : { all: true });
|
|
48251
48282
|
process.stderr.write(`${GREEN}✅ ${vargs[0]} removed${RESET}
|
|
48252
48283
|
`);
|
|
48253
48284
|
return;
|
|
@@ -48255,14 +48286,9 @@ ${DIM}match ${profile.match}/100 · source ${profile.source}${RESET}
|
|
|
48255
48286
|
if (verb === "learn") {
|
|
48256
48287
|
process.stderr.write(`${DIM}learning voice for ${brand.name}…${RESET}
|
|
48257
48288
|
`);
|
|
48258
|
-
const res = await api.refineBrandVoice(
|
|
48289
|
+
const res = await api.refineBrandVoice(projectId, args["from-company"] ? "company" : undefined);
|
|
48259
48290
|
if (!res.profile)
|
|
48260
48291
|
fail("Nothing to learn from — add answers or collect a source first");
|
|
48261
|
-
const { [brand.id]: _stale, ...styleAiAnswers } = onboarding.styleAiAnswers ?? {};
|
|
48262
|
-
await api.patchOnboarding({
|
|
48263
|
-
voiceProfiles: { ...onboarding.voiceProfiles ?? {}, [brand.id]: { ...res, updatedAt: Date.now() } },
|
|
48264
|
-
styleAiAnswers
|
|
48265
|
-
});
|
|
48266
48292
|
if (args.json) {
|
|
48267
48293
|
console.log(JSON.stringify(res, null, 2));
|
|
48268
48294
|
return;
|
|
@@ -48276,16 +48302,13 @@ ${res.profile}
|
|
|
48276
48302
|
const text = vargs.join(" ").trim();
|
|
48277
48303
|
if (!text)
|
|
48278
48304
|
fail('Usage: tfa-cli brand voice correct "<what is off>"');
|
|
48279
|
-
|
|
48280
|
-
if (!stored?.profile)
|
|
48305
|
+
if (!(await api.listVoiceSources(projectId)).profile?.profile)
|
|
48281
48306
|
fail("No voice learned yet — 'tfa-cli brand voice learn' first");
|
|
48282
48307
|
process.stderr.write(`${DIM}applying correction…${RESET}
|
|
48283
48308
|
`);
|
|
48284
|
-
const res = await api.refineBrandVoice(
|
|
48309
|
+
const res = await api.refineBrandVoice(projectId, undefined, text);
|
|
48285
48310
|
if (!res.profile)
|
|
48286
48311
|
fail("The correction pass returned nothing — try rewording it");
|
|
48287
|
-
const { [brand.id]: _stale, ...styleAiAnswers } = onboarding.styleAiAnswers ?? {};
|
|
48288
|
-
await api.patchOnboarding({ voiceProfiles: { ...onboarding.voiceProfiles ?? {}, [brand.id]: { ...res, updatedAt: Date.now() } }, styleAiAnswers });
|
|
48289
48312
|
if (args.json) {
|
|
48290
48313
|
console.log(JSON.stringify(res, null, 2));
|
|
48291
48314
|
return;
|
|
@@ -69765,6 +69788,22 @@ var zUsageUpdate = object({
|
|
|
69765
69788
|
return;
|
|
69766
69789
|
})
|
|
69767
69790
|
});
|
|
69791
|
+
var zNoticeSeverity = union([
|
|
69792
|
+
literal("info"),
|
|
69793
|
+
literal("warning"),
|
|
69794
|
+
literal("error"),
|
|
69795
|
+
string2()
|
|
69796
|
+
]);
|
|
69797
|
+
var zNotice = object({
|
|
69798
|
+
severity: zNoticeSeverity,
|
|
69799
|
+
title: string2().min(1),
|
|
69800
|
+
description: defaultOnError(string2().nullish(), () => {
|
|
69801
|
+
return;
|
|
69802
|
+
}),
|
|
69803
|
+
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
69804
|
+
return;
|
|
69805
|
+
})
|
|
69806
|
+
});
|
|
69768
69807
|
var zCompactionId = string2();
|
|
69769
69808
|
var zCompactionStatus = union([
|
|
69770
69809
|
literal("in_progress"),
|
|
@@ -69833,6 +69872,9 @@ var zSessionUpdate = union([
|
|
|
69833
69872
|
zUsageUpdate.and(object({
|
|
69834
69873
|
sessionUpdate: literal("usage_update")
|
|
69835
69874
|
})),
|
|
69875
|
+
zNotice.and(object({
|
|
69876
|
+
sessionUpdate: literal("notice")
|
|
69877
|
+
})),
|
|
69836
69878
|
zCompactionUpdate.and(object({
|
|
69837
69879
|
sessionUpdate: literal("compaction_update")
|
|
69838
69880
|
})),
|
|
@@ -69894,6 +69936,7 @@ var zSessionConfigOptionsCapabilities = object({
|
|
|
69894
69936
|
return;
|
|
69895
69937
|
})
|
|
69896
69938
|
});
|
|
69939
|
+
var zNoticeCapabilities = record(string2(), unknown());
|
|
69897
69940
|
var zClientSessionCapabilities = object({
|
|
69898
69941
|
compaction: defaultOnError(zCompactionCapabilities.nullish(), () => {
|
|
69899
69942
|
return;
|
|
@@ -69901,6 +69944,9 @@ var zClientSessionCapabilities = object({
|
|
|
69901
69944
|
configOptions: defaultOnError(zSessionConfigOptionsCapabilities.nullish(), () => {
|
|
69902
69945
|
return;
|
|
69903
69946
|
}),
|
|
69947
|
+
notices: defaultOnError(zNoticeCapabilities.nullish(), () => {
|
|
69948
|
+
return;
|
|
69949
|
+
}),
|
|
69904
69950
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
69905
69951
|
return;
|
|
69906
69952
|
})
|
|
@@ -73299,7 +73345,6 @@ Cancelled by user (Ctrl+C)
|
|
|
73299
73345
|
...args.title ? { title: args.title } : {},
|
|
73300
73346
|
...args.note ? { note: args.note } : {},
|
|
73301
73347
|
...priority ? { priority } : {},
|
|
73302
|
-
...args["business-context"] ? { businessContextId: args["business-context"] } : {},
|
|
73303
73348
|
...args.group ? { group: args.group } : {},
|
|
73304
73349
|
...args["group-name"] ? { groupName: args["group-name"] } : {},
|
|
73305
73350
|
...args["group-description"] ? { groupDescription: args["group-description"] } : {}
|
|
@@ -73368,7 +73413,7 @@ Cancelled by user (Ctrl+C)
|
|
|
73368
73413
|
const res = await fetch(`${apiUrl}${restBasePath(apiKey)}/projects/${projectId2}/recommendations/generate`, {
|
|
73369
73414
|
method: "POST",
|
|
73370
73415
|
headers: { "content-type": "application/json", "x-api-key": apiKey },
|
|
73371
|
-
body: JSON.stringify({ projectId: projectId2, ...
|
|
73416
|
+
body: JSON.stringify({ projectId: projectId2, ...direction ? { direction } : {} }),
|
|
73372
73417
|
signal: AbortSignal.timeout(30000)
|
|
73373
73418
|
});
|
|
73374
73419
|
const text = await res.text();
|