@neocompose/cli

中文文档
0.93.5发布于 2026/11/02MITES Module

neocompose原生项目源CLI与双向同步。

中文使用文档
文档目录14 节
  1. 源架构
  2. 运行
  3. Format-4工作副本
  4. 在当地组织资源
  5. 本土新作家
  6. 根值和类拥有的值
  7. 文件
  8. NeoFlow对话编写
  9. 同步工作流程
  10. NeoScript单元测试
  11. 命令
  12. 重新生成对话源名称
  13. 包装
  14. 源格式

neo - Neo Compose项目源CLI

neo 将git友好的Neo Compose项目工作副本与 网页编辑器。工作拷贝格式4是Neo-native: .neo 定义项目 模型和撰写值; .neoflow 定义对话流和托管映像 音频文件以普通二进制文件的形式保存。

当前代理编写指南已导入 cli/skills/neocompose-cli/SKILL.md. 功能规格 neo-compose-specs/new-features 文档设计意图和边缘情况;已发布的编译器、契约和 测试是可执行的事实来源。

源架构

CLI源代码将创作、文档投影和同步分开:

project-source/   parse, lower, and emit .neo/.neoflow plus managed binaries
project-manifest/ semantic bridge between authored source and project documents
project-sync/     diff, merge, conflict, migration, and CAS state handling

流程是 project source -> ProjectSchemaManifest -> project documents -> sync. ProjectSchemaManifest 携带独立版本的序列化文件 契约使得源语法和服务器文档可以在不耦合的情况下发展 它们的版本号。当前的工作区格式仍然是格式4;这个 清单的数字契约版本不是第二个工作副本格式。 依赖项向下指向: project-source 可以使用两个较低的层,而 project-sync 永远不要导入源代码编写或清单代码。

运行

npm i -g @neocompose/cli       # published package; installs `neo` on PATH
node cli/bin/neo.mjs <command> # repository development

在自动化中设置一个带有显式id的工作副本:

neo login --profile editor
neo init --project <id> --version <id> --dir neo

交互式终端可以选择项目、版本和目录。Neo 不安装、不发现或不需要。net。 neo doctor 验证 format-4浏览器安全编译器,VS Code分析合同,跟踪源代码,和 托管的文件的能力。中的畸形记录也会失败 文档的时间。

Format-4工作副本

neo/
  neo.json                         # formatVersion: 4
  Project.neo                      # project defaults/settings
  Root.neo                         # protected root shape; editable root values
  Classes/{System/, ...}
  Interfaces/{System/, ...}
  Enums/{System/, ...}
  Relations.neo                    # generic project relations, when present
  Templates/
  Localization.neo
  LocalizationStatuses/
  Files/
    Images.neo                     # ImageRegistry Images
    AudioClips.neo                 # AudioClipRegistry AudioClips
    Images/                        # tracked image bytes
    AudioClips/                    # tracked audio bytes
  DialogueGroups/
  Dialogues/*.neoflow
  Migrations/*.neo
  **/*.spec.neo                   # colocated local-only NeoScript tests
  .neo/
    state.json                     # private merge/CAS bases; never hand-edit
    conflicts/
    test-build/                    # local test compilation metadata

生产 .neo, .neoflow,并跟踪受支持的托管二进制文件。 托管的 .spec.neo 文件仅用于测试:它们从不输入状态、源 标识,拉/复位,或推。 .neo/ 被忽略的私有状态。没有图式 .csprojc#编写 树,Roslyn编译器,生成的创作DLL,每个函数的sidecar树,或 签入对话JSON。

只有 formatVersion: 4 被接受。格式4是一个彻底的突破;事实并非如此 读取或转换格式为3的c#签出。与老年人一起推动预期的变化 首先,保留您需要的任何本地源代码,然后从 权威服务器:

neo init --project <id> --version <id> --dir neo

对于现有的format-4工作区, neo pull --reset 再生规范 源代码和托管二进制文件。正常的 neo pull 执行一个稳定的id感知 三向合并,尽可能保留源位置,并使用持久的 事务游标,仅获取自上次同步以来更改的记录。 撤销/重置元数据将使该游标失效,并安全地退回到满的状态 快照。

