@zeroxyz/cli 1.0.0 → 1.1.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.
Files changed (2) hide show
  1. package/dist/index.js +299 -62
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -76582,7 +76582,7 @@ init_esm_shims();
76582
76582
 
76583
76583
  // package.json
76584
76584
  var package_default = {
76585
- version: "1.0.0"};
76585
+ version: "1.1.0"};
76586
76586
 
76587
76587
  // src/app.ts
76588
76588
  init_esm_shims();
@@ -147020,9 +147020,293 @@ var getCommand = (appContext) => new Command("get").description(
147020
147020
 
147021
147021
  // src/commands/init-command.ts
147022
147022
  init_esm_shims();
147023
- var INIT_DEPRECATION_MESSAGE = "The recommended way to install Zero and initialize its skill and hooks is via Agent Plugins. See the Zero agent plugin at github.com/officialzeroxyz/zero-plugins. If you need to install Zero manually you can find the binary at https://releases.zero.xyz/latest/zero-<os>-<arch> (one of: zero-macos-arm64, zero-macos-x64, zero-linux-x64, zero-linux-arm64, zero-win-x64.exe) or use npm to install it globally `npm i -g @zeroxyz/cli@latest`. You can find the Zero skill at https://www.zero.xyz/SKILL.md where it can be manually configured with your agent.";
147024
- var initCommand = (_appContext) => new Command("init").description("Deprecated \u2014 install Zero via Agent Plugins").allowExcessArguments(true).allowUnknownOption(true).action(() => {
147025
- console.log(INIT_DEPRECATION_MESSAGE);
147023
+
147024
+ // src/util/install-banner.ts
147025
+ init_esm_shims();
147026
+ var colorsEnabled = () => {
147027
+ if (process.env.NO_COLOR) return false;
147028
+ if (process.env.FORCE_COLOR) return true;
147029
+ return Boolean(process.stdout.isTTY);
147030
+ };
147031
+ var wrap5 = (code, text) => colorsEnabled() ? `\x1B[${code}m${text}\x1B[0m` : text;
147032
+ var color = {
147033
+ bold: (s) => wrap5("1", s),
147034
+ dim: (s) => wrap5("2", s),
147035
+ cyan: (s) => wrap5("36", s),
147036
+ magenta: (s) => wrap5("35", s),
147037
+ green: (s) => wrap5("32", s),
147038
+ yellow: (s) => wrap5("33", s),
147039
+ red: (s) => wrap5("31", s),
147040
+ gray: (s) => wrap5("90", s),
147041
+ boldCyan: (s) => wrap5("1;36", s),
147042
+ boldMagenta: (s) => wrap5("1;35", s),
147043
+ boldGreen: (s) => wrap5("1;32", s),
147044
+ boldRed: (s) => wrap5("1;31", s)
147045
+ };
147046
+ var supportsUnicode = () => {
147047
+ if (process.platform !== "win32") return true;
147048
+ return Boolean(
147049
+ process.env.WT_SESSION || process.env.TERM_PROGRAM === "vscode"
147050
+ );
147051
+ };
147052
+ var SYMBOLS = supportsUnicode() ? { check: "\u2713", arrow: "\u203A", warn: "!" } : { check: "OK", arrow: ">", warn: "!" };
147053
+ var stepSuccess = (label, detail) => {
147054
+ const line = detail ? ` ${color.boldGreen(SYMBOLS.check)} ${label} ${color.dim(detail)}` : ` ${color.boldGreen(SYMBOLS.check)} ${label}`;
147055
+ console.log(line);
147056
+ };
147057
+ var stepWarn = (label, detail) => {
147058
+ const line = detail ? ` ${color.yellow(SYMBOLS.warn)} ${label} ${color.dim(detail)}` : ` ${color.yellow(SYMBOLS.warn)} ${label}`;
147059
+ console.log(line);
147060
+ };
147061
+ var stepSkip = (label, detail) => {
147062
+ const line = detail ? ` ${color.gray(SYMBOLS.arrow)} ${color.dim(`${label} ${detail}`)}` : ` ${color.gray(SYMBOLS.arrow)} ${color.dim(label)}`;
147063
+ console.log(line);
147064
+ };
147065
+ var stepInfo = (message2) => {
147066
+ console.log(` ${color.gray("\xB7")} ${color.dim(message2)}`);
147067
+ };
147068
+ var sectionDivider = () => {
147069
+ console.log("");
147070
+ console.log(color.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
147071
+ console.log("");
147072
+ };
147073
+
147074
+ // src/commands/init-command.ts
147075
+ var SKILL_DIRS = [".claude/skills", ".agents/skills"];
147076
+ var ZERO_SANDBOX_DOMAIN = "*.zero.xyz";
147077
+ var PLUGIN_HOOKS_ROOT = "${CLAUDE_PLUGIN_ROOT}/hooks";
147078
+ var SCRIPT_NAME_PATTERN = /\$\{CLAUDE_PLUGIN_ROOT\}\/hooks\/([a-z0-9][a-z0-9-]*\.sh)/;
147079
+ var fetchText = async (url4) => {
147080
+ const res = await fetch(url4);
147081
+ if (!res.ok) {
147082
+ throw new Error(`GET ${url4} failed with ${res.status}`);
147083
+ }
147084
+ return await res.text();
147085
+ };
147086
+ var entryScriptNames = (entry) => {
147087
+ const names = [];
147088
+ for (const hook of entry.hooks ?? []) {
147089
+ if (typeof hook.command !== "string") continue;
147090
+ const match = hook.command.match(SCRIPT_NAME_PATTERN);
147091
+ if (match?.[1]) names.push(match[1]);
147092
+ }
147093
+ return names;
147094
+ };
147095
+ var expandHome = (path3, home) => {
147096
+ if (path3 === "~") return home;
147097
+ if (path3.startsWith("~/")) return join(home, path3.slice(2));
147098
+ return path3;
147099
+ };
147100
+ var installSkill = (skillsDirs, skillMd, verbose) => {
147101
+ const installed = [];
147102
+ for (const dir of skillsDirs) {
147103
+ const dest = join(dir, "zero");
147104
+ try {
147105
+ mkdirSync(dest, { recursive: true });
147106
+ writeFileSync(join(dest, "SKILL.md"), skillMd);
147107
+ installed.push(join(dest, "SKILL.md"));
147108
+ if (verbose) stepInfo(`wrote ${join(dest, "SKILL.md")}`);
147109
+ } catch (err) {
147110
+ stepWarn(
147111
+ `Could not write the skill under ${dir}`,
147112
+ err instanceof Error ? err.message : String(err)
147113
+ );
147114
+ }
147115
+ }
147116
+ return installed;
147117
+ };
147118
+ var installHookScripts = async (home, hooksJson, webBase, verbose) => {
147119
+ const names = /* @__PURE__ */ new Set();
147120
+ for (const entries of Object.values(hooksJson.hooks)) {
147121
+ for (const entry of entries ?? []) {
147122
+ for (const name of entryScriptNames(entry)) names.add(name);
147123
+ }
147124
+ }
147125
+ if (names.size === 0) {
147126
+ throw new Error("hooks.json declared no recognizable hook scripts");
147127
+ }
147128
+ const hooksDir = join(home, ".zero", "hooks");
147129
+ mkdirSync(hooksDir, { recursive: true });
147130
+ return await Promise.all(
147131
+ [...names].map(async (name) => {
147132
+ const body = await fetchText(`${webBase}/hooks/${name}`);
147133
+ const dest = join(hooksDir, name);
147134
+ writeFileSync(dest, body);
147135
+ chmodSync(dest, 493);
147136
+ if (verbose) stepInfo(`wrote ${dest}`);
147137
+ return name;
147138
+ })
147139
+ );
147140
+ };
147141
+ var registerHooksInClaudeSettings = (home, hooksJson, verbose) => {
147142
+ const hooksDir = join(home, ".zero", "hooks");
147143
+ const settingsPath = join(home, ".claude", "settings.json");
147144
+ let settings = {};
147145
+ if (existsSync(settingsPath)) {
147146
+ try {
147147
+ settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
147148
+ } catch {
147149
+ stepWarn(
147150
+ "Hooks not registered",
147151
+ `${settingsPath} is not valid JSON \u2014 fix it and re-run \`zero init\``
147152
+ );
147153
+ return false;
147154
+ }
147155
+ }
147156
+ if (!settings.hooks || typeof settings.hooks !== "object") {
147157
+ settings.hooks = {};
147158
+ }
147159
+ const hooks = settings.hooks;
147160
+ for (const [event, entries] of Object.entries(hooksJson.hooks)) {
147161
+ for (const entry of entries ?? []) {
147162
+ const scripts = entryScriptNames(entry);
147163
+ if (scripts.length === 0) {
147164
+ if (verbose) {
147165
+ stepInfo(`${event}: entry has no plugin hook script \u2014 skipped`);
147166
+ }
147167
+ continue;
147168
+ }
147169
+ const rewritten = {
147170
+ ...entry,
147171
+ hooks: (entry.hooks ?? []).map((hook) => ({
147172
+ ...hook,
147173
+ command: typeof hook.command === "string" ? hook.command.replaceAll(PLUGIN_HOOKS_ROOT, hooksDir) : hook.command
147174
+ }))
147175
+ };
147176
+ if (!Array.isArray(hooks[event])) hooks[event] = [];
147177
+ const list2 = hooks[event];
147178
+ const existingIdx = list2.findIndex((existing) => {
147179
+ const existingHooks = existing?.hooks;
147180
+ if (!Array.isArray(existingHooks)) return false;
147181
+ return existingHooks.some(
147182
+ (h2) => typeof h2.command === "string" && scripts.some((s) => h2.command.includes(s))
147183
+ );
147184
+ });
147185
+ if (existingIdx >= 0) {
147186
+ list2[existingIdx] = rewritten;
147187
+ if (verbose) stepInfo(`${event}: ${scripts.join(", ")} entry replaced`);
147188
+ } else {
147189
+ list2.push(rewritten);
147190
+ if (verbose) stepInfo(`${event}: ${scripts.join(", ")} entry appended`);
147191
+ }
147192
+ }
147193
+ }
147194
+ if (!settings.sandbox || typeof settings.sandbox !== "object") {
147195
+ settings.sandbox = {};
147196
+ }
147197
+ const sandbox = settings.sandbox;
147198
+ if (!sandbox.network || typeof sandbox.network !== "object") {
147199
+ sandbox.network = {};
147200
+ }
147201
+ const network = sandbox.network;
147202
+ if (!Array.isArray(network.allowedDomains)) {
147203
+ network.allowedDomains = [];
147204
+ }
147205
+ const allowedDomains = network.allowedDomains;
147206
+ if (!allowedDomains.includes(ZERO_SANDBOX_DOMAIN)) {
147207
+ allowedDomains.push(ZERO_SANDBOX_DOMAIN);
147208
+ if (verbose) {
147209
+ stepInfo(`sandbox.network.allowedDomains += ${ZERO_SANDBOX_DOMAIN}`);
147210
+ }
147211
+ }
147212
+ mkdirSync(join(home, ".claude"), { recursive: true });
147213
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
147214
+ `);
147215
+ return true;
147216
+ };
147217
+ var runInit = async (appContext, options = {}) => {
147218
+ const verbose = options.verbose ?? false;
147219
+ appContext.services.analyticsService.capture("init_started", {});
147220
+ let currentStep = "fetch";
147221
+ try {
147222
+ console.log("");
147223
+ console.log(` ${color.boldCyan("Installing Zero")}`);
147224
+ console.log("");
147225
+ console.log(color.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
147226
+ console.log("");
147227
+ const home = homedir();
147228
+ const webBase = appContext.env.ZERO_WEB_URL;
147229
+ const [skillMd, hooksJsonRaw] = await Promise.all([
147230
+ fetchText(`${webBase}/SKILL.md`),
147231
+ fetchText(`${webBase}/hooks.json`)
147232
+ ]);
147233
+ let hooksJson;
147234
+ try {
147235
+ hooksJson = JSON.parse(hooksJsonRaw);
147236
+ } catch {
147237
+ throw new Error(`${webBase}/hooks.json is not valid JSON`);
147238
+ }
147239
+ if (!hooksJson?.hooks || typeof hooksJson.hooks !== "object") {
147240
+ throw new Error(`${webBase}/hooks.json has no "hooks" object`);
147241
+ }
147242
+ if (verbose) {
147243
+ stepInfo(`fetched ${webBase}/SKILL.md and ${webBase}/hooks.json`);
147244
+ }
147245
+ currentStep = "skill";
147246
+ const skillsDirs = [
147247
+ .../* @__PURE__ */ new Set([
147248
+ ...SKILL_DIRS.map((dir) => join(home, dir)),
147249
+ ...(options.skillsDir ?? []).map((dir) => expandHome(dir, home))
147250
+ ])
147251
+ ];
147252
+ const skillsInstalled = installSkill(skillsDirs, skillMd, verbose);
147253
+ if (skillsInstalled.length === 0) {
147254
+ throw new Error("could not write the Zero skill to any skills directory");
147255
+ }
147256
+ stepSuccess("Skill installed", `${skillsInstalled.length} locations`);
147257
+ currentStep = "hooks";
147258
+ const hookScriptsInstalled = await installHookScripts(
147259
+ home,
147260
+ hooksJson,
147261
+ webBase,
147262
+ verbose
147263
+ );
147264
+ stepSuccess("Hook scripts installed", "~/.zero/hooks");
147265
+ currentStep = "settings";
147266
+ const settingsRegistered = registerHooksInClaudeSettings(
147267
+ home,
147268
+ hooksJson,
147269
+ verbose
147270
+ );
147271
+ if (settingsRegistered) {
147272
+ stepSuccess("Hooks registered", "~/.claude/settings.json");
147273
+ }
147274
+ currentStep = "complete";
147275
+ appContext.services.analyticsService.capture("init_completed", {
147276
+ // biome-ignore lint/style/useNamingConvention: snake_case for analytics
147277
+ skills_installed: skillsInstalled,
147278
+ // biome-ignore lint/style/useNamingConvention: snake_case for analytics
147279
+ skills_installed_count: skillsInstalled.length,
147280
+ // biome-ignore lint/style/useNamingConvention: snake_case for analytics
147281
+ hook_scripts_installed: hookScriptsInstalled,
147282
+ // biome-ignore lint/style/useNamingConvention: snake_case for analytics
147283
+ settings_registered: settingsRegistered
147284
+ });
147285
+ sectionDivider();
147286
+ console.log(` ${color.boldGreen("Zero is set up.")}`);
147287
+ console.log(
147288
+ ` ${color.dim("Next: sign in with `zero auth login` \u2014 it prints a URL to approve in your browser.")}`
147289
+ );
147290
+ console.log("");
147291
+ return { skillsInstalled, hookScriptsInstalled, settingsRegistered };
147292
+ } catch (err) {
147293
+ appContext.services.analyticsService.capture("init_failed", {
147294
+ step: currentStep,
147295
+ error: truncateError(err instanceof Error ? err.message : String(err))
147296
+ });
147297
+ throw err;
147298
+ }
147299
+ };
147300
+ var initCommand = (appContext) => new Command("init").description(
147301
+ "Install the Zero skill and hooks for the agent harnesses on this machine"
147302
+ ).option(
147303
+ "-v, --verbose",
147304
+ "Explain why each install step was taken or skipped"
147305
+ ).option(
147306
+ "--skills-dir <dir...>",
147307
+ "Additional skills directories to install the skill into, for harnesses with bespoke locations (e.g. ~/.kiro/skills). ~/.claude/skills and ~/.agents/skills are always written. Note: `zero uninstall` only cleans the default locations."
147308
+ ).action(async (options) => {
147309
+ await runInit(appContext, options);
147026
147310
  });
147027
147311
 
147028
147312
  // src/commands/review-command.ts
@@ -147288,58 +147572,6 @@ Examples:
147288
147572
 
147289
147573
  // src/commands/search-command.ts
147290
147574
  init_esm_shims();
147291
-
147292
- // src/util/install-banner.ts
147293
- init_esm_shims();
147294
- var colorsEnabled = () => {
147295
- if (process.env.NO_COLOR) return false;
147296
- if (process.env.FORCE_COLOR) return true;
147297
- return Boolean(process.stdout.isTTY);
147298
- };
147299
- var wrap5 = (code, text) => colorsEnabled() ? `\x1B[${code}m${text}\x1B[0m` : text;
147300
- var color = {
147301
- bold: (s) => wrap5("1", s),
147302
- dim: (s) => wrap5("2", s),
147303
- cyan: (s) => wrap5("36", s),
147304
- magenta: (s) => wrap5("35", s),
147305
- green: (s) => wrap5("32", s),
147306
- yellow: (s) => wrap5("33", s),
147307
- red: (s) => wrap5("31", s),
147308
- gray: (s) => wrap5("90", s),
147309
- boldCyan: (s) => wrap5("1;36", s),
147310
- boldMagenta: (s) => wrap5("1;35", s),
147311
- boldGreen: (s) => wrap5("1;32", s),
147312
- boldRed: (s) => wrap5("1;31", s)
147313
- };
147314
- var supportsUnicode = () => {
147315
- if (process.platform !== "win32") return true;
147316
- return Boolean(
147317
- process.env.WT_SESSION || process.env.TERM_PROGRAM === "vscode"
147318
- );
147319
- };
147320
- var SYMBOLS = supportsUnicode() ? { check: "\u2713", arrow: "\u203A", warn: "!" } : { check: "OK", arrow: ">", warn: "!" };
147321
- var stepSuccess = (label, detail) => {
147322
- const line = detail ? ` ${color.boldGreen(SYMBOLS.check)} ${label} ${color.dim(detail)}` : ` ${color.boldGreen(SYMBOLS.check)} ${label}`;
147323
- console.log(line);
147324
- };
147325
- var stepWarn = (label, detail) => {
147326
- const line = ` ${color.yellow(SYMBOLS.warn)} ${label} ${color.dim(detail)}` ;
147327
- console.log(line);
147328
- };
147329
- var stepSkip = (label, detail) => {
147330
- const line = detail ? ` ${color.gray(SYMBOLS.arrow)} ${color.dim(`${label} ${detail}`)}` : ` ${color.gray(SYMBOLS.arrow)} ${color.dim(label)}`;
147331
- console.log(line);
147332
- };
147333
- var stepInfo = (message2) => {
147334
- console.log(` ${color.gray("\xB7")} ${color.dim(message2)}`);
147335
- };
147336
- var sectionDivider = () => {
147337
- console.log("");
147338
- console.log(color.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
147339
- console.log("");
147340
- };
147341
-
147342
- // src/commands/search-command.ts
147343
147575
  var DEFAULT_MAX_COST_USD = "30";
147344
147576
  var formatReviewCount2 = (count) => {
147345
147577
  if (count >= 1e3) return `${(count / 1e3).toFixed(1)}k`;
@@ -147528,8 +147760,12 @@ var AGENT_TOOLS = [
147528
147760
  },
147529
147761
  { name: "Cursor", detectDir: ".cursor", skillsDir: ".cursor/skills" }
147530
147762
  ];
147531
- var HOOK_FILES = ["auto-approve-zero.sh", "zero-context.sh"];
147532
- var ZERO_SANDBOX_DOMAIN = "*.zero.xyz";
147763
+ var HOOK_FILES = [
147764
+ "auto-approve-zero.sh",
147765
+ "zero-context.sh",
147766
+ "ensure-runner.sh"
147767
+ ];
147768
+ var ZERO_SANDBOX_DOMAIN2 = "*.zero.xyz";
147533
147769
  var LEGACY_SKILL_NAMES = ["zero"];
147534
147770
  var removeSkills = (home, verbose = false) => {
147535
147771
  const skillNames = LEGACY_SKILL_NAMES;
@@ -147604,7 +147840,8 @@ var stripZeroFromSettings = (settings, verbose) => {
147604
147840
  if (hooks) {
147605
147841
  changed = removeHookEntries(hooks, "PreToolUse", "auto-approve-zero", verbose) || changed;
147606
147842
  changed = removeHookEntries(hooks, "UserPromptSubmit", "zero-context", verbose) || changed;
147607
- for (const key of ["PreToolUse", "UserPromptSubmit"]) {
147843
+ changed = removeHookEntries(hooks, "SessionStart", "ensure-runner", verbose) || changed;
147844
+ for (const key of ["PreToolUse", "UserPromptSubmit", "SessionStart"]) {
147608
147845
  const arr = hooks[key];
147609
147846
  if (Array.isArray(arr) && arr.length === 0) delete hooks[key];
147610
147847
  }
@@ -147614,11 +147851,11 @@ var stripZeroFromSettings = (settings, verbose) => {
147614
147851
  const network = sandbox?.network && typeof sandbox.network === "object" ? sandbox.network : null;
147615
147852
  if (network && Array.isArray(network.allowedDomains)) {
147616
147853
  const domains = network.allowedDomains;
147617
- const next = domains.filter((d3) => d3 !== ZERO_SANDBOX_DOMAIN);
147854
+ const next = domains.filter((d3) => d3 !== ZERO_SANDBOX_DOMAIN2);
147618
147855
  if (next.length !== domains.length) {
147619
147856
  changed = true;
147620
147857
  if (verbose) {
147621
- stepInfo(`sandbox.network.allowedDomains -= ${ZERO_SANDBOX_DOMAIN}`);
147858
+ stepInfo(`sandbox.network.allowedDomains -= ${ZERO_SANDBOX_DOMAIN2}`);
147622
147859
  }
147623
147860
  if (next.length === 0) {
147624
147861
  delete network.allowedDomains;
@@ -148648,7 +148885,7 @@ var createApp = (appContext) => {
148648
148885
  command: actionCommand.name()
148649
148886
  });
148650
148887
  });
148651
- program2.addCommand(initCommand());
148888
+ program2.addCommand(initCommand(appContext));
148652
148889
  program2.addCommand(uninstallCommand(appContext));
148653
148890
  program2.addCommand(searchCommand(appContext));
148654
148891
  program2.addCommand(getCommand(appContext));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroxyz/cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "zero": "dist/index.js",