@fro.bot/systematic 2.18.0 → 2.19.0
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 +1 -1
- package/dist/{index-ek6rskkw.js → index-6evyges6.js} +17 -0
- package/dist/index.js +24 -2
- package/dist/lib/skill-loader.d.ts +2 -1
- package/dist/lib/skills.d.ts +9 -1
- package/package.json +3 -3
- package/skills/claude-permissions-optimizer/SKILL.md +4 -0
- package/skills/orchestrating-swarms/SKILL.md +5 -0
package/dist/cli.js
CHANGED
|
@@ -500,6 +500,21 @@ function extractFrontmatter(filePath) {
|
|
|
500
500
|
metadata = Object.fromEntries(entries);
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
|
+
const deprecatedRaw = data.deprecated;
|
|
504
|
+
let deprecated;
|
|
505
|
+
if (isRecord(deprecatedRaw)) {
|
|
506
|
+
const since = typeof deprecatedRaw.since === "string" && deprecatedRaw.since !== "" ? deprecatedRaw.since : undefined;
|
|
507
|
+
const removal = typeof deprecatedRaw.removal === "string" && deprecatedRaw.removal !== "" ? deprecatedRaw.removal : undefined;
|
|
508
|
+
if (since !== undefined && removal !== undefined) {
|
|
509
|
+
deprecated = { since, removal };
|
|
510
|
+
if (typeof deprecatedRaw.replacement === "string") {
|
|
511
|
+
deprecated.replacement = deprecatedRaw.replacement;
|
|
512
|
+
}
|
|
513
|
+
if (typeof deprecatedRaw.reason === "string") {
|
|
514
|
+
deprecated.reason = deprecatedRaw.reason;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
503
518
|
const argumentHintRaw = extractNonEmptyString(data, "argument-hint");
|
|
504
519
|
const argumentHint = argumentHintRaw?.replace(/^["']|["']$/g, "") || undefined;
|
|
505
520
|
return {
|
|
@@ -508,6 +523,7 @@ function extractFrontmatter(filePath) {
|
|
|
508
523
|
license: extractNonEmptyString(data, "license"),
|
|
509
524
|
compatibility: extractNonEmptyString(data, "compatibility"),
|
|
510
525
|
metadata,
|
|
526
|
+
deprecated,
|
|
511
527
|
disableModelInvocation: extractBoolean(data, "disable-model-invocation"),
|
|
512
528
|
userInvocable: extractBoolean(data, "user-invocable"),
|
|
513
529
|
subtask: data.context === "fork" ? true : extractBoolean(data, "subtask") ?? undefined,
|
|
@@ -538,6 +554,7 @@ function findSkillsInDir(dir, maxDepth = 3) {
|
|
|
538
554
|
license: frontmatter.license,
|
|
539
555
|
compatibility: frontmatter.compatibility,
|
|
540
556
|
metadata: frontmatter.metadata,
|
|
557
|
+
deprecated: frontmatter.deprecated,
|
|
541
558
|
disableModelInvocation: frontmatter.disableModelInvocation,
|
|
542
559
|
userInvocable: frontmatter.userInvocable,
|
|
543
560
|
subtask: frontmatter.subtask,
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
loadConfig,
|
|
14
14
|
loadConfigWithSources,
|
|
15
15
|
parseFrontmatter
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-6evyges6.js";
|
|
17
17
|
|
|
18
18
|
// src/index.ts
|
|
19
19
|
import fs5 from "fs";
|
|
@@ -81,7 +81,8 @@ function loadSkill(skillInfo) {
|
|
|
81
81
|
subtask: skillInfo.subtask,
|
|
82
82
|
agent: skillInfo.agent,
|
|
83
83
|
model: skillInfo.model,
|
|
84
|
-
argumentHint: skillInfo.argumentHint
|
|
84
|
+
argumentHint: skillInfo.argumentHint,
|
|
85
|
+
deprecated: skillInfo.deprecated
|
|
85
86
|
};
|
|
86
87
|
} catch {
|
|
87
88
|
return null;
|
|
@@ -1186,8 +1187,25 @@ function discoverSkillFiles(dir, limit = 10) {
|
|
|
1186
1187
|
return files.map((file) => ` <file>${file}</file>`).join(`
|
|
1187
1188
|
`);
|
|
1188
1189
|
}
|
|
1190
|
+
function formatDeprecationMessage(name, deprecated) {
|
|
1191
|
+
let msg = `[systematic] skill "${name}" is deprecated since ${deprecated.since}; will be removed in ${deprecated.removal}.`;
|
|
1192
|
+
if (deprecated.replacement) {
|
|
1193
|
+
msg += ` Replacement: ${deprecated.replacement}`;
|
|
1194
|
+
if (!deprecated.replacement.endsWith(".")) {
|
|
1195
|
+
msg += ".";
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
if (deprecated.reason) {
|
|
1199
|
+
msg += ` Reason: ${deprecated.reason}`;
|
|
1200
|
+
if (!deprecated.reason.endsWith(".")) {
|
|
1201
|
+
msg += ".";
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
return msg;
|
|
1205
|
+
}
|
|
1189
1206
|
function createSkillTool(options) {
|
|
1190
1207
|
const { bundledSkillsDir, disabledSkills } = options;
|
|
1208
|
+
const warnedSkills = new Set;
|
|
1191
1209
|
const getAllSkills = () => {
|
|
1192
1210
|
return findSkillsInDir(bundledSkillsDir).filter((s) => !disabledSkills.includes(s.name)).map((skillInfo) => loadSkill(skillInfo)).filter((s) => s !== null).sort((a, b) => a.name.localeCompare(b.name));
|
|
1193
1211
|
};
|
|
@@ -1238,6 +1256,10 @@ ${catalog}`;
|
|
|
1238
1256
|
}).map((s) => s.prefixedName);
|
|
1239
1257
|
throw new Error(`Skill "${requestedName}" not found. Available systematic skills: ${availableSystematic.join(", ")}`);
|
|
1240
1258
|
}
|
|
1259
|
+
if (matchedSkill.deprecated && !warnedSkills.has(matchedSkill.name)) {
|
|
1260
|
+
console.warn(formatDeprecationMessage(matchedSkill.name, matchedSkill.deprecated));
|
|
1261
|
+
warnedSkills.add(matchedSkill.name);
|
|
1262
|
+
}
|
|
1241
1263
|
const body = extractSkillBody(matchedSkill.wrappedTemplate);
|
|
1242
1264
|
const dir = path6.dirname(matchedSkill.skillFile);
|
|
1243
1265
|
const base = pathToFileURL2(dir).href;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SkillInfo } from './skills.js';
|
|
1
|
+
import type { SkillDeprecated, SkillInfo } from './skills.js';
|
|
2
2
|
export interface LoadedSkill {
|
|
3
3
|
name: string;
|
|
4
4
|
prefixedName: string;
|
|
@@ -12,6 +12,7 @@ export interface LoadedSkill {
|
|
|
12
12
|
agent?: string;
|
|
13
13
|
model?: string;
|
|
14
14
|
argumentHint?: string;
|
|
15
|
+
deprecated?: SkillDeprecated;
|
|
15
16
|
}
|
|
16
17
|
export declare function formatSkillCommandName(name: string): string;
|
|
17
18
|
export declare function formatSkillDescription(description: string, fallbackName: string): string;
|
package/dist/lib/skills.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
export interface SkillDeprecated {
|
|
2
|
+
since: string;
|
|
3
|
+
removal: string;
|
|
4
|
+
replacement?: string;
|
|
5
|
+
reason?: string;
|
|
6
|
+
}
|
|
1
7
|
export interface SkillFrontmatter {
|
|
2
8
|
name: string;
|
|
3
9
|
description: string;
|
|
4
10
|
license?: string;
|
|
5
11
|
compatibility?: string;
|
|
6
12
|
metadata?: Record<string, string>;
|
|
13
|
+
deprecated?: SkillDeprecated;
|
|
7
14
|
disableModelInvocation?: boolean;
|
|
8
15
|
userInvocable?: boolean;
|
|
9
16
|
subtask?: boolean;
|
|
@@ -20,6 +27,7 @@ export interface SkillInfo {
|
|
|
20
27
|
license?: string;
|
|
21
28
|
compatibility?: string;
|
|
22
29
|
metadata?: Record<string, string>;
|
|
30
|
+
deprecated?: SkillDeprecated;
|
|
23
31
|
disableModelInvocation?: boolean;
|
|
24
32
|
userInvocable?: boolean;
|
|
25
33
|
subtask?: boolean;
|
|
@@ -28,6 +36,6 @@ export interface SkillInfo {
|
|
|
28
36
|
argumentHint?: string;
|
|
29
37
|
allowedTools?: string;
|
|
30
38
|
}
|
|
31
|
-
export declare const SKILL_FRONTMATTER_FIELDS: readonly ["name", "description", "argument-hint", "disable-model-invocation", "allowed-tools", "license", "compatibility", "metadata", "user-invocable", "agent", "model", "context", "subtask"];
|
|
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"];
|
|
32
40
|
export declare function extractFrontmatter(filePath: string): SkillFrontmatter;
|
|
33
41
|
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.
|
|
3
|
+
"version": "2.19.0",
|
|
4
4
|
"description": "Structured engineering workflows for OpenCode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://fro.bot/systematic",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@biomejs/biome": "2.4.15",
|
|
68
|
-
"@opencode-ai/plugin": "1.14.
|
|
69
|
-
"@opencode-ai/sdk": "1.14.
|
|
68
|
+
"@opencode-ai/plugin": "1.14.51",
|
|
69
|
+
"@opencode-ai/sdk": "1.14.51",
|
|
70
70
|
"@types/bun": "latest",
|
|
71
71
|
"@types/js-yaml": "4.0.9",
|
|
72
72
|
"@types/node": "24.12.4",
|
|
@@ -3,6 +3,10 @@ name: claude-permissions-optimizer
|
|
|
3
3
|
context: fork
|
|
4
4
|
description: Optimize Claude Code permissions by finding safe Bash commands from session history and auto-applying them to settings.json. Can run from any coding agent but targets Claude Code specifically. Use when experiencing permission fatigue, too many permission prompts, wanting to optimize permissions, or needing to set up allowlists. Triggers on "optimize permissions", "reduce permission prompts", "allowlist commands", "too many permission prompts", "permission fatigue", "permission setup", or complaints about clicking approve too often.
|
|
5
5
|
subtask: true
|
|
6
|
+
deprecated:
|
|
7
|
+
since: v2.19.0
|
|
8
|
+
removal: v3.0.0
|
|
9
|
+
reason: "Targets Claude Code's ~/.claude/settings.json allowlist mechanism. OpenCode uses a SQLite-backed session-scoped permission model with built-in always-persistence via the always button. No prompt-fatigue analog exists in OpenCode; there is no equivalent allowlist to optimize."
|
|
6
10
|
---
|
|
7
11
|
|
|
8
12
|
# Claude Permissions Optimizer
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
name: orchestrating-swarms
|
|
3
3
|
description: Use when orchestrating multi-agent swarms, coordinating parallel code reviews, creating pipeline workflows with dependencies, building self-organizing task queues, or any task benefiting from divide-and-conquer patterns.
|
|
4
4
|
disable-model-invocation: true
|
|
5
|
+
deprecated:
|
|
6
|
+
since: v2.19.0
|
|
7
|
+
removal: v3.0.0
|
|
8
|
+
replacement: orchestrating-subagents
|
|
9
|
+
reason: "Documents the CEP Teammate API (TeammateTool, spawnTeam, TaskCreate/TaskList/TaskGet, team_name parameter on task(), CC subagent_type names). These primitives do not exist in OpenCode. A replacement skill will cover OpenCode-native parallel task() orchestration."
|
|
5
10
|
---
|
|
6
11
|
|
|
7
12
|
# Swarm Orchestration
|