@sniper.ai/cli 3.1.0 → 3.1.2

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
@@ -7,7 +7,7 @@ CLI tool for scaffolding and managing [SNIPER](https://sniperai.dev/)-enabled pr
7
7
 
8
8
  ## What is SNIPER?
9
9
 
10
- SNIPER (**S**pawn, **N**avigate, **I**mplement, **P**arallelize, **E**valuate, **R**elease) is an AI-powered project lifecycle framework that orchestrates Claude Code agent teams through structured phases -- from discovery and planning through implementation and release. Each phase spawns coordinated teams of specialized agents composed from layered personas.
10
+ SNIPER is an AI-powered project lifecycle framework that orchestrates Claude Code agent teams through structured phases -- from discovery and planning through implementation and release. Each phase spawns coordinated teams of specialized agents composed from layered personas.
11
11
 
12
12
  ## Quick Start
13
13
 
package/dist/index.js CHANGED
@@ -152,12 +152,6 @@ async function composeMixin(basePath, mixinPaths) {
152
152
  }
153
153
  return content;
154
154
  }
155
- function stableStringify(obj) {
156
- if (obj === null || obj === void 0 || typeof obj !== "object") return JSON.stringify(obj ?? null);
157
- if (Array.isArray(obj)) return "[" + obj.map(stableStringify).join(",") + "]";
158
- const sorted = Object.keys(obj).sort();
159
- return "{" + sorted.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
160
- }
161
155
  function mergeHooks(base, ...sources) {
162
156
  const result = { ...base };
163
157
  if (!result.hooks || typeof result.hooks !== "object") {
@@ -171,9 +165,9 @@ function mergeHooks(base, ...sources) {
171
165
  if (!hooks[event]) hooks[event] = [];
172
166
  for (const entry of entries) {
173
167
  const typedEntry = entry;
174
- const matcherKey = stableStringify(typedEntry.matcher || {});
168
+ const matcherKey = String(typedEntry.matcher ?? "");
175
169
  const existing = hooks[event].find(
176
- (h) => stableStringify(h.matcher || {}) === matcherKey
170
+ (h) => String(h.matcher ?? "") === matcherKey
177
171
  );
178
172
  if (existing) {
179
173
  const existingHooks = existing.hooks || [];
@@ -294,12 +288,20 @@ async function scaffoldProject(cwd, config, options = {}) {
294
288
  for (const [event, entries] of Object.entries(pluginContent.hooks)) {
295
289
  if (!Array.isArray(entries)) continue;
296
290
  pluginHooksFormatted[event] = entries.map((entry) => {
297
- if (typeof entry === "object" && entry !== null && "matcher" in entry && typeof entry.matcher === "object" && "hooks" in entry && Array.isArray(entry.hooks)) {
298
- return entry;
291
+ if (typeof entry === "object" && entry !== null && "hooks" in entry && Array.isArray(entry.hooks)) {
292
+ const e = entry;
293
+ if (typeof e.matcher === "object" && e.matcher !== null) {
294
+ const tools = e.matcher.tools;
295
+ if (Array.isArray(tools)) {
296
+ e.matcher = tools.join("|");
297
+ } else {
298
+ delete e.matcher;
299
+ }
300
+ }
301
+ return e;
299
302
  }
300
303
  const cmd = String(entry);
301
304
  return {
302
- matcher: {},
303
305
  hooks: [{
304
306
  type: "command",
305
307
  description: `${pluginName} plugin: ${cmd.split(" ")[0]}`,
@@ -832,16 +834,16 @@ import {
832
834
  access as access4,
833
835
  mkdir as mkdir3
834
836
  } from "fs/promises";
835
- import { join as join6, resolve as resolve2, sep as sep2 } from "path";
837
+ import { join as join6, resolve, sep } from "path";
836
838
  import { execFileSync } from "child_process";
837
839
  import YAML4 from "yaml";
838
840
  function getPackageManagerCommand(config) {
839
841
  return config?.stack?.package_manager || "pnpm";
840
842
  }
841
843
  function assertSafePath(base, untrusted) {
842
- const full = resolve2(base, untrusted);
843
- const safeBase = resolve2(base) + sep2;
844
- if (!full.startsWith(safeBase) && full !== resolve2(base)) {
844
+ const full = resolve(base, untrusted);
845
+ const safeBase = resolve(base) + sep;
846
+ if (!full.startsWith(safeBase) && full !== resolve(base)) {
845
847
  throw new Error(
846
848
  `Invalid name: path traversal detected in "${untrusted}"`
847
849
  );
@@ -1652,7 +1654,7 @@ import * as p7 from "@clack/prompts";
1652
1654
 
1653
1655
  // src/workspace-manager.ts
1654
1656
  import { readFile as readFile8, writeFile as writeFile5, access as access6, mkdir as mkdir5 } from "fs/promises";
1655
- import { join as join9, resolve as resolve3, dirname as dirname2 } from "path";
1657
+ import { join as join9, resolve as resolve2, dirname as dirname2 } from "path";
1656
1658
  import YAML7 from "yaml";
1657
1659
  var WORKSPACE_DIR = ".sniper-workspace";
1658
1660
  var WORKSPACE_CONFIG = "config.yaml";
@@ -1665,7 +1667,7 @@ async function pathExists3(p14) {
1665
1667
  }
1666
1668
  }
1667
1669
  async function findWorkspaceRoot(cwd) {
1668
- let dir = resolve3(cwd);
1670
+ let dir = resolve2(cwd);
1669
1671
  while (true) {
1670
1672
  const configPath = join9(dir, WORKSPACE_DIR, WORKSPACE_CONFIG);
1671
1673
  if (await pathExists3(configPath)) {