mcpField
F
fcode-cli

fcode-cli

github.com/factorialco开发1390 次安装2 周前更新
代码仓库

关于 fcode-cli

fcode-cli 是用于本地开发和测试 Factorial Code 流程,并与 Factorial Code Cloud 同步工作区的命令行工具。它还支持团队级 App 检出、本地 Webhook 测试,以及云端状态和差异检查。

主要功能

  1. 01使用参数本地运行流程
  2. 02拉取和推送工作区更改
  3. 03比较本地与云端状态
  4. 04提供本地 Webhook 和表单测试
  5. 05克隆并同步团队 App

适用场景

  1. 01部署前测试流程
  2. 02解决冲突前查看差异
  3. 03在本地测试 Webhook 和表单
  4. 04处理开发团队拥有的多个 App

MCP 相关

README 未说明其与 MCP 的连接或管理 MCP 服务的功能。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/factorialco/factorial-code-skills --skill fcode-cli

安装后在 Claude Code 中输入/fcode-cli确认已加载。

详细介绍

Factorial Code — CLI

fcode CLI 用于在本地开发和测试流程,并与 Factorial Code Cloud 同步。有关平台模型,请参阅 fcode-core-concepts。

命令流程

在一台机器上首次使用:通过 pnpm install -g @factorialco/fcode-cli 安装,然后运行 fcode clone <workspace-slug>,将云端工作区下载到 <workspace-slug>/ 文件夹中(该命令也会安装这些 Agent 技能;使用 --skipSkillsSetup 可跳过)。App 的 Development 标签页中的“How to build locally”指南会显示其开发工作区的准确克隆命令——请从那里复制;该 slug 是编码后的令牌,不是 App 的 UUID。若要将开发团队拥有的所有 App 下载到同一布局中,请改用 fcode team:clone(见下文)。

在已克隆的工作区中进行修改和测试时:

  1. fcode pull (可选,首先执行)——如果云端可能已发生变化,请先同步,以便使用最新版本。
  2. 编辑本地文件(流程、模块、变量、依赖项)。
  3. fcode add——仅在创建了新资源时使用(新流程、模块、依赖项或变量)。修改现有代码时跳过。
  4. fcode dependencies:install——如果修改了 dependencies/package.json 或 dependencies/requirements.txt。
  5. fcode run <process-slug>——在本地执行流程以进行测试。
  6. fcode push——准备就绪后部署到云端。

推送只会更新当前(未版本化)代码:固定到 stable 别名的使用方(webhook URL 和表单嵌入应始终使用此别名)会继续运行已发布的版本,直到该别名更改指向。发布(发布工作区版本并重新指向 stable)会单独进行,通常通过 Web UI 操作(见下文)。

注意事项

  • 刚创建流程(或其他资源)时,切勿在运行 fcode add 之前运行 fcode run——否则会遇到“Local process not found”。
  • **fcode add 仅用于新资源。**修改现有流程/模块代码或变量时,直接运行 fcode push。
  • **push/pull 上的 --force 会覆盖另一端。**本地与云端内容不一致时,这两个命令都会失败——settings:pull 也不例外,它会拒绝删除未推送的 settings.json。先运行 fcode diff,向用户准确展示哪些内容会被丢弃;只有获得用户明确确认后才能使用 --force。
  • 在 settings.json 中编辑 versions / aliases 会在推送时发布版本:添加标签会发布该工作区版本,移除标签会从云端删除该版本(并级联删除相关内容),重新指向别名则会发布或回滚。settings:versions:* / settings:aliases:* 也遵循相同规则——除非用户明确要求,否则不要修改。
  • 切勿编辑继承的资源。variables.inherited.env、i18n/<locale>.inherited.yaml 以及继承的流程/模块均由父工作区管理,会在拉取时重新生成,且绝不会被推送(见下文)。若要覆盖某个变量,请将该键添加到 variables.env(将区域设置键添加到 i18n/<locale>.yaml);请在所属工作区中编辑流程和模块。

命令

fcode add

向 CLI 注册新的本地资源,以便运行或部署。在创建新流程/模块/依赖项/变量后、运行 run/push 之前执行。仅编辑现有资源后无需执行。

fcode dependencies:install

将依赖项安装到本地工作区。在修改 dependencies/package.json 或 dependencies/requirements.txt 后执行。该命令也会安装继承的包,因此本地运行时解析到的依赖与云端一致。

