maestro-skills 0.1.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/.github/workflows/ci.yml +26 -0
- package/.github/workflows/publish-npm.yml +30 -0
- package/CONTRIBUTING.md +31 -0
- package/LICENSE +21 -0
- package/README.md +300 -0
- package/SECURITY.md +33 -0
- package/docs/github-workflow.md +96 -0
- package/docs/maestro-skills-cli.md +113 -0
- package/package.json +35 -0
- package/packages/maestro-skills/README.md +37 -0
- package/packages/maestro-skills/agents.json +36 -0
- package/packages/maestro-skills/bin/cli.js +37 -0
- package/packages/maestro-skills/lib/detect-agents.js +28 -0
- package/packages/maestro-skills/lib/install.js +58 -0
- package/packages/maestro-skills/lib/paths.js +42 -0
- package/packages/maestro-skills/lib/remove.js +71 -0
- package/packages/maestro-skills/lib/run-manifest.js +92 -0
- package/packages/maestro-skills/lib/setup.js +115 -0
- package/packages/maestro-skills/package.json +47 -0
- package/packages/maestro-skills/test/agents.test.js +17 -0
- package/packages/rodovalhofs-maestro/agents.json +36 -0
- package/packages/rodovalhofs-maestro/bin/cli.js +10 -0
- package/packages/rodovalhofs-maestro/lib/detect-agents.js +28 -0
- package/packages/rodovalhofs-maestro/lib/install.js +58 -0
- package/packages/rodovalhofs-maestro/lib/paths.js +42 -0
- package/packages/rodovalhofs-maestro/lib/remove.js +71 -0
- package/packages/rodovalhofs-maestro/lib/run-manifest.js +92 -0
- package/packages/rodovalhofs-maestro/lib/setup.js +115 -0
- package/packages/rodovalhofs-maestro/package.json +33 -0
- package/scripts/sync-skill-to-cli.mjs +75 -0
- package/scripts/sync-templates.ps1 +22 -0
- package/skills/maestro/SKILL.md +272 -0
- package/skills/maestro/maestro-exclude.example.txt +6 -0
- package/skills/maestro/scripts/bm25.py +70 -0
- package/skills/maestro/scripts/build_manifest.py +183 -0
- package/skills/maestro/scripts/concept_gaps.py +196 -0
- package/skills/maestro/scripts/domains.py +148 -0
- package/skills/maestro/scripts/intents.py +167 -0
- package/skills/maestro/scripts/maestro_paths.py +41 -0
- package/skills/maestro/scripts/route_tasks.py +101 -0
- package/skills/maestro/scripts/routing.py +106 -0
- package/skills/maestro/scripts/search_skills.py +287 -0
- package/skills/maestro/scripts/synonyms.py +47 -0
- package/templates/.github/ISSUE_TEMPLATE/bug_report.yml +34 -0
- package/templates/.github/ISSUE_TEMPLATE/chore.yml +17 -0
- package/templates/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/templates/.github/ISSUE_TEMPLATE/feature_request.yml +27 -0
- package/templates/.github/workflows/ci-failure-to-issue.yml +47 -0
- package/templates/.github/workflows/ci.yml +27 -0
- package/templates/CONTRIBUTING.md +22 -0
- package/templates/labels.json +12 -0
- package/templates/pull_request_template.md +18 -0
- package/tests/fixtures/sample-manifest.json +76 -0
- package/tests/test_concept_gaps.py +63 -0
- package/tests/test_maestro_paths.py +29 -0
- package/tests/test_search_routing.py +161 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { getMaestroPaths, skillSourceDir } from "./paths.js";
|
|
4
|
+
|
|
5
|
+
export function copySkillTo(destDir) {
|
|
6
|
+
const src = skillSourceDir();
|
|
7
|
+
const dest = join(destDir, "maestro");
|
|
8
|
+
rmSync(dest, { recursive: true, force: true });
|
|
9
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
10
|
+
cpSync(src, dest, { recursive: true });
|
|
11
|
+
const pycache = join(dest, "scripts", "__pycache__");
|
|
12
|
+
if (existsSync(pycache)) rmSync(pycache, { recursive: true, force: true });
|
|
13
|
+
return dest;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function migrateLegacyFiles() {
|
|
17
|
+
const paths = getMaestroPaths();
|
|
18
|
+
mkdirSync(paths.home, { recursive: true });
|
|
19
|
+
const migrated = [];
|
|
20
|
+
|
|
21
|
+
if (!existsSync(paths.manifest) && existsSync(paths.legacyManifest)) {
|
|
22
|
+
renameSync(paths.legacyManifest, paths.manifest);
|
|
23
|
+
migrated.push("skills-manifest.json");
|
|
24
|
+
}
|
|
25
|
+
if (!existsSync(paths.exclude) && existsSync(paths.legacyExclude)) {
|
|
26
|
+
renameSync(paths.legacyExclude, paths.exclude);
|
|
27
|
+
migrated.push("maestro-exclude.txt");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const example = join(skillSourceDir(), "maestro-exclude.example.txt");
|
|
31
|
+
if (!existsSync(paths.exclude) && existsSync(example)) {
|
|
32
|
+
cpSync(example, paths.exclude);
|
|
33
|
+
migrated.push("maestro-exclude.txt (from example)");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return migrated;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function saveSetupConfig(config) {
|
|
40
|
+
const { config: configPath } = getMaestroPaths();
|
|
41
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
42
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function loadSetupConfig() {
|
|
46
|
+
const { config: configPath } = getMaestroPaths();
|
|
47
|
+
if (!existsSync(configPath)) return null;
|
|
48
|
+
return JSON.parse(readFileSync(configPath, "utf8"));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function removeSkillFrom(destDir) {
|
|
52
|
+
const dest = join(destDir, "maestro");
|
|
53
|
+
if (existsSync(dest)) {
|
|
54
|
+
rmSync(dest, { recursive: true, force: true });
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const PACKAGE_ROOT = join(__dirname, "..");
|
|
8
|
+
|
|
9
|
+
export function getMaestroHome() {
|
|
10
|
+
return process.env.MAESTRO_HOME || join(homedir(), ".maestro");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getMaestroPaths() {
|
|
14
|
+
const home = getMaestroHome();
|
|
15
|
+
return {
|
|
16
|
+
home,
|
|
17
|
+
manifest: join(home, "skills-manifest.json"),
|
|
18
|
+
exclude: join(home, "maestro-exclude.txt"),
|
|
19
|
+
config: join(home, "config.json"),
|
|
20
|
+
legacyManifest: join(homedir(), ".cursor", "skills-manifest.json"),
|
|
21
|
+
legacyExclude: join(homedir(), ".cursor", "maestro-exclude.txt"),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function loadAgents() {
|
|
26
|
+
const raw = readFileSync(join(PACKAGE_ROOT, "agents.json"), "utf8");
|
|
27
|
+
return JSON.parse(raw).agents;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveSkillsDir(agent, { project = false, cwd = process.cwd() } = {}) {
|
|
31
|
+
const base = project ? cwd : homedir();
|
|
32
|
+
const rel = project ? agent.projectSkillsDir : agent.globalSkillsDir;
|
|
33
|
+
return join(base, rel);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function skillSourceDir() {
|
|
37
|
+
return join(PACKAGE_ROOT, "skill");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function bundledBuildManifest() {
|
|
41
|
+
return join(skillSourceDir(), "scripts", "build_manifest.py");
|
|
42
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { rmSync, existsSync } from "node:fs";
|
|
3
|
+
import { loadSetupConfig, removeSkillFrom } from "./install.js";
|
|
4
|
+
import { getMaestroPaths } from "./paths.js";
|
|
5
|
+
import { detectAgents } from "./detect-agents.js";
|
|
6
|
+
|
|
7
|
+
export async function runRemove(options) {
|
|
8
|
+
p.intro("Maestro remove");
|
|
9
|
+
|
|
10
|
+
const config = loadSetupConfig();
|
|
11
|
+
let targets = config?.agents || [];
|
|
12
|
+
|
|
13
|
+
if (!targets.length || options.all) {
|
|
14
|
+
const agents = detectAgents({ project: false });
|
|
15
|
+
targets = agents.map((a) => ({
|
|
16
|
+
id: a.id,
|
|
17
|
+
label: a.label,
|
|
18
|
+
path: `${a.skillsPath}/maestro`.replace(/\\/g, "/"),
|
|
19
|
+
skillsPath: a.skillsPath,
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!options.yes) {
|
|
24
|
+
const selected = await p.multiselect({
|
|
25
|
+
message: "Remove Maestro skill from:",
|
|
26
|
+
options: targets.map((t) => ({
|
|
27
|
+
value: t.id,
|
|
28
|
+
label: t.label,
|
|
29
|
+
hint: t.skillsPath || t.path,
|
|
30
|
+
})),
|
|
31
|
+
required: true,
|
|
32
|
+
initialValues: targets.map((t) => t.id),
|
|
33
|
+
});
|
|
34
|
+
if (p.isCancel(selected)) {
|
|
35
|
+
p.cancel("Remove cancelled.");
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
targets = targets.filter((t) => selected.includes(t.id));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let cleanHome = false;
|
|
42
|
+
if (!options.yes) {
|
|
43
|
+
const clean = await p.confirm({
|
|
44
|
+
message: "Also remove ~/.maestro/ (manifest, exclude, config)?",
|
|
45
|
+
initialValue: false,
|
|
46
|
+
});
|
|
47
|
+
if (p.isCancel(clean)) {
|
|
48
|
+
p.cancel("Remove cancelled.");
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
cleanHome = Boolean(clean);
|
|
52
|
+
} else if (options.cleanHome) {
|
|
53
|
+
cleanHome = true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
for (const t of targets) {
|
|
57
|
+
const dir = t.skillsPath || t.path.replace(/\/maestro$/, "");
|
|
58
|
+
const removed = removeSkillFrom(dir);
|
|
59
|
+
p.log.info(removed ? `Removed ${dir}/maestro` : `Not found: ${dir}/maestro`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (cleanHome) {
|
|
63
|
+
const { home } = getMaestroPaths();
|
|
64
|
+
if (existsSync(home)) {
|
|
65
|
+
rmSync(home, { recursive: true, force: true });
|
|
66
|
+
p.log.info(`Removed ${home}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
p.outro("Maestro removed.");
|
|
71
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { bundledBuildManifest, getMaestroPaths } from "./paths.js";
|
|
4
|
+
|
|
5
|
+
function pythonCommand() {
|
|
6
|
+
if (process.platform === "win32") {
|
|
7
|
+
const py = spawnSync("py", ["-3", "--version"], { encoding: "utf8" });
|
|
8
|
+
if (py.status === 0) return ["py", "-3"];
|
|
9
|
+
}
|
|
10
|
+
const python3 = spawnSync("python3", ["--version"], { encoding: "utf8" });
|
|
11
|
+
if (python3.status === 0) return ["python3"];
|
|
12
|
+
const python = spawnSync("python", ["--version"], { encoding: "utf8" });
|
|
13
|
+
if (python.status === 0) return ["python"];
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function runBuildManifest({ projectRoot = process.cwd(), quiet = false } = {}) {
|
|
18
|
+
const script = bundledBuildManifest();
|
|
19
|
+
if (!existsSync(script)) {
|
|
20
|
+
return { ok: false, error: `build_manifest.py not found at ${script}` };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const py = pythonCommand();
|
|
24
|
+
if (!py) {
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
error: "Python 3.12+ not found. Install Python and ensure `py -3` or `python3` works.",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const { manifest } = getMaestroPaths();
|
|
32
|
+
const args = [...py, script, "--project-root", projectRoot, "--output", manifest];
|
|
33
|
+
const result = spawnSync(args[0], args.slice(1), {
|
|
34
|
+
encoding: "utf8",
|
|
35
|
+
stdio: quiet ? "pipe" : "inherit",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (result.status !== 0) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
error: result.stderr || `build_manifest exited with code ${result.status}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const line = (result.stdout || "").trim().split("\n").pop();
|
|
46
|
+
return { ok: true, message: line || `Manifest written to ${manifest}` };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function registerOnSkillsSh(agents, { yes = false } = {}) {
|
|
50
|
+
const withCli = agents.filter((a) => a.skillsCliAgent);
|
|
51
|
+
if (!withCli.length) return { ok: true, skipped: true };
|
|
52
|
+
|
|
53
|
+
const args = [
|
|
54
|
+
"skills",
|
|
55
|
+
"add",
|
|
56
|
+
"rodovalhofs/maestro",
|
|
57
|
+
"--skill",
|
|
58
|
+
"maestro",
|
|
59
|
+
"-g",
|
|
60
|
+
"-y",
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
for (const agent of withCli) {
|
|
64
|
+
args.push("-a", agent.skillsCliAgent);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const uniqueAgents = [...new Set(withCli.map((a) => a.skillsCliAgent))];
|
|
68
|
+
const finalArgs = [
|
|
69
|
+
"skills",
|
|
70
|
+
"add",
|
|
71
|
+
"rodovalhofs/maestro",
|
|
72
|
+
"--skill",
|
|
73
|
+
"maestro",
|
|
74
|
+
"-g",
|
|
75
|
+
"-y",
|
|
76
|
+
...uniqueAgents.flatMap((a) => ["-a", a]),
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const result = spawnSync("npx", finalArgs, {
|
|
80
|
+
encoding: "utf8",
|
|
81
|
+
stdio: yes ? "pipe" : "inherit",
|
|
82
|
+
shell: process.platform === "win32",
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (result.status !== 0) {
|
|
86
|
+
return {
|
|
87
|
+
ok: false,
|
|
88
|
+
error: "npx skills add failed (optional step). Install Node.js or run manually.",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return { ok: true };
|
|
92
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { detectAgents, filterAgentsByFlags } from "./detect-agents.js";
|
|
3
|
+
import {
|
|
4
|
+
copySkillTo,
|
|
5
|
+
migrateLegacyFiles,
|
|
6
|
+
saveSetupConfig,
|
|
7
|
+
} from "./install.js";
|
|
8
|
+
import { getMaestroPaths } from "./paths.js";
|
|
9
|
+
import { registerOnSkillsSh, runBuildManifest } from "./run-manifest.js";
|
|
10
|
+
|
|
11
|
+
export async function runSetup(options) {
|
|
12
|
+
const project = Boolean(options.project);
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
|
|
15
|
+
p.intro(project ? "Maestro setup (this project)" : "Maestro setup (global)");
|
|
16
|
+
|
|
17
|
+
let agents = detectAgents({ project, cwd });
|
|
18
|
+
agents = filterAgentsByFlags(agents, options);
|
|
19
|
+
|
|
20
|
+
if (!options.cursor && !options.claude && !options.codex && !options.universal && !options.yes) {
|
|
21
|
+
const selected = await p.multiselect({
|
|
22
|
+
message: "Which agents should receive the Maestro skill?",
|
|
23
|
+
options: agents.map((a) => ({
|
|
24
|
+
value: a.id,
|
|
25
|
+
label: a.label,
|
|
26
|
+
hint: a.skillsPath,
|
|
27
|
+
})),
|
|
28
|
+
required: true,
|
|
29
|
+
initialValues: agents.filter((a) => a.detected).map((a) => a.id),
|
|
30
|
+
});
|
|
31
|
+
if (p.isCancel(selected)) {
|
|
32
|
+
p.cancel("Setup cancelled.");
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
agents = agents.filter((a) => selected.includes(a.id));
|
|
36
|
+
} else if (options.cursor || options.claude || options.codex || options.universal) {
|
|
37
|
+
agents = filterAgentsByFlags(agents, options);
|
|
38
|
+
} else if (options.yes) {
|
|
39
|
+
agents = agents.filter((a) => a.detected);
|
|
40
|
+
if (!agents.length) agents = detectAgents({ project, cwd });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!agents.length) {
|
|
44
|
+
p.cancel("No agents selected.");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let registerSkillsSh = false;
|
|
49
|
+
if (!options.yes && !options.noSkillsRegistry) {
|
|
50
|
+
const reg = await p.confirm({
|
|
51
|
+
message: "Register install on skills.sh via npx skills add? (optional telemetry)",
|
|
52
|
+
initialValue: false,
|
|
53
|
+
});
|
|
54
|
+
if (p.isCancel(reg)) {
|
|
55
|
+
p.cancel("Setup cancelled.");
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
registerSkillsSh = Boolean(reg);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const spinner = p.spinner();
|
|
62
|
+
const installed = [];
|
|
63
|
+
|
|
64
|
+
for (const agent of agents) {
|
|
65
|
+
spinner.start(`Installing Maestro for ${agent.label}…`);
|
|
66
|
+
try {
|
|
67
|
+
const dest = copySkillTo(agent.skillsPath);
|
|
68
|
+
installed.push({ id: agent.id, label: agent.label, path: dest });
|
|
69
|
+
spinner.stop(`Installed → ${dest}`);
|
|
70
|
+
} catch (err) {
|
|
71
|
+
spinner.stop(`Failed for ${agent.label}`);
|
|
72
|
+
p.log.error(String(err.message || err));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const migrated = migrateLegacyFiles();
|
|
77
|
+
if (migrated.length) {
|
|
78
|
+
p.log.info(`Migrated legacy files: ${migrated.join(", ")}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
spinner.start("Building skills manifest…");
|
|
82
|
+
const manifestResult = runBuildManifest({ projectRoot: cwd, quiet: true });
|
|
83
|
+
if (manifestResult.ok) {
|
|
84
|
+
spinner.stop(manifestResult.message);
|
|
85
|
+
} else {
|
|
86
|
+
spinner.stop("Manifest build failed");
|
|
87
|
+
p.log.warn(manifestResult.error);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (registerSkillsSh) {
|
|
91
|
+
spinner.start("Registering on skills.sh…");
|
|
92
|
+
const reg = await registerOnSkillsSh(agents, { yes: options.yes });
|
|
93
|
+
if (reg.ok && !reg.skipped) spinner.stop("Registered on skills.sh");
|
|
94
|
+
else if (!reg.ok) {
|
|
95
|
+
spinner.stop("skills.sh registration skipped");
|
|
96
|
+
p.log.warn(reg.error);
|
|
97
|
+
} else spinner.stop("No skills CLI agents selected");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const paths = getMaestroPaths();
|
|
101
|
+
saveSetupConfig({
|
|
102
|
+
version: 1,
|
|
103
|
+
installedAt: new Date().toISOString(),
|
|
104
|
+
scope: project ? "project" : "global",
|
|
105
|
+
projectRoot: project ? cwd : null,
|
|
106
|
+
agents: installed,
|
|
107
|
+
maestroHome: paths.home,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
p.note(
|
|
111
|
+
installed.map((i) => `${i.label}\n ${i.path}`).join("\n\n"),
|
|
112
|
+
"Installed paths",
|
|
113
|
+
);
|
|
114
|
+
p.outro("Maestro setup complete. Invoke with $maestro or /maestro in your agent.");
|
|
115
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rodovalhofs/maestro",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Maestro skill orchestrator — scoped install with short bin name",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Yuri Rodovalho",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/rodovalhofs/maestro.git",
|
|
10
|
+
"directory": "packages/rodovalhofs-maestro"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"maestro": "./bin/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"bin",
|
|
21
|
+
"lib",
|
|
22
|
+
"skill",
|
|
23
|
+
"agents.json",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"prepack": "node ../../scripts/sync-skill-to-cli.mjs --target rodovalhofs-maestro"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@clack/prompts": "^0.10.1",
|
|
31
|
+
"commander": "^13.1.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Copy canonical skill + shared lib to publishable npm packages.
|
|
4
|
+
* Usage: node scripts/sync-skill-to-cli.mjs [--target maestro-skills|rodovalhofs-maestro|all]
|
|
5
|
+
*/
|
|
6
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { dirname, join, resolve } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const ROOT = resolve(__dirname, "..");
|
|
12
|
+
const SOURCE_SKILL = join(ROOT, "skills", "maestro");
|
|
13
|
+
const PACKAGES = {
|
|
14
|
+
"maestro-skills": join(ROOT, "packages", "maestro-skills"),
|
|
15
|
+
"rodovalhofs-maestro": join(ROOT, "packages", "rodovalhofs-maestro"),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function copyDir(src, dest) {
|
|
19
|
+
if (!existsSync(src)) {
|
|
20
|
+
throw new Error(`Source not found: ${src}`);
|
|
21
|
+
}
|
|
22
|
+
rmSync(dest, { recursive: true, force: true });
|
|
23
|
+
cpSync(src, dest, { recursive: true });
|
|
24
|
+
for (const dir of ["__pycache__", "node_modules"]) {
|
|
25
|
+
const nested = join(dest, "scripts", dir);
|
|
26
|
+
if (existsSync(nested)) rmSync(nested, { recursive: true, force: true });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function copySharedLib(targetPkg) {
|
|
31
|
+
const libSrc = join(PACKAGES["maestro-skills"], "lib");
|
|
32
|
+
const libDest = join(targetPkg, "lib");
|
|
33
|
+
if (targetPkg === PACKAGES["maestro-skills"]) return;
|
|
34
|
+
rmSync(libDest, { recursive: true, force: true });
|
|
35
|
+
cpSync(libSrc, libDest, { recursive: true });
|
|
36
|
+
cpSync(join(PACKAGES["maestro-skills"], "agents.json"), join(targetPkg, "agents.json"));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function syncPackage(name) {
|
|
40
|
+
const pkgDir = PACKAGES[name];
|
|
41
|
+
if (!pkgDir) throw new Error(`Unknown package: ${name}`);
|
|
42
|
+
mkdirSync(pkgDir, { recursive: true });
|
|
43
|
+
copyDir(SOURCE_SKILL, join(pkgDir, "skill"));
|
|
44
|
+
if (name !== "maestro-skills") {
|
|
45
|
+
copySharedLib(pkgDir);
|
|
46
|
+
writeScopedCli(pkgDir);
|
|
47
|
+
}
|
|
48
|
+
console.log(`Synced skill → ${name}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function writeScopedCli(pkgDir) {
|
|
52
|
+
const binPath = join(pkgDir, "bin", "cli.js");
|
|
53
|
+
mkdirSync(join(pkgDir, "bin"), { recursive: true });
|
|
54
|
+
const content = `#!/usr/bin/env node
|
|
55
|
+
import { Command } from "commander";
|
|
56
|
+
import { runRemove } from "../lib/remove.js";
|
|
57
|
+
import { runSetup } from "../lib/setup.js";
|
|
58
|
+
|
|
59
|
+
const program = new Command();
|
|
60
|
+
program.name("maestro").description("Maestro skill orchestrator (@rodovalhofs/maestro)").version("0.1.0");
|
|
61
|
+
program.command("setup").description("Interactive setup").option("--project").option("--cursor").option("--claude").option("--codex").option("--universal").option("-y, --yes").option("--no-skills-registry").action(runSetup);
|
|
62
|
+
program.command("remove").description("Remove Maestro").option("-y, --yes").option("--all").option("--clean-home").action(runRemove);
|
|
63
|
+
program.parseAsync(process.argv);
|
|
64
|
+
`;
|
|
65
|
+
writeFileSync(binPath, content, "utf8");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const arg = process.argv.find((a) => a.startsWith("--target"));
|
|
69
|
+
const target = arg ? arg.split("=")[1] || process.argv[process.argv.indexOf(arg) + 1] : "all";
|
|
70
|
+
|
|
71
|
+
if (target === "all") {
|
|
72
|
+
for (const name of Object.keys(PACKAGES)) syncPackage(name);
|
|
73
|
+
} else {
|
|
74
|
+
syncPackage(target);
|
|
75
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory = $true)]
|
|
3
|
+
[string]$TargetRepo
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
$ErrorActionPreference = "Stop"
|
|
7
|
+
$Source = Join-Path $PSScriptRoot "..\templates"
|
|
8
|
+
$Target = Resolve-Path $TargetRepo
|
|
9
|
+
|
|
10
|
+
Write-Host "Sincronizando templates de $Source para $Target"
|
|
11
|
+
|
|
12
|
+
$githubSrc = Join-Path $Source ".github"
|
|
13
|
+
$githubDst = Join-Path $Target ".github"
|
|
14
|
+
if (Test-Path $githubDst) {
|
|
15
|
+
Remove-Item $githubDst -Recurse -Force
|
|
16
|
+
}
|
|
17
|
+
Copy-Item $githubSrc $githubDst -Recurse -Force
|
|
18
|
+
|
|
19
|
+
Copy-Item (Join-Path $Source "CONTRIBUTING.md") (Join-Path $Target "CONTRIBUTING.md") -Force
|
|
20
|
+
Copy-Item (Join-Path $Source "pull_request_template.md") (Join-Path $Target ".github\pull_request_template.md") -Force
|
|
21
|
+
|
|
22
|
+
Write-Host "Concluido. Revise workflows e adapte comandos de test/build ao seu stack."
|