morphix-env 0.6.0-beta.2 → 0.7.0-beta.1

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
@@ -6,6 +6,8 @@
6
6
 
7
7
  The concise command is `mx-env`; the published `morphix-env` command remains fully supported.
8
8
 
9
+ The package also ships a maintained, value-free Agent Skill (`mx-env skill install`) so agents can adopt the whole workflow — safety rules, configuration schema, commands — without a second distribution; see [Agent workflow](#agent-workflow).
10
+
9
11
  ## Quick start: global local defaults
10
12
 
11
13
  Create this file once:
@@ -202,6 +204,12 @@ mx-env edit --profile api-dev
202
204
  # Generate this project's value-free Agent workflow Skill
203
205
  mx-env doc --profile api-dev
204
206
 
207
+ # Install the packaged Agent Skill (global | project | trellis)
208
+ mx-env skill install --target project
209
+
210
+ # Show per-target install state and template drift
211
+ mx-env skill show
212
+
205
213
  # Value-free audit events
206
214
  mx-env audit tail
207
215
  ```
@@ -217,12 +225,31 @@ Options:
217
225
  | `--no-global` | Ignore `~/.mx-env/.env` and `~/.mx-env/config.json`. |
218
226
  | `--allow-insecure-global` | Explicitly permit a global dotenv file readable by group/other users. Avoid this outside controlled troubleshooting. |
219
227
  | `--print-editor-url` | Explicitly print the one-time local editor URL; normally the browser opens without emitting it to the terminal. |
228
+ | `--target <scope>` | `skill install` destination: `global` (`~/.claude/skills/`), `project` (`.claude/skills/` inside the repo — commit it), or `trellis` (`~/.trellis/skills/` canonical store). |
229
+ | `--force` | Replace an installed skill that differs from this version's template; a modified file is never overwritten without it. |
220
230
  | `-o, --out <path>` / `--filter <prefix>` | Configure public browser-env generation. |
221
231
  | `-v, --verbose` | Show source state and key counts, not values. |
222
232
 
223
233
  ## Agent workflow
224
234
 
225
- `mx-env doc --profile <profile>` writes a value-free workflow Skill to `.agents/skills/morphix-env/SKILL.md` by default. Generated or maintained Skills contain this rule:
235
+ ### Packaged Agent Skill
236
+
237
+ The npm package ships a maintained, value-free Agent Skill at `dist/SKILL.md`. It teaches an agent the full workflow: safety red lines (inspect for validation, `edit` for changes, `run` as the only injection path), the complete `mx-env.config.json` schema for all five providers, a command cheatsheet, project onboarding steps, and troubleshooting. Because it travels with the CLI, it always documents commands that exist in the installed version.
238
+
239
+ ```bash
240
+ # Agent bootstrap straight from npm — no global install required
241
+ npx morphix-env@latest skill install --target project
242
+
243
+ mx-env skill install --target project # <repo>/.claude/skills/morphix-env/SKILL.md — commit it with the repository
244
+ mx-env skill install --target global # ~/.claude/skills/morphix-env/SKILL.md — every project on this machine
245
+ mx-env skill install --target trellis # ~/.trellis/skills/morphix-env/SKILL.md — then `trellis sync skills`
246
+ ```
247
+
248
+ Installs are idempotent: a re-run against an unchanged template is a no-op, and a skill file the user has customized is never overwritten without `--force`. `mx-env skill show` reports each target's install state and whether it still matches the shipped template.
249
+
250
+ ### Project workflow Skill
251
+
252
+ `mx-env doc --profile <profile>` writes a value-free workflow Skill to `.agents/skills/morphix-env/SKILL.md` by default, listing this project's resolved key names and their winning sources. Generated or maintained Skills contain this rule:
226
253
 
227
254
  ```md
228
255
  When the user asks to add, modify, or rotate a credential:
package/dist/SKILL.md ADDED
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: morphix-env
3
+ description: 通过 morphix-env(mx-env)为项目组装、检查、可视化编辑环境变量与密钥——多 provider(本地 .env / dotenvx 加密 / macOS 钥匙串 / Infisical / Doppler)、按 profile 组合、Agent 上下文零密钥。当用户提到环境变量、密钥、API key、credentials、.env、Infisical、Doppler、Keychain、"配置环境"、担心 secret 泄露,或需要 Agent/进程带着密钥运行而值不出现在对话里时使用。
4
+ user-invocable: true
5
+ argument-hint: "[install|show]"
6
+ ---
7
+
8
+ # morphix-env(mx-env)Agent 密钥工作流
9
+
10
+ morphix-env 是密钥**组装层**,不是新的保险库:值永远留在 provider(本地文件、macOS 钥匙串、Infisical、Doppler、dotenvx)里。CLI 只把 profile 选定的 sources 组合成一次性子进程环境,并保证 inspect / audit / run 子进程输出全部脱敏。
11
+
12
+ ## 安全红线(任何情况下都不违反)
13
+
14
+ 1. 绝不打印、记录、索取密钥值:不运行 `env` / `printenv` / `cat .env*` / `doppler secrets get --plain`,也不让用户把值粘贴进对话。
15
+ 2. 只用 key 名验证状态:`mx-env inspect --profile <name>` 输出 key → source 归属与状态,不含值。
16
+ 3. 增删改密钥一律走可视化编辑器:`mx-env edit --profile <name>`(或 `--source <name>`),用户在本地浏览器完成,值不经过 CLI 与对话。
17
+ 4. 进程获得密钥的唯一方式是 `mx-env run`;子进程 stdout/stderr 中的注入值会被替换为 `[REDACTED]`。
18
+
19
+ ## 安装与检测
20
+
21
+ ```bash
22
+ mx-env --version # 检测是否已安装
23
+ npm install -g morphix-env # 安装(mx-env 与 morphix-env 两个 bin 等价)
24
+ npx morphix-env@latest inspect # 免安装试用
25
+ ```
26
+
27
+ ## 配置(mx-env.config.json)
28
+
29
+ 配置文件**不含任何值**,只声明 source 接线与组合顺序。项目级放仓库根 `mx-env.config.json`;用户级 `~/.mx-env/config.json` 可选(全局基线,`--no-global` 可排除)。`~/.mx-env/.env` 是唯一自动发现的值文件(个人默认值)。
30
+
31
+ ```jsonc
32
+ // 项目 mx-env.config.json — 五种 provider 全示例
33
+ {
34
+ "sources": {
35
+ "local": { "provider": "local", "files": [".env.local"], "optional": true, "override": true },
36
+ "encrypted": { "provider": "dotenvx", "files": [".env.shared"] },
37
+ "keychain": { "provider": "os-keychain", "platform": "macos", "service": "com.example/myproject" },
38
+ "infisical": { "provider": "infisical", "paths": ["/team/api"] },
39
+ "doppler": { "provider": "doppler", "project": "my-project", "config": "dev" }
40
+ },
41
+ "profiles": {
42
+ "dev": { "sources": ["keychain", "infisical", "local"] },
43
+ "ci": { "sources": ["doppler"] }
44
+ },
45
+ "defaultProfile": "dev"
46
+ }
47
+ ```
48
+
49
+ 要点:
50
+
51
+ - profile 内 `sources` **从低到高**排列;同 key 冲突默认**报错**,靠后 source 显式 `"override": true` 才覆盖(防止两个环境的同名凭据静默错选)。
52
+ - provider 登录与引导留在 provider 侧(`infisical login`、`doppler login`、dotenvx 解密密钥引导),**不写进项目配置**。
53
+ - 固定基线顺序:`inherited process.env → ~/.mx-env/.env → 全局默认 profile → 项目 profile / legacy 配置 → -f 覆盖文件`。legacy 项目(`infisical` + `envFiles` 字段)无需改动即兼容。
54
+
55
+ ## 命令速查
56
+
57
+ ```bash
58
+ mx-env run --profile dev -- <command> # 组合环境并执行(子进程输出脱敏)
59
+ mx-env run --no-global -- <command> # 排除全局基线,可复现的项目-only 运行
60
+ mx-env generate --out public/__env.js # 生成浏览器公开变量(NEXT_PUBLIC_/VITE_/EXPO_PUBLIC_ 属公开配置例外)
61
+ mx-env inspect [--profile dev] # key 名 + source 归属 + 状态(无值)
62
+ mx-env edit --profile dev | --source X # 一次性可视化编辑器(loopback + 15 分钟 TTL,保存后自动关闭)
63
+ mx-env doc # 生成本项目的 key→source 工作流 Skill(.agents/skills/morphix-env/)
64
+ mx-env audit [tail] # 值无关的本地审计事件
65
+ mx-env skill install [--target global|project|trellis] [--force] # 安装本 Skill
66
+ mx-env skill show # 查看各目标安装状态
67
+ ```
68
+
69
+ ## 进入一个新项目的标准流程
70
+
71
+ 1. `mx-env inspect` — 看是否已有配置、哪些 key 已就绪;无配置时走 legacy `.env.local` / Infisical 兼容路径。
72
+ 2. 项目密钥来源多而杂且无 `mx-env.config.json` → 引导用户创建:给出上面模板改 source 名与 provider 选择,**不填值**。
73
+ 3. 缺值时 `mx-env edit --profile <name>` 打开本地编辑器让用户填写;macOS 浏览器自动打开,编辑器 URL 默认不打印(`--print-editor-url` 显式索取)。
74
+ 4. `mx-env doc` — 生成**本项目**的 key→source 表(`.agents/skills/morphix-env/SKILL.md`,0600),后续以它为准。
75
+ 5. 运行:`mx-env run --profile <name> -- <command>`。
76
+
77
+ ## 故障排查
78
+
79
+ | 症状 | 处理 |
80
+ |---|---|
81
+ | 冲突报错:同 key 来自两个 source | 确认哪个 source 应赢,给靠后的加 `"override": true` |
82
+ | `missing-optional, 0 keys` | `"optional": true` 的文件不存在,属预期;要强制存在就删掉 optional |
83
+ | Keychain 权限弹框 / 拒绝 | 首次访问会请求 service 授权;拒绝后重试或换 service 命名空间 |
84
+ | dotenvx 解密失败 | 解密密钥由 dotenvx 引导路径提供,不在本配置内 |
85
+ | `mx-env: command not found` | `npm install -g morphix-env`,或用 `npx morphix-env@latest` 免安装 |
86
+
87
+ ---
88
+
89
+ 本 Skill 与安装它的 CLI 同版本分发:`mx-env skill install` 覆盖安装即升级。模板内容 value-free;项目专属的 key 清单请以 `mx-env doc` 的输出为准。
package/dist/cli.js CHANGED
@@ -29482,9 +29482,9 @@ var require_jsx_runtime = __commonJS({
29482
29482
 
29483
29483
  // src/cli.ts
29484
29484
  var import_cross_spawn = __toESM(require("cross-spawn"));
29485
- var import_fs7 = require("fs");
29486
- var import_os4 = require("os");
29487
- var import_path7 = require("path");
29485
+ var import_fs8 = require("fs");
29486
+ var import_os5 = require("os");
29487
+ var import_path8 = require("path");
29488
29488
 
29489
29489
  // src/audit.ts
29490
29490
  var import_fs = require("fs");
@@ -37182,11 +37182,81 @@ var StreamingRedactor = class {
37182
37182
  }
37183
37183
  };
37184
37184
 
37185
+ // src/skill.ts
37186
+ var import_fs7 = require("fs");
37187
+ var import_os4 = require("os");
37188
+ var import_path7 = require("path");
37189
+ var SKILL_TARGETS = ["global", "project", "trellis"];
37190
+ function resolveSkillPath(target) {
37191
+ if (target === "project") return (0, import_path7.join)(process.cwd(), ".claude", "skills", "morphix-env", "SKILL.md");
37192
+ if (target === "trellis") return (0, import_path7.join)((0, import_os4.homedir)(), ".trellis", "skills", "morphix-env", "SKILL.md");
37193
+ return (0, import_path7.join)((0, import_os4.homedir)(), ".claude", "skills", "morphix-env", "SKILL.md");
37194
+ }
37195
+ function targetHint(target) {
37196
+ if (target === "project") {
37197
+ return "Project skill installed; commit it so every Agent working in this repository picks it up.";
37198
+ }
37199
+ if (target === "trellis") {
37200
+ return "Installed into the Trellis canonical store; run `trellis sync skills` to distribute it to managed agents.";
37201
+ }
37202
+ return "Installed as a Claude Code global skill; available in every project.";
37203
+ }
37204
+ function printNextSteps() {
37205
+ console.log(`[morphix-env] Next steps:
37206
+ 1. mx-env inspect check this project's config and resolved key names
37207
+ 2. create mx-env.config.json if absent see the skill's configuration section (source wiring only, no values)
37208
+ 3. mx-env edit --profile <name> let the user fill values in the local visual editor
37209
+ 4. mx-env doc generate this project's key-to-source workflow Skill`);
37210
+ }
37211
+ function cmdSkill(subcommand, options) {
37212
+ const templatePath = (0, import_path7.join)(__dirname, "SKILL.md");
37213
+ const template = (0, import_fs7.readFileSync)(templatePath, "utf8");
37214
+ if (subcommand === "show") {
37215
+ console.log(`[morphix-env] Skill template: ${templatePath}`);
37216
+ for (const target2 of SKILL_TARGETS) {
37217
+ const path = resolveSkillPath(target2);
37218
+ if (!(0, import_fs7.existsSync)(path)) {
37219
+ console.log(` ${target2}: not installed (${path})`);
37220
+ continue;
37221
+ }
37222
+ const state = (0, import_fs7.readFileSync)(path, "utf8") === template ? "installed (matches this version)" : "installed (differs from this version)";
37223
+ console.log(` ${target2}: ${state} (${path})`);
37224
+ }
37225
+ return 0;
37226
+ }
37227
+ if (subcommand !== "install") {
37228
+ console.error(`[morphix-env] Unknown skill subcommand "${subcommand}". Use install or show.`);
37229
+ return 1;
37230
+ }
37231
+ const target = options.target ?? "global";
37232
+ if (!SKILL_TARGETS.includes(target)) {
37233
+ console.error(`[morphix-env] Unknown skill target "${options.target}". Use global, project, or trellis.`);
37234
+ return 1;
37235
+ }
37236
+ const dest = resolveSkillPath(target);
37237
+ if ((0, import_fs7.existsSync)(dest)) {
37238
+ if ((0, import_fs7.readFileSync)(dest, "utf8") === template) {
37239
+ console.log(`[morphix-env] Skill already installed and up to date: ${dest}`);
37240
+ return 0;
37241
+ }
37242
+ if (!options.force) {
37243
+ console.error(`[morphix-env] ${dest} exists with different content; refusing to overwrite. Re-run with --force to replace it.`);
37244
+ return 1;
37245
+ }
37246
+ }
37247
+ (0, import_fs7.mkdirSync)((0, import_path7.dirname)(dest), { recursive: true });
37248
+ (0, import_fs7.writeFileSync)(dest, template, { mode: 420 });
37249
+ console.log(`[morphix-env] Installed skill: ${dest}`);
37250
+ console.log(`[morphix-env] ${targetHint(target)}`);
37251
+ printNextSteps();
37252
+ return 0;
37253
+ }
37254
+
37185
37255
  // package.json
37186
37256
  var package_default = {
37187
37257
  name: "morphix-env",
37188
- version: "0.6.0-beta.2",
37189
- description: "Environment variable toolkit \u2014 Infisical integration, local overrides, and client-side runtime injection for Next.js / Vite / Express.",
37258
+ version: "0.7.0-beta.1",
37259
+ description: "Secret composition CLI \u2014 Infisical, Doppler, macOS Keychain, dotenvx, and local files stay value owners; composes them into one value-safe child environment and ships a built-in Agent Skill (mx-env skill install).",
37190
37260
  author: "MorphixAI <dev@morphixai.com>",
37191
37261
  homepage: "https://github.com/Morphicai/morphix-env#readme",
37192
37262
  repository: {
@@ -37201,7 +37271,7 @@ var package_default = {
37201
37271
  "mx-env": "./dist/cli.js"
37202
37272
  },
37203
37273
  scripts: {
37204
- build: "node scripts/build-editor-ui.mjs && tsup src/cli.ts --format cjs --dts --clean --external keytar",
37274
+ build: "node scripts/build-editor-ui.mjs && tsup src/cli.ts --format cjs --dts --clean --external keytar && node scripts/copy-skill.mjs",
37205
37275
  dev: "node scripts/build-editor-ui.mjs && tsup src/cli.ts --format cjs --watch",
37206
37276
  pretest: "pnpm build",
37207
37277
  test: "vitest run",
@@ -37217,7 +37287,12 @@ var package_default = {
37217
37287
  "environment-variables",
37218
37288
  "cross-env",
37219
37289
  "infisical",
37290
+ "doppler",
37291
+ "keychain",
37220
37292
  "secrets",
37293
+ "secret-management",
37294
+ "agent",
37295
+ "agent-skills",
37221
37296
  "runtime-env",
37222
37297
  "nextjs",
37223
37298
  "vite",
@@ -37268,7 +37343,9 @@ function parseArgs(argv) {
37268
37343
  noGlobal: false,
37269
37344
  allowInsecureGlobal: false,
37270
37345
  printEditorUrl: false,
37271
- source: null
37346
+ source: null,
37347
+ target: null,
37348
+ force: false
37272
37349
  };
37273
37350
  let i = 2;
37274
37351
  const command = argv[i];
@@ -37303,6 +37380,10 @@ function parseArgs(argv) {
37303
37380
  args.allowInsecureGlobal = true;
37304
37381
  } else if (arg === "--print-editor-url") {
37305
37382
  args.printEditorUrl = true;
37383
+ } else if (arg === "--target") {
37384
+ if (argv[++i]) args.target = argv[i];
37385
+ } else if (arg === "--force") {
37386
+ args.force = true;
37306
37387
  } else if (args.command === "run") {
37307
37388
  args.subArgs = argv.slice(i);
37308
37389
  break;
@@ -37312,7 +37393,7 @@ function parseArgs(argv) {
37312
37393
  return args;
37313
37394
  }
37314
37395
  function resolveComposition(args) {
37315
- const layers = loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os4.homedir)() });
37396
+ const layers = loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os5.homedir)() });
37316
37397
  return composeEnvironment(layers, {
37317
37398
  profile: args.profile,
37318
37399
  noGlobal: args.noGlobal,
@@ -37320,11 +37401,11 @@ function resolveComposition(args) {
37320
37401
  envName: args.env,
37321
37402
  allowInsecureGlobal: args.allowInsecureGlobal,
37322
37403
  envFiles: args.envFiles,
37323
- homeDir: (0, import_os4.homedir)()
37404
+ homeDir: (0, import_os5.homedir)()
37324
37405
  });
37325
37406
  }
37326
37407
  function generatedOptions(args) {
37327
- const config = loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os4.homedir)() }).project.config;
37408
+ const config = loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os5.homedir)() }).project.config;
37328
37409
  return {
37329
37410
  outFile: args.outFile || config.generate?.out || "public/__env.js",
37330
37411
  filter: args.filter || config.generate?.filter || null
@@ -37333,8 +37414,8 @@ function generatedOptions(args) {
37333
37414
  function generateClientEnv(outFile, filter, environment) {
37334
37415
  let vars = extractPublicVars(environment);
37335
37416
  if (filter) vars = Object.fromEntries(Object.entries(vars).filter(([key]) => key.startsWith(filter)));
37336
- (0, import_fs7.mkdirSync)((0, import_path7.dirname)(outFile), { recursive: true });
37337
- (0, import_fs7.writeFileSync)(outFile, `window.__ENV=${JSON.stringify(vars)};`);
37417
+ (0, import_fs8.mkdirSync)((0, import_path8.dirname)(outFile), { recursive: true });
37418
+ (0, import_fs8.writeFileSync)(outFile, `window.__ENV=${JSON.stringify(vars)};`);
37338
37419
  console.log(`[morphix-env] Generated ${outFile} (${Object.keys(vars).length} client vars)`);
37339
37420
  }
37340
37421
  async function runChild(command, commandArgs, composition) {
@@ -37382,7 +37463,7 @@ async function cmdRun(args) {
37382
37463
  }
37383
37464
  if (args.outFile || generatedOptions(args).outFile) {
37384
37465
  const { outFile, filter } = generatedOptions(args);
37385
- const configured = Boolean(args.outFile || loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os4.homedir)() }).project.config.generate);
37466
+ const configured = Boolean(args.outFile || loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os5.homedir)() }).project.config.generate);
37386
37467
  if (configured) generateClientEnv(outFile, filter, composition.environment);
