Skip to Content
aindex 与配置

aindex 与 .tnmsc.json

如果你只想用一页搞清项目准备和配置,就看这一页。

需要分开的两件事

memory-sync 把下面两项视为不同层:

  • 工作区 aindex 目录下的源内容树
  • 位于 ~/.aindex/.tnmsc.json 的规范全局用户配置文件

它们彼此相关,但不是同一回事。

各自放在哪里

工作区内容

aindex 内容树位于:

TEXT
<workspaceDir>/aindex

这里通常放这些源内容:

  • skills/
  • commands/
  • subagents/
  • rules/
  • app/
  • ext/
  • arch/
  • softwares/
  • global.src.mdx
  • workspace.src.mdx

这里也包含两类和 TypeScript 运行时直接相关的约定文件:

  • 分布在各个内容目录中的 proxy.ts
  • <series>/<project>/project.config.ts

用户配置

当前 tnmsc 唯一会自动加载的用户配置文件是:

TEXT
~/.aindex/.tnmsc.json

当前加载器不会从当前项目目录自动发现 ./.tnmsc.json

proxy.tsproject.config.ts

这两个文件都属于工作区 aindex 内容树的一部分,不属于 ~/.aindex/.tnmsc.json

proxy.ts 的作用

proxy.ts 不是只能放在 aindex/public 下。

它可以位于 aindex 内容树中的很多位置,例如:

TEXT
<workspaceDir>/aindex/app/.../proxy.ts
<workspaceDir>/aindex/softwares/.../proxy.ts
<workspaceDir>/aindex/arch/.../proxy.ts
<workspaceDir>/aindex/ext/.../proxy.ts
<workspaceDir>/aindex/commands/.../proxy.ts
<workspaceDir>/aindex/skills/.../proxy.ts
<workspaceDir>/aindex/subagents/.../proxy.ts

它的通用作用是:

  • 为当前内容单元定义路径转换规则
  • 把逻辑引用路径转换成实际应当读取、写入或解析的目标路径
  • 让路径规则跟随具体内容单元本身,而不是全部硬编码在 Rust 中

也就是说,proxy.ts 更像是“局部路径解析器”或“路径转换钩子”。

aindex/public/proxy.ts 这个特例

其中一个常见特例是:

TEXT
<workspaceDir>/aindex/public/proxy.ts

这个文件负责公共内容树下的路径转换,尤其是 dotfile 映射。

典型场景:

  • .git/info/exclude.vscode/settings.json 这类 dotfile 路径映射到 ____.git/info/exclude____vscode/settings.json
  • tnmsc installdry-run 等流程会通过 SDK 运行时调用它

当前 Rust 侧入口是:

  • DenoRuntime::resolve_public_path(...)
  • 更上层的 resolve_public_path_impl(...)

调用时,运行时会把上下文挂到 globalThis.__tnmsContext,其中至少包含:

JSON
{
  "logicalPath": ".git/info/exclude"
}

从用法上说,proxy.ts 一般应当做的事很简单:

  • 读取 globalThis.__tnmsContext.logicalPath
  • 计算出目标相对路径
  • console.log(...) 输出最终结果

最小示例:

TS
const ctx = (globalThis as typeof globalThis & {
  __tnmsContext?: { logicalPath?: string }
}).__tnmsContext
 
const logicalPath = ctx?.logicalPath ?? ''
const normalized = logicalPath.replaceAll('\\', '/')
 
if (normalized.startsWith('.git/')) {
  console.log(normalized.replace('.git/', '____.git/'))
} else if (normalized.startsWith('.vscode/')) {
  console.log(normalized.replace('.vscode/', '____vscode/'))
} else {
  console.log(normalized)
}

返回约定:

  • 输出必须是一个相对路径字符串
  • Rust 侧会继续做安全校验,拒绝绝对路径和 .. 逃逸路径

如果你的内容单元本身也有局部路径解析需求,那么它自己的 proxy.ts 可以放在对应目录下,而不必复用 aindex/public/proxy.ts

