teamai-cli 0.24.0-beta.2 → 0.24.0-beta.3

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
@@ -91,6 +91,7 @@ Once initialized, every AI session automatically pulls the latest skills / rules
91
91
  <tr><td>Hermes</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td></tr>
92
92
  <tr><td>DeepSeek Harness</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td></tr>
93
93
  <tr><td>Qoder</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td></tr>
94
+ <tr><td>ZCode</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td></tr>
94
95
  </tbody>
95
96
  </table>
96
97
 
package/README.zh-CN.md CHANGED
@@ -91,6 +91,7 @@ teamai init https://github.com/yourorg/yourrepo --scope user
91
91
  <tr><td>Hermes</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td></tr>
92
92
  <tr><td>DeepSeek Harness</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">—</td><td align="center">—</td><td align="center">—</td></tr>
93
93
  <tr><td>Qoder</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td></tr>
94
+ <tr><td>ZCode</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">—</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td><td align="center">✓</td></tr>
94
95
  </tbody>
95
96
  </table>
96
97
 
package/dist/index.js CHANGED
@@ -868,6 +868,17 @@ var init_types = __esm({
868
868
  mcp: ".qoder/settings.json",
869
869
  mcpProject: ".qoder/settings.json"
870
870
  },
871
+ // ZCode: user-level config lives at ~/.zcode/cli/config.json (a shared file
872
+ // that also carries plugin state — reconcile must merge, never replace).
873
+ // Hooks are Claude-shaped but nested under `hooks.events` and gated by
874
+ // `hooks.enabled` (config-file hooks are disabled by default; the writer
875
+ // must force it on). Subagents deploy to ~/.zcode/agents/ as Claude-style
876
+ // Markdown (the CLI also reads <project>/.zcode/agents/ per workspace).
877
+ // User-scope MCP mirrors Claude's shape (`mcpServers` key) in
878
+ // ~/.agents/mcp.json; project scope writes `mcp.servers` inside
879
+ // .zcode/config.json (a different key), which the Claude writer cannot
880
+ // emit — so no mcpProject. ZCode has no user-level rules dir convention.
881
+ zcode: { skills: ".zcode/skills", agents: ".zcode/agents", settings: ".zcode/cli/config.json", mcp: ".agents/mcp.json" },
871
882
  codebuddy: { skills: ".codebuddy/skills", rules: ".codebuddy/rules", settings: ".codebuddy/settings.json", claudemd: ".codebuddy/CODEBUDDY.md", agents: ".codebuddy/agents", mcp: ".codebuddy/mcp.json", mcpProject: ".codebuddy/mcp.json" },
872
883
  openclaw: { skills: ".openclaw/skills", rules: ".openclaw/rules", claudemd: ".openclaw/workspace/AGENTS.md" },
873
884
  hermes: { skills: ".hermes/skills", claudemd: "AGENTS.md" },
@@ -1240,13 +1251,17 @@ function getDispatchCommand(event, tool, matcher, binPath) {
1240
1251
  const matcherArg = matcher && matcher !== "*" ? ` --matcher ${matcher}` : "";
1241
1252
  return `bash -lc "${bin} hook-dispatch ${event} --tool ${tool}${matcherArg} 2>/dev/null" || true`;
1242
1253
  }
1254
+ function getRawDispatchCommand(event, tool, matcher) {
1255
+ const matcherArg = matcher && matcher !== "*" ? ` --matcher ${matcher}` : "";
1256
+ return `teamai hook-dispatch ${event} --tool ${tool}${matcherArg}`;
1257
+ }
1243
1258
  function getWrapperDispatchCommand(event, tool, matcher) {
1244
1259
  const matcherArg = matcher && matcher !== "*" ? ` --matcher ${matcher}` : "";
1245
1260
  return `PATH="$HOME/${TEAMAI_BIN_DIR}:$PATH" teamai hook-dispatch ${event} --tool ${tool}${matcherArg} 2>/dev/null || true`;
1246
1261
  }
1247
1262
  function builtinHookDefs(tool) {
1248
- const withTimeout3 = tool === "cursor" || tool === "workbuddy" || tool === "codebuddy";
1249
- const buildCommand = WRAPPER_TOOLS.has(tool) ? getWrapperDispatchCommand : getDispatchCommand;
1263
+ const withTimeout3 = tool === "cursor" || tool === "workbuddy" || tool === "codebuddy" || tool === "zcode";
1264
+ const buildCommand = tool === "zcode" ? getRawDispatchCommand : WRAPPER_TOOLS.has(tool) ? getWrapperDispatchCommand : getDispatchCommand;
1250
1265
  return BUILTIN_HOOK_SPECS.map((spec) => ({
1251
1266
  source: "builtin",
1252
1267
  key: spec.key,
@@ -2186,6 +2201,7 @@ import path12 from "path";
2186
2201
  import { realpathSync } from "fs";
2187
2202
  function detectFormat(tool) {
2188
2203
  if (CODEX_TOOLS.has(tool)) return "codex";
2204
+ if (ZCODE_TOOLS.has(tool)) return "zcode";
2189
2205
  return CURSOR_TOOLS.has(tool) ? "cursor" : "claude";
2190
2206
  }
2191
2207
  function isCodexTrustGatedTool(tool) {
@@ -2273,6 +2289,27 @@ function toCodexEntry(def) {
2273
2289
  if (def.matcher && def.matcher !== "*") entry.matcher = def.matcher;
2274
2290
  return entry;
2275
2291
  }
2292
+ function toZcodeEntry(def) {
2293
+ const entry = {
2294
+ type: "process",
2295
+ command: "bash",
2296
+ // Stored verbatim: the shell payload must equal `def.command` exactly so
2297
+ // managed-entry detection and the managed-hooks manifest share one command
2298
+ // representation (the same invariant the Codex format keeps). teamai
2299
+ // hook-dispatch is silent and failure-tolerant on its success paths, so no
2300
+ // shell redirection is layered on top of the payload.
2301
+ args: ["-lc", def.command],
2302
+ ...def.timeout !== void 0 ? { timeoutMs: def.timeout * 1e3 } : {}
2303
+ };
2304
+ const group = { hooks: [entry] };
2305
+ if (def.matcher && def.matcher !== "*") group.matcher = def.matcher;
2306
+ return group;
2307
+ }
2308
+ function zcodeEntryCommand(entry) {
2309
+ const hook = entry.hooks?.[0];
2310
+ if (hook?.command === "bash" && hook.args?.[0] === "-lc") return hook.args[1] ?? "";
2311
+ return hook?.command ?? "";
2312
+ }
2276
2313
  function desiredEventOrder(defs, mapEvent) {
2277
2314
  const seen = /* @__PURE__ */ new Set();
2278
2315
  const order = [];
@@ -2412,6 +2449,42 @@ async function reconcileCodexFormat(hooksPath, tool, teamDefs, opts, priorTeamCo
2412
2449
  log.debug(`teamai hooks already up-to-date in ${hooksPath}`);
2413
2450
  }
2414
2451
  }
2452
+ async function reconcileZcodeFormat(settingsPath, tool, teamDefs, opts, priorTeamCommands) {
2453
+ const expanded = expandHome(settingsPath);
2454
+ await ensureDir(path12.dirname(expanded));
2455
+ const cfg = await readJson(expanded) ?? {};
2456
+ if (!cfg.hooks) cfg.hooks = {};
2457
+ let changed = false;
2458
+ if (!opts.removeAll && cfg.hooks.enabled !== true) {
2459
+ cfg.hooks.enabled = true;
2460
+ changed = true;
2461
+ }
2462
+ if (!cfg.hooks.events) cfg.hooks.events = {};
2463
+ const isManaged = (entry) => {
2464
+ const cmd = zcodeEntryCommand(entry);
2465
+ return TEAMAI_COMMAND_MARKERS.some((marker) => cmd.includes(marker)) || priorTeamCommands.has(cmd);
2466
+ };
2467
+ const defs = opts.removeAll ? [] : desiredDefs(tool, teamDefs, opts.builtinOverride);
2468
+ const eventOrder = desiredEventOrder(defs, (e) => e);
2469
+ const eventsMap = cfg.hooks.events;
2470
+ const events = [...eventOrder, ...Object.keys(eventsMap).filter((e) => !eventOrder.includes(e))];
2471
+ for (const event of events) {
2472
+ const existing = eventsMap[event] ?? [];
2473
+ const untouched = existing.filter((e) => !isManaged(e));
2474
+ const desiredEntries = defs.filter((d) => d.event === event).map(toZcodeEntry);
2475
+ const newArr = [...untouched, ...desiredEntries];
2476
+ if (JSON.stringify(existing) !== JSON.stringify(newArr)) {
2477
+ eventsMap[event] = newArr;
2478
+ changed = true;
2479
+ }
2480
+ }
2481
+ if (changed) {
2482
+ await writeJson(expanded, cfg);
2483
+ log.success(`${opts.removeAll ? "Removed" : "Updated"} teamai hooks in ${settingsPath}`);
2484
+ } else {
2485
+ log.debug(`teamai hooks already up-to-date in ${settingsPath}`);
2486
+ }
2487
+ }
2415
2488
  function isAgentHookSupportedTool(tool) {
2416
2489
  return !CURSOR_TOOLS.has(tool);
2417
2490
  }
@@ -2529,6 +2602,8 @@ async function reconcileHooks(settingsPath, tool, teamDefs = [], opts = {}) {
2529
2602
  await reconcileCursorFormat(settingsPath, tool, scopedDefs, opts, priorTeamCommands);
2530
2603
  } else if (format === "codex") {
2531
2604
  await reconcileCodexFormat(settingsPath, tool, scopedDefs, opts, priorTeamCommands);
2605
+ } else if (format === "zcode") {
2606
+ await reconcileZcodeFormat(settingsPath, tool, scopedDefs, opts, priorTeamCommands);
2532
2607
  } else {
2533
2608
  await reconcileClaudeFormat(settingsPath, tool, scopedDefs, {
2534
2609
  ...opts,
@@ -2588,6 +2663,18 @@ async function getHookStatus(settingsPath, tool) {
2588
2663
  });
2589
2664
  return present2 ? "installed" : "missing";
2590
2665
  }
2666
+ if (format === "zcode") {
2667
+ const cfg = await readJson(expanded);
2668
+ const eventsMap = cfg?.hooks?.events;
2669
+ if (!eventsMap) return "missing";
2670
+ const present2 = defs.every((def) => {
2671
+ const want = toZcodeEntry(def);
2672
+ const wantCmd = zcodeEntryCommand(want);
2673
+ const entries = eventsMap[def.event] ?? [];
2674
+ return entries.some((e) => e.matcher === want.matcher && zcodeEntryCommand(e) === wantCmd);
2675
+ });
2676
+ return present2 ? "installed" : "missing";
2677
+ }
2591
2678
  const settings = await readJson(expanded);
2592
2679
  if (!settings?.hooks) return "missing";
2593
2680
  const present = defs.every((def) => {
@@ -2619,6 +2706,17 @@ async function hasTeamaiHooks(settingsPath, tool, manifestPath) {
2619
2706
  })
2620
2707
  );
2621
2708
  }
2709
+ if (format === "zcode") {
2710
+ const j = await readJson(expanded);
2711
+ const eventsMap = j?.hooks?.events;
2712
+ if (!eventsMap) return false;
2713
+ return Object.values(eventsMap).some(
2714
+ (entries) => (entries ?? []).some((e) => {
2715
+ const cmd = zcodeEntryCommand(e);
2716
+ return TEAMAI_COMMAND_MARKERS.some((m) => cmd.includes(m)) || priorTeamCommands.has(cmd);
2717
+ })
2718
+ );
2719
+ }
2622
2720
  const s = await readJson(expanded);
2623
2721
  if (!s?.hooks) return false;
2624
2722
  return Object.values(s.hooks).some(
@@ -2792,7 +2890,7 @@ async function reconcileTeamHooksForConfig(teamConfig, localConfig, opts = {}) {
2792
2890
  await sweepLegacyProjectHooks(teamConfig.toolPaths, localConfig);
2793
2891
  return teamDefs;
2794
2892
  }
2795
- var OPENCLAW_TOOLS, TEAMAI_HOOK_SUBCOMMANDS, TEAMAI_LEGACY_HOOK_SUBCOMMANDS, CLAUDE_TO_CURSOR_EVENTS, CURSOR_TOOLS, CODEX_TOOLS, CODEX_TRUST_GATE_TOOLS, TEAMAI_COMMAND_MARKERS, AGENT_HOOK_EVENTS;
2893
+ var OPENCLAW_TOOLS, TEAMAI_HOOK_SUBCOMMANDS, TEAMAI_LEGACY_HOOK_SUBCOMMANDS, CLAUDE_TO_CURSOR_EVENTS, CURSOR_TOOLS, CODEX_TOOLS, ZCODE_TOOLS, CODEX_TRUST_GATE_TOOLS, TEAMAI_COMMAND_MARKERS, AGENT_HOOK_EVENTS;
2796
2894
  var init_hooks2 = __esm({
2797
2895
  "src/hooks.ts"() {
2798
2896
  "use strict";
@@ -2814,6 +2912,7 @@ var init_hooks2 = __esm({
2814
2912
  };
2815
2913
  CURSOR_TOOLS = /* @__PURE__ */ new Set(["cursor"]);
2816
2914
  CODEX_TOOLS = /* @__PURE__ */ new Set(["codex", "codex-internal", "tcodex"]);
2915
+ ZCODE_TOOLS = /* @__PURE__ */ new Set(["zcode"]);
2817
2916
  CODEX_TRUST_GATE_TOOLS = /* @__PURE__ */ new Set(["codex"]);
2818
2917
  TEAMAI_COMMAND_MARKERS = [
2819
2918
  "teamai pull",
@@ -7769,7 +7868,7 @@ var CLAUDE_TOOLS, CURSOR_TOOLS2, CODEX_TOOLS2, BUDDY_TOOLS, OPENCODE_TOOLS, MCP_
7769
7868
  var init_mcp_format = __esm({
7770
7869
  "src/resources/mcp-format.ts"() {
7771
7870
  "use strict";
7772
- CLAUDE_TOOLS = /* @__PURE__ */ new Set(["claude", "claude-internal", "tclaude", "qoder"]);
7871
+ CLAUDE_TOOLS = /* @__PURE__ */ new Set(["claude", "claude-internal", "tclaude", "qoder", "zcode"]);
7773
7872
  CURSOR_TOOLS2 = /* @__PURE__ */ new Set(["cursor"]);
7774
7873
  CODEX_TOOLS2 = /* @__PURE__ */ new Set(["codex", "codex-internal", "tcodex"]);
7775
7874
  BUDDY_TOOLS = /* @__PURE__ */ new Set(["codebuddy", "workbuddy"]);
@@ -12720,6 +12819,8 @@ function renderForTool(spec, tool) {
12720
12819
  return renderForJoycode(spec);
12721
12820
  case "qoder":
12722
12821
  return renderForClaude(spec);
12822
+ case "zcode":
12823
+ return renderForClaude(spec);
12723
12824
  case "opencode":
12724
12825
  return renderForOpencode(spec);
12725
12826
  }
@@ -12739,6 +12840,7 @@ var init_agent_format = __esm({
12739
12840
  "cursor",
12740
12841
  "joycode",
12741
12842
  "qoder",
12843
+ "zcode",
12742
12844
  "opencode"
12743
12845
  ];
12744
12846
  COMMON_CLAUDE_FIELDS = /* @__PURE__ */ new Set(["name", "description", "model", "tools"]);
@@ -12942,6 +13044,8 @@ function reverseByTool(tool, filePath, content) {
12942
13044
  return reverseFromJoycode(filePath, content);
12943
13045
  case "qoder":
12944
13046
  return reverseFromClaude(filePath, content);
13047
+ case "zcode":
13048
+ return reverseFromClaude(filePath, content);
12945
13049
  case "opencode":
12946
13050
  return reverseFromOpencode(filePath, content);
12947
13051
  }
@@ -14645,6 +14749,7 @@ var init_known_agents = __esm({
14645
14749
  { id: "trae", displayName: "Trae", category: "coding", skillsPath: ".trae/skills" },
14646
14750
  { id: "trae-cn", displayName: "Trae CN", category: "coding", skillsPath: ".trae-cn/skills" },
14647
14751
  { id: "windsurf", displayName: "Windsurf", category: "coding", skillsPath: ".windsurf/skills" },
14752
+ { id: "zcode", displayName: "ZCode", category: "coding", skillsPath: ".zcode/skills" },
14648
14753
  // Lobster family
14649
14754
  { id: "openclaw", displayName: "OpenClaw", category: "lobster", skillsPath: ".openclaw/skills" },
14650
14755
  { id: "qclaw", displayName: "QClaw", category: "lobster", skillsPath: ".qclaw/skills" },
@@ -21162,6 +21267,7 @@ async function resolveTargets(teamConfig, localConfig) {
21162
21267
  for (const [tool, paths] of Object.entries(scopedToolPaths(teamConfig, localConfig))) {
21163
21268
  if (disabled.has(tool)) continue;
21164
21269
  if (whitelist && !whitelist.includes(tool)) continue;
21270
+ if (tool === "zcode") continue;
21165
21271
  const family = familyOf(tool);
21166
21272
  const probe = paths.settings ?? paths.skills ?? paths.agents;
21167
21273
  if (!probe) continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamai-cli",
3
- "version": "0.24.0-beta.2",
3
+ "version": "0.24.0-beta.3",
4
4
  "description": "TeamAI — Make Every Team AI Native (skill sync + shared knowledge base, powered by Git)",
5
5
  "type": "module",
6
6
  "bin": {