fcode run <process-slug> --parameters <filepath | json>

在本地执行流程,用于开发/测试。使用 variables.env / variables.local.env 和给定的参数(或默认使用流程的 parameters.json)。显示日志、结果和错误。

fcode run my-process --parameters '{"key": "value"}'
fcode run my-process --parameters ./params.json
fcode run my-process                                  # default parameters.json
fcode run my-process --locale pt-BR                   # resolve fcode.i18n in that locale

前提条件:如果刚创建了资源,请先运行 fcode add。

--locale 会像云端一样,根据本地 i18n/ 文件解析 fcode.i18n——请参阅 fcode-i18n(其中也说明了为什么标志中的拼写错误会悄无声息地将每个键解析为自身)。

fcode http

启动本地 HTTP 服务(--port,默认为 3000),模拟云端 Webhook 环境,并提供工作区的表单架构,以便无需部署即可测试由 Webhook 触发的流程和表单。

--auth-user / --auth-password 会通过基本身份验证保护本地服务的全部内容。每个流程的 Webhook 身份验证是独立的,并且会严格按照云端的方式执行:服务会从流程的 metadata.json 读取 webhook.authMode,根据 settings.json 中的 webhookAuth 解析 TEAM,并要求在已配置的标头中提供指定变量的值——在 Authorization 中使用 Bearer <token>,在其他任何标头中使用原始值。值来自工作区变量,优先级与每次本地运行相同:variables.inherited.env,之后由 variables.env 覆盖,再由 variables.local.env 覆盖(见下文)。标头查找不区分大小写,但如果标头重复,服务会拒绝请求,而不会将其合并。缺少标头、Bearer 值格式错误、变量未定义、值不匹配,或缺少工作区配置的 TEAM Webhook,都会返回 403,原因会打印到控制台。

在本地需要注意两点:

  • 机密变量下载时会显示为 ******** 占位符,因此在将真实值添加到 variables.local.env 前,本地身份验证只接受 ********。
  • --auth-user / --auth-password 会占用 Authorization 标头,因此不能与要求在该标头中提供凭据的 Webhook 组合使用。服务会在启动时对此发出警告。
fcode pull

从云端下载最新的流程、模块、变量和依赖项,并覆盖本地文件以使其保持一致。如果其他人可能已更改云端资源,或要丢弃本地更改,请在开始工作前运行。--force 仅在用户确认后使用。

fcode push

将本地更改上传到云端。本地更改后运行(仅在创建了新资源时,才需先运行 fcode add);建议先运行 fcode run。--force 仅在用户确认后使用。

fcode status

报告本地与云端之间的差异,但不会更改任一方——包括流程、模块、变量、依赖项、本地化内容和 settings.json。 也提供按资源类型查看的命令:processes:status、modules:status、 variables:status、i18n:status、settings:status。

云端确认一致的继承资源会被隐藏,因为无需对其执行拉取或推送操作;会有一行报告被省略的资源数量。继承资源只要出现差异——过期、新增、已删除、冲突、已修改或敏感性已更改——就会重新显示,因此父级移动资源时不会被悄无声息地忽略。--showInherited 会列出所有继承资源:

fcode status --showInherited        # or any per-resource variant above

继承的敏感变量也会被视为未更改并隐藏:由于从不比较其值,因此它永远不会被报告为最新。

fcode diff [<slug>]

显示差异的具体内容,而 status 只会说明存在差异:以 Git 风格的统一差异格式展示工作区中保存的每个文件,云端为旧版本,本地文件为新版本。各资源的变体命令接受一个可选 slug:processes:diff、modules:diff、variables:diff、i18n:diff、dependencies:diff、settings:diff。

fcode diff                          # the whole workspace
fcode processes:diff my-process     # one process

在解决 pull / push 中的 🔥 (conflict) 之前使用此命令,让用户在选择前了解双方会丢失哪些内容。注意:

  • 本地与云端不同时退出码为 1,同步时退出码为 0,可用作检查。此处的非零退出码就是结果,不应将其作为错误报告。
  • 敏感变量值绝不会输出;双方都会显示为 <sensitive value hidden>,因此变更的密钥会显示在 status 中,但不会显示在此处。
  • 继承资源遵循与 status 相同的规则:云端一致的资源会以数量汇总隐藏;父级移动的资源会显示差异,并标明所属工作区。使用 fcode pull 修复这些差异,绝不要推送——这些资源始终为只读。继承变量会显示为 variables.inherited.env,也就是它们所在的生成文件。