在Unity项目中, neo.json 可以使用 unityConfigPath 而不是存储 projectId 和 versionId. 被引用的 NeoComposeConfig.asset 然后拥有 这些id并接收分支/版本切换。 neo export 写进去 统一项目;没有 unityConfigPath,它提供了链接配置资产 对于这个项目,它可以在Unity项目中找到工作副本。

验证源代码降低,提交准备,动画验证和Unity 的共享文件缓存中 .neo/build/. 一个新的CLI进程可以 重用;保持 neo dev 不需要运行。准确的输入和依赖关系 检查使受影响的结果无效。独立对话散文变化保存 结构性工作,包括提交这些更改的拉操作。结构性来源 编辑仍然需要更广泛的分析和准备。

Export检查输出字节并恢复丢失或修改的生成文件 在不重写未更改的文件的情况下,从其缓存中获取。 neo dev 使用相同的 每次保存后的准备和导出规则。

拉、推和导出拒绝其所拉项目或版本的工作副本 不同于配置,当资产在 CLI。运行 neo branch switch <versionId> 重置和拉配置 的版本。

在当地组织资源

移动 .neo 和 .neoflow 文件放入任何项目文件夹,并组声明 在您喜欢的文件中。保留现有的id。拉,用力,复位 在应用服务器状态之前的当前位置。新的服务器声明使用 默认文件夹。系统声明使用 System 子文件夹,例如 Classes/System, Enums/System,或者 Interfaces/System. 所有权来自于 保留的系统标识,因此项目类型保持其正常的默认值。 受管理的图像和音频也可以移动。更新他们键入的注册表路径。

将大型根或静态初始化器提取到类型化声明中,而不需要导入:

// Configuration/ProjectSortingLayers.neo
List<NeoSortingLayer> SORTING_LAYERS = [
  new NeoSortingLayer() { Name = "Default" }
];

// Inside the Root Assets initializer
SortingLayers = SORTING_LAYERS

现有的嵌套 @id 注释保留在提取的初始化器中。这个 消费成员保留其值ID;使用时不需要身份证。一个聚合 有一个归属赋值。其他参考资料使用 Reference(NAME) 哪里 成员支持引用。独立副本需要新的嵌套id; 编辑器的重复操作将删除旧的id。标量可能有好几个 的主人。如果网络编辑使这些值不同,则内联不同的用途。

共享语言服务为选定的完整文本提供提取到文件的功能 初始化器,内联用于单独使用,并重复。这些声明是局部的 项目设置,不创建运行时全局变量。将它们作为完整值使用 初始化;在可执行表达式中使用它们的名称,例如 BASE + 1 将被拒绝。初始化式循环和歧义 在同步之前聚合所有权验证失败。修复源错误 在使用提取的初始化器重置签出之前,以便它们的布局可以 恢复安全。

移民也可以移动。保持他们的 /// @migration 页眉和 /// @order N 指令,或保留用于排序的数字文件名前缀。

本土新作家

类、接口和枚举都是顶级声明。模式功能, getter和setter是内联的,并作为NeoScript编译;他们没有 分离源文件。

@id("enum-item-rarity-id")
enum ItemRarity {
  @id("rarity-common-id")
  Common = "Common text",
}

@id("class-inventory-item-id")
@storage(allowed: .Immutable)
abstract class InventoryItem<
  @id("inventory-context-generic-id")
  TContext extends SomeClass
> {
  @id("item-name-id")
  @settings(searchBy: .MemberKey)
  virtual string Name = "";

  @id("item-rarity-id")
  abstract ItemRarity Rarity;

  @id("item-stack-size-id")
  @settings(min: 1, max: 999)
  int StackSize = 1;

  @id("item-display-name-id")
  string DisplayName {
    get {
      return $"{Name} ({Rarity})";
    }
  }

  @id("item-use-id")
  abstract void Use(TContext context);
}