aindex/<series>/<project>/project.config.ts 的作用

位置:

TEXT
<workspaceDir>/aindex/<series>/<project>/project.config.ts

例如:

TEXT
<workspaceDir>/aindex/app/myproject/project.config.ts

作用:

  • 为某个项目提供程序化配置
  • 允许脚本根据工作区路径、项目名、系列名等上下文生成最终配置
  • SDK 通过 DenoRuntime::load_project_config(...) 加载它

调用时,运行时会把上下文挂到 globalThis.__tnmsContext,其中包含:

JSON
{
  "workspaceDir": "/repo/demo",
  "aindexDir": "/repo/demo/aindex",
  "projectName": "myproject",
  "seriesName": "app"
}

当前实现下,这个脚本的最直接写法是:

  • globalThis.__tnmsContext 读取上下文
  • 组装一个普通 JSON 对象
  • console.log(JSON.stringify(...)) 输出

最小示例:

TS
const ctx = (globalThis as typeof globalThis & {
  __tnmsContext?: {
    workspaceDir?: string
    aindexDir?: string
    projectName?: string
    seriesName?: string
  }
}).__tnmsContext
 
console.log(
  JSON.stringify({
    name: ctx?.projectName,
    series: ctx?.seriesName,
    workspaceDir: ctx?.workspaceDir,
    aindexDir: ctx?.aindexDir,
    enabled: true
  })
)

返回约定:

  • 标准输出必须是可解析的 JSON 文本
  • Rust 侧会把这段输出再解析成 serde_json::Value

什么时候该用它们

  • 需要给某个内容单元定义局部路径转换规则时,用它附近的 proxy.ts
  • 需要把逻辑上的 dotfile 路径映射到 aindex/public 中的真实存储路径时,用 aindex/public/proxy.ts
  • 需要给某个项目生成动态配置,而不是写死在静态 JSON 里时,用 project.config.ts

如果你只是配置用户偏好、日志级别、插件启停或 workspaceDir,不要写进这两个脚本,而应当放在 ~/.aindex/.tnmsc.json 或项目级 plugin.config.ts 中。

最小准备

至少需要:

  • 一个项目根目录
  • 一棵符合 aindex 约定的源内容树
  • ~/.aindex/.tnmsc.json
  • 一个项目级的 plugin.config.ts

这种拆分是有意为之:

  • ~/.aindex/.tnmsc.json 存放用户级或机器级配置数据
  • plugin.config.ts 存放项目侧的插件装配和程序化覆盖
  • ~/.aindex/.tnmsc.json 还决定哪些已装配的输出插件真正被允许写入

最小示例

JSON
{
  "workspaceDir": "/repo/demo"
}

在这份配置下:

  • 工作区根目录是 /repo/demo
  • aindex 根目录是 /repo/demo/aindex
  • skills 解析为 /repo/demo/aindex/skills
  • 默认的全局 prompt 源文件解析为 /repo/demo/aindex/global.src.mdx
  • 除非你显式设置,否则 logLevel 会回退到 info

~/.aindex/.tnmsc.json 中稳定的顶层字段

这些是当前运行时真正会从全局配置文件中消费的用户侧字段:

字段类型默认值含义
versionstring合并后运行时选项中的 "0.0.0"透传给运行时的版本或发布标记
workspaceDirstring配置里可省略;未提供时从运行时工作目录推导工作区根目录,通常位于 ~/workspace/
logLevelenuminfotrace / debug / info / warn / error
frontMatterobject{ "blankLineAfter": true }Front matter 的格式化行为
codeStylesobject合并后运行时选项中的 { "indent": "space", "tabSize": 2 }暴露给 prompt 求值的用户代码风格偏好
windowsobject{}Windows 和 WSL 专用运行时选项
profileobject省略用户资料元数据
pluginsobject合并后运行时选项中的 {}每个插件输出启用状态的显式覆盖

工作区 aindex 树下的所有内容都保持固定名称和固定相对位置。结构如下:

