@getxflow/cli 0.6.5 → 0.6.6

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/help.js CHANGED
@@ -9,348 +9,368 @@ function help(topic) {
9
9
  (0, ui_1.out)(TOPICS[topic]);
10
10
  return;
11
11
  }
12
- (0, ui_1.out)(`${(0, ui_1.bold)('xflow')} ${(0, ui_1.dim)(version_1.CLI_VERSION)} XFlow application hosting
13
-
14
- ${(0, ui_1.bold)('Getting started')}
15
- xflow login sign in through the browser
16
- xflow init [dir] new project from the platform template
17
- xflow templates which templates are available
18
- xflow link <id> link this folder to a project (id: xflow projects list)
19
- xflow skills pick the agents that get the platform instructions
20
- xflow mcp install give the agent platform access without a terminal
21
-
22
- ${(0, ui_1.bold)('Code')}
23
- xflow status what is on the server and how the local copy differs
24
- xflow push [--force] send the sources as a new revision
25
- xflow pull [--into dir] [--revision N]
26
- fetch the sources (the latest revision by default)
27
-
28
- ${(0, ui_1.bold)('Releasing')}
29
- xflow deploy [--no-push] send the code, ship the functions, build on the platform
30
- xflow publish show the dev version to visitors
31
- xflow rollback <version number> return the project to an earlier version
32
- xflow deployments version history
33
-
34
- ${(0, ui_1.bold)('Functions')}
35
- xflow functions list what is deployed (they ship with xflow deploy)
36
- xflow functions invoke <name> [--data '{"a":1}']
37
- call a function and print the answer
38
- xflow functions logs [name] function crashes: stack and console output
39
- xflow schedules list what runs on a timer
40
- xflow schedules set <name> "0 3 ? * * *"
41
- run a function on a schedule (UTC)
42
- xflow schedules rm <name> take a schedule off
43
- xflow env [check] function variables: what is stored, what is missing
44
- xflow env set NAME=value store a variable
45
- xflow env rm NAME delete a variable
46
- xflow connections connected accounts the project can use, and their variables
47
-
48
- ${(0, ui_1.bold)('Database')}
49
- xflow db status which migrations are applied and which are waiting
50
- xflow db schema [table] tables of the project, or the columns of one
51
- xflow db query "select ..." read data, in a read-only transaction
52
- xflow db migrate [--dry-run] [--allow-destructive]
53
- apply the migrations from migrations/*.sql
54
-
55
- ${(0, ui_1.bold)('Reference')}
56
- xflow logs [--limit N] browser errors from the released application
57
- xflow projects list projects of the organization
58
- xflow projects get [id] project card
59
- xflow whoami whose key this is and what it can do
60
- xflow logout forget the key
61
- xflow update update the CLI itself, and the skill that ships with it
62
-
63
- ${(0, ui_1.bold)('Environment')}
64
- XFLOW_TOKEN access key (for CI, instead of xflow login)
65
- XFLOW_API_URL platform address when it is not app.getxflow.com
66
-
12
+ (0, ui_1.out)(`${(0, ui_1.bold)('xflow')} ${(0, ui_1.dim)(version_1.CLI_VERSION)} XFlow application hosting
13
+
14
+ ${(0, ui_1.bold)('Getting started')}
15
+ xflow login sign in through the browser
16
+ xflow init [dir] new project from the platform template
17
+ xflow templates which templates are available
18
+ xflow link <id> link this folder to a project (id: xflow projects list)
19
+ xflow skills pick the agents that get the platform instructions
20
+ xflow mcp install give the agent platform access without a terminal
21
+
22
+ ${(0, ui_1.bold)('Code')}
23
+ xflow status what is on the server and how the local copy differs
24
+ xflow push [--force] send the sources as a new revision
25
+ xflow pull [--into dir] [--revision N]
26
+ fetch the sources (the latest revision by default)
27
+
28
+ ${(0, ui_1.bold)('Releasing')}
29
+ xflow deploy [--no-push] send the code, ship the functions, build on the platform
30
+ xflow publish show the dev version to visitors
31
+ xflow rollback <version number> return the project to an earlier version
32
+ xflow deployments version history
33
+
34
+ ${(0, ui_1.bold)('Functions')}
35
+ xflow functions list what is deployed (they ship with xflow deploy)
36
+ xflow functions invoke <name> [--data '{"a":1}']
37
+ call a function and print the answer
38
+ xflow functions logs [name] function crashes: stack and console output
39
+ xflow schedules list what runs on a timer
40
+ xflow schedules set <name> "0 3 ? * * *"
41
+ run a function on a schedule (UTC)
42
+ xflow schedules rm <name> take a schedule off
43
+ xflow env [check] function variables: what is stored, what is missing
44
+ xflow env set NAME=value store a variable
45
+ xflow env rm NAME delete a variable
46
+ xflow connections connected accounts the project can use, and their variables
47
+ xflow connections link <name> --as ALIAS
48
+ give the functions the credentials of an account
49
+ xflow connections unlink <ALIAS> [--force]
50
+ take them away again
51
+
52
+ ${(0, ui_1.bold)('Database')}
53
+ xflow db status which migrations are applied and which are waiting
54
+ xflow db schema [table] tables of the project, or the columns of one
55
+ xflow db query "select ..." read data, in a read-only transaction
56
+ xflow db migrate [--dry-run] [--allow-destructive]
57
+ apply the migrations from migrations/*.sql
58
+
59
+ ${(0, ui_1.bold)('Reference')}
60
+ xflow logs [--limit N] browser errors from the released application
61
+ xflow projects list projects of the organization
62
+ xflow projects get [id] project card
63
+ xflow whoami whose key this is and what it can do
64
+ xflow logout forget the key
65
+ xflow update update the CLI itself, and the skill that ships with it
66
+
67
+ ${(0, ui_1.bold)('Environment')}
68
+ XFLOW_TOKEN access key (for CI, instead of xflow login)
69
+ XFLOW_API_URL platform address when it is not app.getxflow.com
70
+
67
71
  More about one command: xflow help <command>`);
68
72
  }
69
73
  const TOPICS = {
70
- update: `${(0, ui_1.bold)('xflow update')}: bring the CLI up to date
71
-
72
- Installs the published version and, if anything changed, rewrites the platform
73
- instructions the agents already have: the skill ships inside the package and shares
74
- its version, so a fresh CLI next to a stale skill means the agent is reading last
75
- month's rules. Copies that are not installed are not created, so it is safe to run
76
- from any folder.
77
-
78
- The platform reports the published version with every answer, which is where the
79
- ${(0, ui_1.bold)('xflow N is out')} line comes from. It appears once a day at most, and never in CI,
80
- where nobody is going to update anything anyway.
81
-
82
- The command works out how this copy was installed from its own path, and refuses to
83
- cross package managers: an install made by pnpm or bun is printed as their own
84
- command rather than handed to npm, which would leave you with two copies and no way
85
- to tell which one answers. Two more cases end the same way. Under ${(0, ui_1.bold)('npx')} there is
86
- nothing to update, only a cache. And a copy inside a project's node_modules is a
87
- dependency of that project: ${(0, ui_1.bold)('npm i -D @getxflow/cli@latest')} is the fix, because
88
- inside npm scripts the local copy wins over anything installed globally.
89
-
90
- A refusal from the platform saying the CLI is too old is a different thing: that one
91
- is a hard gate on a changed contract, and until you run this command nothing else
74
+ update: `${(0, ui_1.bold)('xflow update')}: bring the CLI up to date
75
+
76
+ Installs the published version and, if anything changed, rewrites the platform
77
+ instructions the agents already have: the skill ships inside the package and shares
78
+ its version, so a fresh CLI next to a stale skill means the agent is reading last
79
+ month's rules. Copies that are not installed are not created, so it is safe to run
80
+ from any folder.
81
+
82
+ The platform reports the published version with every answer, which is where the
83
+ ${(0, ui_1.bold)('xflow N is out')} line comes from. It appears once a day at most, and never in CI,
84
+ where nobody is going to update anything anyway.
85
+
86
+ The command works out how this copy was installed from its own path, and refuses to
87
+ cross package managers: an install made by pnpm or bun is printed as their own
88
+ command rather than handed to npm, which would leave you with two copies and no way
89
+ to tell which one answers. Two more cases end the same way. Under ${(0, ui_1.bold)('npx')} there is
90
+ nothing to update, only a cache. And a copy inside a project's node_modules is a
91
+ dependency of that project: ${(0, ui_1.bold)('npm i -D @getxflow/cli@latest')} is the fix, because
92
+ inside npm scripts the local copy wins over anything installed globally.
93
+
94
+ A refusal from the platform saying the CLI is too old is a different thing: that one
95
+ is a hard gate on a changed contract, and until you run this command nothing else
92
96
  will work.`,
93
- db: `${(0, ui_1.bold)('xflow db')}: schema, data, migrations
94
-
95
- xflow db status what is applied and what is waiting
96
- xflow db schema [table] tables of the project, or the columns of one
97
- xflow db query "select ..." read data (--limit N)
98
- xflow db migrate apply migrations/*.sql
99
-
100
- ${(0, ui_1.bold)('schema')} answers a different question than the ${(0, ui_1.bold)('migrations/')} directory: one logical
101
- database is shared by several projects, so the files say what you did, and the schema
102
- says what is actually in there. ${(0, ui_1.bold)('query')} runs inside a READ ONLY transaction, so
103
- writes are rejected by the database itself, not by us reading your SQL.
104
-
105
- ${(0, ui_1.bold)('migrate')}: the files live in the repository (${(0, ui_1.bold)('migrations/0001_init.sql')},
106
- ${(0, ui_1.bold)('migrations/0002_orders.sql')} and so on). The order comes from the file name, which
107
- is why the leading number is required. Every migration runs in its own transaction, the
108
- history is kept in the database itself, and anything already applied is not run again.
109
-
110
- --dry-run report what would be applied without touching the database
111
- --allow-destructive allow operations that destroy data
112
-
113
- About destructive ones. The platform keeps no database history and makes no backups,
114
- so ${(0, ui_1.bold)('DROP TABLE')}, ${(0, ui_1.bold)('DROP COLUMN')}, ${(0, ui_1.bold)('TRUNCATE')} and ${(0, ui_1.bold)('DELETE FROM')} without a
115
- condition need two things at once: this flag, and the right to destroy data on the
116
- access key. That right is off by default, and only its owner turns it on, in the
117
- platform settings under Developers: a flag is something an agent adds by itself, a
118
- right is not. With both in place, the contents of the affected tables are dumped and
119
- kept for 7 days: that is a "caught it right away" safety net, not a backup.
120
- ${(0, ui_1.bold)('DROP DATABASE')} is never allowed, because the database is shared across the
121
- organization.
122
-
123
- Editing an already applied file achieves nothing: the comparison is by name, not by
124
- content. ${(0, ui_1.bold)('xflow db status')} lists such a file separately, so write a new migration
125
- instead.
126
-
127
- One logical database can be attached to several projects, so the history may hold
128
- migrations that are not in your repository. That is normal, but it also means your
97
+ db: `${(0, ui_1.bold)('xflow db')}: schema, data, migrations
98
+
99
+ xflow db status what is applied and what is waiting
100
+ xflow db schema [table] tables of the project, or the columns of one
101
+ xflow db query "select ..." read data (--limit N)
102
+ xflow db migrate apply migrations/*.sql
103
+
104
+ ${(0, ui_1.bold)('schema')} answers a different question than the ${(0, ui_1.bold)('migrations/')} directory: one logical
105
+ database is shared by several projects, so the files say what you did, and the schema
106
+ says what is actually in there. ${(0, ui_1.bold)('query')} runs inside a READ ONLY transaction, so
107
+ writes are rejected by the database itself, not by us reading your SQL.
108
+
109
+ ${(0, ui_1.bold)('migrate')}: the files live in the repository (${(0, ui_1.bold)('migrations/0001_init.sql')},
110
+ ${(0, ui_1.bold)('migrations/0002_orders.sql')} and so on). The order comes from the file name, which
111
+ is why the leading number is required. Every migration runs in its own transaction, the
112
+ history is kept in the database itself, and anything already applied is not run again.
113
+
114
+ --dry-run report what would be applied without touching the database
115
+ --allow-destructive allow operations that destroy data
116
+
117
+ About destructive ones. The platform keeps no database history and makes no backups,
118
+ so ${(0, ui_1.bold)('DROP TABLE')}, ${(0, ui_1.bold)('DROP COLUMN')}, ${(0, ui_1.bold)('TRUNCATE')} and ${(0, ui_1.bold)('DELETE FROM')} without a
119
+ condition need two things at once: this flag, and the right to destroy data on the
120
+ access key. That right is off by default, and only its owner turns it on, in the
121
+ platform settings under Developers: a flag is something an agent adds by itself, a
122
+ right is not. With both in place, the contents of the affected tables are dumped and
123
+ kept for 7 days: that is a "caught it right away" safety net, not a backup.
124
+ ${(0, ui_1.bold)('DROP DATABASE')} is never allowed, because the database is shared across the
125
+ organization.
126
+
127
+ Editing an already applied file achieves nothing: the comparison is by name, not by
128
+ content. ${(0, ui_1.bold)('xflow db status')} lists such a file separately, so write a new migration
129
+ instead.
130
+
131
+ One logical database can be attached to several projects, so the history may hold
132
+ migrations that are not in your repository. That is normal, but it also means your
129
133
  migration can break somebody else's application.`,
130
- logs: `${(0, ui_1.bold)('xflow logs')} and ${(0, ui_1.bold)('xflow functions logs')}: project errors
131
-
132
- One stream per project: crashes of the released application in the browser and
133
- crashes of the cloud functions. The last 200 entries are kept, older ones fall off.
134
-
135
- --limit N how many to show (10 by default)
136
-
137
- A function reports its own crashes: Yandex exposes its logs only over gRPC, so the
138
- wrapper catches the exception, carries the tail of the console with it (the last 40
139
- ${(0, ui_1.bold)('console.log')} lines of that call) and sends it to the platform. Successful calls
140
- write nothing, otherwise every request would pay for it in latency.
141
-
142
- What never reaches this list: a crash while the module is starting (the function
143
- never gets as far as the wrapper), going over 90 seconds, and running out of memory.
144
- Those show up in the answer to ${(0, ui_1.bold)('xflow functions invoke')}.
145
-
146
- Browser errors are collected by ${(0, ui_1.bold)('src/utils/error-logger.ts')} of the template and
134
+ logs: `${(0, ui_1.bold)('xflow logs')} and ${(0, ui_1.bold)('xflow functions logs')}: project errors
135
+
136
+ One stream per project: crashes of the released application in the browser and
137
+ crashes of the cloud functions. The last 200 entries are kept, older ones fall off.
138
+
139
+ --limit N how many to show (10 by default)
140
+
141
+ A function reports its own crashes: Yandex exposes its logs only over gRPC, so the
142
+ wrapper catches the exception, carries the tail of the console with it (the last 40
143
+ ${(0, ui_1.bold)('console.log')} lines of that call) and sends it to the platform. Successful calls
144
+ write nothing, otherwise every request would pay for it in latency.
145
+
146
+ What never reaches this list: a crash while the module is starting (the function
147
+ never gets as far as the wrapper), going over 90 seconds, and running out of memory.
148
+ Those show up in the answer to ${(0, ui_1.bold)('xflow functions invoke')}.
149
+
150
+ Browser errors are collected by ${(0, ui_1.bold)('src/utils/error-logger.ts')} of the template and
147
151
  only from released addresses: a local ${(0, ui_1.bold)('npm run dev')} writes nothing here.`,
148
- env: `${(0, ui_1.bold)('xflow env')}: environment variables of the functions
149
-
150
- Keys, passwords and third-party addresses are kept by the platform, not by the
151
- repository. A value goes up and never comes back: the only place to see it is inside
152
- the function. So keep your own copy wherever you got it from.
153
-
154
- xflow env what is stored (names, not values)
155
- xflow env check what the functions of this project are missing
156
- xflow env set SMTP_PASSWORD=… store
157
- xflow env rm SMTP_PASSWORD delete
158
-
159
- --scope project visible to this project only, not the whole organization
160
-
161
- ${(0, ui_1.bold)('check')} reads the sources in ${(0, ui_1.bold)('functions/')} and looks for ${(0, ui_1.bold)('process.env.NAME')}
162
- references. The same rule applies on deploy: a function receives only the variables it
163
- mentions by name. A name assembled from an expression (${(0, ui_1.bold)("process.env['KEY_' + n]")})
164
- never reaches the environment, so read variables literally.
165
-
166
- The value reaches the function on deploy, not at the moment it is stored: after
167
- ${(0, ui_1.bold)('env set')} run ${(0, ui_1.bold)('xflow deploy')}. The build ships a function whose code did not
168
- change but whose variables did, so nothing is left holding an old value. The same after a
152
+ env: `${(0, ui_1.bold)('xflow env')}: environment variables of the functions
153
+
154
+ Keys, passwords and third-party addresses are kept by the platform, not by the
155
+ repository. A value goes up and never comes back: the only place to see it is inside
156
+ the function. So keep your own copy wherever you got it from.
157
+
158
+ xflow env what is stored (names, not values)
159
+ xflow env check what the functions of this project are missing
160
+ xflow env set SMTP_PASSWORD=… store
161
+ xflow env rm SMTP_PASSWORD delete
162
+
163
+ --scope project visible to this project only, not the whole organization
164
+
165
+ ${(0, ui_1.bold)('check')} reads the sources in ${(0, ui_1.bold)('functions/')} and looks for ${(0, ui_1.bold)('process.env.NAME')}
166
+ references. The same rule applies on deploy: a function receives only the variables it
167
+ mentions by name. A name assembled from an expression (${(0, ui_1.bold)("process.env['KEY_' + n]")})
168
+ never reaches the environment, so read variables literally.
169
+
170
+ The value reaches the function on deploy, not at the moment it is stored: after
171
+ ${(0, ui_1.bold)('env set')} run ${(0, ui_1.bold)('xflow deploy')}. The build ships a function whose code did not
172
+ change but whose variables did, so nothing is left holding an old value. The same after a
169
173
  delete: a function already deployed keeps the old value until its next deploy.`,
170
- connections: `${(0, ui_1.bold)('xflow connections')}: accounts connected to the organization
171
-
172
- Somebody signs in to Yandex Metrika, Bitrix or a mail service once, in the platform,
173
- and that account becomes a connection of the organization. Linked to a project, it
174
- hands its credentials to the cloud functions as environment variables. Nobody has to
175
- paste a token into the repository, and nobody sees the value: it goes straight from
176
- the platform into the function.
177
-
178
- xflow connections what this project can use, and what it already uses
179
-
180
- Every row says whether the connection is linked to this project (its alias) and what
181
- state the access is in. ${(0, ui_1.bold)('available, not linked')} is the useful one: the account
182
- exists in the organization, but this project gets nothing from it yet.
183
-
184
- Variables are named after the alias: an OAuth connection called ${(0, ui_1.bold)('YANDEX_METRIKA')}
185
- gives ${(0, ui_1.bold)('YANDEX_METRIKA_TOKEN')}, a key-based one gives a variable per field. They
186
- arrive at a function on its next deploy, like every other variable, so after a change
187
- run ${(0, ui_1.bold)('xflow deploy')}. A token close to expiry is renewed by any build on the way;
188
- a revoked one is not renewed by anything until a human reconnects the account.
189
-
190
- Linking is done by a person, in the project settings under Connectors, and there is no
191
- command for it yet. That is on purpose: a link hands somebody else's credentials to
192
- everyone who deploys the project, and access to a connection is granted per person.
193
- The same goes for connecting a new account and for switching one off.`,
194
- schedules: `${(0, ui_1.bold)('xflow schedules')}: running functions on a timer
195
-
196
- A schedule is a Yandex timer trigger: it calls the function itself, with no
197
- application and no browser involved.
198
-
199
- xflow schedules set report "0 3 ? * * *" every day at 03:00
200
- xflow schedules set digest "0 */4 ? * * *" every 4 hours
201
- xflow schedules rm report take off every schedule of a function
202
-
203
- Six fields: ${(0, ui_1.bold)('minutes hours day-of-month month day-of-week year')}. Exactly one of
204
- the day-of-month and day-of-week fields has to be ${(0, ui_1.bold)('?')}, which is not our quirk but
205
- how Yandex works. ${(0, ui_1.bold)('The time is always UTC')}, local time is not understood.
206
-
207
- --payload '{"mode":"full"}' the body the function will receive
208
-
209
- A scheduled run arrives at the handler as a POST with no headers, and the project
210
- token is not checked on it: such an event cannot be forged from outside. The function
211
- has to be deployed already, since the schedule points at it and not the other way round.
212
-
213
- A failed run shows up in ${(0, ui_1.bold)('xflow functions logs')}: nobody is watching a scheduled
174
+ connections: `${(0, ui_1.bold)('xflow connections')}: accounts connected to the organization
175
+
176
+ Somebody signs in to Yandex Metrika, Bitrix or a mail service once, in the platform,
177
+ and that account becomes a connection of the organization. Linked to a project, it
178
+ hands its credentials to the cloud functions as environment variables. Nobody has to
179
+ paste a token into the repository, and nobody sees the value: it goes straight from
180
+ the platform into the function.
181
+
182
+ xflow connections what this project can use, and what it already uses
183
+ xflow connections link <name> --as ALIAS
184
+ hand its credentials to the functions
185
+ xflow connections unlink <ALIAS> take them away again
186
+
187
+ Every row says whether the connection is linked to this project (its alias) and what
188
+ state the access is in. ${(0, ui_1.bold)('available, not linked')} is the useful one: the account
189
+ exists in the organization, but this project gets nothing from it yet: link it.
190
+
191
+ Both commands take the name of the connection, the first column of the list, and both
192
+ also take its identifier. ${(0, ui_1.bold)('unlink')} takes the alias as well, and prefers it: the
193
+ alias is the name your own code already uses. One organization can hold several accounts
194
+ of the same service under one name; then the command prints their identifiers and asks
195
+ for one of those instead of guessing.
196
+
197
+ ${(0, ui_1.bold)('unlink')} refuses while a function still reads one of the variables and names
198
+ those functions; ${(0, ui_1.bold)('--force')} goes through anyway.
199
+
200
+ Variables are named after the alias: an OAuth connection called ${(0, ui_1.bold)('YANDEX_METRIKA')}
201
+ gives ${(0, ui_1.bold)('YANDEX_METRIKA_TOKEN')}, a key-based one gives a variable per field. They
202
+ arrive at a function on its next deploy, like every other variable, so after a change
203
+ run ${(0, ui_1.bold)('xflow deploy')}. A token close to expiry is renewed by any build on the way;
204
+ a revoked one is not renewed by anything until a human reconnects the account.
205
+
206
+ Linking needs a right on the key, ${(0, ui_1.bold)('connections:link')}. Keys are issued with it,
207
+ and a person can take it away in the platform settings under Developers; a key cannot give
208
+ it back to itself. Losing it is what the refusal says, and the answer is to ask a person,
209
+ not to look for another route. Either way only the accounts granted to you personally can
210
+ be linked at all: that rule holds whatever the key is allowed to do.
211
+
212
+ Connecting a new account and switching one off stay with a person, in the platform
213
+ interface. There is no command for either.`,
214
+ schedules: `${(0, ui_1.bold)('xflow schedules')}: running functions on a timer
215
+
216
+ A schedule is a Yandex timer trigger: it calls the function itself, with no
217
+ application and no browser involved.
218
+
219
+ xflow schedules set report "0 3 ? * * *" every day at 03:00
220
+ xflow schedules set digest "0 */4 ? * * *" every 4 hours
221
+ xflow schedules rm report take off every schedule of a function
222
+
223
+ Six fields: ${(0, ui_1.bold)('minutes hours day-of-month month day-of-week year')}. Exactly one of
224
+ the day-of-month and day-of-week fields has to be ${(0, ui_1.bold)('?')}, which is not our quirk but
225
+ how Yandex works. ${(0, ui_1.bold)('The time is always UTC')}, local time is not understood.
226
+
227
+ --payload '{"mode":"full"}' the body the function will receive
228
+
229
+ A scheduled run arrives at the handler as a POST with no headers, and the project
230
+ token is not checked on it: such an event cannot be forged from outside. The function
231
+ has to be deployed already, since the schedule points at it and not the other way round.
232
+
233
+ A failed run shows up in ${(0, ui_1.bold)('xflow functions logs')}: nobody is watching a scheduled
214
234
  function, so the wrapper reports a crash the same way it does on an ordinary call.`,
215
- invoke: `${(0, ui_1.bold)('xflow functions invoke')} <name>: call a function
216
-
217
- Calls it exactly the way the application does: the project token plus a visitor pass
218
- for the person who owns the key, so the function sees a real caller and its role.
219
- Both are taken from the platform, no local .env is needed.
220
-
221
- --data '{"a":1}' request body (the method becomes POST by default)
222
- --method GET a different method
223
-
224
- Prints the status, the response time and the body. A non-zero exit code on 4xx and
225
- 5xx: in CI such a call has to fail the step. The cause of a crash is shown by
235
+ invoke: `${(0, ui_1.bold)('xflow functions invoke')} <name>: call a function
236
+
237
+ Calls it exactly the way the application does: the project token plus a visitor pass
238
+ for the person who owns the key, so the function sees a real caller and its role.
239
+ Both are taken from the platform, no local .env is needed.
240
+
241
+ --data '{"a":1}' request body (the method becomes POST by default)
242
+ --method GET a different method
243
+
244
+ Prints the status, the response time and the body. A non-zero exit code on 4xx and
245
+ 5xx: in CI such a call has to fail the step. The cause of a crash is shown by
226
246
  ${(0, ui_1.bold)('xflow functions logs <name>')}.`,
227
- mcp: `${(0, ui_1.bold)('xflow mcp install')}: connect the agent to the platform directly
228
-
229
- Writes the MCP server into the configuration of a client that has its own connect
230
- command: today that is Claude Code, and for the rest the command prints what to enter
231
- by hand. After that the agent runs the platform without a terminal: it inspects the
232
- database, applies migrations, ships and calls functions, sets schedules, reads logs.
233
- The commands stay: code, builds and releases are still done by the CLI, because
234
- pushing sources through MCP means filling the agent context and spending your money.
235
-
236
- The command takes the access key from your own login and does not print it: usually
237
- the agent runs this command itself, and everything printed lands in its context and in
238
- the chat history.
239
-
240
- --show-token print the key anyway (not while under an agent)
241
-
242
- There is one key per person per organization and its scope is not narrowed: the agent
243
- sees every project of the organization and names the one it needs. It takes the
247
+ mcp: `${(0, ui_1.bold)('xflow mcp install')}: connect the agent to the platform directly
248
+
249
+ Writes the MCP server into the configuration of a client that has its own connect
250
+ command: today that is Claude Code, and for the rest the command prints what to enter
251
+ by hand. After that the agent runs the platform without a terminal: it inspects the
252
+ database, applies migrations, ships and calls functions, sets schedules, reads logs.
253
+ The commands stay: code, builds and releases are still done by the CLI, because
254
+ pushing sources through MCP means filling the agent context and spending your money.
255
+
256
+ The command takes the access key from your own login and does not print it: usually
257
+ the agent runs this command itself, and everything printed lands in its context and in
258
+ the chat history.
259
+
260
+ --show-token print the key anyway (not while under an agent)
261
+
262
+ There is one key per person per organization and its scope is not narrowed: the agent
263
+ sees every project of the organization and names the one it needs. It takes the
244
264
  project from the ${(0, ui_1.bold)('project_id')} argument, not from your folder, which it cannot see.`,
245
- skills: `${(0, ui_1.bold)('xflow skills')}: platform instructions for an AI agent
246
-
247
- An agent has no way to know about XFlow: the platform is not in its training. The
248
- instructions explain how to release and publish, where the design system components
249
- come from, and where to look for production errors. ${(0, ui_1.bold)('init')} and ${(0, ui_1.bold)('link')} lay them
250
- down on their own for the common agents, so this command exists to pick tools
251
- precisely. Refreshing after a CLI update is not your job any more: the skill and the
252
- CLI ship as one version, and ${(0, ui_1.bold)('xflow update')} rewrites the copies you already have.
253
-
254
- Run in a terminal, it asks two questions: where (this project, or the home folder,
255
- which makes the skill visible in every project) and for which agents. Copies that are
256
- already installed come pre-selected and are updated in place. Without a terminal, in
257
- CI or when an agent runs the command, there are no questions: the defaults plus every
258
- already installed copy are refreshed.
259
-
260
- xflow skills list the agents, their folders and what is installed
261
- --agent claude,cursor exact agents, no questions asked
262
- --global the home folder instead of the project
263
- --yes no questions: defaults plus what is installed
264
- --refresh rewrite the copies that exist, create none
265
-
266
- The format is shared (agentskills.io) and inside a project most tools read the shared
267
- .agents/skills folder, so the paths differ mostly in the home directory. Cursor also
268
- gets .cursor/rules/xflow.mdc: its older versions do not read the shared format.
269
-
270
- Plus a few pointer lines in ${(0, ui_1.bold)('AGENTS.md')}. A skill is picked up lazily, only when its
271
- description matches the task, and "add a customers table" will not trigger it. AGENTS.md
272
- is always read by the agent, which is why the pointer is appended there, at the end of
265
+ skills: `${(0, ui_1.bold)('xflow skills')}: platform instructions for an AI agent
266
+
267
+ An agent has no way to know about XFlow: the platform is not in its training. The
268
+ instructions explain how to release and publish, where the design system components
269
+ come from, and where to look for production errors. ${(0, ui_1.bold)('init')} and ${(0, ui_1.bold)('link')} lay them
270
+ down on their own for the common agents, so this command exists to pick tools
271
+ precisely. Refreshing after a CLI update is not your job any more: the skill and the
272
+ CLI ship as one version, and ${(0, ui_1.bold)('xflow update')} rewrites the copies you already have.
273
+
274
+ Run in a terminal, it asks two questions: where (this project, or the home folder,
275
+ which makes the skill visible in every project) and for which agents. Copies that are
276
+ already installed come pre-selected and are updated in place. Without a terminal, in
277
+ CI or when an agent runs the command, there are no questions: the defaults plus every
278
+ already installed copy are refreshed.
279
+
280
+ xflow skills list the agents, their folders and what is installed
281
+ --agent claude,cursor exact agents, no questions asked
282
+ --global the home folder instead of the project
283
+ --yes no questions: defaults plus what is installed
284
+ --refresh rewrite the copies that exist, create none
285
+
286
+ The format is shared (agentskills.io) and inside a project most tools read the shared
287
+ .agents/skills folder, so the paths differ mostly in the home directory. Cursor also
288
+ gets .cursor/rules/xflow.mdc: its older versions do not read the shared format.
289
+
290
+ Plus a few pointer lines in ${(0, ui_1.bold)('AGENTS.md')}. A skill is picked up lazily, only when its
291
+ description matches the task, and "add a customers table" will not trigger it. AGENTS.md
292
+ is always read by the agent, which is why the pointer is appended there, at the end of
273
293
  the file and once. ${(0, ui_1.bold)('CLAUDE.md')} is left alone: Claude Code reads .claude/skills anyway.`,
274
- push: `${(0, ui_1.bold)('xflow push')}: send the sources
275
-
276
- The whole working copy goes up at once, as one revision. What is not sent:
277
- node_modules, .git, dist, build, .next, any .env, plus everything listed in
278
- .xflowignore and in the ignore field of xflow.json.
279
-
280
- If the server holds a revision newer than the one you worked from, the push is
281
- rejected. That means somebody pushed before you: fetch their changes alongside
282
- (${(0, ui_1.bold)('xflow pull --into ./server-copy')}), merge them in git on your side, and retry.
283
-
284
- --force overwrites the server revision. Before that the CLI shows whose work you are
285
- about to destroy and asks for confirmation by typing the project name. In a
286
- non-interactive run (CI, an agent) there is no way to confirm: a version conflict has
294
+ push: `${(0, ui_1.bold)('xflow push')}: send the sources
295
+
296
+ The whole working copy goes up at once, as one revision. What is not sent:
297
+ node_modules, .git, dist, build, .next, any .env, plus everything listed in
298
+ .xflowignore and in the ignore field of xflow.json.
299
+
300
+ If the server holds a revision newer than the one you worked from, the push is
301
+ rejected. That means somebody pushed before you: fetch their changes alongside
302
+ (${(0, ui_1.bold)('xflow pull --into ./server-copy')}), merge them in git on your side, and retry.
303
+
304
+ --force overwrites the server revision. Before that the CLI shows whose work you are
305
+ about to destroy and asks for confirmation by typing the project name. In a
306
+ non-interactive run (CI, an agent) there is no way to confirm: a version conflict has
287
307
  to fail the build rather than silently destroy somebody else's work.`,
288
- pull: `${(0, ui_1.bold)('xflow pull')}: fetch the sources
289
-
290
- By default it fetches the latest revision into the project folder and refuses to write
291
- into a non-empty one: the platform cannot merge changes, that is git's job.
292
-
293
- --into <dir> unpack alongside, to compare
294
- --revision <N> a specific revision (the list: xflow deployments)
308
+ pull: `${(0, ui_1.bold)('xflow pull')}: fetch the sources
309
+
310
+ By default it fetches the latest revision into the project folder and refuses to write
311
+ into a non-empty one: the platform cannot merge changes, that is git's job.
312
+
313
+ --into <dir> unpack alongside, to compare
314
+ --revision <N> a specific revision (the list: xflow deployments)
295
315
  --force overwrite the folder completely`,
296
- deploy: `${(0, ui_1.bold)('xflow deploy')}: build and release
297
-
298
- Three steps: sending the sources, shipping the cloud functions, building the application.
299
- The build command and the output directory come from xflow.json (npm run build and dist
300
- by default).
301
-
302
- --no-push do not send sources, build from the latest server revision
303
- --force allow overwriting the server revision while sending
304
- --allow-removals agree in advance to remove the functions gone from the sources
305
-
306
- The platform builds, in a clean sandbox on one Node version for everybody, so "it
307
- worked on my machine" no longer depends on your machine. Before the build the project
308
- is checked against the template: mismatches are printed as a list and the build does
309
- not start at all.
310
-
311
- Everything in ${(0, ui_1.bold)('functions/<name>/index.ts')} is bundled and shipped by the same run,
312
- before the application is built. That order is not a convention but the only one that
313
- works: the addresses of the functions are baked into the bundle, so they have to exist
314
- first. A function whose code and variables did not change is left alone, and a function
315
- that fails to ship fails the whole build.
316
-
317
- A function gone from the sources would be deleted from the cloud along with its
318
- schedules, and that is final: one created again later gets a different address. So the
319
- build does not start at all until you say yes. In a terminal the CLI names the functions
320
- and asks; without one (CI, an agent) it stops and ${(0, ui_1.bold)('--allow-removals')} is the only way
321
- to agree. If the sources hold no functions at all while the cloud holds several, nothing
322
- is deleted and nothing is asked: that looks like a directory which never made it (a
323
- ${(0, ui_1.bold)('functions/')} line in .xflowignore) rather than a decision.
324
-
325
- The database is not part of this: migrations change data in ways nothing can undo, so
326
- they stay their own command (${(0, ui_1.bold)('xflow db migrate')}).
327
-
328
- The built version is visible on the project page, and the CLI prints the link. Visitors
329
- see it after ${(0, ui_1.bold)('xflow publish')}. The address of the build itself is not printed:
330
- it carries the version number, and after the next publish such a link quietly serves an
316
+ deploy: `${(0, ui_1.bold)('xflow deploy')}: build and release
317
+
318
+ Three steps: sending the sources, shipping the cloud functions, building the application.
319
+ The build command and the output directory come from xflow.json (npm run build and dist
320
+ by default).
321
+
322
+ --no-push do not send sources, build from the latest server revision
323
+ --force allow overwriting the server revision while sending
324
+ --allow-removals agree in advance to remove the functions gone from the sources
325
+
326
+ The platform builds, in a clean sandbox on one Node version for everybody, so "it
327
+ worked on my machine" no longer depends on your machine. Before the build the project
328
+ is checked against the template: mismatches are printed as a list and the build does
329
+ not start at all.
330
+
331
+ Everything in ${(0, ui_1.bold)('functions/<name>/index.ts')} is bundled and shipped by the same run,
332
+ before the application is built. That order is not a convention but the only one that
333
+ works: the addresses of the functions are baked into the bundle, so they have to exist
334
+ first. A function whose code and variables did not change is left alone, and a function
335
+ that fails to ship fails the whole build.
336
+
337
+ A function gone from the sources would be deleted from the cloud along with its
338
+ schedules, and that is final: one created again later gets a different address. So the
339
+ build does not start at all until you say yes. In a terminal the CLI names the functions
340
+ and asks; without one (CI, an agent) it stops and ${(0, ui_1.bold)('--allow-removals')} is the only way
341
+ to agree. If the sources hold no functions at all while the cloud holds several, nothing
342
+ is deleted and nothing is asked: that looks like a directory which never made it (a
343
+ ${(0, ui_1.bold)('functions/')} line in .xflowignore) rather than a decision.
344
+
345
+ The database is not part of this: migrations change data in ways nothing can undo, so
346
+ they stay their own command (${(0, ui_1.bold)('xflow db migrate')}).
347
+
348
+ The built version is visible on the project page, and the CLI prints the link. Visitors
349
+ see it after ${(0, ui_1.bold)('xflow publish')}. The address of the build itself is not printed:
350
+ it carries the version number, and after the next publish such a link quietly serves an
331
351
  old copy.`,
332
- init: `${(0, ui_1.bold)('xflow init')} [dir]: a new project
333
-
334
- Lays down the platform template: React on Vite, Tailwind, a set of components
335
- (${(0, ui_1.bold)('src/components/ui')}) and ready-made blocks (${(0, ui_1.bold)('src/components/blocks')}): table,
336
- form, filters, kanban, charts. Projects created in the web get the same template, which
337
- is what makes the applications look alike.
338
-
339
- Building the interface on top of these components and the tokens in ${(0, ui_1.bold)('src/index.css')}
340
- is not a formality: your own palette on top of them looks foreign inside the platform.
341
-
342
- --name <name> project name (the folder name by default)
343
- --template <id> a different template (the list: xflow templates)
344
- --database <id> attach a logical database of the organization
345
-
346
- The order: the project is created on the platform first, because without it there is
347
- nowhere to get the token for .env. If writing the files fails, the project stays empty
352
+ init: `${(0, ui_1.bold)('xflow init')} [dir]: a new project
353
+
354
+ Lays down the platform template: React on Vite, Tailwind, a set of components
355
+ (${(0, ui_1.bold)('src/components/ui')}) and ready-made blocks (${(0, ui_1.bold)('src/components/blocks')}): table,
356
+ form, filters, kanban, charts. Projects created in the web get the same template, which
357
+ is what makes the applications look alike.
358
+
359
+ Building the interface on top of these components and the tokens in ${(0, ui_1.bold)('src/index.css')}
360
+ is not a formality: your own palette on top of them looks foreign inside the platform.
361
+
362
+ --name <name> project name (the folder name by default)
363
+ --template <id> a different template (the list: xflow templates)
364
+ --database <id> attach a logical database of the organization
365
+
366
+ The order: the project is created on the platform first, because without it there is
367
+ nowhere to get the token for .env. If writing the files fails, the project stays empty
348
368
  and the CLI explains how to pick it up with the link command.`,
349
- rollback: `${(0, ui_1.bold)('xflow rollback')} <version number>: return an earlier build
350
-
351
- Switches the project to the chosen build. Only the build comes back: the sources stay
352
- at their own revision, and returning them is a separate decision
353
- (${(0, ui_1.bold)('xflow pull --revision N --into ./old-version')}).
354
-
369
+ rollback: `${(0, ui_1.bold)('xflow rollback')} <version number>: return an earlier build
370
+
371
+ Switches the project to the chosen build. Only the build comes back: the sources stay
372
+ at their own revision, and returning them is a separate decision
373
+ (${(0, ui_1.bold)('xflow pull --revision N --into ./old-version')}).
374
+
355
375
  Visitors keep seeing the published version until ${(0, ui_1.bold)('xflow publish')} is run.`,
356
376
  };