@aksp/opencrew 1.2.1 → 1.2.2
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/CHANGELOG.md +48 -0
- package/package.json +9 -3
- package/src/cli.js +48 -13
- package/src/commands/init.js +4 -3
- package/src/commands/update.js +1 -0
- package/src/lib/fsx.js +7 -1
- package/src/lib/prompts.js +15 -9
- package/src/lib/ui.js +0 -1
- package/templates/.mcp.json +1 -0
- package/templates/_opencrew/.opencrew-version +1 -1
- package/templates/_opencrew/config/playwright.config.json +1 -2
- package/templates/_opencrew/core/prompts/discovery.prompt.md +1 -1
- package/templates/_opencrew/core/runner.pipeline.md +17 -1
- package/templates/_opencrew/core/skills.engine.md +13 -12
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,54 @@
|
|
|
3
3
|
All notable changes to opencrew are documented here.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
5
5
|
|
|
6
|
+
## [1.2.2] — 2026-08-02
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- **`parseArgs` truncates values containing `=`**: flags like `--description=foo=bar`
|
|
10
|
+
no longer lose everything after the second `=`.
|
|
11
|
+
- **`version` npm script uses `require()` in ESM project**: extracted to a dedicated
|
|
12
|
+
`scripts/stamp-version.js` that uses proper ESM imports.
|
|
13
|
+
- **`skills.engine.md` numbering was out of order** in Operation 2 (Install a Skill):
|
|
14
|
+
steps 3/4 repeated instead of continuing 5–9. Cross-references updated accordingly.
|
|
15
|
+
- **`init` now aborts when a workspace already exists** instead of proceeding with
|
|
16
|
+
`overwrite: false` (which silently did nothing). It prints instructions to use
|
|
17
|
+
`update` or reinstall from scratch.
|
|
18
|
+
- **`deleteDir` semantics**: now returns `false` when the path does not exist (was `true`).
|
|
19
|
+
- **`.env.example` placeholders** (`[REDACTED:API key param]`) removed — these were
|
|
20
|
+
security-redaction artifacts from the tooling, not real file content. No code change.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **Short flags**: `-y` (yes), `-v` (version), `-h` (help) now work alongside their
|
|
24
|
+
`--long-form` equivalents.
|
|
25
|
+
- **`OPENCREW_CATALOG_URL` env var**: forks can override the skill catalog base URL
|
|
26
|
+
without editing `catalog.json`. Documented in `CONTRIBUTING.md` → Forking.
|
|
27
|
+
- **`update` now warns** that catalog skills are fully overwritten before refreshing them.
|
|
28
|
+
- **`readJson` error messages now include the file path** (e.g. `Failed to read
|
|
29
|
+
/path/to/package.json: file not found`).
|
|
30
|
+
- **`pickIdes` validates preselected IDs**: unknown IDs from `--ide` are filtered with
|
|
31
|
+
a warning instead of being passed through silently.
|
|
32
|
+
- **`c.gray` removed** (unused). **`confirm()` removed** (dead code, never imported).
|
|
33
|
+
- **ESLint** (`eslint.config.js` + `npm run lint` + CI step) with `@eslint/js` flat config.
|
|
34
|
+
- **55 tests** (up from 30): new coverage for `paths.js`, `ui.js`, `fsx.js` error
|
|
35
|
+
scenarios, `normalizeIdes` string input, CLI smoke tests.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- **CI `npm audit` raised from `moderate` to `high`** to avoid spurious build failures
|
|
39
|
+
from dev-dependency vulnerabilities without attack vectors.
|
|
40
|
+
- **Playwright config**: `channel: "chrome"` removed — uses bundled Chromium for better
|
|
41
|
+
portability. `.mcp.json` now includes a `_comment` field explaining how to upgrade the
|
|
42
|
+
pinned `@playwright/mcp` version.
|
|
43
|
+
- **Node version check** in `cli.js` now uses a proper semver comparison that handles
|
|
44
|
+
`||` ranges (e.g. `>=18.0.0 || >=20.0.0`).
|
|
45
|
+
|
|
46
|
+
### Docs
|
|
47
|
+
- **`discovery.prompt.md`**: `crew_code` uniqueness is now self-service (`ls crews/`)
|
|
48
|
+
instead of depending on the orchestrator to pass a list.
|
|
49
|
+
- **`runner.pipeline.md`**: language contract table documents all fixed PT-BR headers
|
|
50
|
+
and the policy for adding new ones.
|
|
51
|
+
- **`CONTRIBUTING.md`**: new "Forking" section with catalog URL, package name, and
|
|
52
|
+
publish instructions.
|
|
53
|
+
|
|
6
54
|
## [1.2.1] — 2026-08-02
|
|
7
55
|
|
|
8
56
|
### Changed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aksp/opencrew",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
21
|
"start": "node bin/opencrew.js",
|
|
22
|
-
"test": "node --test tests/cli.test.js tests/docs.test.js tests/fsx.test.js tests/ides.test.js tests/init.test.js tests/update.test.js",
|
|
23
|
-
"
|
|
22
|
+
"test": "node --test tests/cli.test.js tests/docs.test.js tests/fsx.test.js tests/ides.test.js tests/init.test.js tests/paths.test.js tests/ui.test.js tests/update.test.js",
|
|
23
|
+
"lint": "eslint src/ tests/ scripts/",
|
|
24
|
+
"version": "node scripts/stamp-version.js && git add templates/_opencrew/.opencrew-version"
|
|
24
25
|
},
|
|
25
26
|
"keywords": [
|
|
26
27
|
"ai-agents",
|
|
@@ -53,5 +54,10 @@
|
|
|
53
54
|
"dependencies": {
|
|
54
55
|
"@inquirer/checkbox": "^5.1.0",
|
|
55
56
|
"@inquirer/confirm": "^5.1.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@eslint/js": "^9.0.0",
|
|
60
|
+
"eslint": "^9.0.0",
|
|
61
|
+
"globals": "^17.9.0"
|
|
56
62
|
}
|
|
57
63
|
}
|
package/src/cli.js
CHANGED
|
@@ -5,16 +5,52 @@ import { init } from './commands/init.js';
|
|
|
5
5
|
import { update } from './commands/update.js';
|
|
6
6
|
import { c, log, err, warn, info } from './lib/ui.js';
|
|
7
7
|
|
|
8
|
+
// Extract the minimum required Node version from an engines.node range string.
|
|
9
|
+
// Handles: ">=20.0.0", "^20.5", ">=18.0.0 || >=20.0.0", plain "20.0.0".
|
|
10
|
+
function minNodeVersion(range) {
|
|
11
|
+
// Split on || and take the lowest version (user is expected to meet at least one).
|
|
12
|
+
const parts = range.split(/\s*\|\|\s*/);
|
|
13
|
+
let lowest = null;
|
|
14
|
+
for (const part of parts) {
|
|
15
|
+
const v = part.replace(/[^0-9.]/g, '');
|
|
16
|
+
if (!v) continue;
|
|
17
|
+
if (!lowest || lt(v, lowest)) lowest = v;
|
|
18
|
+
}
|
|
19
|
+
return lowest;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Simple semver comparison (no prerelease tags). Returns true if a < b.
|
|
23
|
+
function lt(a, b) {
|
|
24
|
+
const pa = a.split('.').map(Number);
|
|
25
|
+
const pb = b.split('.').map(Number);
|
|
26
|
+
for (let i = 0; i < 3; i++) {
|
|
27
|
+
const na = pa[i] || 0;
|
|
28
|
+
const nb = pb[i] || 0;
|
|
29
|
+
if (na !== nb) return na < nb;
|
|
30
|
+
}
|
|
31
|
+
return false; // equal
|
|
32
|
+
}
|
|
33
|
+
|
|
8
34
|
function parseArgs(argv) {
|
|
9
35
|
const opts = { _: [] };
|
|
10
36
|
for (const a of argv) {
|
|
11
37
|
if (a.startsWith('--')) {
|
|
12
|
-
const
|
|
13
|
-
|
|
38
|
+
const eq = a.indexOf('=');
|
|
39
|
+
const k = eq > -1 ? a.slice(2, eq) : a.slice(2);
|
|
40
|
+
const v = eq > -1 ? a.slice(eq + 1) : true;
|
|
41
|
+
opts[k] = v;
|
|
42
|
+
} else if (a.startsWith('-') && a.length === 2) {
|
|
43
|
+
// Short flags: -y → yes, -v → version, -h → help
|
|
44
|
+
const short = a[1];
|
|
45
|
+
opts[short] = true;
|
|
14
46
|
} else {
|
|
15
47
|
opts._.push(a);
|
|
16
48
|
}
|
|
17
49
|
}
|
|
50
|
+
// Normalize short flags to their long-form equivalents.
|
|
51
|
+
if (opts.y) opts.yes = true;
|
|
52
|
+
if (opts.v) opts.version = true;
|
|
53
|
+
if (opts.h) opts.help = true;
|
|
18
54
|
return opts;
|
|
19
55
|
}
|
|
20
56
|
|
|
@@ -28,13 +64,14 @@ ${c.bold('Usage')}
|
|
|
28
64
|
${c.bold('Commands')}
|
|
29
65
|
init Scaffold an opencrew workspace in the current folder
|
|
30
66
|
update Refresh the framework (keeps your crews, memory and .env)
|
|
67
|
+
upgrade Alias for update
|
|
31
68
|
help Show this help
|
|
32
69
|
version Print the version
|
|
33
70
|
|
|
34
71
|
${c.bold('Options for init')}
|
|
35
72
|
--ide=a,b Preselect IDEs (skip the prompt). Valid: ${allIdeIds().join(', ')}
|
|
36
73
|
--all Configure every supported IDE
|
|
37
|
-
--yes
|
|
74
|
+
--yes, -y Non-interactive; accept defaults
|
|
38
75
|
|
|
39
76
|
${c.bold('Options for update')}
|
|
40
77
|
--check Dry-run: report whether an update is available without making changes
|
|
@@ -43,6 +80,7 @@ ${c.bold('Examples')}
|
|
|
43
80
|
npx @aksp/opencrew init
|
|
44
81
|
npx @aksp/opencrew init --ide=claude-code,codex
|
|
45
82
|
npx @aksp/opencrew init --all
|
|
83
|
+
npx @aksp/opencrew init -y
|
|
46
84
|
npx @aksp/opencrew update
|
|
47
85
|
npx @aksp/opencrew update --check
|
|
48
86
|
`);
|
|
@@ -66,16 +104,13 @@ export async function run(argv) {
|
|
|
66
104
|
|
|
67
105
|
// Validate Node version against engines.node requirement.
|
|
68
106
|
if (engines.node) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
process.exitCode = 1;
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
107
|
+
const required = minNodeVersion(engines.node);
|
|
108
|
+
const current = process.versions.node;
|
|
109
|
+
if (required && lt(current, required)) {
|
|
110
|
+
warn(`opencrew requires Node.js ${engines.node}. You have v${current}.`);
|
|
111
|
+
info(`Upgrade Node or use a compatible version.`);
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
return;
|
|
79
114
|
}
|
|
80
115
|
}
|
|
81
116
|
|
package/src/commands/init.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import { promises as fs } from 'node:fs';
|
|
3
3
|
import { templatesDir, packageJsonPath } from '../lib/paths.js';
|
|
4
4
|
import { copyDir, exists, writeFileSafe, readJson } from '../lib/fsx.js';
|
|
5
|
-
import {
|
|
5
|
+
import { ideById, allIdeIds } from '../lib/ides.js';
|
|
6
6
|
import { pickIdes } from '../lib/prompts.js';
|
|
7
7
|
import { c, log, info, ok, warn, step } from '../lib/ui.js';
|
|
8
8
|
|
|
@@ -17,8 +17,9 @@ export async function init(opts = {}) {
|
|
|
17
17
|
const alreadyInstalled = await exists(path.join(target, '_opencrew', 'core'));
|
|
18
18
|
if (alreadyInstalled) {
|
|
19
19
|
warn('An opencrew workspace already exists here.');
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
info(`To update only the framework, use: ${c.cyan('npx @aksp/opencrew update')}`);
|
|
21
|
+
info(`To reinstall from scratch, delete _opencrew/ first, then run init again.`);
|
|
22
|
+
return;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
// 1. Copy the framework payload (never clobber user work).
|
package/src/commands/update.js
CHANGED
|
@@ -59,6 +59,7 @@ export async function update(opts = {}) {
|
|
|
59
59
|
// the catalog — are never touched, since copyDir only visits paths that exist
|
|
60
60
|
// in the source (templates/skills/).
|
|
61
61
|
step('Refreshing catalog skills');
|
|
62
|
+
warn('Catalog skills are fully overwritten — your edits to any built-in skill files will be lost.');
|
|
62
63
|
let s = 0;
|
|
63
64
|
await copyDir(path.join(templatesDir, 'skills'), path.join(target, 'skills'), {
|
|
64
65
|
overwrite: true,
|
package/src/lib/fsx.js
CHANGED
|
@@ -57,6 +57,7 @@ export async function writeFileSafe(p, content, { overwrite = true } = {}) {
|
|
|
57
57
|
* @returns {Promise<boolean>} true if something was deleted, false if it didn't exist.
|
|
58
58
|
*/
|
|
59
59
|
export async function deleteDir(p) {
|
|
60
|
+
if (!(await exists(p))) return false;
|
|
60
61
|
try {
|
|
61
62
|
await fs.rm(p, { recursive: true, force: true });
|
|
62
63
|
return true;
|
|
@@ -66,5 +67,10 @@ export async function deleteDir(p) {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
export async function readJson(p) {
|
|
69
|
-
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(await fs.readFile(p, 'utf8'));
|
|
72
|
+
} catch (e) {
|
|
73
|
+
const reason = e.code === 'ENOENT' ? 'file not found' : e.message;
|
|
74
|
+
throw new Error(`Failed to read ${p}: ${reason}`);
|
|
75
|
+
}
|
|
70
76
|
}
|
package/src/lib/prompts.js
CHANGED
|
@@ -4,9 +4,22 @@ import { IDES, allIdeIds } from './ides.js';
|
|
|
4
4
|
import { warn } from './ui.js';
|
|
5
5
|
|
|
6
6
|
export async function pickIdes({ preselected } = {}) {
|
|
7
|
+
const validIds = new Set(allIdeIds());
|
|
7
8
|
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
9
|
+
|
|
10
|
+
// Filter and validate preselected IDs.
|
|
11
|
+
let chosen = preselected?.length ? preselected : null;
|
|
12
|
+
if (chosen) {
|
|
13
|
+
const invalid = chosen.filter((id) => !validIds.has(id));
|
|
14
|
+
if (invalid.length) {
|
|
15
|
+
warn(`Unknown IDE(s) ignored: ${invalid.join(', ')}. Valid: ${allIdeIds().join(', ')}`);
|
|
16
|
+
chosen = chosen.filter((id) => validIds.has(id));
|
|
17
|
+
}
|
|
18
|
+
if (!chosen.length) chosen = null; // fall through to defaults
|
|
19
|
+
}
|
|
20
|
+
|
|
8
21
|
if (!isTTY) {
|
|
9
|
-
|
|
22
|
+
if (!chosen) chosen = allIdeIds();
|
|
10
23
|
warn(`Non-interactive terminal — configuring IDEs: ${chosen.join(', ')}`);
|
|
11
24
|
return chosen;
|
|
12
25
|
}
|
|
@@ -18,7 +31,7 @@ export async function pickIdes({ preselected } = {}) {
|
|
|
18
31
|
...IDES.map((i) => ({
|
|
19
32
|
name: i.label,
|
|
20
33
|
value: i.id,
|
|
21
|
-
checked:
|
|
34
|
+
checked: chosen ? chosen.includes(i.id) : i.id === 'claude-code',
|
|
22
35
|
})),
|
|
23
36
|
new Separator(),
|
|
24
37
|
],
|
|
@@ -26,10 +39,3 @@ export async function pickIdes({ preselected } = {}) {
|
|
|
26
39
|
});
|
|
27
40
|
return answer;
|
|
28
41
|
}
|
|
29
|
-
|
|
30
|
-
export async function confirm(message, def = true) {
|
|
31
|
-
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
32
|
-
if (!isTTY) return def;
|
|
33
|
-
const { default: confirmPrompt } = await import('@inquirer/confirm');
|
|
34
|
-
return confirmPrompt({ message, default: def });
|
|
35
|
-
}
|
package/src/lib/ui.js
CHANGED
package/templates/.mcp.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.2.
|
|
1
|
+
1.2.2
|
|
@@ -251,7 +251,7 @@ target_formats: # content crews only; empty list for others
|
|
|
251
251
|
|
|
252
252
|
The `crew_code` must be a short, URL-safe slug derived from the crew's purpose (e.g., `content-calendar`, `competitor-tracker`, `lead-notify`).
|
|
253
253
|
|
|
254
|
-
**CRITICAL — Name uniqueness:** The `crew_code` MUST NEVER match any existing folder name in `crews/`.
|
|
254
|
+
**CRITICAL — Name uniqueness:** The `crew_code` MUST NEVER match any existing folder name in `crews/`. Before finalizing, run `ls crews/ 2>/dev/null` (Bash) to list existing crew directories. If the slug you derive matches an existing folder, append a numeric suffix (`-2`, `-3`, etc.) until it is unique. Never reuse an existing crew folder name — doing so would overwrite another crew's files.
|
|
255
255
|
|
|
256
256
|
---
|
|
257
257
|
|
|
@@ -28,7 +28,23 @@ Before starting execution:
|
|
|
28
28
|
when `false`, skip ALL of them; never create, update, or delete
|
|
29
29
|
`crews/{name}/state.json`.
|
|
30
30
|
|
|
31
|
-
> **Note on language**:
|
|
31
|
+
> **Note on language**: The structural labels listed below are **fixed PT-BR** and must
|
|
32
|
+
> never be translated — opencrew's primary supported audience is PT-BR (see AGENTS.md →
|
|
33
|
+
> Language Handling). Only the *content* written under these headers follows the user's
|
|
34
|
+
> preferred language.
|
|
35
|
+
>
|
|
36
|
+
> | Fixed PT-BR header | Location | Purpose |
|
|
37
|
+
> |---|---|---|
|
|
38
|
+
> | `## Estilo de Escrita` | `memories.md` | Writing style rules accumulated per crew |
|
|
39
|
+
> | `## Design Visual` | `memories.md` | Visual design preferences per crew |
|
|
40
|
+
> | `## Estrutura de Conteúdo` | `memories.md` | Content structure rules per crew |
|
|
41
|
+
> | `## Proibições Explícitas` | `memories.md` | User bans and hard blocks per crew |
|
|
42
|
+
> | `## Técnico (específico do crew)` | `memories.md` | Technical crew-specific settings |
|
|
43
|
+
> | `Data \| Run ID \| Tema \| Output \| Resultado` | `runs.md` | Run history table columns |
|
|
44
|
+
>
|
|
45
|
+
> When adding new structural sections to `memories.md` or `runs.md`, keep headers in PT-BR
|
|
46
|
+
> unless the user base expands beyond PT-BR — at that point, discuss a migration strategy
|
|
47
|
+
> (e.g. i18n key mapping) rather than mixing languages in a single file.
|
|
32
48
|
|
|
33
49
|
1b. **Memory format migration** — After loading `memories.md`, check whether it uses the new format by scanning for the `## Estilo de Escrita` section header:
|
|
34
50
|
```bash
|
|
@@ -20,10 +20,11 @@ You are the Skills Engine. Your job is to manage skill integrations for opencrew
|
|
|
20
20
|
### Catalog URL Resolution
|
|
21
21
|
|
|
22
22
|
When fetching skill files from the catalog, resolve the base URL in this order:
|
|
23
|
-
1.
|
|
24
|
-
2.
|
|
23
|
+
1. Check the `OPENCREW_CATALOG_URL` environment variable — if set, use it directly as the base URL. This allows forks to point to their own catalog without editing catalog.json.
|
|
24
|
+
2. Read `skills/catalog.json` (installed locally during init/update) → use its `baseUrl` field
|
|
25
|
+
3. If not available, default to:
|
|
25
26
|
`https://raw.githubusercontent.com/alberthpalhares/opencrew/main/templates/skills`
|
|
26
|
-
|
|
27
|
+
4. Append `/<name>/SKILL.md` (or other file paths) to the base URL
|
|
27
28
|
|
|
28
29
|
## How Skills Are Detected
|
|
29
30
|
|
|
@@ -122,21 +123,21 @@ For the full SKILL.md specification, see `skills/opencrew-skill-creator/referenc
|
|
|
122
123
|
- If fetch fails (404 or network error) → **ERROR**: "Skill '<name>' not found in the skills catalog."
|
|
123
124
|
- Do NOT proceed if the SKILL.md cannot be fetched.
|
|
124
125
|
|
|
125
|
-
|
|
126
|
+
5. **Create the skill directory**:
|
|
126
127
|
```
|
|
127
128
|
skills/<name>/
|
|
128
129
|
```
|
|
129
130
|
|
|
130
|
-
|
|
131
|
+
6. **Write SKILL.md** to `skills/<name>/SKILL.md`
|
|
131
132
|
|
|
132
|
-
|
|
133
|
+
7. **Fetch additional files** (if the skill requires them):
|
|
133
134
|
- If the SKILL.md frontmatter has `script.path` → fetch the script file from:
|
|
134
135
|
`{baseUrl}/<name>/{script.path}`
|
|
135
136
|
Create subdirectories (e.g., `scripts/`) as needed.
|
|
136
137
|
- If the skill has a `references/` directory mentioned → fetch those files too.
|
|
137
138
|
- If the skill has an `assets/` directory mentioned → fetch those files too.
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
8. **Parse SKILL.md frontmatter** and check requirements:
|
|
140
141
|
|
|
141
142
|
#### a. Environment Variables (if `env:` is present)
|
|
142
143
|
|
|
@@ -169,7 +170,7 @@ For the full SKILL.md specification, see `skills/opencrew-skill-creator/referenc
|
|
|
169
170
|
1. Yes, overwrite
|
|
170
171
|
2. No, keep existing
|
|
171
172
|
If "No" → skip MCP configuration but still complete installation
|
|
172
|
-
3. Use the values already collected in step
|
|
173
|
+
3. Use the values already collected in step 8.a for each env var in the skill's `env`
|
|
173
174
|
array (do not ask again).
|
|
174
175
|
4. Add to `mcpServers`:
|
|
175
176
|
```json
|
|
@@ -187,7 +188,7 @@ For the full SKILL.md specification, see `skills/opencrew-skill-creator/referenc
|
|
|
187
188
|
|
|
188
189
|
1. Read `.claude/settings.local.json` (create with `{"mcpServers": {}}` if it doesn't exist)
|
|
189
190
|
2. Check for `server_name` conflict (same as stdio above)
|
|
190
|
-
3. Use the values already collected in step
|
|
191
|
+
3. Use the values already collected in step 8.a for each env var in the skill's `env`
|
|
191
192
|
array (do not ask again).
|
|
192
193
|
4. Build the mcpServers entry:
|
|
193
194
|
- Start with `{ "type": "http", "url": "{url}" }`
|
|
@@ -208,7 +209,7 @@ For the full SKILL.md specification, see `skills/opencrew-skill-creator/referenc
|
|
|
208
209
|
#### d. Script Setup (if `type: script` or `type: hybrid`)
|
|
209
210
|
|
|
210
211
|
1. Verify the script file exists at `skills/<name>/{script.path}`
|
|
211
|
-
- If missing and wasn't fetched in step
|
|
212
|
+
- If missing and wasn't fetched in step 7 → **ERROR**: "Script file not found. Installation may be incomplete."
|
|
212
213
|
2. If the skill lists dependencies in `script.dependencies`:
|
|
213
214
|
- For `runtime: node` → run: `npm install {packages}`
|
|
214
215
|
- For `runtime: python` → run: `pip install {packages}`
|
|
@@ -219,7 +220,7 @@ For the full SKILL.md specification, see `skills/opencrew-skill-creator/referenc
|
|
|
219
220
|
|
|
220
221
|
No additional setup needed. The skill is fully defined by its SKILL.md instructions.
|
|
221
222
|
|
|
222
|
-
|
|
223
|
+
9. **Confirm installation**:
|
|
223
224
|
"✅ {name} installed! Crews can now use `{name}` in their skills list."
|
|
224
225
|
|
|
225
226
|
### 3. Create a Custom Skill
|
|
@@ -300,7 +301,7 @@ before the pipeline begins (fail fast).
|
|
|
300
301
|
d. **Verify env vars** (if `env:` is present):
|
|
301
302
|
- Check each variable in `.env`
|
|
302
303
|
- If any are missing → ask the user conversationally, right here in chat, the same
|
|
303
|
-
way as Operation 2, step
|
|
304
|
+
way as Operation 2, step 8.a (never point them to the `.env` file to edit it
|
|
304
305
|
themselves). If they provide a value, write it to `.env` and continue. If they
|
|
305
306
|
skip, warn: "⚠️ Skill '{skill}' is missing environment variable(s): {list}. It may
|
|
306
307
|
not work correctly." — but do NOT block pipeline execution either way.
|