@fro.bot/systematic 1.11.1 → 1.12.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/LICENSE +1 -1
- package/README.md +91 -27
- package/dist/cli.js +14 -2
- package/dist/{index-we4f9de3.js → index-0ftaxvrt.js} +166 -61
- package/dist/index.js +8 -5
- package/dist/lib/agents.d.ts +3 -1
- package/dist/lib/manifest.d.ts +21 -0
- package/dist/lib/validation.d.ts +2 -0
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2026 Marcus R. Brown <git@mrbro.dev>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
6
|
this software and associated documentation files (the "Software"), to deal in
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
<br>
|
|
17
17
|
|
|
18
|
-
**[Overview](#overview)** · **[Quick Start](#quick-start)** · **[Skills](#skills)** · **[Agents](#agents)** · **[Commands](#commands)** · **[Development](#development)**
|
|
18
|
+
**[Overview](#overview)** · **[Quick Start](#quick-start)** · **[Skills](#skills)** · **[Agents](#agents)** · **[Commands](#commands)** · **[CLI](#cli)** · **[Configuration](#configuration)** · **[Development](#development)**
|
|
19
19
|
|
|
20
20
|
</div>
|
|
21
21
|
|
|
@@ -38,11 +38,12 @@ Most AI coding assistants respond to requests without structure or methodology.
|
|
|
38
38
|
|
|
39
39
|
### Key Features
|
|
40
40
|
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
41
|
+
- **Structured Skills** — Pre-built workflows for brainstorming, planning, and code review
|
|
42
|
+
- **Specialized Agents** — Purpose-built subagents for architecture, security, and performance
|
|
43
|
+
- **Zero Configuration** — Works immediately after installation via config hooks
|
|
44
|
+
- **Extensible** — Add project-specific skills and commands alongside bundled ones
|
|
45
|
+
- **Batteries Included** — 8 skills, 11 agents, and 9 commands ship with the npm package
|
|
46
|
+
- **CLI Tooling** — Inspect, list, and convert assets from the command line
|
|
46
47
|
|
|
47
48
|
## Quick Start
|
|
48
49
|
|
|
@@ -169,16 +170,52 @@ Commands are slash-invokable shortcuts that trigger workflows or actions.
|
|
|
169
170
|
| `/workflows:plan` | Create detailed implementation plans |
|
|
170
171
|
| `/workflows:review` | Run code review with specialized agents |
|
|
171
172
|
| `/workflows:work` | Execute planned work systematically |
|
|
172
|
-
| `/workflows:compound` |
|
|
173
|
+
| `/workflows:compound` | Document recently solved problems to build team knowledge |
|
|
173
174
|
|
|
174
175
|
### Utility Commands
|
|
175
176
|
|
|
176
177
|
| Command | Description |
|
|
177
178
|
|---------|-------------|
|
|
178
|
-
| `/systematic:lfg` |
|
|
179
|
-
| `/systematic:create-agent-skill` | Create a new skill with guidance |
|
|
180
|
-
| `/systematic:deepen-plan` |
|
|
181
|
-
| `/systematic:agent-native-audit` | Audit code for agent-native patterns |
|
|
179
|
+
| `/systematic:lfg` | Full autonomous engineering workflow — plan, then execute |
|
|
180
|
+
| `/systematic:create-agent-skill` | Create a new skill with expert guidance |
|
|
181
|
+
| `/systematic:deepen-plan` | Enhance a plan with parallel research for each section |
|
|
182
|
+
| `/systematic:agent-native-audit` | Audit code for agent-native architecture patterns |
|
|
183
|
+
|
|
184
|
+
## CLI
|
|
185
|
+
|
|
186
|
+
Systematic includes a CLI for inspecting and converting assets outside of OpenCode.
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
systematic <command> [options]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Commands
|
|
193
|
+
|
|
194
|
+
| Command | Description |
|
|
195
|
+
|---------|-------------|
|
|
196
|
+
| `list [type]` | List available skills, agents, or commands |
|
|
197
|
+
| `convert <type> <file>` | Convert a CEP file and output the result to stdout |
|
|
198
|
+
| `config show` | Show current configuration and file contents |
|
|
199
|
+
| `config path` | Print config file locations |
|
|
200
|
+
|
|
201
|
+
### Examples
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# List all bundled skills
|
|
205
|
+
systematic list skills
|
|
206
|
+
|
|
207
|
+
# List all bundled agents
|
|
208
|
+
systematic list agents
|
|
209
|
+
|
|
210
|
+
# Convert a Claude Code agent to OpenCode format
|
|
211
|
+
systematic convert agent ./agents/my-agent.md
|
|
212
|
+
|
|
213
|
+
# Convert with a specific agent mode
|
|
214
|
+
systematic convert agent ./agents/my-agent.md --mode=primary
|
|
215
|
+
|
|
216
|
+
# Show configuration
|
|
217
|
+
systematic config show
|
|
218
|
+
```
|
|
182
219
|
|
|
183
220
|
## Configuration
|
|
184
221
|
|
|
@@ -186,16 +223,31 @@ Systematic works out of the box, but you can customize it via configuration file
|
|
|
186
223
|
|
|
187
224
|
### Plugin Configuration
|
|
188
225
|
|
|
189
|
-
|
|
226
|
+
Configuration is loaded from multiple locations and merged (later sources override earlier ones):
|
|
227
|
+
|
|
228
|
+
1. **User config:** `~/.config/opencode/systematic.json`
|
|
229
|
+
2. **Project config:** `.opencode/systematic.json`
|
|
230
|
+
3. **Custom config:** `$OPENCODE_CONFIG_DIR/systematic.json` (if `OPENCODE_CONFIG_DIR` is set)
|
|
190
231
|
|
|
191
232
|
```json
|
|
192
233
|
{
|
|
193
234
|
"disabled_skills": ["git-worktree"],
|
|
194
235
|
"disabled_agents": [],
|
|
195
|
-
"disabled_commands": []
|
|
236
|
+
"disabled_commands": [],
|
|
237
|
+
"bootstrap": {
|
|
238
|
+
"enabled": true
|
|
239
|
+
}
|
|
196
240
|
}
|
|
197
241
|
```
|
|
198
242
|
|
|
243
|
+
| Option | Type | Default | Description |
|
|
244
|
+
|--------|------|---------|-------------|
|
|
245
|
+
| `disabled_skills` | `string[]` | `[]` | Skills to exclude from registration |
|
|
246
|
+
| `disabled_agents` | `string[]` | `[]` | Agents to exclude from registration |
|
|
247
|
+
| `disabled_commands` | `string[]` | `[]` | Commands to exclude from registration |
|
|
248
|
+
| `bootstrap.enabled` | `boolean` | `true` | Inject the `using-systematic` guide into system prompts |
|
|
249
|
+
| `bootstrap.file` | `string` | — | Custom bootstrap file path (overrides default) |
|
|
250
|
+
|
|
199
251
|
### Project-Specific Content
|
|
200
252
|
|
|
201
253
|
Add your own skills, agents, and commands alongside bundled ones:
|
|
@@ -219,7 +271,7 @@ The plugin exposes one tool to OpenCode:
|
|
|
219
271
|
|
|
220
272
|
| Tool | Description |
|
|
221
273
|
|------|-------------|
|
|
222
|
-
| `systematic_skill` | Load Systematic bundled skills by name |
|
|
274
|
+
| `systematic_skill` | Load Systematic bundled skills by name. Lists available skills in its description and returns formatted skill content when invoked. |
|
|
223
275
|
|
|
224
276
|
For non-Systematic skills (project or user-level), use OpenCode's native `skill` tool.
|
|
225
277
|
|
|
@@ -247,9 +299,9 @@ flowchart TB
|
|
|
247
299
|
style G fill:#0f0f23,stroke:#F5A623,color:#B2F5EA
|
|
248
300
|
```
|
|
249
301
|
|
|
250
|
-
1. **`config` hook** —
|
|
251
|
-
2. **`tool` hook** — Registers the `systematic_skill` tool
|
|
252
|
-
3. **`system.transform` hook** — Injects the "Using Systematic" guide into system prompts
|
|
302
|
+
1. **`config` hook** — Discovers and merges bundled skills, agents, and commands into your OpenCode configuration. Existing config takes precedence over bundled content. Skills are registered as commands with the `systematic:` prefix.
|
|
303
|
+
2. **`tool` hook** — Registers the `systematic_skill` tool, which lists available skills in its XML description and loads skill content on demand.
|
|
304
|
+
3. **`system.transform` hook** — Injects the "Using Systematic" bootstrap guide into system prompts, teaching the AI how to discover and invoke skills.
|
|
253
305
|
|
|
254
306
|
This architecture ensures skills, agents, and commands are available immediately without manual setup.
|
|
255
307
|
|
|
@@ -286,20 +338,27 @@ bun test
|
|
|
286
338
|
### Project Structure
|
|
287
339
|
|
|
288
340
|
```
|
|
341
|
+
systematic/
|
|
289
342
|
├── src/
|
|
290
|
-
│ ├── index.ts # Plugin entry point
|
|
343
|
+
│ ├── index.ts # Plugin entry point (SystematicPlugin)
|
|
291
344
|
│ ├── cli.ts # CLI entry point
|
|
292
345
|
│ └── lib/
|
|
293
346
|
│ ├── bootstrap.ts # System prompt injection
|
|
294
|
-
│ ├── config.ts # JSONC config loading
|
|
295
|
-
│ ├── config-handler.ts # OpenCode config hook
|
|
296
|
-
│ ├──
|
|
347
|
+
│ ├── config.ts # JSONC config loading + merging
|
|
348
|
+
│ ├── config-handler.ts # OpenCode config hook implementation
|
|
349
|
+
│ ├── converter.ts # CEP-to-OpenCode content conversion
|
|
350
|
+
│ ├── skill-tool.ts # systematic_skill tool factory
|
|
351
|
+
│ ├── skill-loader.ts # Skill content loading + formatting
|
|
297
352
|
│ ├── skills.ts # Skill discovery
|
|
298
353
|
│ ├── agents.ts # Agent discovery
|
|
299
|
-
│
|
|
300
|
-
├──
|
|
301
|
-
├──
|
|
302
|
-
|
|
354
|
+
│ ├── commands.ts # Command discovery
|
|
355
|
+
│ ├── frontmatter.ts # YAML frontmatter parsing
|
|
356
|
+
│ ├── validation.ts # Agent config validation + type guards
|
|
357
|
+
│ └── walk-dir.ts # Recursive directory walker
|
|
358
|
+
├── skills/ # 8 bundled skills (SKILL.md files)
|
|
359
|
+
├── agents/ # 11 bundled agents (4 categories)
|
|
360
|
+
├── commands/ # 9 bundled commands (with workflows/ subdir)
|
|
361
|
+
├── docs/ # Starlight documentation site
|
|
303
362
|
├── tests/
|
|
304
363
|
│ ├── unit/ # Unit tests
|
|
305
364
|
│ └── integration/ # Integration tests
|
|
@@ -317,6 +376,9 @@ bun test tests/unit/skills.test.ts
|
|
|
317
376
|
|
|
318
377
|
# Run integration tests
|
|
319
378
|
bun test tests/integration
|
|
379
|
+
|
|
380
|
+
# Run all tests
|
|
381
|
+
bun test
|
|
320
382
|
```
|
|
321
383
|
|
|
322
384
|
### Contributing
|
|
@@ -325,13 +387,15 @@ See [`AGENTS.md`](./AGENTS.md) for detailed development guidelines, code style c
|
|
|
325
387
|
|
|
326
388
|
## Converting from Claude Code
|
|
327
389
|
|
|
328
|
-
Migrating skills, agents, or commands from Claude Code (CEP) to Systematic? See the [Conversion Guide](https://fro.bot/systematic/guides/conversion-guide) for field mappings and examples.
|
|
390
|
+
Migrating skills, agents, or commands from Claude Code (CEP) to Systematic? See the [Conversion Guide](https://fro.bot/systematic/guides/conversion-guide/) for field mappings and examples. Also available as [local Markdown](./docs/CONVERSION-GUIDE.md).
|
|
329
391
|
|
|
330
392
|
## References
|
|
331
393
|
|
|
394
|
+
- [Systematic Documentation](https://fro.bot/systematic) — Full documentation site
|
|
332
395
|
- [OpenCode Documentation](https://opencode.ai/docs/) — Official OpenCode platform docs
|
|
396
|
+
- [OpenCode Plugin API](https://opencode.ai/docs/plugins) — Plugin development reference
|
|
333
397
|
- [Compound Engineering Plugin](https://github.com/EveryInc/compound-engineering-plugin) — Original Claude Code workflows
|
|
334
|
-
- [
|
|
398
|
+
- [Source Code](https://github.com/marcusrbrown/systematic) — View the implementation
|
|
335
399
|
|
|
336
400
|
## License
|
|
337
401
|
|
package/dist/cli.js
CHANGED
|
@@ -6,12 +6,24 @@ import {
|
|
|
6
6
|
findCommandsInDir,
|
|
7
7
|
findSkillsInDir,
|
|
8
8
|
getConfigPaths
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-0ftaxvrt.js";
|
|
10
10
|
|
|
11
11
|
// src/cli.ts
|
|
12
12
|
import fs from "fs";
|
|
13
13
|
import path from "path";
|
|
14
|
-
var
|
|
14
|
+
var getPackageVersion = () => {
|
|
15
|
+
try {
|
|
16
|
+
const packageJsonPath = path.resolve(import.meta.dirname, "..", "package.json");
|
|
17
|
+
if (!fs.existsSync(packageJsonPath))
|
|
18
|
+
return "unknown";
|
|
19
|
+
const content = fs.readFileSync(packageJsonPath, "utf8");
|
|
20
|
+
const parsed = JSON.parse(content);
|
|
21
|
+
return parsed.version ?? "unknown";
|
|
22
|
+
} catch {
|
|
23
|
+
return "unknown";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var VERSION = getPackageVersion();
|
|
15
27
|
var HELP = `
|
|
16
28
|
systematic - OpenCode plugin for systematic engineering workflows
|
|
17
29
|
|
|
@@ -138,7 +138,7 @@ function extractBashPermission(data) {
|
|
|
138
138
|
}
|
|
139
139
|
return null;
|
|
140
140
|
}
|
|
141
|
-
function buildPermissionObject(edit, bash, webfetch, doom_loop, external_directory) {
|
|
141
|
+
function buildPermissionObject(edit, bash, webfetch, doom_loop, external_directory, task, skill) {
|
|
142
142
|
const permission = {};
|
|
143
143
|
if (edit)
|
|
144
144
|
permission.edit = edit;
|
|
@@ -150,6 +150,10 @@ function buildPermissionObject(edit, bash, webfetch, doom_loop, external_directo
|
|
|
150
150
|
permission.doom_loop = doom_loop;
|
|
151
151
|
if (external_directory)
|
|
152
152
|
permission.external_directory = external_directory;
|
|
153
|
+
if (task)
|
|
154
|
+
permission.task = task;
|
|
155
|
+
if (skill)
|
|
156
|
+
permission.skill = skill;
|
|
153
157
|
return Object.keys(permission).length > 0 ? permission : undefined;
|
|
154
158
|
}
|
|
155
159
|
function normalizePermission(value) {
|
|
@@ -170,7 +174,13 @@ function normalizePermission(value) {
|
|
|
170
174
|
const external_directory = extractSimplePermission(value, "external_directory");
|
|
171
175
|
if (external_directory === null)
|
|
172
176
|
return;
|
|
173
|
-
|
|
177
|
+
const task = extractSimplePermission(value, "task");
|
|
178
|
+
if (task === null)
|
|
179
|
+
return;
|
|
180
|
+
const skill = extractSimplePermission(value, "skill");
|
|
181
|
+
if (skill === null)
|
|
182
|
+
return;
|
|
183
|
+
return buildPermissionObject(edit, bash, webfetch, doom_loop, external_directory, task, skill);
|
|
174
184
|
}
|
|
175
185
|
function extractString(data, key, fallback = "") {
|
|
176
186
|
const value = data[key];
|
|
@@ -262,7 +272,8 @@ function extractAgentFrontmatter(content) {
|
|
|
262
272
|
disable: extractBoolean(data, "disable"),
|
|
263
273
|
mode: isAgentMode(data.mode) ? data.mode : undefined,
|
|
264
274
|
color: extractNonEmptyString(data, "color"),
|
|
265
|
-
|
|
275
|
+
steps: extractNumber(data, "steps"),
|
|
276
|
+
hidden: extractBoolean(data, "hidden") ?? undefined,
|
|
266
277
|
permission: normalizePermission(data.permission)
|
|
267
278
|
};
|
|
268
279
|
}
|
|
@@ -308,6 +319,7 @@ function extractCommandFrontmatter(content) {
|
|
|
308
319
|
|
|
309
320
|
// src/lib/converter.ts
|
|
310
321
|
import fs3 from "fs";
|
|
322
|
+
var CONVERTER_VERSION = 2;
|
|
311
323
|
var cache = new Map;
|
|
312
324
|
var TOOL_MAPPINGS = [
|
|
313
325
|
[/\bTask\s+tool\b/gi, "delegate_task tool"],
|
|
@@ -336,18 +348,42 @@ var PATH_REPLACEMENTS = [
|
|
|
336
348
|
[/\/compound-engineering:/g, "/systematic:"],
|
|
337
349
|
[/compound-engineering:/g, "systematic:"]
|
|
338
350
|
];
|
|
339
|
-
var
|
|
340
|
-
"
|
|
341
|
-
"
|
|
342
|
-
"
|
|
343
|
-
"
|
|
344
|
-
"
|
|
345
|
-
"
|
|
346
|
-
"
|
|
347
|
-
"
|
|
348
|
-
"
|
|
349
|
-
|
|
350
|
-
|
|
351
|
+
var TOOL_NAME_MAP = {
|
|
352
|
+
task: "delegate_task",
|
|
353
|
+
todowrite: "todowrite",
|
|
354
|
+
askuserquestion: "question",
|
|
355
|
+
websearch: "google_search",
|
|
356
|
+
webfetch: "webfetch",
|
|
357
|
+
skill: "skill",
|
|
358
|
+
read: "read",
|
|
359
|
+
write: "write",
|
|
360
|
+
edit: "edit",
|
|
361
|
+
bash: "bash",
|
|
362
|
+
grep: "grep",
|
|
363
|
+
glob: "glob"
|
|
364
|
+
};
|
|
365
|
+
var PERMISSION_MODE_MAP = {
|
|
366
|
+
full: {
|
|
367
|
+
edit: "allow",
|
|
368
|
+
bash: "allow",
|
|
369
|
+
webfetch: "allow"
|
|
370
|
+
},
|
|
371
|
+
default: {
|
|
372
|
+
edit: "ask",
|
|
373
|
+
bash: "ask",
|
|
374
|
+
webfetch: "ask"
|
|
375
|
+
},
|
|
376
|
+
plan: {
|
|
377
|
+
edit: "deny",
|
|
378
|
+
bash: "deny",
|
|
379
|
+
webfetch: "ask"
|
|
380
|
+
},
|
|
381
|
+
bypassPermissions: {
|
|
382
|
+
edit: "allow",
|
|
383
|
+
bash: "allow",
|
|
384
|
+
webfetch: "allow"
|
|
385
|
+
}
|
|
386
|
+
};
|
|
351
387
|
function inferTemperature(name, description) {
|
|
352
388
|
const sample = `${name} ${description ?? ""}`.toLowerCase();
|
|
353
389
|
if (/(review|audit|security|sentinel|oracle|lint|verification|guardian)/.test(sample)) {
|
|
@@ -384,27 +420,6 @@ function transformBody(body) {
|
|
|
384
420
|
}
|
|
385
421
|
return result;
|
|
386
422
|
}
|
|
387
|
-
function removeFields(data, fieldsToRemove) {
|
|
388
|
-
const result = {};
|
|
389
|
-
for (const [key, value] of Object.entries(data)) {
|
|
390
|
-
if (!fieldsToRemove.includes(key)) {
|
|
391
|
-
result[key] = value;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
return result;
|
|
395
|
-
}
|
|
396
|
-
function transformSkillFrontmatter(data) {
|
|
397
|
-
return removeFields(data, CC_ONLY_SKILL_FIELDS);
|
|
398
|
-
}
|
|
399
|
-
function transformCommandFrontmatter(data) {
|
|
400
|
-
const cleaned = removeFields(data, CC_ONLY_COMMAND_FIELDS);
|
|
401
|
-
if (typeof cleaned.model === "string" && cleaned.model !== "inherit") {
|
|
402
|
-
cleaned.model = normalizeModel(cleaned.model);
|
|
403
|
-
} else if (cleaned.model === "inherit") {
|
|
404
|
-
delete cleaned.model;
|
|
405
|
-
}
|
|
406
|
-
return cleaned;
|
|
407
|
-
}
|
|
408
423
|
function normalizeModel(model) {
|
|
409
424
|
if (model.includes("/"))
|
|
410
425
|
return model;
|
|
@@ -418,37 +433,127 @@ function normalizeModel(model) {
|
|
|
418
433
|
return `google/${model}`;
|
|
419
434
|
return `anthropic/${model}`;
|
|
420
435
|
}
|
|
421
|
-
function
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
436
|
+
function canonicalizeToolName(name) {
|
|
437
|
+
const lower = name.trim().toLowerCase();
|
|
438
|
+
return TOOL_NAME_MAP[lower] ?? lower;
|
|
439
|
+
}
|
|
440
|
+
function isValidSteps(value) {
|
|
441
|
+
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value > 0;
|
|
442
|
+
}
|
|
443
|
+
function mapStepsField(data) {
|
|
444
|
+
if (data.steps !== undefined) {
|
|
445
|
+
if (isValidSteps(data.steps)) {
|
|
446
|
+
delete data.maxTurns;
|
|
447
|
+
delete data.maxSteps;
|
|
448
|
+
}
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const candidates = [];
|
|
452
|
+
if (isValidSteps(data.maxTurns))
|
|
453
|
+
candidates.push(data.maxTurns);
|
|
454
|
+
if (isValidSteps(data.maxSteps))
|
|
455
|
+
candidates.push(data.maxSteps);
|
|
456
|
+
if (candidates.length > 0) {
|
|
457
|
+
data.steps = Math.min(...candidates);
|
|
458
|
+
delete data.maxTurns;
|
|
459
|
+
delete data.maxSteps;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function mapToolsField(data) {
|
|
463
|
+
if (data.tools !== undefined && !Array.isArray(data.tools)) {
|
|
464
|
+
if (isToolsMap(data.tools)) {
|
|
465
|
+
mergeDisallowedTools(data);
|
|
466
|
+
}
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (Array.isArray(data.tools)) {
|
|
470
|
+
const toolsMap = {};
|
|
471
|
+
for (const tool of data.tools) {
|
|
472
|
+
if (typeof tool === "string") {
|
|
473
|
+
toolsMap[canonicalizeToolName(tool)] = true;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (Object.keys(toolsMap).length > 0) {
|
|
477
|
+
data.tools = toolsMap;
|
|
478
|
+
} else {
|
|
479
|
+
delete data.tools;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
mergeDisallowedTools(data);
|
|
483
|
+
}
|
|
484
|
+
function mergeDisallowedTools(data) {
|
|
485
|
+
if (!Array.isArray(data.disallowedTools))
|
|
486
|
+
return;
|
|
487
|
+
const existing = isToolsMap(data.tools) ? data.tools : {};
|
|
488
|
+
for (const tool of data.disallowedTools) {
|
|
489
|
+
if (typeof tool === "string") {
|
|
490
|
+
existing[canonicalizeToolName(tool)] = false;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (Object.keys(existing).length > 0) {
|
|
494
|
+
data.tools = existing;
|
|
495
|
+
}
|
|
496
|
+
delete data.disallowedTools;
|
|
497
|
+
}
|
|
498
|
+
function mapPermissionMode(data) {
|
|
499
|
+
if (data.permission !== undefined) {
|
|
500
|
+
const normalized = normalizePermission(data.permission);
|
|
501
|
+
if (normalized) {
|
|
502
|
+
data.permission = normalized;
|
|
503
|
+
delete data.permissionMode;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (typeof data.permissionMode !== "string")
|
|
508
|
+
return;
|
|
509
|
+
const mapped = PERMISSION_MODE_MAP[data.permissionMode];
|
|
510
|
+
data.permission = mapped ?? { edit: "ask", bash: "ask", webfetch: "ask" };
|
|
511
|
+
delete data.permissionMode;
|
|
512
|
+
}
|
|
513
|
+
function mapHiddenField(data) {
|
|
514
|
+
if (data["disable-model-invocation"] === true || data.disableModelInvocation === true) {
|
|
515
|
+
data.hidden = true;
|
|
516
|
+
delete data["disable-model-invocation"];
|
|
517
|
+
delete data.disableModelInvocation;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
function normalizeModelField(data) {
|
|
521
|
+
if (typeof data.model === "string" && data.model !== "inherit") {
|
|
522
|
+
data.model = normalizeModel(data.model);
|
|
523
|
+
} else if (data.model === "inherit") {
|
|
524
|
+
delete data.model;
|
|
525
|
+
}
|
|
435
526
|
}
|
|
436
527
|
function transformAgentFrontmatter(data, agentMode) {
|
|
528
|
+
const result = { ...data };
|
|
529
|
+
result.mode = isAgentMode(data.mode) ? data.mode : agentMode;
|
|
437
530
|
const name = typeof data.name === "string" ? data.name : "";
|
|
438
531
|
const description = typeof data.description === "string" ? data.description : "";
|
|
439
|
-
const mode = isAgentMode(data.mode) ? data.mode : agentMode;
|
|
440
|
-
const newData = { mode };
|
|
441
532
|
if (description) {
|
|
442
|
-
|
|
533
|
+
result.description = description;
|
|
443
534
|
} else if (name) {
|
|
444
|
-
|
|
535
|
+
result.description = `${name} agent`;
|
|
445
536
|
}
|
|
446
|
-
|
|
447
|
-
|
|
537
|
+
normalizeModelField(result);
|
|
538
|
+
result.temperature = typeof data.temperature === "number" ? data.temperature : inferTemperature(name, description);
|
|
539
|
+
mapStepsField(result);
|
|
540
|
+
mapToolsField(result);
|
|
541
|
+
mapPermissionMode(result);
|
|
542
|
+
mapHiddenField(result);
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
function transformSkillFrontmatter(data) {
|
|
546
|
+
const result = { ...data };
|
|
547
|
+
normalizeModelField(result);
|
|
548
|
+
if (result.context === "fork") {
|
|
549
|
+
result.subtask = true;
|
|
448
550
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
551
|
+
return result;
|
|
552
|
+
}
|
|
553
|
+
function transformCommandFrontmatter(data) {
|
|
554
|
+
const result = { ...data };
|
|
555
|
+
normalizeModelField(result);
|
|
556
|
+
return result;
|
|
452
557
|
}
|
|
453
558
|
function convertContent(content, type, options = {}) {
|
|
454
559
|
if (content === "")
|
|
@@ -458,7 +563,7 @@ function convertContent(content, type, options = {}) {
|
|
|
458
563
|
return options.skipBodyTransform ? content : transformBody(content);
|
|
459
564
|
}
|
|
460
565
|
if (parseError) {
|
|
461
|
-
return content;
|
|
566
|
+
return options.skipBodyTransform ? content : transformBody(content);
|
|
462
567
|
}
|
|
463
568
|
const shouldTransformBody = !options.skipBodyTransform;
|
|
464
569
|
const transformedBody = shouldTransformBody ? transformBody(body) : body;
|
|
@@ -484,7 +589,7 @@ function convertFileWithCache(filePath, type, options = {}) {
|
|
|
484
589
|
const fd = fs3.openSync(filePath, "r");
|
|
485
590
|
try {
|
|
486
591
|
const stats = fs3.fstatSync(fd);
|
|
487
|
-
const cacheKey = `${filePath}:${type}:${options.source ?? "bundled"}:${options.agentMode ?? "subagent"}:${options.skipBodyTransform ?? false}`;
|
|
592
|
+
const cacheKey = `${CONVERTER_VERSION}:${filePath}:${type}:${options.source ?? "bundled"}:${options.agentMode ?? "subagent"}:${options.skipBodyTransform ?? false}`;
|
|
488
593
|
const cached = cache.get(cacheKey);
|
|
489
594
|
if (cached != null && cached.mtimeMs === stats.mtimeMs) {
|
|
490
595
|
return cached.converted;
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
findSkillsInDir,
|
|
9
9
|
loadConfig,
|
|
10
10
|
parseFrontmatter
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-0ftaxvrt.js";
|
|
12
12
|
|
|
13
13
|
// src/index.ts
|
|
14
14
|
import fs3 from "fs";
|
|
@@ -22,7 +22,7 @@ import path from "path";
|
|
|
22
22
|
function getToolMappingTemplate(bundledSkillsDir) {
|
|
23
23
|
return `**Tool Mapping for OpenCode:**
|
|
24
24
|
When skills reference tools you don't have, substitute OpenCode equivalents:
|
|
25
|
-
- \`TodoWrite\` \u2192 \`
|
|
25
|
+
- \`TodoWrite\` \u2192 \`todowrite\`
|
|
26
26
|
- \`Task\` tool with subagents \u2192 Use OpenCode's subagent system (@mention)
|
|
27
27
|
- \`Skill\` tool \u2192 OpenCode's native \`skill\` tool
|
|
28
28
|
- \`SystematicSkill\` tool \u2192 \`systematic_skill\` (Systematic plugin skills)
|
|
@@ -155,7 +155,8 @@ function loadAgentAsConfig(agentInfo) {
|
|
|
155
155
|
disable,
|
|
156
156
|
mode,
|
|
157
157
|
color,
|
|
158
|
-
|
|
158
|
+
steps,
|
|
159
|
+
hidden,
|
|
159
160
|
permission
|
|
160
161
|
} = extractAgentFrontmatter(converted);
|
|
161
162
|
const config = {
|
|
@@ -176,8 +177,10 @@ function loadAgentAsConfig(agentInfo) {
|
|
|
176
177
|
config.mode = mode;
|
|
177
178
|
if (color !== undefined)
|
|
178
179
|
config.color = color;
|
|
179
|
-
if (
|
|
180
|
-
config.
|
|
180
|
+
if (steps !== undefined)
|
|
181
|
+
config.steps = steps;
|
|
182
|
+
if (hidden !== undefined)
|
|
183
|
+
config.hidden = hidden;
|
|
181
184
|
if (permission !== undefined)
|
|
182
185
|
config.permission = permission;
|
|
183
186
|
return config;
|
package/dist/lib/agents.d.ts
CHANGED
|
@@ -21,7 +21,9 @@ export interface AgentFrontmatter {
|
|
|
21
21
|
/** Hex color code */
|
|
22
22
|
color?: string;
|
|
23
23
|
/** Max agentic iterations */
|
|
24
|
-
|
|
24
|
+
steps?: number;
|
|
25
|
+
/** Whether this agent is hidden from model invocation */
|
|
26
|
+
hidden?: boolean;
|
|
25
27
|
/** Permission settings */
|
|
26
28
|
permission?: PermissionConfig;
|
|
27
29
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ManifestSource {
|
|
2
|
+
repo: string;
|
|
3
|
+
branch: string;
|
|
4
|
+
url: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ManifestDefinition {
|
|
7
|
+
source: string;
|
|
8
|
+
upstream_path: string;
|
|
9
|
+
upstream_commit: string;
|
|
10
|
+
synced_at: string;
|
|
11
|
+
notes: string;
|
|
12
|
+
}
|
|
13
|
+
export interface SyncManifest {
|
|
14
|
+
$schema?: string;
|
|
15
|
+
sources: Record<string, ManifestSource>;
|
|
16
|
+
definitions: Record<string, ManifestDefinition>;
|
|
17
|
+
}
|
|
18
|
+
export declare function validateManifest(data: unknown): data is SyncManifest;
|
|
19
|
+
export declare function readManifest(filePath: string): SyncManifest | null;
|
|
20
|
+
export declare function writeManifest(filePath: string, manifest: SyncManifest): void;
|
|
21
|
+
export declare function findStaleEntries(manifest: SyncManifest, existingPaths: string[]): string[];
|
package/dist/lib/validation.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface PermissionConfig {
|
|
|
9
9
|
webfetch?: PermissionSetting;
|
|
10
10
|
doom_loop?: PermissionSetting;
|
|
11
11
|
external_directory?: PermissionSetting;
|
|
12
|
+
task?: PermissionSetting;
|
|
13
|
+
skill?: PermissionSetting;
|
|
12
14
|
}
|
|
13
15
|
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
14
16
|
export declare function isPermissionSetting(value: unknown): value is PermissionSetting;
|