aindex 与 .tnmsc.json
如果你只想用一页搞清项目准备和配置,就看这一页。
需要分开的两件事
memory-sync 把下面两项视为不同层:
- 工作区 aindex 目录下的源内容树
- 位于
~/.aindex/.tnmsc.json的规范全局用户配置文件
它们彼此相关,但不是同一回事。
各自放在哪里
工作区内容
aindex 内容树位于:
<workspaceDir>/aindex这里通常放这些源内容:
skills/commands/subagents/rules/app/ext/arch/softwares/global.src.mdxworkspace.src.mdx
这里也包含两类和 TypeScript 运行时直接相关的约定文件:
- 分布在各个内容目录中的
proxy.ts <series>/<project>/project.config.ts
用户配置
当前 tnmsc 唯一会自动加载的用户配置文件是:
~/.aindex/.tnmsc.json当前加载器不会从当前项目目录自动发现 ./.tnmsc.json。
proxy.ts 与 project.config.ts
这两个文件都属于工作区 aindex 内容树的一部分,不属于 ~/.aindex/.tnmsc.json。
proxy.ts 的作用
proxy.ts 不是只能放在 aindex/public 下。
它可以位于 aindex 内容树中的很多位置,例如:
<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 这个特例
其中一个常见特例是:
<workspaceDir>/aindex/public/proxy.ts这个文件负责公共内容树下的路径转换,尤其是 dotfile 映射。
典型场景:
- 把
.git/info/exclude、.vscode/settings.json这类 dotfile 路径映射到____.git/info/exclude、____vscode/settings.json tnmsc install、dry-run等流程会通过 SDK 运行时调用它
当前 Rust 侧入口是:
DenoRuntime::resolve_public_path(...)- 更上层的
resolve_public_path_impl(...)
调用时,运行时会把上下文挂到 globalThis.__tnmsContext,其中至少包含:
{
"logicalPath": ".git/info/exclude"
}从用法上说,proxy.ts 一般应当做的事很简单:
- 读取
globalThis.__tnmsContext.logicalPath - 计算出目标相对路径
- 用
console.log(...)输出最终结果
最小示例:
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 的作用
位置:
<workspaceDir>/aindex/<series>/<project>/project.config.ts例如:
<workspaceDir>/aindex/app/myproject/project.config.ts作用:
- 为某个项目提供程序化配置
- 允许脚本根据工作区路径、项目名、系列名等上下文生成最终配置
- SDK 通过
DenoRuntime::load_project_config(...)加载它
调用时,运行时会把上下文挂到 globalThis.__tnmsContext,其中包含:
{
"workspaceDir": "/repo/demo",
"aindexDir": "/repo/demo/aindex",
"projectName": "myproject",
"seriesName": "app"
}当前实现下,这个脚本的最直接写法是:
- 从
globalThis.__tnmsContext读取上下文 - 组装一个普通 JSON 对象
- 用
console.log(JSON.stringify(...))输出
最小示例:
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还决定哪些已装配的输出插件真正被允许写入
最小示例
{
"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 中稳定的顶层字段
这些是当前运行时真正会从全局配置文件中消费的用户侧字段:
| 字段 | 类型 | 默认值 | 含义 |
|---|---|---|---|
version | string | 合并后运行时选项中的 "0.0.0" | 透传给运行时的版本或发布标记 |
workspaceDir | string | 配置里可省略;未提供时从运行时工作目录推导 | 工作区根目录,通常位于 ~/workspace/ 下 |
logLevel | enum | info | trace / debug / info / warn / error |
frontMatter | object | { "blankLineAfter": true } | Front matter 的格式化行为 |
codeStyles | object | 合并后运行时选项中的 { "indent": "space", "tabSize": 2 } | 暴露给 prompt 求值的用户代码风格偏好 |
windows | object | {} | Windows 和 WSL 专用运行时选项 |
profile | object | 省略 | 用户资料元数据 |
plugins | object | 合并后运行时选项中的 {} | 每个插件输出启用状态的显式覆盖 |
工作区 aindex 树下的所有内容都保持固定名称和固定相对位置。结构如下:
<workspaceDir>/
aindex/
skills/
commands/
subagents/
rules/
app/
ext/
arch/
softwares/
global.src.mdx
global.mdx
workspace.src.mdx
workspace.mdx这棵树里的固定路径都不能通过 ~/.aindex/.tnmsc.json 进行用户配置。
frontMatter
{
"frontMatter": {
"blankLineAfter": true
}
}格式差异请参见 Front Matter。
codeStyles
{
"codeStyles": {
"indent": "space",
"tabSize": 2
}
}| 字段 | 类型 | 含义 |
|---|---|---|
codeStyles.indent | "tab" | "space" | 首选缩进方式 |
codeStyles.tabSize | integer | 首选缩进宽度 |
也接受额外键,这样你可以把一些轻量的个人风格偏好放在同一个地方。
这个区块本身是可选的。即使你省略它,运行时仍会注入 codeStyles.indent = "space" 和 codeStyles.tabSize = 2。
编译 prompts 时,这些值可在 MDX 表达式中使用,例如 {codeStyles.indent} 和 {codeStyles.tabSize}。
windows
{
"windows": {
"wsl2": {
"instances": ["Ubuntu", "Ubuntu-24.04"]
}
}
}| 字段 | 类型 | 含义 |
|---|---|---|
windows.wsl2.instances | string | string[] | Windows 专用集成所使用的 WSL 实例名称 |
profile
profile 是一个开放对象。schema 明确识别这些可选字段:
nameusernamegenderbirthday
也接受额外键。
plugins
当前运行时也识别 plugins 区块:
{
"plugins": {
"git": true,
"claudeCode": false,
"trae": true
}
}每个键只接受布尔值:
true:允许该已装配插件产出输出false:禁止该插件生成输出,但仍保留清理行为
如果 plugins 含有任何不受支持的键,tnmsc 现在会把它视为硬性配置错误:
- 它会记录哪个键不受支持
- 它会打印受支持键的列表
- 它会直接退出,而不是静默忽略这个错误项
已知键包括:
agentsMdclaudeCodecodexcursordroidgeminigitjetbrainsjetbrainsCodeStylekiroopencodeqoderreadmetraetraeCnvscodewarpwindsurfzed
当前内建默认行为是:
git默认启用readme默认启用- 其他已知插件键默认禁用,直到你显式开启
plugins.readme 同时控制 README 类输出和 .editorconfig。
请使用 plugins.git,不要使用 plugins.gitExclude。
这个区块控制的是实际输出行为。项目级的 plugin.config.ts 仍然负责装配可用插件集合,但仅仅完成装配并不代表该插件一定会写文件。
Warning 某些目标路径,例如
.codex/、.claude/或其他工具配置目录,必须是真实目录。如果同名文件占据了该路径,tnmsc 会把它视为目录/文件类型冲突,并阻止输出生成。这个恢复路径的目标是避免冲突并让同步继续。当前运行时的做法是给出警告、删除阻塞文件,并自动重建预期的目录结构。
无效配置示例:
{
"plugins": {
"vscode": true,
"codex": true,
"foo": true
}
}这份配置会失败,因为 foo 不是受支持的键。
已移除的遗留字段
不要把这些字段重新放回新的 ~/.aindex/.tnmsc.json 文件:
agentsaindex、dir,以及旧的*.src/*.dist路径对覆盖项,例如skills、commands、subAgents、rules、globalPrompt、workspacePrompt、app、ext、arch和softwarescommandSeriesOptionsoutputScopescleanupProtection- 更早期的实验性或 consolidation 之前的字段,例如
externalProjects、excludePatterns和shadowSourceProject
某些兼容层在迁移期间可能仍会解析这些键或给出警告,但它们已经不再属于受支持的用户侧配置界面。
接下来读什么
- 如果你想了解命令工作流,继续看第一次安装流程
- 如果你需要插件装配说明,阅读 plugin.config.ts
- 如果你需要清理或输出边界行为,继续看 CLI