fcode remote:add <workspace-slug>

将已克隆的工作区文件夹指向另一个云端工作区,使后续的 fcode pull / push 改为与该工作区同步——这就是在工作区之间提升代码的方式(例如,从 dev → prod)。不要随意使用:受控的提升流程见 fcode-release。

fcode team:clone / team:pull / team:status

一次操作开发团队拥有的所有 App——这里的开发团队指仪表板中的人员团队,而非工作区意义上的团队(参见 fcode-ama)。不带参数运行 team:clone 会列出你所属的开发团队,供你复制 ID;只传入一个参数时,则会直接开始克隆:

fcode team:clone                 # lists your teams, or clones the only one
fcode team:clone <teamId>

此命令会为每个 App 创建一个文件夹,其中包含 App 的元数据文件,以及该 App 工作区的检出副本:

acme-payroll/
┣ 📂 .fcode/team.json      # the team and the Apps cloned into it
┣ 📂 .claude/skills/       # installed once, symlinked into every App below
┗ 📂 payroll-sync/
  ┣ 📜 settings.json       # the App — name, description, id (mirror)
  ┣ 📜 README.md           # the App's README — yours, pushed with `fcode app:push`
  ┣ 📜 MARKETPLACE.md      # the marketplace listing — yours, pushed with `fcode app:push`
  ┣ 📜 CHANGELOG.md        # generated from the App's releases (mirror)
  ┣ 📂 marketplace/logo.*  # the App logo set in the dashboard (mirror)
  ┗ 📂 app/                # a normal workspace — settings.json, processes/, …

检出副本名为 app,而不是它原来的 dev-<token> slug:slug 会保存在元数据中,而该目录只是一个检出副本——可以使用 fcode remote:add 将其改为指向 prod 工作区。每一层级的 settings.json 都描述该层级所包含的对象;由于它们位于不同目录中,因此不会相互冲突。

在 App 工作区中,所有常规命令都照常可用;团队命令仅额外提供跨 App 操作的命令:

  • team:pull 会重新读取团队:克隆上次运行后新增的 App,拉取每个工作区,并刷新每个 App 的元数据文件。已退出团队的 App 会报告,但绝不会删除——如果想删除其文件夹,请自行操作。
  • team:status 会报告每个 App 的 README.md 和 MARKETPLACE.md 的状态(最新、本地已修改、已过期、冲突),然后在 App 工作区中以各自的标题运行 fcode status。
  • **没有 team:push。**代码需在工作区内逐个 App 推送;App 的 README 和上架信息可通过 fcode app:push 推送(见下文)。
  • App 文件夹中的文件分为两类。镜像文件——settings.json、CHANGELOG.md、marketplace/logo.*——每次拉取时都会重写;编辑这些文件不会更改上游内容(在仪表板中重命名 App;发布说明则是请求发布时填写的备注)。自有文件——README.md 和 MARKETPLACE.md——修改后会予以保留:只有自上次同步后未更改的文件才会在拉取时被覆盖,并会报告保留了哪些文件。
  • 某个 App 失败不会中止整个运行:失败的 App 会列在摘要中,重新运行 team:pull 时只会重试仍缺失的内容。若仪表板无法提供某个元数据文件,该文件会保持原样并作为警告报告;这不会导致该 App 的克隆失败。
fcode app:push

将 App 文件夹中的 README.md 和 MARKETPLACE.md 上传到控制台。在 App 文件夹或其 app/ 检出目录中的任意位置运行此命令——它会通过 settings.json 和 app/ 这对文件识别文件夹。此命令只传输文档,不会传输代码。

