@usefillo/cli 0.19.0 → 0.20.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/dist/index.js CHANGED
@@ -815,6 +815,7 @@ async function provisionWorkspace(flags, usageHint, apiBase = API) {
815
815
  }
816
816
  }
817
817
  const workspaceName = flagString(flags, "workspace-name") ?? defaultWorkspaceName();
818
+ const promptCopyId = flagString(flags, "pc")?.trim();
818
819
  const res = await api(
819
820
  "/workspaces/provision",
820
821
  {
@@ -823,7 +824,8 @@ async function provisionWorkspace(flags, usageHint, apiBase = API) {
823
824
  email: email3,
824
825
  source: "cli",
825
826
  ...name ? { name } : {},
826
- ...workspaceName ? { workspaceName } : {}
827
+ ...workspaceName ? { workspaceName } : {},
828
+ ...promptCopyId ? { promptCopyId } : {}
827
829
  })
828
830
  },
829
831
  apiBase
@@ -958,7 +960,7 @@ async function init(flags) {
958
960
  }
959
961
  var initCommand = {
960
962
  name: "init",
961
- flags: ["email", "name", "workspace-name"],
963
+ flags: ["email", "name", "workspace-name", "pc"],
962
964
  run: (_args, flags) => init(flags)
963
965
  };
964
966
 
@@ -1210,7 +1212,7 @@ var skillCommand = {
1210
1212
  };
1211
1213
 
1212
1214
  // src/commands/agent.ts