源标识符是持久化的名称。 @settings 和 @storage 是 由它们的声明上下文键入;无效字段和枚举情况为 诊断。Swift-like .EnumCase 语法适用于任何期望的枚举 类型是已知的。集中的注释,例如 @id, @visibility, @relations 进行横切行为。从来没有作者 @system;它是 为平台拥有的系统记录保留。 @visibility(.Hidden) 标志着 类的成员选择器和类树省略;缺席意味着可见。

列表可以重复 @index 和 @column 属性上命名字段的注释 entry类。索引需要一个非本地化的 string 或者单次选择 enum;列也可以针对保留的 __other__ Key,它携带 子类添加的每个字段的默认布局。

@id("outpost-list-id")
@settings(kind: .Unordered)
@index(member: Slug, kind: .Unique)
@column(member: Slug, width: 158, pin: .Leading)
@column(member: Notes, visibility: .Hidden)
public List<Outpost> Outposts = [];

稳定id在重命名、重新排序和文件移动中保持身份。省略一个 @id 只是为了创造一些东西。成功的真实推送会分配ID和 重写来源;试运行、验证失败、上传失败和CAS失败 保持源字节对字节不变。集合项标识使用相同的 本机注释:

Tags = [
  @id("story-tag-item-id")
  "story",
];

根值和类拥有的值

Root.neo 包含编译器拥有的 Root root = new() { ... } 信封。 它的成员名、类型、id、锁注释和存储设置是 受保护,而 root.Assets, root.Save, root.Session, root.User 值初始化式是可编辑的。

可重用值存储在普通项目类的静态成员中。有 没有 ValueRegistry 或生成 Values 名称空间。

@id("assets-class-id")
@storage(allowed: .Immutable)
class Assets {
  @id("capitol-member-id")
  static Outpost Capitol = new {
    Name = "Capitol",
    Image = Images.Capitol.Slice(0),
  };

  @id("home-getter-id")
  static Outpost Home {
    get {
      return Assets.Capitol;
    }
  }
}

成员ID锚定存储的绑定;不添加第二个ID到静态 初始化器。嵌套的类和集合行保持独立标识。

默认值在创建值时实现一次。现有实例不需要 与以后的类默认值更改保持链接。逻辑查找/对话引用 使用本机类型的内部变量。对值类型的引用,例如 Reference<int>,指定成员路径:

Reference(Assets.Capitol)
Reference(root.Assets.Cosmetics.Pants)
Reference(root.Player.Gold)
Reference<PantsAsset>(key: "pants.long")
Reference<NeoDialogue>(id: "dialogue-id")

Project.neo,输入纹理/音频模板,本地化配置和 状态、优先组/选项、对话组和直接关系使用 相同的顶级类型声明语法。编译器派生出结构 行标识、存储位置、通用戳记、本地化文本链接以及 其他不可创作源的持久性细节。

文件

图像和音频在类型注册表中声明并直接引用:

ImageRegistry Images = new() {
  @id("sword-image-file-id")
  @settings(template: PixelArt)
  NeoImage Sword = new("Files/Images/Sword.png");
}

AudioClipRegistry AudioClips = new() {
  @id("sword-hit-audio-file-id")
  @settings(template: SoundEffect)
  NeoAudioClip SwordHit = new("Files/AudioClips/SwordHit.wav");
}

使用 Images.Sword.Slice(0) 来一杯雪碧和 AudioClips.SwordHit 对于音频 成员。将支持的二进制文件放入 Files/Images/ 或者 Files/AudioClips/ 创建一个临时符号;状态/差异报告它,和一个 成功的push写入显式声明和分配的ID。 neo files add 可以在push之前创建挂起的声明。

Pull和push比较服务器验证的SHA-256摘要。不同的本地/远程 字节保存本地文件,并将经过验证的远程端置于 .neo/conflicts/files/<file-id>/ 直到显式解决。

NeoFlow对话编写

每一个 .neoflow 文件直接包含一个密封的非泛型类 来源于系统 NeoDialogue 输入和一个所需的触发器 覆盖。对话函数和词法值绑定是普通类型的 新代码。主要语言环境散文是内联的;其他区域设置和工作流元数据 保留在本地化文本记录中。

