@fro.bot/systematic 2.33.0 → 2.33.1

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/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  findCommandsInDir,
7
7
  findSkillsInDir,
8
8
  getConfigPaths
9
- } from "./index-bwrrk4a8.js";
9
+ } from "./index-vyzhzvap.js";
10
10
 
11
11
  // src/cli.ts
12
12
  import fs from "fs";
@@ -515,32 +515,35 @@ function parseDeprecated(data) {
515
515
  }
516
516
  return deprecated;
517
517
  }
518
+ function extractFrontmatterFromContent(content) {
519
+ const { data, parseError } = parseFrontmatter(content);
520
+ if (parseError) {
521
+ return { name: "", description: "" };
522
+ }
523
+ const metadata = parseMetadata(data);
524
+ const deprecated = parseDeprecated(data);
525
+ const argumentHintRaw = extractNonEmptyString(data, "argument-hint");
526
+ const argumentHint = argumentHintRaw?.replace(/^["']|["']$/g, "") || undefined;
527
+ return {
528
+ name: extractString(data, "name"),
529
+ description: extractString(data, "description"),
530
+ license: extractNonEmptyString(data, "license"),
531
+ compatibility: extractNonEmptyString(data, "compatibility"),
532
+ metadata,
533
+ deprecated,
534
+ disableModelInvocation: extractBoolean(data, "disable-model-invocation"),
535
+ userInvocable: extractBoolean(data, "user-invocable"),
536
+ subtask: data.context === "fork" ? true : extractBoolean(data, "subtask") ?? undefined,
537
+ agent: extractNonEmptyString(data, "agent"),
538
+ model: extractNonEmptyString(data, "model"),
539
+ argumentHint: argumentHint !== "" ? argumentHint : undefined,
540
+ allowedTools: extractNonEmptyString(data, "allowed-tools")
541
+ };
542
+ }
518
543
  function extractFrontmatter(filePath) {
519
544
  try {
520
545
  const content = fs3.readFileSync(filePath, "utf8");
521
- const { data, parseError } = parseFrontmatter(content);
522
- if (parseError) {
523
- return { name: "", description: "" };
524
- }
525
- const metadata = parseMetadata(data);
526
- const deprecated = parseDeprecated(data);
527
- const argumentHintRaw = extractNonEmptyString(data, "argument-hint");
528
- const argumentHint = argumentHintRaw?.replace(/^["']|["']$/g, "") || undefined;
529
- return {
530
- name: extractString(data, "name"),
531
- description: extractString(data, "description"),
532
- license: extractNonEmptyString(data, "license"),
533
- compatibility: extractNonEmptyString(data, "compatibility"),
534
- metadata,
535
- deprecated,
536
- disableModelInvocation: extractBoolean(data, "disable-model-invocation"),
537
- userInvocable: extractBoolean(data, "user-invocable"),
538
- subtask: data.context === "fork" ? true : extractBoolean(data, "subtask") ?? undefined,
539
- agent: extractNonEmptyString(data, "agent"),
540
- model: extractNonEmptyString(data, "model"),
541
- argumentHint: argumentHint !== "" ? argumentHint : undefined,
542
- allowedTools: extractNonEmptyString(data, "allowed-tools")
543
- };
546
+ return extractFrontmatterFromContent(content);
544
547
  } catch {
545
548
  return { name: "", description: "" };
546
549
  }
@@ -16422,4 +16425,4 @@ function extractCommandFrontmatter(content) {
16422
16425
  };
16423
16426
  }
16424
16427
 
16425
- export { parseFrontmatter, isRecord, convertContent, convertFileWithCache, walkDir, extractFrontmatter, findSkillsInDir, exports_external, AgentOverlaySchema, CategoryOverlaySchema, loadConfig, loadConfigWithSources, getConfigPaths, findAgentsInDir, extractAgentFrontmatter, findCommandsInDir, extractCommandFrontmatter };
16428
+ export { parseFrontmatter, isRecord, convertContent, convertFileWithCache, walkDir, extractFrontmatterFromContent, findSkillsInDir, exports_external, AgentOverlaySchema, CategoryOverlaySchema, loadConfig, loadConfigWithSources, getConfigPaths, findAgentsInDir, extractAgentFrontmatter, findCommandsInDir, extractCommandFrontmatter };
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  exports_external,
7
7
  extractAgentFrontmatter,
8
8
  extractCommandFrontmatter,
9
- extractFrontmatter,
9
+ extractFrontmatterFromContent,
10
10
  findAgentsInDir,
11
11
  findCommandsInDir,
12
12
  findSkillsInDir,
@@ -15,10 +15,10 @@ import {
15
15
  loadConfigWithSources,
16
16
  parseFrontmatter,
17
17
  walkDir
18
- } from "./index-bwrrk4a8.js";
18
+ } from "./index-vyzhzvap.js";
19
19
 
20
20
  // src/index.ts
21
- import fs7 from "fs";
21
+ import fs6 from "fs";
22
22
  import path9 from "path";
23
23
  import { fileURLToPath as fileURLToPath2 } from "url";
24
24
 
@@ -240,7 +240,6 @@ ${skillUsage}${catalogSection}
240
240
  }
241
241
 
242
242
  // src/lib/config-handler.ts
243
- import fs5 from "fs";
244
243
  import os3 from "os";
245
244
  import path7 from "path";
246
245
 
@@ -707,15 +706,13 @@ function globSkillFiles(rootDir, subdirNames) {
707
706
  return results;
708
707
  }
709
708
  function toDiscoveredSkill(skillPath, rootId) {
710
- let stat;
709
+ let content;
711
710
  try {
712
- stat = fs3.statSync(skillPath);
711
+ content = fs3.readFileSync(skillPath, "utf8");
713
712
  } catch {
714
713
  return;
715
714
  }
716
- if (!stat.isFile())
717
- return;
718
- const frontmatter = extractFrontmatter(skillPath);
715
+ const frontmatter = extractFrontmatterFromContent(content);
719
716
  const name = frontmatter.name;
720
717
  if (!name || !isValidSkillName(name))
721
718
  return;
@@ -723,6 +720,7 @@ function toDiscoveredSkill(skillPath, rootId) {
723
720
  name,
724
721
  description: frontmatter.description,
725
722
  frontmatter,
723
+ body: parseFrontmatter(content).body,
726
724
  skillPath,
727
725
  root: rootId
728
726
  };
@@ -1226,10 +1224,8 @@ function collectSkillsAsCommands(dir, disabledSkills) {
1226
1224
  function loadDiscoveredSkillAsCommand(skill) {
1227
1225
  const description = formatSkillDescription(skill.description, skill.name);
1228
1226
  if (skill.frontmatter.disableModelInvocation === true) {
1229
- const content = fs5.readFileSync(skill.skillPath, "utf8");
1230
- const { body } = parseFrontmatter(content);
1231
1227
  return {
1232
- template: wrapSkillTemplate(skill.skillPath, body),
1228
+ template: wrapSkillTemplate(skill.skillPath, skill.body),
1233
1229
  description
1234
1230
  };
1235
1231
  }
@@ -1245,7 +1241,7 @@ function buildDiscoveredSkillShimTemplate(skillName) {
1245
1241
  $ARGUMENTS
1246
1242
  </user-request>`;
1247
1243
  }
1248
- function collectDiscoveredSkillsAsCommands(startDir, homeDir, configDir, opencodeConfigDirOverride) {
1244
+ function collectDiscoveredSkillsAsCommands(startDir, homeDir, configDir, opencodeConfigDirOverride, disabledCommands) {
1249
1245
  const commands = {};
1250
1246
  let discovered;
1251
1247
  try {
@@ -1261,6 +1257,8 @@ function collectDiscoveredSkillsAsCommands(startDir, homeDir, configDir, opencod
1261
1257
  for (const skill of discovered) {
1262
1258
  if (skill.frontmatter.userInvocable === false)
1263
1259
  continue;
1260
+ if (disabledCommands.includes(skill.name))
1261
+ continue;
1264
1262
  try {
1265
1263
  commands[skill.name] = loadDiscoveredSkillAsCommand(skill);
1266
1264
  } catch {}
@@ -1296,7 +1294,7 @@ function createConfigHandler(deps) {
1296
1294
  const resolvedOverlays = resolveAgentOverlaySet(validatedOverlays);
1297
1295
  const bundledAgents = collectAgents(bundledAgentsDir2, systematicConfig.disabled_agents, nativeAgents, resolvedOverlays, availabilitySet);
1298
1296
  const bundledCommands = collectCommands(bundledCommandsDir, systematicConfig.disabled_commands);
1299
- const discoveredSkillCommands = systematicConfig.skills_as_commands !== false ? collectDiscoveredSkillsAsCommands(directory, homeDir, opencodeConfigDir, opencodeConfigDirOverride) : {};
1297
+ const discoveredSkillCommands = systematicConfig.skills_as_commands !== false ? collectDiscoveredSkillsAsCommands(directory, homeDir, opencodeConfigDir, opencodeConfigDirOverride, systematicConfig.disabled_commands) : {};
1300
1298
  const bundledAgentKeys = new Set(Object.keys(bundledAgents));
1301
1299
  config.agent = mergeSystematicEntries(existingAgents, bundledAgents, (key, agent) => bundledAgentKeys.has(key) && isSystematicAgentConfig(agent));
1302
1300
  const emittedCommands = {
@@ -1331,7 +1329,7 @@ function normalizePath(path8) {
1331
1329
  }
1332
1330
 
1333
1331
  // src/lib/skill-tool.ts
1334
- import fs6 from "fs";
1332
+ import fs5 from "fs";
1335
1333
  import path8 from "path";
1336
1334
  import { pathToFileURL as pathToFileURL2 } from "url";
1337
1335
  import { tool } from "@opencode-ai/plugin/tool";
@@ -1356,7 +1354,7 @@ function discoverSkillFiles(dir, limit = 10) {
1356
1354
  if (files.length >= limit)
1357
1355
  return;
1358
1356
  try {
1359
- const entries = fs6.readdirSync(currentDir, { withFileTypes: true });
1357
+ const entries = fs5.readdirSync(currentDir, { withFileTypes: true });
1360
1358
  for (const entry of entries) {
1361
1359
  if (files.length >= limit)
1362
1360
  break;
@@ -1487,9 +1485,9 @@ var bundledCommandsDir = path9.join(packageRoot2, "commands");
1487
1485
  var packageJsonPath = path9.join(packageRoot2, "package.json");
1488
1486
  var getPackageVersion = () => {
1489
1487
  try {
1490
- if (!fs7.existsSync(packageJsonPath))
1488
+ if (!fs6.existsSync(packageJsonPath))
1491
1489
  return "unknown";
1492
- const content = fs7.readFileSync(packageJsonPath, "utf8");
1490
+ const content = fs6.readFileSync(packageJsonPath, "utf8");
1493
1491
  const parsed = JSON.parse(content);
1494
1492
  return parsed.version ?? "unknown";
1495
1493
  } catch {
@@ -15,6 +15,9 @@ export interface DiscoveredSkill {
15
15
  name: string;
16
16
  description: string;
17
17
  frontmatter: SkillFrontmatter;
18
+ /** SKILL.md body (frontmatter stripped), read once at discovery so callers
19
+ * that inline the body don't re-read the file. */
20
+ body: string;
18
21
  skillPath: string;
19
22
  root: DiscoveryRootId;
20
23
  }
@@ -37,5 +37,11 @@ export interface SkillInfo {
37
37
  allowedTools?: string;
38
38
  }
39
39
  export declare const SKILL_FRONTMATTER_FIELDS: readonly ["name", "description", "argument-hint", "disable-model-invocation", "allowed-tools", "license", "compatibility", "metadata", "deprecated", "user-invocable", "agent", "model", "context", "subtask"];
40
+ /**
41
+ * Parse skill frontmatter from already-read file content. Split out from
42
+ * `extractFrontmatter` so callers that also need the body (e.g. discovered-skill
43
+ * command emission) can read the file once and derive both. Never throws.
44
+ */
45
+ export declare function extractFrontmatterFromContent(content: string): SkillFrontmatter;
40
46
  export declare function extractFrontmatter(filePath: string): SkillFrontmatter;
41
47
  export declare function findSkillsInDir(dir: string, maxDepth?: number): SkillInfo[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fro.bot/systematic",
3
- "version": "2.33.0",
3
+ "version": "2.33.1",
4
4
  "description": "Structured engineering workflows for OpenCode",
5
5
  "type": "module",
6
6
  "homepage": "https://fro.bot/systematic",