vskill 0.1.9 → 0.1.11

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 (43) hide show
  1. package/README.md +15 -1
  2. package/dist/commands/add-wizard.test.d.ts +1 -0
  3. package/dist/commands/add-wizard.test.js +285 -0
  4. package/dist/commands/add-wizard.test.js.map +1 -0
  5. package/dist/commands/add.d.ts +3 -0
  6. package/dist/commands/add.js +143 -27
  7. package/dist/commands/add.js.map +1 -1
  8. package/dist/commands/add.test.js +123 -0
  9. package/dist/commands/add.test.js.map +1 -1
  10. package/dist/commands/audit.d.ts +2 -2
  11. package/dist/commands/audit.js +36 -49
  12. package/dist/commands/audit.js.map +1 -1
  13. package/dist/index.js +7 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/installer/canonical.d.ts +9 -0
  16. package/dist/installer/canonical.js +63 -0
  17. package/dist/installer/canonical.js.map +1 -0
  18. package/dist/installer/canonical.test.d.ts +1 -0
  19. package/dist/installer/canonical.test.js +117 -0
  20. package/dist/installer/canonical.test.js.map +1 -0
  21. package/dist/scanner/patterns.js +2 -2
  22. package/dist/scanner/patterns.js.map +1 -1
  23. package/dist/utils/agent-filter.d.ts +16 -0
  24. package/dist/utils/agent-filter.js +28 -0
  25. package/dist/utils/agent-filter.js.map +1 -0
  26. package/dist/utils/agent-filter.test.d.ts +1 -0
  27. package/dist/utils/agent-filter.test.js +64 -0
  28. package/dist/utils/agent-filter.test.js.map +1 -0
  29. package/dist/utils/project-root.d.ts +18 -0
  30. package/dist/utils/project-root.js +47 -0
  31. package/dist/utils/project-root.js.map +1 -0
  32. package/dist/utils/project-root.test.d.ts +1 -0
  33. package/dist/utils/project-root.test.js +74 -0
  34. package/dist/utils/project-root.test.js.map +1 -0
  35. package/dist/utils/prompts.d.ts +20 -0
  36. package/dist/utils/prompts.js +103 -0
  37. package/dist/utils/prompts.js.map +1 -0
  38. package/dist/utils/prompts.test.d.ts +1 -0
  39. package/dist/utils/prompts.test.js +155 -0
  40. package/dist/utils/prompts.test.js.map +1 -0
  41. package/dist/utils/validation.js +1 -1
  42. package/dist/utils/validation.js.map +1 -1
  43. package/package.json +1 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { AgentDefinition } from "../agents/agents-registry.js";
