@flowapt/flowiq-cli 0.12.3 → 0.12.4

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 CHANGED
@@ -1310,6 +1310,12 @@ flowiq report deck build <org_id> 2026-08 --refresh # metrics only; statu
1310
1310
  flowiq report deck narrate <org_id> 2026-08 # copy only (hand edits are kept)
1311
1311
  flowiq report deck narrate <org_id> 2026-08 --only changes,action_points # rewrite just these copy fields, keep the rest as written
1312
1312
  flowiq report deck check <org_id> 2026-08 # fact-check the copy as shown (hand edits too) against the figures; rewrites nothing
1313
+ flowiq report deck dismiss <org_id> 2026-08 honest_read --note "stands" # keep a flagged sentence as written (recorded)
1314
+ flowiq report deck edit <org_id> 2026-08 honest_read --text "…" # hand-edit one copy field (--clear restores the generated text)
1315
+ flowiq report config <org_id> # the org's report settings
1316
+ flowiq report config <org_id> --set deck.org_type='"non_store"' --set deck.outcome='{"source":"handover","label_singular":"request","label_plural":"requests"}'
1317
+ # settings: deck.org_type, deck.outcome (handover | ticket_status | keyword | tag | link_click), deck.entry_points (in-store QR / ad pre-fills),
1318
+ # deck.agent_display_name, deck.client_display_name, deck.go_live_month, report.email.recipients
1313
1319
  flowiq report deck inputs <org_id> 2026-08 --file inputs.json # the super-admin input form
1314
1320
  flowiq report deck approve <org_id> 2026-08 # refused until every required input is present
1315
1321
  flowiq report deck send <org_id> 2026-08 --test-to me@flowapt.com # one test copy, status untouched
package/TEAM-GUIDE.md CHANGED
@@ -275,6 +275,9 @@ several.
275
275
  | See whether a client deck can be approved, and what is still missing | `flowiq report deck status <org_id> 2026-08` |
276
276
  | Rewrite one part of a deck's copy without touching the rest (e.g. the changes column and action points) | `flowiq report deck narrate <org_id> 2026-08 --only changes,suggested_updates,action_points` |
277
277
  | Check a deck's wording against its figures before it goes out (e.g. a heading that says a group "leads" when it does not) | `flowiq report deck check <org_id> 2026-08` — lists each unsupported statement with a fix; rewrites nothing |
278
+ | A fact-check flag is wrong and the sentence should stay | `flowiq report deck dismiss <org_id> 2026-08 <field> --note "why"` (or Inputs → Fact check → Keep as written) |
279
+ | Change the wording of one part of a deck from the terminal | `flowiq report deck edit <org_id> 2026-08 <field> --text "…"` (`--clear` puts the generated text back) |
280
+ | See or change a client's report settings (in-person "win", till QR codes, recipients, names) | `flowiq report config <org_id>` to see; `--set deck.outcome='{…}'`, `--set deck.entry_points='[…]'`, `--set report.email.recipients='["a@b.co"]'` to change |
278
281
  | Send yourself a test copy of a client deck (PDF from flowiq@flowapt.com) | `flowiq report deck send <org_id> 2026-08 --test-to you@flowapt.com` — status untouched |
279
282
  | Take a tile, pill or card off a client deck (and its PDF) for one month | On `/reporting/deck` open **Inputs** (the rail beside the slides) → Show or hide; or `flowiq report deck inputs <org_id> 2026-08 --file inputs.json` with `{ "hidden": { "tile:tail": true } }` |
280
283
  | Approve a client deck / send it to the client | `flowiq report deck approve <org_id> 2026-08` then `… send … --client` (or let the 09:00 SAST schedule send it on the 5th) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowapt/flowiq-cli",
3
- "version": "0.12.3",
3
+ "version": "0.12.4",
4
4
  "description": "Command-line tool for FlowIQ staff: round-trip agent prompts, questionnaires, fine-tuning, pin-board tasks, webhooks, templates, agent-updates, chat exports, and live agent testing without ever touching service-role credentials.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -95,6 +95,48 @@ function printClaims(issues) {
95
95
  for (const i of issues) console.log(` ${i.path}: "${i.quote}" (${i.why}) → ${i.fix}`);
96
96
  }
97
97
 