图构造函数使用仅限neoflow的尾体。 => Node 最后 return Node; 是相等的目的地;没有可授权的 to: 论点。终端文本/动作节点可以省略目的地,而触发器, 选择和结果都需要一个。

@id("capitol-dialogue-id")
@settings(name: "Capitol: cold boot", saveOptionChoices: true)
sealed class CapitolColdBoot : NeoDialogue {
  @primary Outpost capitol = Assets.Capitol;

  @id("can-start-function-id")
  bool CanStart() {
    return capitol.Name == "Capitol";
  }

  @id("capitol-trigger-id")
  override Trigger Trigger = new(
    group: CapitolDialogues.High,
    when: [
      @id("can-start-condition-use-id")
      CanStart,
    ]
  ) => Welcome;

  @id("welcome-node-id")
  Text Welcome = new(name: "Welcome!") {
    """
    Welcome to {capitol.Name}.
    """

    @id("continue-option-id")
    Option Continue = new() {
      """
      Tell me more.
      """
      return Finish;
    }
  }

  @id("finish-node-id")
  Text Finish = new() {
    """
    Until next time.
    """
  }
}

持久化条件使用、操作调用、突变、暂停、选项等 结果各有各的稳定 @id. 通过词汇进行引用 类的绑定和传递函数调用派生相同的链接值 网页编辑器。运行 neo dialogue dryrun <ref> 对话后编辑遍历 选项路径针对新的保存并捕获运行时存储所有权错误。

同步工作流程

neo pull
# edit .neo, .neoflow, and managed binaries
neo status
neo diff
neo dialogue dryrun <ref>
neo push --dry-run
neo push

拉紧跟着状态或推干跑必须是语义的 无操作。如果它报告创作更改,那么停止并报告一个往返错误 推动。

Pull按稳定标识合并源概念和集合,而不是按 索引。冲突是显式的,并阻塞编译。编辑源文件 期望的结果,或使用 neo resolve --mine|--theirs 作为整体 方便。没有强制cas旁路。接受所需的兼容性 只有在检查后才会碰撞 neo push --accept-bump.

一个push在本地准备提交:它重新编译改变了的NeoScript和 受模式影响的调用者,物化值,并验证整个图 对着被拉的头。服务器检查头部,每个更改的CAS库, 授权和行形状,然后自动提交语义记录更改, 本地化的主区域设置编辑和分级文件。它只接受来自 一个CLI在它自己的NeoScript编译器修订版。 neo push --dry-run 运行 同样的准备加上完整的从源到唱片的排练。

通过编辑它们的跟踪来创建类、存储值、文件声明和对话框 .neo 或者 .neoflow 直接来源。下添加托管二进制文件 Files/Images/ 或者 Files/AudioClips/; neo push 发现它们并将它们与源事务放在一起。CLI故意没有并行支架或低级内容写入命令。

NeoScript单元测试

的地方 *.spec.neo 文件在项目源代码旁边的任何地方。他们看到了完整的 本地准备的生产图——包括未推入的声明、值和 函数体-加上仅测试类型的前奏。生产源从未见过 测试全局。

describe("Player.TakeDamage", () => {
  test("rejects negative damage", () => {
    var player = new Player();
    expect(() => { player.TakeDamage(-1); }).toThrow("negative");
  });
});

运行所有测试,按文件/目录缩小范围,或使用。过滤完整测试名称 JavaScript正则表达式:

neo test
neo test Classes/Player.spec.neo
neo test -t "TakeDamage"
neo test --seed=17
neo test --maxWorkers=4
neo test --runInBand
neo test --reporter=json --outputFile=.neo/test-results.json

--seed 接受一个带符号的安全十进制整数,取2^32的约模。JSON 报告记录有效种子。没有它,项目指纹选择 种子。注册和每个隔离测试重新开始;beforeEach,身体, 和after共享测试的流。工作线程计数和过滤器不会改变 开始的水流。 neo script eval --seed 17 种子单一评价 服务器快照。

本地候选人评估保留待处理的身份 .neo/export.json 因此,随机存储的结构在测试、试运行、导出和推送中都是一致的。 一个只有身份的文件并不意味着Unity导出成功。缓存的候选人 恢复丢失的保留和重建冲突。推钩消耗 家长准备的候选人;不完整的钩子元数据显式失败。

