@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/bin.js +7 -0
- package/dist/commands/connections.js +52 -0
- package/dist/help.js +328 -303
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/xflow/SKILL.md +451 -444
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
|
-
|
|
48
|
-
|
|
49
|
-
xflow db
|
|
50
|
-
xflow db
|
|
51
|
-
xflow db
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
xflow
|
|
57
|
-
xflow projects
|
|
58
|
-
xflow
|
|
59
|
-
xflow
|
|
60
|
-
xflow
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
};
|