TEXT
<workspaceDir>/
  aindex/
    skills/
    commands/
    subagents/
    rules/
    app/
    ext/
    arch/
    softwares/
    global.src.mdx
    global.mdx
    workspace.src.mdx
    workspace.mdx

这棵树里的固定路径都不能通过 ~/.aindex/.tnmsc.json 进行用户配置。

frontMatter

JSON
{
  "frontMatter": {
    "blankLineAfter": true
  }
}

格式差异请参见 Front Matter

codeStyles

JSON
{
  "codeStyles": {
    "indent": "space",
    "tabSize": 2
  }
}
字段类型含义
codeStyles.indent"tab" | "space"首选缩进方式
codeStyles.tabSizeinteger首选缩进宽度

也接受额外键,这样你可以把一些轻量的个人风格偏好放在同一个地方。

这个区块本身是可选的。即使你省略它,运行时仍会注入 codeStyles.indent = "space"codeStyles.tabSize = 2

编译 prompts 时,这些值可在 MDX 表达式中使用,例如 {codeStyles.indent}{codeStyles.tabSize}

windows

JSON
{
  "windows": {
    "wsl2": {
      "instances": ["Ubuntu", "Ubuntu-24.04"]
    }
  }
}
字段类型含义
windows.wsl2.instancesstring | string[]Windows 专用集成所使用的 WSL 实例名称

profile

profile 是一个开放对象。schema 明确识别这些可选字段:

  • name
  • username
  • gender
  • birthday

也接受额外键。

plugins

当前运行时也识别 plugins 区块:

JSON
{
  "plugins": {
    "git": true,
    "claudeCode": false,
    "trae": true
  }
}

每个键只接受布尔值:

  • true:允许该已装配插件产出输出
  • false:禁止该插件生成输出,但仍保留清理行为

如果 plugins 含有任何不受支持的键,tnmsc 现在会把它视为硬性配置错误:

  • 它会记录哪个键不受支持
  • 它会打印受支持键的列表
  • 它会直接退出,而不是静默忽略这个错误项

已知键包括:

  • agentsMd
  • claudeCode
  • codex
  • cursor
  • droid
  • gemini
  • git
  • jetbrains
  • jetbrainsCodeStyle
  • kiro
  • opencode
  • qoder
  • readme
  • trae
  • traeCn
  • vscode
  • warp
  • windsurf
  • zed

当前内建默认行为是:

  • git 默认启用
  • readme 默认启用
  • 其他已知插件键默认禁用,直到你显式开启

plugins.readme 同时控制 README 类输出和 .editorconfig

请使用 plugins.git,不要使用 plugins.gitExclude

这个区块控制的是实际输出行为。项目级的 plugin.config.ts 仍然负责装配可用插件集合,但仅仅完成装配并不代表该插件一定会写文件。

Warning 某些目标路径,例如 .codex/.claude/ 或其他工具配置目录,必须是真实目录。如果同名文件占据了该路径,tnmsc 会把它视为目录/文件类型冲突,并阻止输出生成。

这个恢复路径的目标是避免冲突并让同步继续。当前运行时的做法是给出警告、删除阻塞文件,并自动重建预期的目录结构。

无效配置示例:

JSON
{
  "plugins": {
    "vscode": true,
    "codex": true,
    "foo": true
  }
}

这份配置会失败,因为 foo 不是受支持的键。

已移除的遗留字段

不要把这些字段重新放回新的 ~/.aindex/.tnmsc.json 文件:

  • agents
  • aindexdir,以及旧的 *.src / *.dist 路径对覆盖项,例如 skillscommandssubAgentsrulesglobalPromptworkspacePromptappextarchsoftwares
  • commandSeriesOptions
  • outputScopes
  • cleanupProtection
  • 更早期的实验性或 consolidation 之前的字段,例如 externalProjectsexcludePatternsshadowSourceProject

某些兼容层在迁移期间可能仍会解析这些键或给出警告,但它们已经不再属于受支持的用户侧配置界面。

接下来读什么

Last updated on