98
+ export async function config(orgId, opts) {
99
+ if (!orgId) { console.error("Give the organization id."); process.exit(1); }
100
+ const pairs = opts.set ?? [];
101
+ let r;
102
+ try {
103
+ if (!pairs.length) r = await http.get("report", { organization_id: orgId, config: 1 });
104
+ else {
105
+ const set = {};
106
+ for (const p of pairs) {
107
+ const i = p.indexOf("=");
108
+ if (i < 1) { console.error(`--set needs path=value (got "${p}")`); process.exit(1); }
109
+ const raw = p.slice(i + 1);
110
+ let v; try { v = JSON.parse(raw); } catch { v = raw; }
111
+ set[p.slice(0, i)] = v;
112
+ }
113
+ if (opts.dryRun) { console.log(JSON.stringify({ would_set: set }, null, 2)); return; }
114
+ r = await http.post("report", { organization_id: orgId, action: "config_set", set });
115
+ }
116
+ } catch (e) { console.error(`Config failed: ${e.message}`); process.exit(1); }
117
+ if (opts.json) { console.log(JSON.stringify(r, null, 2)); return; }
118
+ if (r.before) for (const [k, v] of Object.entries(r.after)) console.log(`${k}: ${JSON.stringify(r.before[k])} → ${JSON.stringify(v)}`);
119
+ else for (const [k, v] of Object.entries(r.config)) console.log(`${k}: ${JSON.stringify(v)}`);
120
+ }
121
+
122
+ export async function dismiss(orgId, month, path, opts) {
123
+ requireArgs(orgId, month);
124
+ const r = await post("dismiss_claim", orgId, month, { path, ...(opts.quote ? { quote: opts.quote } : {}), ...(opts.note ? { note: opts.note } : {}) }, "Dismiss");
125
+ if (opts.json) { console.log(JSON.stringify(r, null, 2)); return; }
126
+ console.log(`Kept as written: ${r.dismissed} fact-check flag${r.dismissed === 1 ? "" : "s"} on ${path}`);
127
+ if (r.status) console.log(` status: ${r.status}${r.missing?.length ? ` · needed: ${r.missing.join(" · ")}` : ""}`);
128
+ }
129
+
130
+ export async function edit(orgId, month, path, opts) {
131
+ requireArgs(orgId, month);
132
+ const text = opts.clear ? "" : opts.text;
133
+ if (typeof text !== "string") { console.error("Give --text \"…\" (or --clear to put the generated wording back)."); process.exit(1); }
134
+ const r = await post("save_override", orgId, month, { path, text }, "Edit");
135
+ if (opts.json) { console.log(JSON.stringify(r, null, 2)); return; }
136
+ console.log(r.cleared ? `Generated wording restored on ${path}` : `Saved your wording on ${path}`);
137
+ if (r.status) console.log(` status: ${r.status}${r.missing?.length ? ` · needed: ${r.missing.join(" · ")}` : ""}`);
138
+ }
139
+
98
140
  export async function generate(orgId, month, opts) {
99
141
  requireArgs(orgId, month);
100
142
  const r = await post("generate", orgId, month, { refresh: !!opts.refresh, force: !!opts.force }, "Generate");
package/src/index.js CHANGED
@@ -365,7 +365,7 @@ export function run(argv) {
365
365
  .action((orgId, opts) => hoursCmd.packageClear(orgId, opts));
366
366
 
367
367
  // report deck — the monthly client deck (build / copy / approve / send)
368
- const report = program.command("report").description("Client reporting: the monthly 10-slide client deck");
368
+ const report = program.command("report").description("Client reporting: the monthly client deck (a cover and five slides) and its settings");
369
369
  const deck = report.command("deck").description("The monthly client deck for one org and month (/reporting/deck)");
370
370
  deck.command("status <organization_id> <month>")
371
371
  .description("What exists for the month, the workflow status and what still blocks approval")
@@ -385,6 +385,24 @@ export function run(argv) {
385
385
  .description("Fact-check the copy as the slides show it (hand edits included) against the month's figures; rewrites nothing")
386
386
  .option("--json", "raw JSON output")
387
387
  .action((orgId, month, opts) => reportCmd.check(orgId, month, opts));
388
+ report.command("config <organization_id>")
389
+ .description("Show or change an org's report settings: deck.org_type, deck.outcome, deck.entry_points, deck.agent_display_name, deck.client_display_name, deck.go_live_month, report.email.recipients")
390
+ .option("--set <path=json>", "a setting to change, JSON value (repeatable), e.g. --set deck.org_type='\"non_store\"'", (v, acc) => [...acc, v], [])
391
+ .option("--dry-run", "print what would be set")
392
+ .option("--json", "raw JSON output")
393
+ .action((orgId, opts) => reportCmd.config(orgId, opts));
394
+ deck.command("dismiss <organization_id> <month> <path>")
395
+ .description("Keep a sentence as written: drop the fact-check flag(s) on one copy field (who and when are recorded)")
396
+ .option("--quote <words>", "only the flag quoting these words (default: every open flag on the field)")
397
+ .option("--note <text>", "why it stands")
398
+ .option("--json", "raw JSON output")
399
+ .action((orgId, month, path, opts) => reportCmd.dismiss(orgId, month, path, opts));
400
+ deck.command("edit <organization_id> <month> <path>")
401
+ .description("Hand-edit one copy field (e.g. honest_read, plan.agent_upgrades); shows on the slide as an edit with your name")
402
+ .option("--text <text>", "the new wording")
403
+ .option("--clear", "put the generated wording back")
404
+ .option("--json", "raw JSON output")
405
+ .action((orgId, month, path, opts) => reportCmd.edit(orgId, month, path, opts));
388
406
  deck.command("generate <organization_id> <month>")
389
407
  .description("Build the metrics (if missing, or --refresh) and write the copy")
390
408
  .option("--refresh", "rebuild the metrics first")