默认情况下,规范文件与最多四个可用CPU工作线程并行运行。 集 test.maxWorkers 在 neo.json 或者用 --maxWorkers <positive integer>. --runInBand 覆盖两者并串行运行。单个选择 文件在主进程中运行。每个文件中的钩子和测试保持有序; fixture和mock保持隔离。报告、保存文件和测试注册命令。

JSON报告器使用 schemaVersion: 2. 失败帧包含一个成员名 和可选的 file, line, column. 没有文件的帧包括 coordinateSpace 区分身体相对位置;未知位置是 省略。从版本1升级的消费者必须允许这些可选位置。

JSON输出文件是自动写入的。报告区分已经过的启动 以及从总结的测试工作中执行,这可能会超过并行运行的时间 运行。JSON timings.workerStartupMs 测量worker初始化和 timings.executeMs 度量经过的执行。

测试编译并验证本地候选程序一次。他们省略了额外的来源 连载和重降排练使用的 neo push --dry-run;生产 语法、类型检查和整个图验证仍然是必需的。规范编制 跨缓存丢失共享一个不可变的编译器上下文和模式索引。

测试编译元数据和经过实验验证的准备项目缓存 住在 .neo/test-build/;它们和测试文件都不是服务器记录。 生产源,管理文件,配置,工作空间状态,CLI版本, 和编译器修订使准备的项目无效,而只编辑一个 .spec.neo File重用它。丢失、损坏或校验和不匹配的缓存 重新构建条目。工作空间必须初始化或拉一次 .neo/state.json 包含离线项目事实,但正在运行测试 不执行登录或网络请求。

本机函数不能在本地求值器中执行,因此会失败 除非被嘲笑,否则关闭。使用 mock.native(Member), mock.function(Member),或者 spyOn(Member),然后配置 returns, returnsOnce, throws, throwsOnce, doesNothing,或者 implementation. 模拟和调用历史记录在每个测试中是隔离的。

要进行门推送,请将其中一个或两个命令添加到 neo.json:

{
  "prePushHook": "neo test",
  "prePushDryRunHook": "neo test --reporter=json --outputFile=.neo/test-results.json"
}

real-push钩子故意不被用于演练:任意钩子 命令可能有副作用。每个适用的钩子只在local之后运行 候选人验证和认证前/网络活动;一个非零 退出中止。 neo push --no-verify 是显式本地旁路,而不是服务器 授权边界。

命令

命令目的
--version打印安装的CLI包版本。
login [--api <url>]验证选定的概要文件。
whoami [--api <url>]检查选定的概要文件。
logout [--api <url>]删除一个API源的存储凭据并撤销其会话。
init --project <id> [--version <id>]创建一个format-4工作副本并执行其第一次重置拉取。
doctor验证格式/编译器/编辑器/源/文件契约;否。净的发现。
pull [--force|--reset] [--regenerate-source-names]合并远程更改或重新生成规范源代码和二进制文件。
status [--json]编译源代码和汇总语义记录和上传意图。
diff [--json]显示语义记录、跨度、摘要和上传意图。
push [--dry-run] [--accept-bump] [--no-verify]验证或提交一个原子比较-交换事务。
test [file-or-dir ...] [-t pattern]编译未推送的本地候选程序并运行 *.spec.neo 测试。
dev [--unity-project <dir>]运行 neo export 每次局部变化之后;不要拉或推。
resolve --mine|--theirs用一方解决当前所有的源/二进制冲突。
script check|compile|eval编译或预览带有项目上下文的NeoScript;永远不要提交写。
dialogue dryrun <ref>模拟本地编写的对话候选人。
loc检查或编辑未在主语言环境源中表示的本地化数据。
migrate new|list|check|run|prune编写和管理跟踪的NeoScript迁移。
branch管理写时复制分支。
merge合并分支变更。
release剪切、发布、存档或恢复发布。
channel管理发布渠道。
history检查并有意改写保留下来的历史。
export [--unity-project <dir>]将工作副本(包括本地编辑)写入Unity项目中。

