@sweny-ai/core 0.1.38 → 0.1.39

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.
@@ -8,7 +8,8 @@ import { slack } from "../skills/slack.js";
8
8
  import { sentry } from "../skills/sentry.js";
9
9
  import { datadog } from "../skills/datadog.js";
10
10
  import { notification } from "../skills/notification.js";
11
- import { loadCustomSkills, configuredSkills, createSkillMap } from "../skills/index.js";
11
+ import { createSkillMap } from "../skills/index.js";
12
+ import { loadCustomSkills, configuredSkills } from "../skills/custom-loader.js";
12
13
  // ─── Helpers ─────────────────────────────────────────────────────
13
14
  const mockCtx = (config = {}) => ({
14
15
  config,
package/dist/browser.d.ts CHANGED
@@ -9,7 +9,7 @@ export type { Skill, SkillCategory, Tool, ToolContext, ConfigField, JSONSchema,
9
9
  export { consoleLogger } from "./types.js";
10
10
  export { execute } from "./executor.js";
11
11
  export type { ExecuteOptions } from "./executor.js";
12
- export { github, linear, slack, sentry, datadog, notification, builtinSkills, createSkillMap, allSkills, isSkillConfigured, configuredSkills, validateWorkflowSkills, } from "./skills/index.js";
12
+ export { github, linear, slack, sentry, datadog, notification, builtinSkills, createSkillMap, allSkills, isSkillConfigured, configuredBuiltinSkills, validateWorkflowSkills, } from "./skills/index.js";
13
13
  export type { SkillValidationResult } from "./skills/index.js";
14
14
  export { workflowZ, nodeZ, edgeZ, skillZ, parseWorkflow, validateWorkflow, workflowJsonSchema } from "./schema.js";
15
15
  export type { WorkflowError } from "./schema.js";
package/dist/browser.js CHANGED
@@ -8,8 +8,8 @@
8
8
  export { consoleLogger } from "./types.js";
9
9
  // Executor
10
10
  export { execute } from "./executor.js";
11
- // Skills
12
- export { github, linear, slack, sentry, datadog, notification, builtinSkills, createSkillMap, allSkills, isSkillConfigured, configuredSkills, validateWorkflowSkills, } from "./skills/index.js";
11
+ // Skills (browser-safe — no filesystem access, no `process.env` reads)
12
+ export { github, linear, slack, sentry, datadog, notification, builtinSkills, createSkillMap, allSkills, isSkillConfigured, configuredBuiltinSkills, validateWorkflowSkills, } from "./skills/index.js";
13
13
  // Schema & validation
14
14
  export { workflowZ, nodeZ, edgeZ, skillZ, parseWorkflow, validateWorkflow, workflowJsonSchema } from "./schema.js";
15
15
  // Studio adapter
package/dist/cli/e2e.js CHANGED
@@ -11,7 +11,8 @@ import chalk from "chalk";
11
11
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
12
12
  import { execute } from "../executor.js";
13
13
  import { ClaudeClient } from "../claude.js";
14
- import { createSkillMap, configuredSkills } from "../skills/index.js";
14
+ import { createSkillMap } from "../skills/index.js";
15
+ import { configuredSkills } from "../skills/custom-loader.js";
15
16
  import { consoleLogger } from "../types.js";
16
17
  import { validateWorkflow } from "../schema.js";
17
18
  // ── Template variable resolution ───────────────────────────────────────
package/dist/cli/main.js CHANGED
@@ -10,7 +10,8 @@ import { execute } from "../executor.js";
10
10
  import { triageWorkflow, implementWorkflow, seedContentWorkflow } from "../workflows/index.js";
11
11
  import { consoleLogger } from "../types.js";
12
12
  import { ClaudeClient } from "../claude.js";
13
- import { createSkillMap, configuredSkills } from "../skills/index.js";
13
+ import { createSkillMap } from "../skills/index.js";
14
+ import { configuredSkills } from "../skills/custom-loader.js";
14
15
  import { buildAutoMcpServers, buildProviderContext } from "../mcp.js";
15
16
  import { loadAdditionalContext } from "../templates.js";
16
17
  import { validateWorkflow as validateWorkflowSchema } from "../schema.js";
package/dist/index.d.ts CHANGED
@@ -27,8 +27,9 @@ export { execute } from "./executor.js";
27
27
  export type { ExecuteOptions } from "./executor.js";
28
28
  export { ClaudeClient } from "./claude.js";
29
29
  export type { ClaudeClientOptions } from "./claude.js";
30
- export { github, linear, slack, sentry, datadog, notification, supabase, builtinSkills, createSkillMap, allSkills, isSkillConfigured, configuredSkills, validateWorkflowSkills, } from "./skills/index.js";
30
+ export { github, linear, slack, sentry, datadog, notification, supabase, builtinSkills, createSkillMap, allSkills, isSkillConfigured, configuredBuiltinSkills, validateWorkflowSkills, } from "./skills/index.js";
31
31
  export type { SkillValidationResult } from "./skills/index.js";
32
+ export { loadCustomSkills, configuredSkills } from "./skills/custom-loader.js";
32
33
  export { workflowZ, nodeZ, edgeZ, skillZ, parseWorkflow, validateWorkflow, workflowJsonSchema } from "./schema.js";
33
34
  export type { WorkflowError } from "./schema.js";
34
35
  export { buildAutoMcpServers, buildProviderContext } from "./mcp.js";
package/dist/index.js CHANGED
@@ -27,7 +27,9 @@ export { execute } from "./executor.js";
27
27
  // Claude client
28
28
  export { ClaudeClient } from "./claude.js";
29
29
  // Skills
30
- export { github, linear, slack, sentry, datadog, notification, supabase, builtinSkills, createSkillMap, allSkills, isSkillConfigured, configuredSkills, validateWorkflowSkills, } from "./skills/index.js";
30
+ export { github, linear, slack, sentry, datadog, notification, supabase, builtinSkills, createSkillMap, allSkills, isSkillConfigured, configuredBuiltinSkills, validateWorkflowSkills, } from "./skills/index.js";
31
+ // Node-only skill discovery (filesystem-based)
32
+ export { loadCustomSkills, configuredSkills } from "./skills/custom-loader.js";
31
33
  // Schema & validation
32
34
  export { workflowZ, nodeZ, edgeZ, skillZ, parseWorkflow, validateWorkflow, workflowJsonSchema } from "./schema.js";
33
35
  // MCP auto-injection
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Custom skill discovery — Node-only.
3
+ *
4
+ * Lives outside `skills/index.ts` so the registry stays browser-safe. Anything
5
+ * that needs `node:fs` / `node:path` / `process.cwd()` belongs here.
6
+ */
7
+ import type { Skill } from "../types.js";
8
+ /**
9
+ * Load custom skills from a `.claude/skills/` directory.
10
+ *
11
+ * Custom skills are instruction-only (no tools or config) — they provide
12
+ * guidance documents that the coding agent reads from the filesystem.
13
+ * Registering them here ensures workflow validation recognises the skill IDs
14
+ * so nodes referencing them don't produce spurious warnings.
15
+ */
16
+ export declare function loadCustomSkills(cwd?: string): Skill[];
17
+ /**
18
+ * From all builtins + custom repo skills, return only the skills that are usable.
19
+ * Built-in skills are filtered by env vars; custom skills are always included.
20
+ *
21
+ * Node-only: reads `.claude/skills/` from disk. Browser code should call
22
+ * `configuredBuiltinSkills` from `@sweny-ai/core/browser` instead.
23
+ */
24
+ export declare function configuredSkills(env?: Record<string, string | undefined>, cwd?: string): Skill[];
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Custom skill discovery — Node-only.
3
+ *
4
+ * Lives outside `skills/index.ts` so the registry stays browser-safe. Anything
5
+ * that needs `node:fs` / `node:path` / `process.cwd()` belongs here.
6
+ */
7
+ import { readdirSync, readFileSync, existsSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import YAML from "yaml";
10
+ import { builtinSkills, isSkillConfigured } from "./index.js";
11
+ /**
12
+ * Load custom skills from a `.claude/skills/` directory.
13
+ *
14
+ * Custom skills are instruction-only (no tools or config) — they provide
15
+ * guidance documents that the coding agent reads from the filesystem.
16
+ * Registering them here ensures workflow validation recognises the skill IDs
17
+ * so nodes referencing them don't produce spurious warnings.
18
+ */
19
+ export function loadCustomSkills(cwd = process.cwd()) {
20
+ const skillsDir = join(cwd, ".claude", "skills");
21
+ if (!existsSync(skillsDir))
22
+ return [];
23
+ const skills = [];
24
+ let entries;
25
+ try {
26
+ entries = readdirSync(skillsDir, { withFileTypes: true })
27
+ .filter((d) => d.isDirectory())
28
+ .map((d) => d.name);
29
+ }
30
+ catch {
31
+ return [];
32
+ }
33
+ for (const dirName of entries) {
34
+ const skillFile = join(skillsDir, dirName, "SKILL.md");
35
+ if (!existsSync(skillFile))
36
+ continue;
37
+ try {
38
+ const content = readFileSync(skillFile, "utf-8");
39
+ const frontmatter = parseFrontmatter(content);
40
+ if (!frontmatter?.name)
41
+ continue;
42
+ skills.push({
43
+ id: frontmatter.name,
44
+ name: frontmatter.name,
45
+ description: frontmatter.description ?? `Custom skill: ${frontmatter.name}`,
46
+ category: "general",
47
+ config: {},
48
+ tools: [],
49
+ });
50
+ }
51
+ catch {
52
+ // Skip malformed skill files
53
+ }
54
+ }
55
+ return skills;
56
+ }
57
+ /** Extract YAML frontmatter from a markdown file (between --- delimiters). */
58
+ function parseFrontmatter(content) {
59
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
60
+ if (!match)
61
+ return null;
62
+ try {
63
+ return YAML.parse(match[1]);
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ }
69
+ /**
70
+ * From all builtins + custom repo skills, return only the skills that are usable.
71
+ * Built-in skills are filtered by env vars; custom skills are always included.
72
+ *
73
+ * Node-only: reads `.claude/skills/` from disk. Browser code should call
74
+ * `configuredBuiltinSkills` from `@sweny-ai/core/browser` instead.
75
+ */
76
+ export function configuredSkills(env = process.env, cwd) {
77
+ const configured = builtinSkills.filter((s) => isSkillConfigured(s, env));
78
+ const custom = loadCustomSkills(cwd);
79
+ // Deduplicate: built-in skills take precedence over custom skills with the same ID
80
+ const ids = new Set(configured.map((s) => s.id));
81
+ for (const skill of custom) {
82
+ if (!ids.has(skill.id)) {
83
+ configured.push(skill);
84
+ ids.add(skill.id);
85
+ }
86
+ }
87
+ return configured;
88
+ }
@@ -2,6 +2,10 @@
2
2
  * Skill Registry
3
3
  *
4
4
  * All built-in skills + helpers to build a skill map from config.
5
+ *
6
+ * This module is browser-safe — no `node:fs`, no `node:path`, no `process`.
7
+ * Custom skill discovery (filesystem-based) lives in `./custom-loader.js`,
8
+ * which is Node-only and re-exported from `@sweny-ai/core` (the Node entry).
5
9
  */
6
10
  import type { Skill, SkillCategory } from "../types.js";
7
11
  import { github } from "./github.js";
@@ -14,15 +18,6 @@ import { notification } from "./notification.js";
14
18
  import { supabase } from "./supabase.js";
15
19
  export declare const builtinSkills: Skill[];
16
20
  export { github, linear, slack, sentry, datadog, betterstack, notification, supabase };
17
- /**
18
- * Load custom skills from a `.claude/skills/` directory.
19
- *
20
- * Custom skills are instruction-only (no tools or config) — they provide
21
- * guidance documents that the coding agent reads from the filesystem.
22
- * Registering them here ensures workflow validation recognises the skill IDs
23
- * so nodes referencing them don't produce spurious warnings.
24
- */
25
- export declare function loadCustomSkills(cwd?: string): Skill[];
26
21
  /**
27
22
  * Build a skill map from an array of skills.
28
23
  * Pass to `execute()` as the `skills` option.
@@ -47,10 +42,13 @@ export declare function allSkills(): Map<string, Skill>;
47
42
  */
48
43
  export declare function isSkillConfigured(skill: Skill, env?: Record<string, string | undefined>): boolean;
49
44
  /**
50
- * From all builtins + custom repo skills, return only the skills that are usable.
51
- * Built-in skills are filtered by env vars; custom skills are always included.
45
+ * Browser-safe variant of `configuredSkills`: returns only the *built-in* skills
46
+ * whose required env vars are present. Does not touch the filesystem.
47
+ *
48
+ * Node callers should use `configuredSkills` from `@sweny-ai/core`, which also
49
+ * loads custom skills from `.claude/skills/`.
52
50
  */
53
- export declare function configuredSkills(env?: Record<string, string | undefined>, cwd?: string): Skill[];
51
+ export declare function configuredBuiltinSkills(env?: Record<string, string | undefined>): Skill[];
54
52
  /**
55
53
  * Validate that a workflow's skill requirements are satisfiable.
56
54
  *
@@ -2,10 +2,11 @@
2
2
  * Skill Registry
3
3
  *
4
4
  * All built-in skills + helpers to build a skill map from config.
5
+ *
6
+ * This module is browser-safe — no `node:fs`, no `node:path`, no `process`.
7
+ * Custom skill discovery (filesystem-based) lives in `./custom-loader.js`,
8
+ * which is Node-only and re-exported from `@sweny-ai/core` (the Node entry).
5
9
  */
6
- import { readdirSync, readFileSync, existsSync } from "node:fs";
7
- import { join } from "node:path";
8
- import YAML from "yaml";
9
10
  import { github } from "./github.js";
10
11
  import { linear } from "./linear.js";
11
12
  import { slack } from "./slack.js";
@@ -17,65 +18,6 @@ import { supabase } from "./supabase.js";
17
18
  // ─── Built-in skill catalog ─────────────────────────────────────
18
19
  export const builtinSkills = [github, linear, slack, sentry, datadog, betterstack, notification, supabase];
19
20
  export { github, linear, slack, sentry, datadog, betterstack, notification, supabase };
20
- // ─── Custom skill discovery ─────────────────────────────────────
21
- /**
22
- * Load custom skills from a `.claude/skills/` directory.
23
- *
24
- * Custom skills are instruction-only (no tools or config) — they provide
25
- * guidance documents that the coding agent reads from the filesystem.
26
- * Registering them here ensures workflow validation recognises the skill IDs
27
- * so nodes referencing them don't produce spurious warnings.
28
- */
29
- export function loadCustomSkills(cwd = process.cwd()) {
30
- const skillsDir = join(cwd, ".claude", "skills");
31
- if (!existsSync(skillsDir))
32
- return [];
33
- const skills = [];
34
- let entries;
35
- try {
36
- entries = readdirSync(skillsDir, { withFileTypes: true })
37
- .filter((d) => d.isDirectory())
38
- .map((d) => d.name);
39
- }
40
- catch {
41
- return [];
42
- }
43
- for (const dirName of entries) {
44
- const skillFile = join(skillsDir, dirName, "SKILL.md");
45
- if (!existsSync(skillFile))
46
- continue;
47
- try {
48
- const content = readFileSync(skillFile, "utf-8");
49
- const frontmatter = parseFrontmatter(content);
50
- if (!frontmatter?.name)
51
- continue;
52
- skills.push({
53
- id: frontmatter.name,
54
- name: frontmatter.name,
55
- description: frontmatter.description ?? `Custom skill: ${frontmatter.name}`,
56
- category: "general",
57
- config: {},
58
- tools: [],
59
- });
60
- }
61
- catch {
62
- // Skip malformed skill files
63
- }
64
- }
65
- return skills;
66
- }
67
- /** Extract YAML frontmatter from a markdown file (between --- delimiters). */
68
- function parseFrontmatter(content) {
69
- const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
70
- if (!match)
71
- return null;
72
- try {
73
- return YAML.parse(match[1]);
74
- }
75
- catch {
76
- return null;
77
- }
78
- }
79
21
  // ─── Registry helpers ───────────────────────────────────────────
80
22
  /**
81
23
  * Build a skill map from an array of skills.
@@ -110,7 +52,7 @@ export function allSkills() {
110
52
  * Optional fields are validated by individual tool handlers at call time,
111
53
  * so missing optional config never disqualifies the skill.
112
54
  */
113
- export function isSkillConfigured(skill, env = process.env) {
55
+ export function isSkillConfigured(skill, env = {}) {
114
56
  for (const field of Object.values(skill.config)) {
115
57
  if (field.required && field.env && !env[field.env])
116
58
  return false;
@@ -118,21 +60,14 @@ export function isSkillConfigured(skill, env = process.env) {
118
60
  return true;
119
61
  }
120
62
  /**
121
- * From all builtins + custom repo skills, return only the skills that are usable.
122
- * Built-in skills are filtered by env vars; custom skills are always included.
63
+ * Browser-safe variant of `configuredSkills`: returns only the *built-in* skills
64
+ * whose required env vars are present. Does not touch the filesystem.
65
+ *
66
+ * Node callers should use `configuredSkills` from `@sweny-ai/core`, which also
67
+ * loads custom skills from `.claude/skills/`.
123
68
  */
124
- export function configuredSkills(env = process.env, cwd) {
125
- const configured = builtinSkills.filter((s) => isSkillConfigured(s, env));
126
- const custom = loadCustomSkills(cwd);
127
- // Deduplicate: built-in skills take precedence over custom skills with the same ID
128
- const ids = new Set(configured.map((s) => s.id));
129
- for (const skill of custom) {
130
- if (!ids.has(skill.id)) {
131
- configured.push(skill);
132
- ids.add(skill.id);
133
- }
134
- }
135
- return configured;
69
+ export function configuredBuiltinSkills(env = {}) {
70
+ return builtinSkills.filter((s) => isSkillConfigured(s, env));
136
71
  }
137
72
  export function validateWorkflowSkills(workflow, available) {
138
73
  const configured = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sweny-ai/core",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sweny": "./dist/cli/main.js"