2
+ export interface InstallOptions {
3
+ global: boolean;
4
+ projectRoot: string;
5
+ }
6
+ export declare function ensureCanonicalDir(base: string): string;
7
+ export declare function createRelativeSymlink(target: string, linkPath: string): boolean;
8
+ export declare function installSymlink(skillName: string, content: string, agents: AgentDefinition[], opts: InstallOptions): string[];
9
+ export declare function installCopy(skillName: string, content: string, agents: AgentDefinition[], opts: InstallOptions): string[];
@@ -0,0 +1,63 @@
1
+ import { mkdirSync, writeFileSync, symlinkSync, lstatSync, rmSync } from "node:fs";
2
+ import { join, relative, dirname } from "node:path";
3
+ export function ensureCanonicalDir(base) {
4
+ const dir = join(base, ".agents", "skills");
5
+ mkdirSync(dir, { recursive: true });
6
+ return dir;
7
+ }
8
+ export function createRelativeSymlink(target, linkPath) {
9
+ try {
10
+ const relTarget = relative(dirname(linkPath), target);
11
+ // Remove existing symlink/dir at linkPath
12
+ try {
13
+ const stat = lstatSync(linkPath);
14
+ if (stat.isSymbolicLink() || stat.isDirectory()) {
15
+ rmSync(linkPath, { recursive: true, force: true });
16
+ }
17
+ }
18
+ catch {
19
+ // Does not exist, fine
20
+ }
21
+ symlinkSync(relTarget, linkPath, "dir");
22
+ return true;
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ export function installSymlink(skillName, content, agents, opts) {
29
+ const base = opts.projectRoot;
30
+ const canonicalSkillDir = join(ensureCanonicalDir(base), skillName);
31
+ mkdirSync(canonicalSkillDir, { recursive: true });
32
+ writeFileSync(join(canonicalSkillDir, "SKILL.md"), content);
33
+ const installed = [];
34
+ for (const agent of agents) {
35
+ const agentSkillsDir = join(base, agent.localSkillsDir);
36
+ mkdirSync(agentSkillsDir, { recursive: true });
37
+ const linkPath = join(agentSkillsDir, skillName);
38
+ const ok = createRelativeSymlink(canonicalSkillDir, linkPath);
39
+ if (ok) {
40
+ installed.push(linkPath);
41
+ }
42
+ else {
43
+ // Fallback to copy
44
+ mkdirSync(linkPath, { recursive: true });
45
+ writeFileSync(join(linkPath, "SKILL.md"), content);
46
+ installed.push(linkPath);
47
+ }
48
+ }
49
+ return installed;
50
+ }
51
+ export function installCopy(skillName, content, agents, opts) {
52
+ const base = opts.projectRoot;
53
+ const installed = [];
54
+ for (const agent of agents) {
55
+ const agentSkillsDir = join(base, agent.localSkillsDir);
56
+ const skillDir = join(agentSkillsDir, skillName);
57
+ mkdirSync(skillDir, { recursive: true });
58
+ writeFileSync(join(skillDir, "SKILL.md"), content);
59
+ installed.push(skillDir);
60
+ }
61
+ return installed;
62
+ }
63
+ //# sourceMappingURL=canonical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/installer/canonical.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,117 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdirSync, mkdtempSync, rmSync, readFileSync, lstatSync, readlinkSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { installSymlink, installCopy, createRelativeSymlink, ensureCanonicalDir, } from "./canonical.js";
6
+ function makeAgent(overrides = {}) {
7
+ return {
8
+ id: "claude-code",
9
+ displayName: "Claude Code",
10
+ localSkillsDir: ".claude/commands",
11
+ globalSkillsDir: "~/.claude/commands",
12
+ isUniversal: false,
13
+ detectInstalled: "which claude",
14
+ parentCompany: "Anthropic",
15
+ featureSupport: {
16
+ slashCommands: true,
17
+ hooks: true,
18
+ mcp: true,
19
+ customSystemPrompt: true,
20
+ },
21
+ ...overrides,
22
+ };
23
+ }
24
+ describe("canonical installer", () => {
25
+ let tempDir;
26
+ beforeEach(() => {
27
+ tempDir = mkdtempSync(join(tmpdir(), "vskill-canonical-"));
28
+ });
29
+ afterEach(() => {
30
+ rmSync(tempDir, { recursive: true, force: true });
31
+ });
32
+ describe("ensureCanonicalDir", () => {
33
+ it("creates .agents/skills/ directory under base", () => {
34
+ const dir = ensureCanonicalDir(tempDir);
35
+ expect(dir).toBe(join(tempDir, ".agents", "skills"));
36
+ expect(lstatSync(dir).isDirectory()).toBe(true);
37
+ });
38
+ it("is idempotent - does not throw if dir exists", () => {
39
+ ensureCanonicalDir(tempDir);
40
+ expect(() => ensureCanonicalDir(tempDir)).not.toThrow();
41
+ });
42
+ });
43
+ describe("createRelativeSymlink", () => {
44
+ it("creates a symlink with correct relative path", () => {
45
+ const canonicalDir = join(tempDir, ".agents", "skills", "my-skill");
46
+ const agentDir = join(tempDir, ".claude", "commands", "my-skill");
47
+ mkdirSync(canonicalDir, { recursive: true });
48
+ mkdirSync(join(tempDir, ".claude", "commands"), { recursive: true });
49
+ const result = createRelativeSymlink(canonicalDir, agentDir);
50
+ expect(result).toBe(true);
51
+ expect(lstatSync(agentDir).isSymbolicLink()).toBe(true);
52
+ const target = readlinkSync(agentDir);
53
+ expect(target).toBe(join("..", "..", ".agents", "skills", "my-skill"));
54
+ });
55
+ it("returns false when symlink creation fails", () => {
56
+ // Target doesn't exist, but we mock fs to throw EPERM
57
+ const result = createRelativeSymlink("/nonexistent/path", "/also/nonexistent");
58
+ expect(result).toBe(false);
59
+ });
60
+ });
61
+ describe("installSymlink", () => {
62
+ it("creates canonical dir with SKILL.md and symlinks for each agent", () => {
63
+ const agents = [
64
+ makeAgent({ id: "claude-code", localSkillsDir: ".claude/commands" }),
65
+ makeAgent({ id: "cursor", localSkillsDir: ".cursor/skills" }),
66
+ ];
67
+ const result = installSymlink("my-skill", "# My Skill\nContent here", agents, {
68
+ global: false,
69
+ projectRoot: tempDir,
70
+ });
71
+ // Canonical SKILL.md exists
72
+ const canonicalPath = join(tempDir, ".agents", "skills", "my-skill", "SKILL.md");
73
+ expect(readFileSync(canonicalPath, "utf-8")).toBe("# My Skill\nContent here");
74
+ // Each agent dir has a symlink
75
+ const claudeLink = join(tempDir, ".claude", "commands", "my-skill");
76
+ expect(lstatSync(claudeLink).isSymbolicLink()).toBe(true);
77
+ const cursorLink = join(tempDir, ".cursor", "skills", "my-skill");
78
+ expect(lstatSync(cursorLink).isSymbolicLink()).toBe(true);
79
+ // Returned paths include all locations
80
+ expect(result).toHaveLength(2);
81
+ });
82
+ it("overwrites existing symlink or directory at target", () => {
83
+ const agents = [makeAgent()];
84
+ // Pre-create a regular directory at the target
85
+ const existingDir = join(tempDir, ".claude", "commands", "my-skill");
86
+ mkdirSync(existingDir, { recursive: true });
87
+ installSymlink("my-skill", "# Content", agents, {
88
+ global: false,
89
+ projectRoot: tempDir,
90
+ });
91
+ // Should now be a symlink, not a directory
92
+ expect(lstatSync(existingDir).isSymbolicLink()).toBe(true);
93
+ });
94
+ });
95
+ describe("installCopy", () => {
96
+ it("creates independent copies in each agent directory", () => {
97
+ const agents = [
98
+ makeAgent({ id: "claude-code", localSkillsDir: ".claude/commands" }),
99
+ makeAgent({ id: "cursor", localSkillsDir: ".cursor/skills" }),
100
+ ];
101
+ const result = installCopy("my-skill", "# My Skill\nContent", agents, {
102
+ global: false,
103
+ projectRoot: tempDir,
104
+ });
105
+ // Each agent has its own copy
106
+ const claudePath = join(tempDir, ".claude", "commands", "my-skill", "SKILL.md");
107
+ expect(readFileSync(claudePath, "utf-8")).toBe("# My Skill\nContent");
108
+ const cursorPath = join(tempDir, ".cursor", "skills", "my-skill", "SKILL.md");
109
+ expect(readFileSync(cursorPath, "utf-8")).toBe("# My Skill\nContent");
110
+ // No canonical .agents/ directory
111
+ const canonicalDir = join(tempDir, ".agents");
112
+ expect(() => lstatSync(canonicalDir)).toThrow();
113
+ expect(result).toHaveLength(2);
114
+ });
115
+ });
116
+ });
117
+ //# sourceMappingURL=canonical.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.test.js","sourceRoot":"","sources":["../../src/installer/canonical.test.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  // ---------------------------------------------------------------------------
2
2
  // Tier 1 Security Scan Patterns
3
- // 37 regex-based patterns for static analysis of skill content.
3
+ // 38 regex-based patterns for static analysis of skill content.
4
4
  // ---------------------------------------------------------------------------
5
5
  // ---- Patterns (38 total) --------------------------------------------------
6
6
  export const SCAN_PATTERNS = [
@@ -66,7 +66,7 @@ export const SCAN_PATTERNS = [
66
66
  name: "Pipe-to-shell execution",
67
67
  severity: "critical",
68
68
  description: "Detects curl/wget output piped directly to a shell interpreter (download-and-execute)",
69
- pattern: /\b(?:curl|wget)\b[^|]*\|\s*(?:ba|z|da|k)?sh\b/g,
69
+ pattern: /\b(?:curl|wget)\b[^|]*\|\s*(?:(?:\/\w+)*\/)?(?:env\s+)?(?:ba|z|da|k)?sh\b/g,
70
70
  category: "command-injection",
71
71
  },
72
72
  // --- Data Exfiltration (8-12) --------------------------------------------
@@ -1 +1 @@
1
- {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/scanner/patterns.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/scanner/patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Agent filtering for the --agent flag.
3
+ *
4
+ * Filters a list of detected agents down to only the ones the user
5
+ * explicitly requested. Throws a descriptive error when any requested
6
+ * ID is not found among the detected agents.
7
+ */
8
+ import type { AgentDefinition } from "../agents/agents-registry.js";
9
+ /**
10
+ * Filter `agents` to only those whose `id` appears in `requestedIds`.
11
+ *
12
+ * - If `requestedIds` is `undefined` or an empty array, all agents are returned.
13
+ * - If any requested ID does not match a detected agent, an error is thrown
14
+ * listing the available agent IDs.
15
+ */
16
+ export declare function filterAgents(agents: AgentDefinition[], requestedIds?: string[]): AgentDefinition[];
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Agent filtering for the --agent flag.
3
+ *
4
+ * Filters a list of detected agents down to only the ones the user
5
+ * explicitly requested. Throws a descriptive error when any requested
6
+ * ID is not found among the detected agents.
7
+ */
8
+ /**
9
+ * Filter `agents` to only those whose `id` appears in `requestedIds`.
10
+ *
11
+ * - If `requestedIds` is `undefined` or an empty array, all agents are returned.
12
+ * - If any requested ID does not match a detected agent, an error is thrown
13
+ * listing the available agent IDs.
14
+ */
15
+ export function filterAgents(agents, requestedIds) {
16
+ if (!requestedIds || requestedIds.length === 0) {
17
+ return agents;
18
+ }
19
+ const available = new Set(agents.map((a) => a.id));
20
+ const missing = requestedIds.filter((id) => !available.has(id));
21
+ if (missing.length > 0) {
22
+ const availableList = agents.map((a) => a.id).join(", ");
23
+ throw new Error(`Unknown agent(s): ${missing.join(", ")}. Available: ${availableList}`);
24
+ }
25
+ const requested = new Set(requestedIds);
26
+ return agents.filter((a) => requested.has(a.id));
27
+ }
28
+ //# sourceMappingURL=agent-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-filter.js","sourceRoot":"","sources":["../../src/utils/agent-filter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAyB,EACzB,YAAuB;IAEvB,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAEhE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,qBAAqB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,aAAa,EAAE,CACvE,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,64 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { filterAgents } from "./agent-filter.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Helpers
5
+ // ---------------------------------------------------------------------------
6
+ function makeAgent(overrides = {}) {
7
+ return {
8
+ id: "claude-code",
9
+ displayName: "Claude Code",
10
+ localSkillsDir: ".claude/commands",
11
+ globalSkillsDir: "~/.claude/commands",
12
+ isUniversal: false,
13
+ detectInstalled: "which claude",
14
+ parentCompany: "Anthropic",
15
+ featureSupport: {
16
+ slashCommands: true,
17
+ hooks: true,
18
+ mcp: true,
19
+ customSystemPrompt: true,
20
+ },
21
+ ...overrides,
22
+ };
23
+ }
24
+ const claudeAgent = makeAgent({ id: "claude-code", displayName: "Claude Code" });
25
+ const cursorAgent = makeAgent({ id: "cursor", displayName: "Cursor" });
26
+ const windsurf = makeAgent({ id: "windsurf", displayName: "Windsurf" });
27
+ const allAgents = [claudeAgent, cursorAgent, windsurf];
28
+ // ---------------------------------------------------------------------------
29
+ // Tests
30
+ // ---------------------------------------------------------------------------
31
+ describe("filterAgents", () => {
32
+ // TC-001: No filter returns all agents
33
+ it("returns all agents when requestedIds is undefined", () => {
34
+ const result = filterAgents(allAgents, undefined);
35
+ expect(result).toEqual(allAgents);
36
+ });
37
+ // TC-002: Single filter returns only matching
38
+ it("returns only the matching agent when filtering by single ID", () => {
39
+ const result = filterAgents(allAgents, ["claude-code"]);
40
+ expect(result).toHaveLength(1);
41
+ expect(result[0].id).toBe("claude-code");
42
+ });
43
+ // TC-003: Multiple filters returns all matching
44
+ it("returns all matching agents when filtering by multiple IDs", () => {
45
+ const result = filterAgents(allAgents, ["claude-code", "cursor"]);
46
+ expect(result).toHaveLength(2);
47
+ expect(result.map((a) => a.id)).toEqual(["claude-code", "cursor"]);
48
+ });
49
+ // TC-004: Unknown ID throws with available agents listed
50
+ it("throws error listing available agents when ID is unknown", () => {
51
+ expect(() => filterAgents(allAgents, ["nonexistent"])).toThrow(/Unknown agent\(s\): nonexistent/);
52
+ expect(() => filterAgents(allAgents, ["nonexistent"])).toThrow(/Available: claude-code, cursor, windsurf/);
53
+ });
54
+ // TC-005: Mix of valid and invalid throws
55
+ it("throws error mentioning only the invalid IDs", () => {
56
+ expect(() => filterAgents(allAgents, ["claude-code", "nonexistent"])).toThrow(/Unknown agent\(s\): nonexistent/);
57
+ });
58
+ // TC-006: Empty array returns all (same as undefined)
59
+ it("returns all agents when requestedIds is an empty array", () => {
60
+ const result = filterAgents(allAgents, []);
61
+ expect(result).toEqual(allAgents);
62
+ });
63
+ });
64
+ //# sourceMappingURL=agent-filter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-filter.test.js","sourceRoot":"","sources":["../../src/utils/agent-filter.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAS,SAAS,CAAC,YAAsC,EAAE;IACzD,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,WAAW,EAAE,aAAa;QAC1B,cAAc,EAAE,kBAAkB;QAClC,eAAe,EAAE,oBAAoB;QACrC,WAAW,EAAE,KAAK;QAClB,eAAe,EAAE,cAAc;QAC/B,aAAa,EAAE,WAAW;QAC1B,cAAc,EAAE;YACd,aAAa,EAAE,IAAI;YACnB,KAAK,EAAE,IAAI;YACX,GAAG,EAAE,IAAI;YACT,kBAAkB,EAAE,IAAI;SACzB;QACD,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,WAAW,GAAG,SAAS,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAAC;AACjF,MAAM,WAAW,GAAG,SAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;AACvE,MAAM,QAAQ,GAAG,SAAS,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;AAExE,MAAM,SAAS,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;AAEvD,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,uCAAuC;IACvC,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,8CAA8C;IAC9C,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,gDAAgD;IAChD,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,yDAAyD;IACzD,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAC5D,iCAAiC,CAClC,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAC5D,0CAA0C,CAC3C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,0CAA0C;IAC1C,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,GAAG,EAAE,CACV,YAAY,CAAC,SAAS,EAAE,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC,CACxD,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,sDAAsD;IACtD,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Smart project root resolution.
3
+ *
4
+ * Walks up the directory tree from a starting directory, looking for
5
+ * well-known project markers (`.git`, `package.json`, etc.).
6
+ * Returns the absolute path of the nearest directory that contains
7
+ * any marker, or `null` if none is found.
8
+ */
9
+ /** Markers that indicate a project root directory. */
10
+ export declare const PROJECT_MARKERS: readonly [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", "requirements.txt", "pom.xml", "vskill.lock", ".specweave"];
11
+ /**
12
+ * Walk up the directory tree from `startDir` and return the absolute
13
+ * path of the first directory that contains any project marker.
14
+ *
15
+ * Returns `null` when the filesystem root is reached without finding
16
+ * any marker.
17
+ */
18
+ export declare function findProjectRoot(startDir: string): string | null;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Smart project root resolution.
3
+ *
4
+ * Walks up the directory tree from a starting directory, looking for
5
+ * well-known project markers (`.git`, `package.json`, etc.).
6
+ * Returns the absolute path of the nearest directory that contains
7
+ * any marker, or `null` if none is found.
8
+ */
9
+ import { existsSync } from "node:fs";
10
+ import { dirname, resolve } from "node:path";
11
+ /** Markers that indicate a project root directory. */
12
+ export const PROJECT_MARKERS = [
13
+ ".git",
14
+ "package.json",
15
+ "Cargo.toml",
16
+ "go.mod",
17
+ "pyproject.toml",
18
+ "requirements.txt",
19
+ "pom.xml",
20
+ "vskill.lock",
21
+ ".specweave",
22
+ ];
23
+ /**
24
+ * Walk up the directory tree from `startDir` and return the absolute
25
+ * path of the first directory that contains any project marker.
26
+ *
27
+ * Returns `null` when the filesystem root is reached without finding
28
+ * any marker.
29
+ */
30
+ export function findProjectRoot(startDir) {
31
+ let dir = resolve(startDir);
32
+ // eslint-disable-next-line no-constant-condition
33
+ while (true) {
34
+ for (const marker of PROJECT_MARKERS) {
35
+ if (existsSync(resolve(dir, marker))) {
36
+ return dir;
37
+ }
38
+ }
39
+ const parent = dirname(dir);
40
+ if (parent === dir) {
41
+ // Reached filesystem root
42
+ return null;
43
+ }
44
+ dir = parent;
45
+ }
46
+ }
47
+ //# sourceMappingURL=project-root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-root.js","sourceRoot":"","sources":["../../src/utils/project-root.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,sDAAsD;AACtD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,MAAM;IACN,cAAc;IACd,YAAY;IACZ,QAAQ;IACR,gBAAgB;IAChB,kBAAkB;IAClB,SAAS;IACT,aAAa;IACb,YAAY;CACJ,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,IAAI,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE5B,iDAAiD;IACjD,OAAO,IAAI,EAAE,CAAC;QACZ,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;YACrC,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;gBACrC,OAAO,GAAG,CAAC;YACb,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,0BAA0B;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,74 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { join } from "node:path";
3
+ // ---------------------------------------------------------------------------
4
+ // Mock node:fs — only existsSync is used by findProjectRoot
5
+ // ---------------------------------------------------------------------------
6
+ const mockExistsSync = vi.fn();
7
+ vi.mock("node:fs", () => ({
8
+ existsSync: (...args) => mockExistsSync(...args),
9
+ }));
10
+ // ---------------------------------------------------------------------------
11
+ // Import module under test AFTER mocks
12
+ // ---------------------------------------------------------------------------
13
+ const { findProjectRoot, PROJECT_MARKERS } = await import("./project-root.js");
14
+ // ---------------------------------------------------------------------------
15
+ // Helpers
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Configure mockExistsSync to return true only for paths
19
+ * that are in the `existing` set.
20
+ */
21
+ function setExistingPaths(existing) {
22
+ mockExistsSync.mockImplementation((p) => existing.has(p));
23
+ }
24
+ // ---------------------------------------------------------------------------
25
+ // Tests
26
+ // ---------------------------------------------------------------------------
27
+ beforeEach(() => {
28
+ vi.clearAllMocks();
29
+ });
30
+ describe("findProjectRoot", () => {
31
+ // TC-001: Finds .git at parent when cwd is subdirectory
32
+ it("finds .git at parent when cwd is a subdirectory", () => {
33
+ const projectDir = "/home/user/project";
34
+ const startDir = join(projectDir, "src", "components");
35
+ setExistingPaths(new Set([join(projectDir, ".git")]));
36
+ expect(findProjectRoot(startDir)).toBe(projectDir);
37
+ });
38
+ // TC-002: Finds package.json at ancestor
39
+ it("finds package.json at ancestor directory", () => {
40
+ const projectDir = "/home/user/project";
41
+ const startDir = join(projectDir, "deep", "nested", "dir");
42
+ setExistingPaths(new Set([join(projectDir, "package.json")]));
43
+ expect(findProjectRoot(startDir)).toBe(projectDir);
44
+ });
45
+ // TC-003: Returns null when no markers anywhere
46
+ it("returns null when no markers exist anywhere up to root", () => {
47
+ setExistingPaths(new Set());
48
+ expect(findProjectRoot("/some/random/path")).toBeNull();
49
+ });
50
+ // TC-004: Nearest wins when markers at multiple levels
51
+ it("returns nearest directory when markers exist at multiple levels", () => {
52
+ const outer = "/home/user/project";
53
+ const inner = join(outer, "submodule");
54
+ const startDir = join(inner, "src");
55
+ setExistingPaths(new Set([join(outer, ".git"), join(inner, ".git")]));
56
+ expect(findProjectRoot(startDir)).toBe(inner);
57
+ });
58
+ // TC-005: Returns cwd itself when it has markers
59
+ it("returns cwd itself when it contains markers", () => {
60
+ const startDir = "/home/user/project";
61
+ setExistingPaths(new Set([join(startDir, ".git")]));
62
+ expect(findProjectRoot(startDir)).toBe(startDir);
63
+ });
64
+ // Additional: verifies all markers are recognized
65
+ it("recognizes every marker in PROJECT_MARKERS", () => {
66
+ for (const marker of PROJECT_MARKERS) {
67
+ vi.clearAllMocks();
68
+ const dir = "/home/user/project";
69
+ setExistingPaths(new Set([join(dir, marker)]));
70
+ expect(findProjectRoot(dir)).toBe(dir);
71
+ }
72
+ });
73
+ });
74
+ //# sourceMappingURL=project-root.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-root.test.js","sourceRoot":"","sources":["../../src/utils/project-root.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Readable, Writable } from "node:stream";
2
+ export declare function isTTY(): boolean;
3
+ export interface CheckboxItem {
4
+ label: string;
5
+ description?: string;
6
+ checked?: boolean;
7
+ }
8
+ export interface CheckboxOptions {
9
+ title?: string;
10
+ }
11
+ export interface ChoiceItem {
12
+ label: string;
13
+ hint?: string;
14
+ }
15
+ export interface Prompter {
16
+ promptCheckboxList(items: CheckboxItem[], options?: CheckboxOptions): Promise<number[]>;
17
+ promptChoice(question: string, choices: ChoiceItem[]): Promise<number>;
18
+ promptConfirm(question: string, defaultYes?: boolean): Promise<boolean>;
19
+ }
20
+ export declare function createPrompter(input?: Readable, output?: Writable): Prompter;