37387
37468
  }
37388
37469
  const [command, ...commandArgs] = args.subArgs;
@@ -37420,7 +37501,7 @@ async function cmdEdit(args) {
37420
37501
  }
37421
37502
  const composition = await resolveComposition(args);
37422
37503
  if (args.source && !composition.sourceEntries.some((entry) => entry.name === args.source)) {
37423
- const layers = loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os4.homedir)() });
37504
+ const layers = loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os5.homedir)() });
37424
37505
  const declared = layers.project.config.sources?.[args.source] ? { source: layers.project.config.sources[args.source], baseDir: layers.project.baseDir } : !args.noGlobal && layers.global.config.sources?.[args.source] ? { source: layers.global.config.sources[args.source], baseDir: layers.global.baseDir } : null;
37425
37506
  if (!declared) {
37426
37507
  console.error(`[morphix-env] Unknown source "${args.source}".`);
@@ -37438,7 +37519,7 @@ async function cmdEdit(args) {
37438
37519
  }
37439
37520
  async function cmdDoc(args) {
37440
37521
  const composition = await resolveComposition(args);
37441
- const outFile = args.outFile || (0, import_path7.join)(process.cwd(), ".agents", "skills", "morphix-env", "SKILL.md");
37522
+ const outFile = args.outFile || (0, import_path8.join)(process.cwd(), ".agents", "skills", "morphix-env", "SKILL.md");
37442
37523
  const keyRows = Object.entries(composition.provenance).sort(([a], [b]) => a.localeCompare(b)).map(([key, provenance]) => `| \`${key}\` | ${provenance.source} (${provenance.provider}) |`).join("\n") || "| _No resolved keys_ | \u2014 |";
37443
37524
  const skill = `---
37444
37525
  name: morphix-env
@@ -37472,18 +37553,18 @@ ${keyRows}
37472
37553
 
37473
37554
  Secret values and value prefixes do not belong in this Skill, command output, audit records, or conversation context.
37474
37555
  `;
37475
- (0, import_fs7.mkdirSync)((0, import_path7.dirname)(outFile), { recursive: true });
37476
- (0, import_fs7.writeFileSync)(outFile, skill, { mode: 384 });
37556
+ (0, import_fs8.mkdirSync)((0, import_path8.dirname)(outFile), { recursive: true });
37557
+ (0, import_fs8.writeFileSync)(outFile, skill, { mode: 384 });
37477
37558
  console.log(`[morphix-env] Generated value-free workflow Skill: ${outFile}`);
37478
37559
  return 0;
37479
37560
  }
37480
37561
  function cmdAudit(args) {
37481
- const file = (0, import_path7.join)((0, import_os4.homedir)(), ".mx-env", "audit", `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
37482
- if (!(0, import_fs7.existsSync)(file)) {
37562
+ const file = (0, import_path8.join)((0, import_os5.homedir)(), ".mx-env", "audit", `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
37563
+ if (!(0, import_fs8.existsSync)(file)) {
37483
37564
  console.log("[morphix-env] No audit events for today.");
37484
37565
  return 0;
37485
37566
  }
37486
- const lines = (0, import_fs7.readFileSync)(file, "utf8").trim().split("\n").filter(Boolean);
37567
+ const lines = (0, import_fs8.readFileSync)(file, "utf8").trim().split("\n").filter(Boolean);
37487
37568
  const selected = args.subArgs[0] === "tail" ? lines.slice(-20) : lines;
37488
37569
  for (const line of selected) console.log(line);
37489
37570
  return 0;
@@ -37499,6 +37580,8 @@ Usage:
37499
37580
  mx-env doc [options] Generate a value-free project Skill
37500
37581
  mx-env audit [tail] Read value-free local audit events
37501
37582
  mx-env edit --profile <name> Open the one-shot visual editor
37583
+ mx-env skill install [--target <t>] Install the Agent Skill (global|project|trellis)
37584
+ mx-env skill show Show skill install status per target
37502
37585
 
37503
37586
  Both mx-env and morphix-env are supported.
37504
37587
 
@@ -37512,6 +37595,8 @@ Options:
37512
37595
  --no-global Ignore ~/.mx-env/.env and ~/.mx-env/config.json
37513
37596
  --allow-insecure-global Allow a global .env with permissive file mode
37514
37597
  --print-editor-url Explicitly print the one-time local editor URL
37598
+ --target <scope> Skill install target: global, project, or trellis
37599
+ --force Overwrite an installed skill that differs from this version
37515
37600
  -v, --verbose Print source status and key counts only
37516
37601
  --help, -h Show this help
37517
37602
  --version Show version
@@ -37533,6 +37618,10 @@ async function main() {
37533
37618
  return cmdEdit(args);
37534
37619
  case "doc":
37535
37620
  return cmdDoc(args);
37621
+ case "skill": {
37622
+ const positional = process.argv.slice(3).find((arg) => !arg.startsWith("-")) ?? "install";
37623
+ return cmdSkill(positional, { target: args.target, force: args.force });
37624
+ }
37536
37625
  case "--help":
37537
37626
  case "-h":
37538
37627
  case "help":
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "morphix-env",
3
- "version": "0.6.0-beta.2",
4
- "description": "Environment variable toolkit — Infisical integration, local overrides, and client-side runtime injection for Next.js / Vite / Express.",
3
+ "version": "0.7.0-beta.1",
4
+ "description": "Secret composition CLI — Infisical, Doppler, macOS Keychain, dotenvx, and local files stay value owners; composes them into one value-safe child environment and ships a built-in Agent Skill (mx-env skill install).",
5
5
  "author": "MorphixAI <dev@morphixai.com>",
6
6
  "homepage": "https://github.com/Morphicai/morphix-env#readme",
7
7
  "repository": {
@@ -16,7 +16,7 @@
16
16
  "mx-env": "./dist/cli.js"
17
17
  },
18
18
  "scripts": {
19
- "build": "node scripts/build-editor-ui.mjs && tsup src/cli.ts --format cjs --dts --clean --external keytar",
19
+ "build": "node scripts/build-editor-ui.mjs && tsup src/cli.ts --format cjs --dts --clean --external keytar && node scripts/copy-skill.mjs",
20
20
  "dev": "node scripts/build-editor-ui.mjs && tsup src/cli.ts --format cjs --watch",
21
21
  "pretest": "pnpm build",
22
22
  "test": "vitest run",
@@ -32,7 +32,12 @@
32
32
  "environment-variables",
33
33
  "cross-env",
34
34
  "infisical",
35
+ "doppler",
36
+ "keychain",
35
37
  "secrets",
38
+ "secret-management",
39
+ "agent",
40
+ "agent-skills",
36
41
  "runtime-env",
37
42
  "nextjs",
38
43
  "vite",