除了…之外 neo loc,内容创作通过 追踪原生来源和 neo push. 本地化命令可能会发生变化 权威本地化记录: .neo 不能完全代表;运行 neo pull 随后,在进一步的源代码编辑或推送之前。

login, whoami, logout 使用当前的工作区 apiBaseUrl 当 在下面跑 neo.json. 一个显式的 --api 需要优先。外 工作空间,它们使用CLI构建的默认API源。Login打印 在请求或存储凭据之前选择的来源。

令牌在可用时使用操作系统凭证存储和受保护的本地文件 只能作为退路。CI可以使用 NEO_COMPOSE_TOKEN 或者 --token-stdin。这个 编辑器配置文件无法发布版本;服务器授权仍然是 安全边界。

重新生成对话源名称

每次拉扯,包括 --force 和 --reset,保存对话源名称 服务器存储。来替换生成的默认值,例如 Value_1a2b3c4d5e6f, NeoFunction_…,或者 Conditions1 使用从编辑器派生的名称,运行:

neo pull --regenerate-source-names
neo status
neo push --dry-run

您选择的名字将被保留。当绑定被重命名时,引用它的代码也被重命名 重写以匹配。自定义链接值首选非空字符串成员 Name在对话范围内使用PascalCase,在节点内使用camelCase。

拉动将重新生成的名称作为局部更改留下。id不变,和 之前不会向服务器写入任何内容 neo push 成功。

包装

node cli/build.mjs 捆绑了Node编排器和浏览器安全的Neo 语言/编译器/编辑资产。npm包中没有c# SDK, Roslyn 应用程序、DLL或。NET运行时元数据。包检查拒绝那些 构件并验证是否存在共享的编译器资产和技能。

开发时的有用检查:

npm run typecheck
npx vitest run cli
npm --prefix cli run test:package

在发布、打包和发布之前运行存储库的完整验证套件 练习VS Code扩展,验证Hello World和live neowyn 格式-4无操作工作流,并运行 npm run doctor 最后的。

源格式

CLI和NeoScript VS Code扩展使用相同的格式化器。把项目 偏好, .editorconfig,包括在父目录 neo/:

[*.{neo,neoflow}]
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true

嵌套的EditorConfig节覆盖父节。没有明确的 按照惯例,CLI再生使用两个空格、LF和最后一个换行符。VS代码 扩展使用编辑器设置作为回退并禁用缩进 默认是猜测。要在同步和编辑器保存中使用四个空格或制表符, 将首选项设置为 .editorconfig.

当发出的令牌不变时,Push保留已授权的文本,包括 普通注释和空白行。Pull保留文件而不改变语义。 仅格式化的主体和源位置的差异不会创建稍后的推送, 甚至与其他编辑一起。本地测试使用当前文件位置; neo push --force-recompile 显式刷新存储位置。内部的变化 字符串字面值仍然很重要。 必须重新生成的文件使用共享格式化策略。网络编辑使用 共享的两个空格默认值,并将包装器缩进排除在存储体之外。

版本与发布记录

@neocompose/cli 共发布 346 个版本,首次发布于 2026/06/12;过去 12 个月发布了 346 个版本。

版本发布日期距今
0.93.5latest2026/11/021 天前
0.93.42026/11/011 天前
0.93.32026/11/012 天前
0.93.22026/10/312 天前
0.93.12026/10/313 天前
0.93.02026/10/313 天前

关于 @neocompose/cli 的常见问题

@neocompose/cli 是什么?

neocompose原生项目源CLI与双向同步。

如何安装 @neocompose/cli?

在项目目录运行 npm install @neocompose/cli,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 neo,可以用 npx neo 直接运行。

@neocompose/cli 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/neocompose__cli 是否存在。

@neocompose/cli 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@neocompose/cli 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@neocompose/cli 可以商用吗?

@neocompose/cli 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@neocompose/cli 还在维护吗?

最新版本 0.93.5 发布于 2026/11/02(1 天前);至今共发布 346 个版本,其中过去 12 个月发布了 346 个;首次发布于 2026/06/12。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。