morphix-env 0.8.0 → 0.10.0

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/README.md CHANGED
@@ -55,7 +55,7 @@ The same key from two sources fails by default; the later source must declare `"
55
55
  }
56
56
  ```
57
57
 
58
- Providers: `infisical` · `doppler` · `os-keychain` (macOS) · `dotenvx` (encrypted files) · `local` (dotenv files). Provider login and bootstrap stay on the provider side (`infisical login`, `doppler login`, dotenvx key bootstrap) and never enter repository config.
58
+ Providers: `infisical` · `doppler` · `os-keychain` (macOS) · `dotenvx` (encrypted files) · `local` (plaintext dotenv files — **development only**; move them to encrypted storage with `mx-env migrate`). Provider login and bootstrap stay on the provider side (`infisical login`, `doppler login`, dotenvx key bootstrap) and never enter repository config.
59
59
 
60
60
  ## Compared with existing secret management
61
61
 
@@ -90,6 +90,51 @@ This is leakage minimization, not a cryptographic boundary: a process that recei
90
90
 
91
91
  `mx-env run` without `--serve` is unchanged: values are injected into the environment and redacted from forwarded output.
92
92
 
93
+ ## Terminal shims
94
+
95
+ For commands you run constantly, shims remove the `mx-env run --` prefix entirely. Declare a command list and generate shims once:
96
+
97
+ ```jsonc
98
+ // ~/.mx-env/config.json (global) and/or mx-env.config.json (project)
99
+ { "shims": ["node", "pnpm"] }
100
+ ```
101
+
102
+ ```bash
103
+ mx-env shell-init # generate shims in ~/.mx-env/shims, print the PATH line
104
+ mx-env shell-init --write # also maintain a marked block in ~/.zshrc / ~/.bashrc
105
+ mx-env shell-init --remove # remove shims and the rc block
106
+ ```
107
+
108
+ After the PATH line is active, typing `pnpm dev` is exactly `mx-env run -- pnpm dev`: same composition, same redaction, same exit code. Undeclared commands are untouched.
109
+
110
+ - The effective list is the union of the global and project lists. A shim is only an entry hook: **what gets injected is always decided by the configuration in effect where the command runs**, so one `pnpm` shim serves every project's own profile.
111
+ - `run` removes the shims directory from the child's PATH before composing, so a tool invoked again inside the run (or by a provider plugin mid-composition) resolves to the real binary — injection happens exactly once, never recursively.
112
+ - `shell-init` is idempotent: re-running converges the directory to the declared list, `--write`/`--remove` use marked rc blocks and never touch your other lines or handmade files.
113
+ - Command names are validated (bare names only; mx-env's own command names are reserved). Invalid entries fail `shell-init` loudly but only warn in composition paths — a convenience layer never breaks `run`.
114
+ - Audit events record `via: "shim"` vs `"cli"` so the two channels stay distinguishable.
115
+
116
+ **Boundary.** Shims buy convenience, not concealment: injected values live in the child's environment and are visible to same-uid processes. When the consumer is an agent you do not trust with the values, use `run --serve` instead. macOS/Linux only; Windows keeps the explicit `run` form. Do not place files in `~/.mx-env/shims` by hand.
117
+
118
+ ## Retiring plaintext: `mx-env migrate`
119
+
120
+ Plaintext dotenv files are a development convenience, not a storage end-state — file permissions do not protect them from a same-uid agent process. `mx-env migrate` moves them into encrypted storage (dotenvx encrypted files, or the macOS Keychain) with a backup and a value-level equivalence check at every step:
121
+
122
+ ```bash
123
+ mx-env migrate # read-only plan: units, files, key names (never values)
124
+ mx-env migrate --to dotenvx # encrypt in place; declared sources flip to provider dotenvx
125
+ mx-env migrate --to keychain --source mysource # values move to service mx-env:mysource; plaintext is deleted
126
+ ```
127
+
128
+ Scope: the global `~/.mx-env/.env` (dotenvx target only) plus every declared `local` source in the global and project configs. Legacy `.env.local`/`envFiles` are reported as hints — declare them as sources first. Two sources sharing one file are refused: split them first.
129
+
130
+ - Every unit gets a **0600 backup** (`<file>.mx-env-backup-<timestamp>`) and a **post-migration equivalence check** — decrypted or keychain-read-back values must match the plaintext snapshot exactly — before any config is rewritten. On failure the plaintext and config are restored from backup and the backup paths printed. Backups stay until you delete them yourself.
131
+ - dotenvx migrations pin the file model (`--no-native`): the private key lands in a 0600 `.env.keys` beside the file — portable and CI-friendly — instead of the OS keychain. An unignored `.env.keys` inside a git repo earns a loud warning; the encrypted `.env` itself is safe to commit (that is the dotenvx model).
132
+ - The global file needs no config change: composition sniffs the encryption markers and loads it through the dotenvx provider automatically, with the same 0600 gate on `.env.keys` the plaintext file had.
133
+ - Verification goes through `dotenvx decrypt`, never `run`, so a same-named shell export cannot shadow the check. At compose time, dotenvx sources are file-value-wins (`--overload`) — the same semantics `local` had, so migration does not change what your commands see.
134
+ - Migrations are recorded in the value-free audit (`profile: migrate`).
135
+
136
+ `--dry-run` with `--to` prints the full execution plan without writing. The keychain target is macOS-only and serves declared sources; the dotenvx target needs the dotenvx CLI (`npm i -g @dotenvx/dotenvx` or a project devDependency).
137
+
93
138
  ## Provider plugins
94
139
 
95
140
  Any executable on PATH named `mx-env-provider-<name>` is a provider — new remote stores need no changes to `config.ts` / `sources.ts` / `editor.ts`:
@@ -122,6 +167,7 @@ mx-env export [--profile agents] # eval-able export KEY='value' lines (va
122
167
  mx-env render <template> <output> # substitute ${VAR} into a config file (mode 0600)
123
168
  mx-env inject <template> <output> # resolve mx-env://profile/KEY references into a file (mode 0600)
124
169
  mx-env inspect [--profile dev] # key names + provenance, no values
170
+ mx-env migrate [--to dotenvx|keychain] # move plaintext local sources into encrypted storage
125
171
  mx-env edit [--profile dev | --source s] # one-shot visual editor
126
172
  mx-env generate --out public/__env.js # public browser runtime config
127
173
  mx-env doc # write this project's key→source skill
@@ -145,6 +191,8 @@ mx-env skill install --target trellis # ~/.trellis/skills/morphix-env/ — the
145
191
 
146
192
  Installs are idempotent, and a skill file the user has customized is never overwritten without `--force`. `mx-env skill show` reports each target's install state and template drift.
147
193
 
194
+ When the consumer is an agent, prefer `mx-env run --serve -- <command>`: values never enter any process environment, and the agent fetches them one at a time over loopback. Keep secrets in encrypted storage (`mx-env migrate`) and this forms the chain where an agent never touches plaintext — at rest or in env. (Once native keychain ACLs land, the keychain itself can additionally gate access behind Touch ID.)
195
+
148
196
  For project-specific guidance, `mx-env doc --profile <name>` generates a value-free skill listing this project's resolved key names and their winning sources (`.agents/skills/morphix-env/SKILL.md`).
149
197
 
150
198
  ## Legacy configuration
package/dist/SKILL.md CHANGED
@@ -50,6 +50,7 @@ npx morphix-env@latest inspect # 免安装试用
50
50
  要点:
51
51
 
52
52
  - profile 内 `sources` **从低到高**排列;同 key 冲突默认**报错**,靠后 source 显式 `"override": true` 才覆盖(防止两个环境的同名凭据静默错选)。
53
+ - `local`(明文 dotenv)**仅开发用**;长期存储用 dotenvx(加密文件)或 os-keychain,迁移走 `mx-env migrate`。
53
54
  - provider 登录与引导留在 provider 侧(`infisical login`、`doppler login`、dotenvx 解密密钥引导),**不写进项目配置**。
54
55
  - plugin source:PATH 上的 `mx-env-provider-<name> <KEY>` 把值写到 stdout(退出码 0);插件自带登录,失败信息不含值。
55
56
  - 固定基线顺序:`inherited process.env → ~/.mx-env/.env → 全局默认 profile → 项目 profile / legacy 配置 → -f 覆盖文件`。legacy 项目(`infisical` + `envFiles` 字段)无需改动即兼容。
@@ -71,8 +72,14 @@ mx-env doc # 生成本项目的 key→source 工
71
72
  mx-env audit [tail] # 值无关的本地审计事件
72
73
  mx-env skill install [--target global|project|trellis] [--force] # 安装本 Skill
73
74
  mx-env skill show # 查看各目标安装状态
75
+ mx-env shell-init [--write|--remove] # 为声明的命令生成 PATH shim(shims: ["node","pnpm"] 配置项)
76
+ mx-env migrate [--to dotenvx|keychain] # local 明文迁加密存储(无 --to 为只读 plan;备份+等价验证+可回滚)
74
77
  ```
75
78
 
79
+ **明文退场指引**:`local` provider(明文 dotenv 文件)定位是**仅开发用**——文件权限防不住同 uid 的 agent 进程。发现项目或全局在用明文源(`mx-env inspect` 里标 `[plaintext, dev-only]`),引导用户跑 `mx-env migrate` 看 plan,再 `--to dotenvx`(加密文件,跨机/CI 友好)或 `--to keychain`(macOS 钥匙串)。迁移有 0600 备份与值级等价验证,失败自动还原。legacy `.env.local` 不自动迁移——先引导声明为 source。
80
+
81
+ **shim 消费指引**:配置里声明过 `shims` 且执行过 `shell-init` 的机器上,裸敲被声明命令(如 `pnpm dev`)等价于 `mx-env run -- pnpm dev`——你可以依赖它,无需加前缀。但 shim 是方便性不是隐藏:值仍在子进程 env。**需要值不进 env 的场景(高风险 agent 能力、不可信子进程树)必须显式用 `run --serve`**,不要依赖 shim。audit 里 `via: "shim"` 与 `"cli"` 可区分两种来路。
82
+
76
83
  `export` / `render` / `inject` / `run` 均支持 `--dry-run`(只报 key/变量名,不出值)。值永不出现在 shell 历史里:`eval "$(mx-env export --profile dev)"` 才是 export 的消费方式。
77
84
 
78
85
  ## 进入一个新项目的标准流程