@getxflow/cli 0.6.4 → 0.6.5

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