@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 +1 -1
- package/dist/index.js +19 -17
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
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
|
|
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 =
|
|
168
|
+
const matcherKey = String(typedEntry.matcher ?? "");
|
|
175
169
|
const existing = hooks[event].find(
|
|
176
|
-
(h) =>
|
|
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 && "
|
|
298
|
-
|
|
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
|
|
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 =
|
|
843
|
-
const safeBase =
|
|
844
|
-
if (!full.startsWith(safeBase) && full !==
|
|
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
|
|
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 =
|
|
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)) {
|