1213
- var BOOTSTRAP_USAGE = 'To set up a workspace I need an email for your recovery link. Re-run: npx @usefillo/cli@latest agent bootstrap --email you@company.com [--name "Your Name"]. (Already have an account? `fillo login`.)';
1215
+ var BOOTSTRAP_USAGE = 'To set up a workspace I need the human\'s real work email for the recovery link. Ask the human for their work email once \u2014 never invent an address or use a documentation placeholder \u2014 then re-run: npx @usefillo/cli@latest agent bootstrap --email <work-email> [--name "Your Name"]. (Already have an account? `fillo login`.)';
1214
1216
  async function bootstrapStandalone(flags, apiBase) {
1215
1217
  if (flags.account === true) {
1216
1218
  die(
@@ -1403,9 +1405,10 @@ function agentHelp() {
1403
1405
 
1404
1406
  ${boldRaw("Commands")}
1405
1407
  agent bootstrap Set up a workspace and install the Build with Fillo skill
1406
- ${dimRaw("--email you@company.com provision a fresh workspace (a TTY confirms your git identity)")}
1408
+ ${dimRaw("--email <work-email> provision a fresh workspace (ask the human first; a TTY confirms git identity)")}
1407
1409
  ${dimRaw('--name "Your Name" optional display name')}
1408
1410
  ${dimRaw("--workspace-name <name> name the new workspace (default: this repo/directory)")}
1411
+ ${dimRaw("--pc <uuid> optional marketing stitch id from /agents?pc=")}
1409
1412
  ${dimRaw("--api <url> target a different Fillo deployment (default: FILLO_API or https://fillo.so)")}
1410
1413
  ${dimRaw("--run <id> --token <token> instead: attach to an open browser modal")}
1411
1414
  ${dimRaw("--account with --run/--token: approve an existing workspace in the browser")}
@@ -1432,6 +1435,7 @@ var agentCommand = {
1432
1435
  "email",
1433
1436
  "name",
1434
1437
  "workspace-name",
1438
+ "pc",
1435
1439
  "run",
1436
1440
  "token",
1437
1441
  "api",
@@ -2075,10 +2079,30 @@ function printDestination(body) {
2075
2079
  console.log(
2076
2080
  ` ${dim("Role grant:")} ${grant ? `${terminalText(grant.roleId)} in ${terminalText(grant.guildId)}${grant.autoJoin ? " (auto-join)" : ""}` : "off"}`
2077
2081
  );
2078
- if (!body.webhookMatches) {
2082
+ if (!body.webhookMatches && body.connectionLabel) {
2079
2083
  console.log(
2080
2084
  `
2081
- ${bold("This form points at a different webhook than the project does.")} It keeps failing until you re-run \`fillo discord enable <form>\`.`
2085
+ ${dim(
2086
+ `This form posts to its own channel; the project default is ${terminalText(body.connectionLabel)}. Re-point it with \`fillo discord enable <form> --channel <channelId>\`.`
2087
+ )}`
2088
+ );
2089
+ }
2090
+ const servers = body.servers ?? [];
2091
+ if (servers.length > 0) {
2092
+ console.log("");
2093
+ printTable(
2094
+ ["SERVER", "ID"],
2095
+ servers.map((server) => [terminalText(server.name ?? "(name unavailable)"), server.guildId])
2096
+ );
2097
+ console.log(`
2098
+ ${dim("Aim a form: fillo discord enable <form> --channel <channelId>")}`);
2099
+ }
2100
+ const channels = body.channels ?? [];
2101
+ if (servers.length === 0 && channels.length > 1) {
2102
+ console.log("");
2103
+ printTable(
2104
+ ["CHANNEL", "WEBHOOK ID"],
2105
+ channels.map((channel) => [terminalText(channel.label), channel.webhookId])
2082
2106
  );
2083
2107
  }
2084
2108
  }
@@ -2105,18 +2129,35 @@ function parseRole(raw) {
2105
2129
  async function enable(form, flags) {
2106
2130
  const json = jsonMode(flags);
2107
2131
  if (!form)
2108
- die("Usage: fillo discord enable <form> [--fields a,b,c] [--early-signal 5|10|25|off]");
2132
+ die(
2133
+ "Usage: fillo discord enable <form> [--channel <webhookId>] [--fields a,b,c] [--early-signal 5|10|25|off]"
2134
+ );
2109
2135
  const token = requireToken();
2110
2136
  const current = await fetchDestination(token, form);
2111
- if (!current.connected || !current.connectionWebhookId) {
2137
+ const channels = current.channels ?? [];
2138
+ if ((!current.connected || !current.connectionWebhookId) && channels.length === 0) {
2112
2139
  die(
2113
2140
  "Discord isn't connected to this project. Run `fillo discord connect`, or `fillo discord webhook` to paste a channel URL."
2114
2141
  );
2115
2142
  }
2143
+ const rawChannel = flagString(flags, "channel");
2144
+ if (rawChannel !== void 0 && !SNOWFLAKE.test(rawChannel.trim())) {
2145
+ die("--channel must be a Discord channel id (right-click the channel \u2192 Copy Channel ID).");
2146
+ }
2147
+ const targetChannelId = rawChannel?.trim() ?? null;
2148
+ const fallbackWebhookId = current.connectionWebhookId ?? (channels.length === 1 ? channels[0]?.webhookId ?? null : null);
2149
+ if (!current.enabled && !targetChannelId && !fallbackWebhookId) {
2150
+ die(
2151
+ "Pass --channel <channelId> to pick where this form posts. `fillo discord status <form>` lists the connected servers."
2152
+ );
2153
+ }
2116
2154
  const patch = {};
2117
- if (!current.enabled || !current.webhookMatches) {
2155
+ if (targetChannelId) {
2156
+ patch.enabled = true;
2157
+ patch.channelId = targetChannelId;
2158
+ } else if (!current.enabled && fallbackWebhookId) {
2118
2159
  patch.enabled = true;
2119
- patch.webhookId = current.connectionWebhookId;
2160
+ patch.webhookId = fallbackWebhookId;
2120
2161
  }
2121
2162
  const rawFields = flagString(flags, "fields");
2122
2163
  if (rawFields !== void 0) patch.includeFieldIds = parseFields(rawFields);
@@ -2244,6 +2285,7 @@ function discordHelp() {
2244
2285
  ${dimRaw(`reads the URL from a hidden prompt, or ${WEBHOOK_URL_ENV}`)}
2245
2286
  discord status <form> What this form sends, to where, with which extras
2246
2287
  discord enable <form> Start sending \u2014 and set any of the options below
2288
+ ${dimRaw("--channel <channelId> which channel this form posts to (bot lane)")}
2247
2289
  ${dimRaw("--fields a,b,c up to three field ids (none = link only)")}
2248
2290
  ${dimRaw("--early-signal 5|10|25 first N responses arrive in full (off to stop)")}
2249
2291
  ${dimRaw("--role <guildId>/<roleId> grant that role on an accepted response")}
@@ -2263,7 +2305,7 @@ function discordHelp() {
2263
2305
  }
2264
2306
  var discordCommand = {
2265
2307
  name: "discord",
2266
- flags: ["label", "fields", "early-signal", "role", "auto-join"],
2308
+ flags: ["label", "channel", "fields", "early-signal", "role", "auto-join"],
2267
2309
  run: (args, flags) => discord(args[0], args.slice(1), flags),
2268
2310
  help: discordHelp
2269
2311
  };
@@ -3774,7 +3816,7 @@ var schemaShape = object({
3774
3816
  });
3775
3817
  var MAX_SCHEMA_VERSION = 1;
3776
3818
  var FILLO_SCHEMA_VERSION = 1;
3777
- var FILLO_SDK_VERSION = true ? "0.19.0" : "0.0.0-dev";
3819
+ var FILLO_SDK_VERSION = true ? "0.20.0" : "0.0.0-dev";
3778
3820
  function str(value, max, fallback = "") {
3779
3821
  return typeof value === "string" ? value.trim().slice(0, max) : fallback;
3780
3822
  }
@@ -20,8 +20,12 @@ Never require a provider-specific agent command.
20
20
  with a three-line plan before running anything, for example: "1) I install
21
21
  Fillo's SDK and skill. 2) I build the form inside your app. 3) You get an
22
22
  email to claim your workspace, where responses live." Add that a few
23
- permission prompts may need approving along the way. Skip the recap when
24
- Fillo is already set up in the repo.
23
+ permission prompts may need approving along the way. Then, if their work
24
+ email is not already in this task, ask them for it once. Do not invent an
25
+ address, infer or scrape it, or use a documentation placeholder as the
26
+ address. Run `npx @usefillo/cli@latest agent bootstrap --email <their email>`
27
+ with the address they give you. Skip the recap and the email ask when Fillo
28
+ is already set up in the repo or a handoff already supplied a workspace.
25
29
  2. Inspect the task environment and any host repository. For an embed, identify
26
30
  its framework, package manager, target route, existing Fillo packages, theme
27
31
  provider/switch, light and dark selectors, CSS `color-scheme`, design tokens,
@@ -37,12 +37,16 @@
37
37
  - Older existing-account handoff: run its exact
38
38
  `login --api … --run … --token …` command, wait for approval, then run the
39
39
  supplied `agent connect --account` command.
40
- - New workspace outside a browser handoff: set it up from the terminal. Run
41
- `npx @usefillo/cli@latest init --email <address>` to provision a capped
42
- preview workspace, email its link, and store the `pk_` you build against. Only
43
- pass `--email` when the user explicitly supplies the address; never infer or
44
- scrape it. `https://fillo.so/start` stays available when the user prefers the
45
- dashboard.
40
+ - New workspace outside a browser handoff: ask the human once for their real
41
+ work email if it is not already in the task. Never invent an address, never
42
+ infer or scrape one, and never use a documentation placeholder as the
43
+ address. Then run
44
+ `npx @usefillo/cli@latest agent bootstrap --email <their email>` to provision
45
+ a capped preview workspace, email its link, store the `pk_` you build
46
+ against, and install the skill. Use
47
+ `npx @usefillo/cli@latest init --email <their email>` only when you need the
48
+ workspace without the skill. `https://fillo.so/start` stays available when
49
+ the user prefers the dashboard.
46
50
 
47
51
  Never inspect `~/.fillo/config.json`, expose the account token, or call
48
52
  `provisionWorkspace()` during component render.
@@ -78,7 +82,7 @@ workspace:
78
82
 
79
83
  ```bash
80
84
  npx @usefillo/cli@latest claim
81
- # Sent a claim link to you@company.com. Approval code: 4KT2-9QF1
85
+ # Sent a claim link to alex@acme.dev. Approval code: 4KT2-9QF1
82
86
  # Open the link in that inbox — it shows this code — and approve this terminal.
83
87
  ```
84
88
 
@@ -180,10 +180,13 @@ downstream writes duplicate-safe.
180
180
  With a CLI login, connect Discord and manage its per-form settings — plus
181
181
  mint a connector token for n8n or Zapier — without a dashboard trip.
182
182
 
183
- Connect a channel one of two ways. On a deployment where Fillo's Discord app
184
- is configured, `discord connect` opens Discord's own consent screen — it
185
- includes the channel picker. Print the URL and let the user approve it; do
186
- not loop, the same as `storage connect drive`/`box`:
183
+ Connect one of two ways. On a deployment where Fillo's Discord app is
184
+ configured, `discord connect` opens Discord's consent screen: ONE approval
185
+ adds Fillo's bot to the chosen server (Manage Webhooks only — it can't read
186
+ messages) and connects the first channel. After that, channels are picked
187
+ per form with `enable --channel` — no further approvals. Print the URL and
188
+ let the user approve it; do not loop, the same as `storage connect
189
+ drive`/`box`:
187
190
 
188
191
  ```bash
189
192
  npx @usefillo/cli@latest discord connect
@@ -209,8 +212,13 @@ standing message (default: link only):
209
212
  npx @usefillo/cli@latest discord enable customer-intake --fields email,plan
210
213
  ```
211
214
 
212
- `enable` takes three more flags beyond field selection:
215
+ `enable` takes more flags beyond field selection:
213
216
 
217
+ - `--channel <channelId>` aims this form at any channel of a connected
218
+ server (right-click the channel in Discord → Copy Channel ID); Fillo
219
+ resolves the channel through its bot and creates or reuses the channel's
220
+ webhook. Each form pins its own channel, so two forms can post to two
221
+ rooms. `discord status <form>` lists the connected servers.
214
222
  - `--early-signal 5|10|25` sends every answered field — not only the picked
215
223
  three — for that many responses, then reverts to the standing message on
216
224
  its own; `--early-signal off` turns it back off early.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefillo/cli",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "Create and publish Fillo forms, and install the Fillo Agent Skill.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -34,7 +34,7 @@
34
34
  "@types/node": "^22.10.0",
35
35
  "tsup": "^8.4.0",
36
36
  "typescript": "^5.8.3",
37
- "@usefillo/core": "0.19.0"
37
+ "@usefillo/core": "0.20.0"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "tsup && node scripts/copy-skill.mjs",