cd payroll-sync
fcode app:push            # uploads the files that changed since the last sync
fcode app:push --force    # local wins over a cloud edit
  • README.md 是 App 的 README,也会显示在控制台 App 页面的 README 标签页中,并可在此编辑。空白文件会清除 README;如果云端 README 从未编写过,则会以占位内容(# <App name> + 描述)同步回来,以便编辑该文件。
  • MARKETPLACE.md 是 Publication 标签页中的上架信息:YAML 前置元数据包含 tagline、category_id(DatoCMS 类别 ID)、support_link、help_link(http(s):// 或 mailto:),之后的正文是完整描述(Markdown,1–5000 个字符)。由控制台管理的字段——publication_state、datocms_id——会以注释形式显示,且不会推送。已关联的 DatoCMS 记录在市场中仍优先于这些字段(参见 fcode-ama)。
  • 冲突:如果某个文件自上次拉取后在本地和控制台都发生了更改,则会拒绝推送。--force 会以本地文件为准;删除文件并运行 fcode team:pull 则会以控制台为准。如果文件仅落后于云端,则会跳过,并提示拉取。
  • 如果控制台拒绝某个文件,系统会报告相关字段和原因(例如,标语超过 140 个字符);另一个文件仍会推送,且命令会以非零状态码退出。
  • 推送后,本地文件会重写为拉取时生成的规范格式,因此 team:status 会将其识别为最新状态。
fcode settings:pull / settings:push / settings:status

单独同步 settings.json 中的工作区级设置:settings:pull 会将云端设置写入文件,settings:push 会应用文件中的设置,settings:status 会报告设置是在本地、云端还是两边发生了更改。普通的 fcode pull / fcode push 也会包含这些设置,并在最后处理,以便引用的错误处理程序进程 slug 能对应到已存在的进程。

versions / aliases 字段的同步方式与文件中的其他字段相同:settings:push 会将它们与云端进行比对并应用差异——发布本地列出但云端尚不存在的版本(保留其 comment);删除已从文件中移除的版本前,会逐个询问确认(删除操作会级联;--force 会跳过提示);并创建、重新指向或删除别名以保持一致。settings:status 也会比较这些字段;如果 settings.json 存在尚未推送的本地编辑,settings:pull 会拒绝覆盖。

fcode settings:versions:* / fcode settings:aliases:*

工作区版本控制会发布整个工作区的一个版本:团队拥有的每个流程和模块都会获得带有相同标签的版本,并且在已发布的快照中,裸模块导入会固定到该版本(模型见 fcode-core-concepts)。发布通常通过 Web UI(团队设置 → Versions 标签页)进行;这些命令是命令式的等效操作,而编辑 settings.json 中的 versions / aliases 后推送,则是声明式的操作。 除非收到明确要求,否则不要创建版本或移动 stable。

fcode settings:versions:create v1.0.0 --comment "First stable release"
fcode settings:versions:list
fcode settings:versions:delete v1.0.0     # cascades; asks confirmation unless --force

fcode settings:aliases:set stable v1.0.0  # create or re-point; rollback = older tag
fcode settings:aliases:list
fcode settings:aliases:delete stable
  • settings:versions:create 会跳过已带有完全相同标签的实体,并报告各实体的摘要(已创建 / 已跳过 / 失败——即版本清单),随后拉取内容,以便本地刷新 versions/<tag>/ 文件夹和 settings.json。部分失败后使用相同标签重新运行,只会发布仍缺失的内容。
  • settings:versions:delete 会级联删除:删除带有该标签的所有自有流程/模块版本,以及引用它们的别名、执行记录和计划。
  • settings:aliases:set 会执行创建或更新——它会在所有已发布目标标签的自有实体上创建别名,或将现有别名重新指向该标签(不包含该标签的实体会被跳过并报告)。将 stable 重新指向较旧的标签即为回滚:所有固定到 stable 的使用方都会在一次操作中切换。
fcode i18n:*

i18n:pull / i18n:push / i18n:status / i18n:add <locale> / i18n:remove <locale> / i18n:reset 用于同步工作区的翻译文件—— i18n/<locale>.yaml,以及只读且被 git 忽略的 i18n/<locale>.inherited.yaml(由 pull 写入)。聚合命令 fcode pull / push / status 已包含区域设置。文件格式、继承模型和 国际化工作流详见 fcode-i18n。

流程元数据——metadata.json

每个流程文件夹都包含 processes/<slug>/metadata.json,它是流程名称、描述、标签、触发器和设置的事实来源。它支持通过 push / pull 双向同步:编辑文件并运行 fcode push,即可在云端更改这些设置,无需使用控制面板。更改会在 fcode status 中显示为 🔺 已修改。

字段类型含义
namestring显示名称(默认使用 slug)
descriptionstring, optional流程描述
tagsstring[]标签(默认值为 [])
webhookobject, optionalWebhook 触发器:enabled(boolean)用于开启流程的 Webhook 端点;authMode(NONE | TEAM | CUSTOM)指定调用方的身份验证方式——公开、继承工作区 settings.json 中的 webhookAuth,或使用流程自己的配置;auth({ headerName?, variableKey },仅与 CUSTOM 搭配使用)用于指定标头名称,以及保存预期令牌的团队变量
factorialobject, optional指定流程如何作为 Factorial Action 暴露给 Factorial(参见 fcode-factorial-actions):enabled(boolean)为总开关;awaitResult(boolean,默认值为 true,Factorial 会等待结果);requiredPolicies(string[][],Factorial 策略键的 AND 组之间采用 OR 关系);每个入口点各有一个子块,且各自有 enabled 字段——uiTrigger(locationId,启用时必填,≤ 200 个字符;label,唯一可接受 fcode.i18n("key") 令牌的字段;icon)、form(appTool,在 Factorial 中 App 自己的页面上提供表单;public,已弃用)、agentTool(Factorial One 工具契约:description、effect READ | WRITE | DESTRUCTIVE——未设置时按 destructive 处理——、whenToUse、whenNotToUse[]、preconditions[]、doesNotDo[]、degradation、simulatesFor)以及 backend
formobject, optional旧版,与 factorial.form 保持同步:enabled(boolean)是 Forms 开关(参见 fcode-forms);appRole(INSTALL、SETTINGS、USER_FACING_FORM、UNINSTALL):USER_FACING_FORM 现在对应 factorial.form.appTool,而三个生命周期值在该块中没有对应项,因此保留在此处(保留的生命周期 slug 是替代方案,而非取代项——参见 fcode-factorial-actions);authMode(FACTORIAL、NONE)决定调用方是否需要 Factorial 账号,而 factorial.form.public 是对应的开关
uiTriggerobject, optional旧版,与 factorial.uiTrigger 保持同步(参见 fcode-ui-triggers):enabled、locationId、label、icon 和 awaitResult(现在为 factorial.awaitResult)
lifecycleRole—非文件字段:INSTALL | SETTINGS | UNINSTALL | SYNC,由平台根据流程的 form.appRole 推导;若未声明,则根据保留的 slug install、settings、uninstall、sync 推导;由 CLI 和 API 报告,但不会写入 metadata.json(参见 fcode-factorial-actions)
{
  "name": "Order sync",
  "description": "Syncs Shopify orders into Factorial",
  "tags": ["integration", "shopify"],
  "webhook": {
    "enabled": true,
    "authMode": "CUSTOM",
    "auth": { "variableKey": "SHOPIFY_WEBHOOK_TOKEN" }
  },
  "form": { "enabled": false }
}

继承工作区配置的 Webhook 使用 "webhook": { "enabled": true, "authMode": "TEAM" },而公开 Webhook 仅使用 "webhook": { "enabled": true }。

暴露给 Factorial 的流程包含 factorial 块;旧版 form 和 uiTrigger 键仍可能存在,并会与该块保持同步:

{
  "name": "Approve pending time off",
  "tags": ["timeoff"],
  "factorial": {
    "enabled": true,
    "awaitResult": false,
    "requiredPolicies": [["company.manage_timeoff"], ["company.admin"]],
    "uiTrigger": { "enabled": true, "locationId": "calendar.header.admin", "label": "fcode.i18n(\"acme.approve.button\")", "icon": "Bell" },
    "form": { "enabled": true },
    "agentTool": {
      "enabled": true,
      "description": "Approves every time-off request still pending for a team.",
      "effect": "WRITE",
      "whenToUse": "The user asks to approve the pending time-off requests of a team.",
      "whenNotToUse": ["The user wants to approve a single, named request."],
      "preconditions": ["The team has at least one pending request."],
      "doesNotDo": ["It does not notify the employees whose requests were approved."]
    },
    "backend": { "enabled": true }
  }
}

市场应用的安装表单就是 slug 为保留值 install 的流程(平台会据此推导 lifecycleRole),并启用其表单:

{
  "name": "Connect your account",
  "tags": ["setup"],
  "factorial": { "enabled": true, "form": { "enabled": true } }
}

说明:

  • webhook.auth.variableKey 只存储变量的名称,绝不存储令牌 — 因此可以安全地提交该文件。变量不必事先存在;在它存在之前,对 webhook 的每次调用都会被拒绝,并返回 403。普通变量和机密变量都可使用。
  • authMode: TEAM 会继承 settings.json 中的 webhookAuth。 如果缺少该 配置,webhook 会拒绝每次调用 — 绝不会按公开处理。这在 MCP 中很重要:Agent 可以设置 authMode: TEAM,但没有团队设置工具,因此必须预先存在该配置 (在 settings.json 中设置并运行 fcode settings:push)。
  • webhook.auth.headerName 默认为 Authorization,其值必须为 Bearer <token>;任何其他标头都会携带原始变量值。有效名称只能包含 RFC 7230 令牌字符,最多 64 个字符,并且 Cookie、Host 和 Fcode- 前缀会被拒绝。 建议使用默认值:自定义标头无法获得代理和日志管道为 Authorization 提供的 脱敏处理。只有在发送方无法设置 Authorization 时才使用自定义标头 — Factorial 自带的 webhook 发送方就是这种情况,它会将令牌放在 x-factorial-wh-challenge 中。
  • form.appRole 和 webhook.authMode 在未设置或为 NONE 时会省略, webhook.auth.headerName 在值为 Authorization 时也会省略,因此表单只包含 "form": { "enabled": true }。要解除受保护 webhook 的保护,请显式 写入 "authMode": "NONE" — 省略该字段会保留已存储的模式;不带 authMode: CUSTOM 发送 auth 会被拒绝。
  • 对于新进程,安装、设置和卸载应优先使用保留的生命周期 slug;对于 App 在其 自有页面上提供的表单,应使用 factorial.form.appTool,而不是 form.appRole。 对于已经发布的 App,appRole 会一直用于命名其生命周期表单 — 没有迁移期限。 推送时,如果文件仍包含 appRole: USER_FACING_FORM,其角色会保留:如果没有 appTool,CLI 会根据该角色推导 appTool,并停止从旧键发送该角色。
  • factorial 块也会省略默认值:awaitResult 为 true 时、requiredPolicies 为空时、form.public 和 form.appTool 为 false 时、agentTool 文本未设置且 列表为空时,以及任何 enabled 为 false 的子块都会省略。未向 Factorial 暴露的进程完全没有 factorial 键;尚无契约的 Factorial One 工具只包含 "factorial": { "enabled": true, "agentTool": { "enabled": true } }。 启用 factorial.uiTrigger 却未设置 locationId,推送时会被拒绝。
  • 每次推送都会决定表单是否公开。 含有 factorial 块的文件总会发送 form.public,平台会据此写入身份验证模式。因此,在控制台中发布为公开的 表单,如果下次推送的文件未写入 "public": true,就会恢复为要求使用 Factorial 账户。请先运行 fcode pull,或在文件中设置此标记并保留。
  • 如果文件同时包含 factorial 和旧版 form / uiTrigger 键,fcode push 会发送 factorial,平台会将其同步到旧版块(规则见 fcode-factorial-actions)。 早期草案中的 factorial.title / factorial.description 在推送时会被忽略, 并在拉取时删除。
  • fcode pull 仍会为每个进程写入 "uiTrigger": { "enabled": false }(旧版 块);只有在设置了 locationId、label 和 icon 时才会写入这些字段, awaitResult 则仅在为 true 时写入。
  • 如果缺少 metadata.json,fcode add 会创建 { "name": "<slug>", "tags": [] };如果 JSON 无效,则会发出警告并回退到这些默认值。
调用 Webhook — 在 URL 中固定版本

Webhook 端点为 https://code.factorialhr.com/platform/api/<team-slug>/webhooks/<process-slug>。 务必使用 version_tag 查询参数固定版本,并将其指向 stable 别名——订阅系统很少允许设置请求标头:

curl -X POST "https://code.factorialhr.com/platform/api/<team-slug>/webhooks/<process-slug>?version_tag=stable"
  • version_tag 接受版本标签(v1.0.0)或别名。请使用 stable:它 始终存在,发布或回滚时只需移动别名——无需改动外部系统。它等同于 Fcode-Version-Tag 标头,并且优先级高于该标头。version_tag、async 和 locale 是 保留名称,会在参数传递到流程前被剥离(locale 用于选择执行语言——请参阅 fcode-i18n)。
  • 未知或格式错误的版本不会导致调用失败。 流程会运行当前版本,平台只会在服务器端记录警告——拼写错误会导致当前版本静默运行。当运行结果异常时,请检查执行版本。

工作区设置 — settings.json

位于工作区根目录的单例文件,用于保存工作区级设置。通过 fcode settings:pull / settings:push / settings:status 同步,并包含在普通的 fcode push / pull 中(最后推送,因此被引用的错误处理进程会先存在)。

字段类型含义
parentTeams数组此工作区继承进程、模块和变量的团队(仅直接父级,最多 5 个)。每个条目可以是普通 slug(父级实时解析),也可以是 { slug, version },用于将该父级固定到其某个工作区版本——标签或别名
zoneId字符串,可选团队时区(例如用于计划任务)
errorHandlerConfig对象,可选{ "processSlug": "<slug>", "tag": null } — 执行出错时调用的进程;tag 用于将其固定到某个版本标签或别名(null = 当前版本)
webhookAuth对象,可选{ headerName?, variableKey } — 每个 authMode: TEAM webhook 都会继承的配置
primaryLocale字符串,可选工作区的主要语言:调用方未指定语言时使用的区域设置,也是未翻译键的键级回退(参见 fcode-i18n)
versions数组,可选工作区版本:{ tag, comment?, createdAt? } — 声明新的 tag 并推送即可发布;省略 createdAt,云端会自动填入
aliases数组,可选工作区别名:{ name, tag }
{
  "parentTeams": ["shared-utils", { "slug": "base-app", "version": "stable" }],
  "zoneId": "Europe/Madrid",
  "errorHandlerConfig": { "processSlug": "error-handler", "tag": null },
  "webhookAuth": {
    "headerName": "x-factorial-wh-challenge",
    "variableKey": "FACTORIAL_CHALLENGE_TOKEN"
  },
  "versions": [
    { "tag": "v1.0.0", "comment": "First stable release", "createdAt": "2026-08-01T10:00:00" }
  ],
  "aliases": [{ "name": "stable", "tag": "v1.0.0" }]
}

错误处理程序通过 slug(而非 id)引用,因此 settings.json 可跨工作区移植;CLI 会在推送时将其解析为云端 id。

父级实时解析时,parentTeams 条目会写成普通 slug;固定后则写成 { slug, version } —— 读取时接受这两种形式,因此手写的 slug 列表仍然有效。version 是该父级 工作区版本的标签或别名,必须在该父级中存在,否则推送会被拒绝。固定版本会带来哪些变化,请参阅 fcode-core-concepts;除非明确要求,否则不要添加或更改固定项。

versions 和 aliases 是同步状态,而非只读镜像:它们会计入内容哈希(编辑后会在 fcode status 中显示为已修改),且 settings:push 会根据上述差异语义应用这些更改。比较的只有标签集合和 name → tag 配对 — 已发布版本的 comment 不能再更改,createdAt 由服务器分配。

webhookAuth 是整个工作区共用的一份配置,因此多个 webhook 使用的令牌可以在同一处命名并轮换。关于它有两点需要注意:

  • 此配置仅适用于单个工作区,不会通过 parentTeams 继承。 鉴权根据 webhook URL 中指定的工作区解析,而不是代码所属的工作区,因此,从基础应用继承 webhook 进程的应用仍需配置自己的 webhookAuth 条目。
  • 移除该对象并推送会清除云端配置,导致所有继承该配置的 webhook 拒绝所有调用。

磁盘上的继承资源

fcode pull 会将从 parentTeams 继承的所有内容与工作区自身的资源放在一起:variables.inherited.env、i18n/<locale>.inherited.yaml、dependencies/package.inherited.json / requirements.inherited.txt,以及 processes/ 和 modules/ 中继承的流程/模块文件夹。CLI 会将它们保留为父级所有:

  • 只读 — 流程/模块文件的写入模式为 444;需要使用 chmod 才能编辑时,就应停止操作,并在所属工作区中修改。
  • 通过 .gitignore 中由 CLI 管理的区块进行 Git 忽略;每次 pull 时都会重新生成该区块 — 不要手动编辑。
  • fcode push 永远不会上传这些文件。 如果本地修改了其中某个文件,系统会记录警告并指出所属团队 — 使用 fcode processes:pull / modules:pull(或聚合命令 fcode pull)还原。
  • *:status 命令只会列出与云端不同的继承资源(其余资源可使用 --showInherited 查看),并通过名为 inherited 的列标明所属工作区(🔗 <slug>)。
  • 从固定版本的父级继承时,获取的是该版本的内容,而不是父级当前的代码,且仅包括该固定版本已发布的资源 — 父级之后新增的流程不会被拉取。修改 settings.json 中的固定版本并再次 pull,才能更新这些文件。

有关继承模型(解析顺序、覆盖、固定版本),请参阅 fcode-core-concepts。

三个变量文件

团队变量存储在工作区根目录的三个 .env 文件中:

文件内容是否同步
variables.env此工作区拥有的变量已提交;推送和拉取
variables.inherited.env从父级工作区(parentTeams)继承的变量仅拉取;Git 忽略(CLI 会添加相应条目)
variables.local.env仅本地覆盖项永不推送,永不拉取

本地运行时的解析顺序(优先级从高到低)与云端一致:variables.local.env → variables.env → variables.inherited.env。

优先级由哪个文件声明了某个键决定,而非其值 — 因此,将 variables.env 中的键置空,会以空字符串覆盖继承的变量,而不会回退到父级值。

覆盖继承的变量

将键添加到 variables.env 中就是覆盖。 从此以后,CLI 会将其视为此工作区自身的变量:fcode status 会将其显示为新增项,fcode push 会在此处创建它,而 fcode variables:add 也会提供它。

  • 不要将父级变量复制到子工作区中,以便“让它们可用” — 它们本来就能解析。只有当此工作区确实需要不同的值时,才添加键。(在继承功能出现之前配置的工作区可能仍保留这类副本,现在它们会遮蔽父级变量 — 包括未触碰的 ******** 占位符,它们会遮蔽原本能够解析的机密。请向用户指出这些副本,而不要删除。)
  • 删除你的覆盖项(从 variables.env 中移除该键并推送)后,父级值会恢复。

有关模型和 Web UI 的行为,请参阅 fcode-core-concepts;有关运行时 fcode.variables 的行为,请参阅 fcode-javascript / fcode-python。

文件名由设置项指定(variablesFileName、inheritedVariablesFileName、localVariablesFileName)— 除非工作区另有说明,否则请使用以上默认值。

变量敏感性 — variables.meta.json

将每个变量映射到其敏感性标记的工作区根目录文件:

{
  "ACME_API_KEY": { "isSensitive": true },
  "ACME_BASE_URL": { "isSensitive": false }
}
  • 使用 fcode variables:add --sensitive 创建敏感变量(然后设置其值并推送);标记会写入此文件。
  • 运行时通过 fcode.variables.set 创建的变量默认是敏感变量——对于普通配置,传入 sensitive: false(JS)/ sensitive=False(Python)。请参阅 fcode-javascript / fcode-python。
  • 敏感值绝不会离开云端:pull 会在 variables.env 中写入占位符 ********;对于继承的密钥,也会在 variables.inherited.env 中写入此占位符。不要替换任一文件中的占位符——将真实值放入 variables.local.env,供本地运行使用。在远程环境中,执行仍可使用继承密钥的真实值(请参阅 fcode-core-concepts);只有本地副本会被屏蔽。
  • 推送后,isSensitive 不可更改。在 variables.meta.json 中编辑该值会导致推送被拒绝(fcode status 中显示 🚫)——请还原为与远程环境一致。
获取本地运行所需的密钥值

如果本地运行(fcode run、发现脚本)需要一个尚未放入 variables.local.env 的真实密钥值,请让用户提供。如果用户不愿与 Agent 分享该值,请让他们自行将 KEY=value 行添加到 variables.local.env——本地运行会使用该值,且该值不会出现在对话中。

  • variables.local.env 中的值绝不会被推送。 请提醒用户还要在远程演示环境中手动创建这些密钥变量——fcode push 不会传输这些值。
  • FACTORIAL_TOKEN:仅在本地需要——远程环境会自动填充该变量,因此不要在远程环境中创建它。要获取该值,用户需在 Factorial Code 应用详情页完成 OAuth 流程,然后在 OAuth Dev 应用中使用复制下拉选项复制生成的令牌,并将其放入 variables.local.env(或根据用户偏好由其分享)。如果要在特定已安装公司的上下文中运行,则在 Test marketplace 应用页面的“…”菜单中,使用 Copy FACTORIAL_TOKEN 复制该 deploy- 工作区的令牌——放入同一文件,处理方式相同。
  • 获取后,绝不要在输出或日志中回显密钥值。

示例

开发周期(新流程):

fcode add
fcode dependencies:install            # if dependencies changed
fcode run shopify-order-sync --parameters '{"dateFrom":"2024-01-01","dateTo":"2024-01-31"}'
fcode push                            # no need to re-run `add` if nothing new was created

部署已有且经过测试的流程:

fcode push                            # `add` not needed — process already registered

评论

支持 Markdown