@drunkcoding/agents-and-skills 0.0.30 → 0.0.32
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/.claude-plugin/marketplace.json +21 -4
- package/README.md +1 -0
- package/package.json +1 -1
- package/plugins/html-effectiveness/.claude-plugin/plugin.json +1 -1
- package/plugins/multica-tool/.claude-plugin/plugin.json +5 -0
- package/plugins/multica-tool/agents/export.md +17 -0
- package/plugins/multica-tool/agents/import.md +17 -0
- package/plugins/multica-tool/agents/sync.md +17 -0
- package/plugins/multica-tool/commands/export.md +6 -0
- package/plugins/multica-tool/commands/import.md +6 -0
- package/plugins/multica-tool/commands/sync.md +6 -0
- package/plugins/multica-tool/scripts/lib.mjs +93 -0
- package/plugins/multica-tool/scripts/multica-export.mjs +136 -0
- package/plugins/multica-tool/scripts/multica-import.mjs +146 -0
- package/plugins/multica-tool/scripts/multica-sync.mjs +66 -0
- package/plugins/multica-tool/skills/export/SKILL.md +61 -0
- package/plugins/multica-tool/skills/import/SKILL.md +49 -0
- package/plugins/multica-tool/skills/sync/SKILL.md +50 -0
- package/plugins/plugin-validator/.claude-plugin/plugin.json +1 -1
- package/plugins/team-share/.claude-plugin/plugin.json +1 -1
- package/plugins/team-share/skills/codegraph-setup/SKILL.md +5 -5
- package/plugins/tech-graph/.claude-plugin/plugin.json +1 -1
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"name": "tech-graph",
|
|
13
13
|
"source": "./plugins/tech-graph",
|
|
14
14
|
"description": "6-step wizard for technical diagrams (SVG/PNG) via fireworks-tech-graph",
|
|
15
|
-
"version": "0.0.
|
|
15
|
+
"version": "0.0.32",
|
|
16
16
|
"category": "diagram",
|
|
17
17
|
"keywords": [
|
|
18
18
|
"diagram",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"name": "html-effectiveness",
|
|
27
27
|
"source": "./plugins/html-effectiveness",
|
|
28
28
|
"description": "Generate self-contained interactive HTML reports from 20 upstream templates via a conversational agent.",
|
|
29
|
-
"version": "0.0.
|
|
29
|
+
"version": "0.0.32",
|
|
30
30
|
"category": "reports",
|
|
31
31
|
"keywords": [
|
|
32
32
|
"html",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"name": "plugin-validator",
|
|
42
42
|
"source": "./plugins/plugin-validator",
|
|
43
43
|
"description": "Orchestrated validator for Claude Code plugins — validates skills, agents, commands, and hooks across every plugin under plugins/**.",
|
|
44
|
-
"version": "0.0.
|
|
44
|
+
"version": "0.0.32",
|
|
45
45
|
"category": "tooling",
|
|
46
46
|
"keywords": [
|
|
47
47
|
"validation",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"name": "team-share",
|
|
58
58
|
"source": "./plugins/team-share",
|
|
59
59
|
"description": "Onboard your team with an interactive setup menu: install CodeGraph, build the Understand-Anything knowledge graph, and share Claude Code settings — run any combination, all idempotent.",
|
|
60
|
-
"version": "0.0.
|
|
60
|
+
"version": "0.0.32",
|
|
61
61
|
"category": "tooling",
|
|
62
62
|
"keywords": [
|
|
63
63
|
"onboarding",
|
|
@@ -68,6 +68,23 @@
|
|
|
68
68
|
"understand-anything",
|
|
69
69
|
"git-lfs"
|
|
70
70
|
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "multica-tool",
|
|
74
|
+
"source": "./plugins/multica-tool",
|
|
75
|
+
"description": "Export, import, and sync Multica skills, agents, and squads between workspaces.",
|
|
76
|
+
"version": "0.0.32",
|
|
77
|
+
"category": "workflow",
|
|
78
|
+
"keywords": [
|
|
79
|
+
"multica",
|
|
80
|
+
"migration",
|
|
81
|
+
"export",
|
|
82
|
+
"import",
|
|
83
|
+
"sync",
|
|
84
|
+
"skills",
|
|
85
|
+
"agents",
|
|
86
|
+
"squads"
|
|
87
|
+
]
|
|
71
88
|
}
|
|
72
89
|
]
|
|
73
90
|
}
|
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ Published on npm as [`@drunkcoding/agents-and-skills`](https://www.npmjs.com/pac
|
|
|
14
14
|
| [`plugin-validator`](plugins/plugin-validator) | Orchestrated validator that checks every plugin's skills, agents, commands, and hooks for spec compliance — runs in parallel and proposes batched fixes. |
|
|
15
15
|
| [`team-share`](plugins/team-share) | Onboarding helper that shares Claude plugin settings, scaffolds `CLAUDE.md` when missing, refreshes the Understand-Anything graph, and stages the resulting repo artifacts for review. |
|
|
16
16
|
| [`auto-power`](plugins/auto-power) | Single-command hands-off pipeline that wraps `obra/superpowers`. Auto-answers safe clarifying questions during spec, then runs plan → arch+sec → impl → verify → review → ff-merge with no further touchpoints. Checkpointed and resumable. Escalates on substantive failures. |
|
|
17
|
+
| [`multica-tool`](plugins/multica-tool) | Export, import, and sync Multica skills, agents, and squads between workspaces. |
|
|
17
18
|
|
|
18
19
|
## team-superpower v3
|
|
19
20
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "html-effectiveness",
|
|
3
3
|
"displayName": "HTML Effectiveness Reports",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.32",
|
|
5
5
|
"description": "Generate self-contained interactive HTML reports from 20 upstream templates via a conversational agent.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Steven Hoang"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: export
|
|
3
|
+
description: Use when delegating a Multica export as a background task. Runs the multica-tool:export skill in its own context for long background migrations and returns the final JSON report.
|
|
4
|
+
tools: Bash, Read, Skill
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Multica Export Executor
|
|
8
|
+
|
|
9
|
+
Standalone executor for the `multica-tool:export` skill. Runs the export operation to completion and returns the final JSON report.
|
|
10
|
+
|
|
11
|
+
## Behavior
|
|
12
|
+
|
|
13
|
+
You are a standalone executor. Invoke the `multica-tool:export` skill with the arguments passed to you, run it to completion, and return the final JSON report. You are NOT part of a coordinated team.
|
|
14
|
+
|
|
15
|
+
1. Invoke the `multica-tool:export` skill, forwarding all arguments received.
|
|
16
|
+
2. Wait for the skill to complete.
|
|
17
|
+
3. Return the final JSON report from the skill output.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: import
|
|
3
|
+
description: Use when delegating a Multica import as a background task. Runs the multica-tool:import skill in its own context for long background migrations and returns the final JSON report.
|
|
4
|
+
tools: Bash, Read, Skill
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Multica Import Executor
|
|
8
|
+
|
|
9
|
+
Standalone executor for the `multica-tool:import` skill. Runs the import operation to completion and returns the final JSON report.
|
|
10
|
+
|
|
11
|
+
## Behavior
|
|
12
|
+
|
|
13
|
+
You are a standalone executor. Invoke the `multica-tool:import` skill with the arguments passed to you, run it to completion, and return the final JSON report. You are NOT part of a coordinated team.
|
|
14
|
+
|
|
15
|
+
1. Invoke the `multica-tool:import` skill, forwarding all arguments received.
|
|
16
|
+
2. Wait for the skill to complete.
|
|
17
|
+
3. Return the final JSON report from the skill output.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sync
|
|
3
|
+
description: Use when delegating a Multica sync as a background task. Runs the multica-tool:sync skill in its own context for long background migrations and returns the final JSON report.
|
|
4
|
+
tools: Bash, Read, Skill
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Multica Sync Executor
|
|
8
|
+
|
|
9
|
+
Standalone executor for the `multica-tool:sync` skill. Runs the sync operation to completion and returns the final JSON report.
|
|
10
|
+
|
|
11
|
+
## Behavior
|
|
12
|
+
|
|
13
|
+
You are a standalone executor. Invoke the `multica-tool:sync` skill with the arguments passed to you, run it to completion, and return the final JSON report. You are NOT part of a coordinated team.
|
|
14
|
+
|
|
15
|
+
1. Invoke the `multica-tool:sync` skill, forwarding all arguments received.
|
|
16
|
+
2. Wait for the skill to complete.
|
|
17
|
+
3. Return the final JSON report from the skill output.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
export function slugify(name) {
|
|
4
|
+
const s = String(name)
|
|
5
|
+
.toLowerCase()
|
|
6
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
7
|
+
.replace(/^-+|-+$/g, "");
|
|
8
|
+
return s || "unnamed";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function realExec(args) {
|
|
12
|
+
return spawnSync("multica", args, { encoding: "utf8" });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function makeCli(exec, { workspaceId } = {}) {
|
|
16
|
+
function run(args) {
|
|
17
|
+
let full = args;
|
|
18
|
+
if (workspaceId) {
|
|
19
|
+
full = [...args, "--workspace-id", workspaceId];
|
|
20
|
+
}
|
|
21
|
+
const res = exec(full);
|
|
22
|
+
if (res.status !== 0) throw new Error(res.stderr?.trim() || `multica exited ${res.status}`);
|
|
23
|
+
return res.stdout;
|
|
24
|
+
}
|
|
25
|
+
function json(args) {
|
|
26
|
+
const fullArgs = workspaceId ? [...args, "--workspace-id", workspaceId, "--output", "json"] : [...args, "--output", "json"];
|
|
27
|
+
const res = exec(fullArgs);
|
|
28
|
+
if (res.status !== 0) throw new Error(res.stderr?.trim() || `multica exited ${res.status}`);
|
|
29
|
+
return JSON.parse(res.stdout);
|
|
30
|
+
}
|
|
31
|
+
return { run, json };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function requireAuth(exec) {
|
|
35
|
+
const res = exec(["auth", "status"]);
|
|
36
|
+
if (res.status !== 0) throw new Error("Not authenticated. Run: multica login");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function findByName(list, name) {
|
|
40
|
+
const hits = (list || []).filter((x) => x.name === name);
|
|
41
|
+
if (hits.length > 1) throw new Error(`Duplicate name "${name}" — refusing to guess`);
|
|
42
|
+
return hits[0] || null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function resolveWorkspaceId(cli, name) {
|
|
46
|
+
const list = cli.json(["workspace", "list"]);
|
|
47
|
+
const hits = list.filter((w) => w.name === name);
|
|
48
|
+
if (hits.length === 0) throw new Error(`Unknown workspace "${name}"`);
|
|
49
|
+
if (hits.length > 1) throw new Error(`Ambiguous workspace "${name}"`);
|
|
50
|
+
return hits[0].id;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const listRuntimes = (cli) => cli.json(["runtime", "list"]);
|
|
54
|
+
export const listSkills = (cli) => cli.json(["skill", "list"]);
|
|
55
|
+
export const listAgents = (cli) => cli.json(["agent", "list"]);
|
|
56
|
+
export const listSquads = (cli) => cli.json(["squad", "list"]);
|
|
57
|
+
|
|
58
|
+
// Get-wrappers: the ONLY place that knows the raw CLI field names. They
|
|
59
|
+
// return a stable camelCase shape so downstream code never sees snake_case.
|
|
60
|
+
export function getSkill(cli, id) {
|
|
61
|
+
const s = cli.json(["skill", "get", id]);
|
|
62
|
+
return {
|
|
63
|
+
id: s.id, name: s.name, description: s.description,
|
|
64
|
+
content: s.content ?? "", config: s.config ?? {},
|
|
65
|
+
files: (s.files ?? []).map((f) => ({ path: f.path, content: f.content })),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function getAgent(cli, id) {
|
|
70
|
+
const a = cli.json(["agent", "get", id]);
|
|
71
|
+
return {
|
|
72
|
+
id: a.id, name: a.name, description: a.description, instructions: a.instructions,
|
|
73
|
+
model: a.model, visibility: a.visibility,
|
|
74
|
+
maxConcurrentTasks: a.max_concurrent_tasks,
|
|
75
|
+
runtimeConfig: a.runtime_config,
|
|
76
|
+
customArgs: a.custom_args,
|
|
77
|
+
thinkingLevel: a.thinking_level,
|
|
78
|
+
runtimeId: a.runtime_id,
|
|
79
|
+
hasCustomEnv: a.has_custom_env,
|
|
80
|
+
mcpConfig: a.mcp_config,
|
|
81
|
+
skills: (a.skills ?? []).map((sk) => ({ id: sk.id, name: sk.name })),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function getSquad(cli, id) {
|
|
86
|
+
const s = cli.json(["squad", "get", id]);
|
|
87
|
+
return { id: s.id, name: s.name, description: s.description, leaderId: s.leader_id };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const getSquadMembers = (cli, id) =>
|
|
91
|
+
(cli.json(["squad", "member", "list", id]) ?? []).map((m) => ({
|
|
92
|
+
memberId: m.member_id, memberType: m.member_type, role: m.role || "member",
|
|
93
|
+
}));
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import * as nodeFs from "node:fs";
|
|
2
|
+
import { slugify, getSkill, getAgent, getSquad, getSquadMembers, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
|
|
3
|
+
|
|
4
|
+
const nonEmpty = (v) => v && typeof v === "object" && Object.keys(v).length > 0;
|
|
5
|
+
|
|
6
|
+
export function redactAgent(a) {
|
|
7
|
+
// a is a normalized (camelCase) agent from getAgent.
|
|
8
|
+
const { id, hasCustomEnv, mcpConfig, skills, runtimeId, ...rest } = a;
|
|
9
|
+
const hadSecrets = !!hasCustomEnv || nonEmpty(mcpConfig);
|
|
10
|
+
return {
|
|
11
|
+
record: { ...rest, sourceRuntimeId: runtimeId, skillNames: [], hadSecrets },
|
|
12
|
+
hadSecrets,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function buildManifest({ scope, sourceWorkspaceId, skills, agents, squad }) {
|
|
17
|
+
const seenSkills = new Map();
|
|
18
|
+
for (const s of skills) if (!seenSkills.has(s.name)) seenSkills.set(s.name, s);
|
|
19
|
+
const seenAgents = new Map();
|
|
20
|
+
for (const a of agents) if (!seenAgents.has(a.name)) seenAgents.set(a.name, a);
|
|
21
|
+
return {
|
|
22
|
+
version: "1",
|
|
23
|
+
scope,
|
|
24
|
+
sourceWorkspaceId,
|
|
25
|
+
skills: [...seenSkills.values()].map((s) => ({ name: s.name, dir: `skills/${slugify(s.name)}`, sourceId: s.sourceId })),
|
|
26
|
+
agents: [...seenAgents.values()].map((a) => ({ name: a.name, file: `agents/${slugify(a.name)}.json`, sourceRuntimeId: a.sourceRuntimeId, skillNames: a.skillNames, hadSecrets: !!a.hadSecrets })),
|
|
27
|
+
squads: squad ? [{ name: squad.name, file: `squads/${slugify(squad.name)}.json`, description: squad.description ?? "", leaderName: squad.leaderName, members: squad.members }] : [],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function collectSkill(cli, id, skills) {
|
|
32
|
+
const s = getSkill(cli, id);
|
|
33
|
+
if (!skills.has(s.name)) skills.set(s.name, s);
|
|
34
|
+
return s.name;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Keyed by agent id (so squad leaderId/memberId resolve to names). Stores the
|
|
38
|
+
// normalized agent, its redaction result, and its skill names.
|
|
39
|
+
function collectAgent(cli, id, agentsById, skills) {
|
|
40
|
+
if (agentsById.has(id)) return agentsById.get(id);
|
|
41
|
+
const a = getAgent(cli, id);
|
|
42
|
+
const skillNames = a.skills.map((sk) => collectSkill(cli, sk.id, skills));
|
|
43
|
+
const red = redactAgent(a);
|
|
44
|
+
const entry = { raw: a, red, skillNames };
|
|
45
|
+
agentsById.set(id, entry);
|
|
46
|
+
return entry;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs = nodeFs }) {
|
|
50
|
+
const skills = new Map(); // name -> normalized skill
|
|
51
|
+
const agentsById = new Map(); // id -> { raw, red, skillNames }
|
|
52
|
+
let squad = null;
|
|
53
|
+
|
|
54
|
+
if (scope === "skill") collectSkill(cli, ids.skillId, skills);
|
|
55
|
+
if (scope === "agent") collectAgent(cli, ids.agentId, agentsById, skills);
|
|
56
|
+
if (scope === "squad") {
|
|
57
|
+
const sq = getSquad(cli, ids.squadId);
|
|
58
|
+
const members = getSquadMembers(cli, ids.squadId).filter((m) => m.memberType === "agent");
|
|
59
|
+
for (const m of members) collectAgent(cli, m.memberId, agentsById, skills);
|
|
60
|
+
if (!agentsById.has(sq.leaderId)) collectAgent(cli, sq.leaderId, agentsById, skills);
|
|
61
|
+
const nameOf = (id) => agentsById.get(id)?.raw.name;
|
|
62
|
+
squad = {
|
|
63
|
+
name: sq.name,
|
|
64
|
+
description: sq.description,
|
|
65
|
+
leaderName: nameOf(sq.leaderId),
|
|
66
|
+
members: members.map((m) => ({ agentName: nameOf(m.memberId), role: m.role })),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const manifest = buildManifest({
|
|
71
|
+
scope, sourceWorkspaceId,
|
|
72
|
+
skills: [...skills.values()].map((s) => ({ name: s.name, sourceId: s.id })),
|
|
73
|
+
agents: [...agentsById.values()].map((a) => ({ name: a.raw.name, sourceRuntimeId: a.raw.runtimeId, skillNames: a.skillNames, hadSecrets: a.red.hadSecrets })),
|
|
74
|
+
squad,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const warnings = [];
|
|
78
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
79
|
+
|
|
80
|
+
for (const entry of manifest.skills) {
|
|
81
|
+
const s = skills.get(entry.name);
|
|
82
|
+
const dir = `${outDir}/${entry.dir}`;
|
|
83
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
84
|
+
fs.writeFileSync(`${dir}/SKILL.md`, s.content ?? "");
|
|
85
|
+
fs.writeFileSync(`${dir}/config.json`, JSON.stringify(s.config ?? {}, null, 2));
|
|
86
|
+
for (const f of s.files ?? []) fs.writeFileSync(`${dir}/${f.path}`, f.content ?? "");
|
|
87
|
+
}
|
|
88
|
+
// Index agent entries by name for the manifest writing loop.
|
|
89
|
+
const agentByName = new Map([...agentsById.values()].map((a) => [a.raw.name, a]));
|
|
90
|
+
for (const entry of manifest.agents) {
|
|
91
|
+
const { raw, red, skillNames } = agentByName.get(entry.name);
|
|
92
|
+
const record = { ...red.record, skillNames };
|
|
93
|
+
if (red.hadSecrets) warnings.push(raw.name);
|
|
94
|
+
fs.mkdirSync(`${outDir}/agents`, { recursive: true });
|
|
95
|
+
fs.writeFileSync(`${outDir}/${entry.file}`, JSON.stringify(record, null, 2));
|
|
96
|
+
}
|
|
97
|
+
for (const entry of manifest.squads) {
|
|
98
|
+
fs.mkdirSync(`${outDir}/squads`, { recursive: true });
|
|
99
|
+
fs.writeFileSync(`${outDir}/${entry.file}`, JSON.stringify(entry, null, 2));
|
|
100
|
+
}
|
|
101
|
+
fs.writeFileSync(`${outDir}/manifest.json`, JSON.stringify(manifest, null, 2));
|
|
102
|
+
return { manifest, warnings };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function main() {
|
|
106
|
+
const args = process.argv.slice(2);
|
|
107
|
+
const get = (flag) => { const i = args.indexOf(flag); return i !== -1 ? args[i + 1] : null; };
|
|
108
|
+
|
|
109
|
+
const scope = get("--scope");
|
|
110
|
+
const id = get("--id");
|
|
111
|
+
const out = get("--out");
|
|
112
|
+
const workspace = get("--workspace"); // optional: source workspace name
|
|
113
|
+
|
|
114
|
+
if (!scope || !id || !out) {
|
|
115
|
+
console.error("Usage: multica-export.mjs --scope <skill|agent|squad> --id <id> --out <dir> [--workspace <name>]");
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
requireAuth(realExec);
|
|
120
|
+
|
|
121
|
+
let sourceWorkspaceId = "";
|
|
122
|
+
const resolver = makeCli(realExec);
|
|
123
|
+
if (workspace) sourceWorkspaceId = resolveWorkspaceId(resolver, workspace);
|
|
124
|
+
const cli = workspace ? makeCli(realExec, { workspaceId: sourceWorkspaceId }) : resolver;
|
|
125
|
+
|
|
126
|
+
const ids = {};
|
|
127
|
+
if (scope === "skill") ids.skillId = id;
|
|
128
|
+
else if (scope === "agent") ids.agentId = id;
|
|
129
|
+
else if (scope === "squad") ids.squadId = id;
|
|
130
|
+
else { console.error(`Unknown scope "${scope}" — use skill|agent|squad`); process.exit(1); }
|
|
131
|
+
|
|
132
|
+
const result = exportResource({ cli, scope, ids, outDir: out, sourceWorkspaceId, fs: nodeFs });
|
|
133
|
+
console.log(JSON.stringify(result, null, 2));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (import.meta.url === `file://${process.argv[1]}`) main();
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import * as nodeFs from "node:fs";
|
|
2
|
+
import { listSkills, listAgents, listSquads, findByName, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
|
|
3
|
+
|
|
4
|
+
export function importSkills({ cli, manifest, dir, fs = nodeFs }) {
|
|
5
|
+
const idMap = new Map();
|
|
6
|
+
let created = 0, updated = 0;
|
|
7
|
+
const existing = listSkills(cli);
|
|
8
|
+
|
|
9
|
+
for (const s of manifest.skills) {
|
|
10
|
+
const sdir = dir === "." ? s.dir : `${dir}/${s.dir}`;
|
|
11
|
+
const contentPath = `${sdir}/SKILL.md`;
|
|
12
|
+
const configPath = `${sdir}/config.json`;
|
|
13
|
+
const config = fs.existsSync(configPath) ? fs.readFileSync(configPath, "utf8") : "{}";
|
|
14
|
+
const match = findByName(existing, s.name);
|
|
15
|
+
let id;
|
|
16
|
+
if (match) {
|
|
17
|
+
cli.run(["skill", "update", match.id, "--content-file", contentPath, "--config", config]);
|
|
18
|
+
id = match.id; updated++;
|
|
19
|
+
} else {
|
|
20
|
+
const out = cli.run(["skill", "create", "--name", s.name, "--content-file", contentPath, "--config", config]);
|
|
21
|
+
id = JSON.parse(out).id; created++;
|
|
22
|
+
}
|
|
23
|
+
idMap.set(s.name, id);
|
|
24
|
+
// upsert extra files (everything except SKILL.md and config.json)
|
|
25
|
+
for (const f of fs.readdirSync(sdir)) {
|
|
26
|
+
if (f === "SKILL.md" || f === "config.json") continue;
|
|
27
|
+
cli.run(["skill", "files", "upsert", id, "--path", f, "--content-file", `${sdir}/${f}`]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return { idMap, created, updated };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function importAgents({ cli, manifest, dir, skillIdMap, runtimeMap, fs = nodeFs }) {
|
|
34
|
+
const idMap = new Map();
|
|
35
|
+
let created = 0, updated = 0;
|
|
36
|
+
const existing = listAgents(cli);
|
|
37
|
+
|
|
38
|
+
for (const a of manifest.agents) {
|
|
39
|
+
const rec = JSON.parse(fs.readFileSync(`${dir}/${a.file}`, "utf8"));
|
|
40
|
+
const targetRuntime = runtimeMap.get(rec.sourceRuntimeId);
|
|
41
|
+
if (!targetRuntime) throw new Error(`Unmapped runtime "${rec.sourceRuntimeId}" for agent "${rec.name}"`);
|
|
42
|
+
// Only pass optional flags when present — `--model ""` would CLEAR the model.
|
|
43
|
+
const common = [
|
|
44
|
+
"--visibility", rec.visibility ?? "private",
|
|
45
|
+
"--max-concurrent-tasks", String(rec.maxConcurrentTasks ?? 6),
|
|
46
|
+
];
|
|
47
|
+
if (rec.instructions) common.push("--instructions", rec.instructions);
|
|
48
|
+
if (rec.model) common.push("--model", rec.model);
|
|
49
|
+
if (rec.thinkingLevel) common.push("--thinking-level", rec.thinkingLevel);
|
|
50
|
+
if (rec.runtimeConfig && Object.keys(rec.runtimeConfig).length) common.push("--runtime-config", JSON.stringify(rec.runtimeConfig));
|
|
51
|
+
if (Array.isArray(rec.customArgs) && rec.customArgs.length) common.push("--custom-args", JSON.stringify(rec.customArgs));
|
|
52
|
+
const match = findByName(existing, rec.name);
|
|
53
|
+
let id;
|
|
54
|
+
if (match) {
|
|
55
|
+
cli.run(["agent", "update", match.id, "--runtime-id", targetRuntime, ...common]);
|
|
56
|
+
id = match.id; updated++;
|
|
57
|
+
} else {
|
|
58
|
+
const out = cli.run(["agent", "create", "--name", rec.name, "--runtime-id", targetRuntime, ...common]);
|
|
59
|
+
id = JSON.parse(out).id; created++;
|
|
60
|
+
}
|
|
61
|
+
idMap.set(rec.name, id);
|
|
62
|
+
const skillIds = (rec.skillNames ?? []).map((n) => skillIdMap.get(n)).filter(Boolean);
|
|
63
|
+
cli.run(["agent", "skills", "set", id, "--skill-ids", skillIds.join(",")]);
|
|
64
|
+
}
|
|
65
|
+
return { idMap, created, updated };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function importSquad({ cli, squad, agentIdMap }) {
|
|
69
|
+
const existing = listSquads(cli);
|
|
70
|
+
const leaderId = agentIdMap.get(squad.leaderName);
|
|
71
|
+
const match = findByName(existing, squad.name);
|
|
72
|
+
let id, created = 0, updated = 0;
|
|
73
|
+
if (match) {
|
|
74
|
+
cli.run(["squad", "update", match.id, "--leader", leaderId, "--description", squad.description ?? ""]);
|
|
75
|
+
id = match.id; updated++;
|
|
76
|
+
} else {
|
|
77
|
+
const out = cli.run(["squad", "create", "--name", squad.name, "--leader", leaderId, "--description", squad.description ?? ""]);
|
|
78
|
+
id = JSON.parse(out).id; created++;
|
|
79
|
+
}
|
|
80
|
+
for (const m of squad.members) {
|
|
81
|
+
if (m.agentName === squad.leaderName) continue;
|
|
82
|
+
cli.run(["squad", "member", "add", id, "--member-id", agentIdMap.get(m.agentName), "--role", m.role, "--type", "agent"]);
|
|
83
|
+
}
|
|
84
|
+
return { newId: id, created, updated };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function collectSourceRuntimes(manifest) {
|
|
88
|
+
return [...new Set((manifest.agents ?? []).map((a) => a.sourceRuntimeId).filter(Boolean))];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function importBundle({ cli, dir, runtimeMap, fs = nodeFs }) {
|
|
92
|
+
const manifest = JSON.parse(fs.readFileSync(`${dir}/manifest.json`, "utf8"));
|
|
93
|
+
const missing = collectSourceRuntimes(manifest).filter((r) => !runtimeMap.has(r));
|
|
94
|
+
if (missing.length) throw new Error(`Unmapped runtimes: ${missing.join(", ")} — aborting before any write`);
|
|
95
|
+
|
|
96
|
+
const skillRes = importSkills({ cli, manifest, dir, fs });
|
|
97
|
+
const agentRes = importAgents({ cli, manifest, dir, skillIdMap: skillRes.idMap, runtimeMap, fs });
|
|
98
|
+
let squadRes = { newId: null, created: 0, updated: 0 };
|
|
99
|
+
if (manifest.squads?.length) squadRes = importSquad({ cli, squad: manifest.squads[0], agentIdMap: agentRes.idMap });
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
created: { skills: skillRes.created, agents: agentRes.created, squads: squadRes.created },
|
|
103
|
+
updated: { skills: skillRes.updated, agents: agentRes.updated, squads: squadRes.updated },
|
|
104
|
+
skillIdMap: Object.fromEntries(skillRes.idMap),
|
|
105
|
+
agentIdMap: Object.fromEntries(agentRes.idMap),
|
|
106
|
+
squadId: squadRes.newId,
|
|
107
|
+
secretsReminder: (manifest.agents ?? []).filter((a) => a.hadSecrets).map((a) => a.name),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function parseRuntimeMap(raw) {
|
|
112
|
+
// Parse "srcId1=dstId1,srcId2=dstId2" into a Map.
|
|
113
|
+
const map = new Map();
|
|
114
|
+
if (!raw) return map;
|
|
115
|
+
for (const pair of raw.split(",")) {
|
|
116
|
+
const eq = pair.indexOf("=");
|
|
117
|
+
if (eq === -1) continue;
|
|
118
|
+
map.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim());
|
|
119
|
+
}
|
|
120
|
+
return map;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function main() {
|
|
124
|
+
const args = process.argv.slice(2);
|
|
125
|
+
const get = (flag) => { const i = args.indexOf(flag); return i !== -1 ? args[i + 1] : null; };
|
|
126
|
+
|
|
127
|
+
const dir = get("--dir");
|
|
128
|
+
const workspace = get("--workspace");
|
|
129
|
+
const rawMap = get("--runtime-map");
|
|
130
|
+
|
|
131
|
+
if (!dir || !workspace) {
|
|
132
|
+
console.error("Usage: multica-import.mjs --dir <folder> --workspace <name> [--runtime-map <src=dst,...>]");
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
requireAuth(realExec);
|
|
137
|
+
const resolver = makeCli(realExec);
|
|
138
|
+
const wsId = resolveWorkspaceId(resolver, workspace);
|
|
139
|
+
const cli = makeCli(realExec, { workspaceId: wsId });
|
|
140
|
+
const runtimeMap = parseRuntimeMap(rawMap);
|
|
141
|
+
|
|
142
|
+
const result = importBundle({ cli, dir, runtimeMap, fs: nodeFs });
|
|
143
|
+
console.log(JSON.stringify(result, null, 2));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (import.meta.url === `file://${process.argv[1]}`) main();
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as nodeFs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { makeCli, resolveWorkspaceId, findByName, listSkills, listAgents, listSquads, realExec, requireAuth } from "./lib.mjs";
|
|
5
|
+
import { exportResource } from "./multica-export.mjs";
|
|
6
|
+
import { importBundle } from "./multica-import.mjs";
|
|
7
|
+
|
|
8
|
+
export function resolveScopeId(cli, type, name) {
|
|
9
|
+
const lists = { skill: listSkills, agent: listAgents, squad: listSquads };
|
|
10
|
+
if (!lists[type]) throw new Error(`Unknown type "${type}" (skill|agent|squad)`);
|
|
11
|
+
const match = findByName(lists[type](cli), name);
|
|
12
|
+
if (!match) throw new Error(`Unknown ${type} "${name}" in source workspace`);
|
|
13
|
+
const key = { skill: "skillId", agent: "agentId", squad: "squadId" }[type];
|
|
14
|
+
return { scope: type, ids: { [key]: match.id } };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function sync({ exec, type, name, srcWsName, destWsName, tmpDir, runtimeMap, fs = nodeFs }) {
|
|
18
|
+
const resolver = makeCli(exec); // no ws — for workspace list
|
|
19
|
+
const srcId = resolveWorkspaceId(resolver, srcWsName);
|
|
20
|
+
const destId = resolveWorkspaceId(resolver, destWsName);
|
|
21
|
+
const srcCli = makeCli(exec, { workspaceId: srcId });
|
|
22
|
+
const destCli = makeCli(exec, { workspaceId: destId });
|
|
23
|
+
|
|
24
|
+
const { scope, ids } = resolveScopeId(srcCli, type, name);
|
|
25
|
+
exportResource({ cli: srcCli, scope, ids, outDir: tmpDir, sourceWorkspaceId: srcId, fs });
|
|
26
|
+
return importBundle({ cli: destCli, dir: tmpDir, runtimeMap, fs });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseRuntimeMap(raw) {
|
|
30
|
+
const map = new Map();
|
|
31
|
+
if (!raw) return map;
|
|
32
|
+
for (const pair of raw.split(",")) {
|
|
33
|
+
const eq = pair.indexOf("=");
|
|
34
|
+
if (eq === -1) continue;
|
|
35
|
+
map.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim());
|
|
36
|
+
}
|
|
37
|
+
return map;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function main() {
|
|
41
|
+
// Usage: multica-sync.mjs <type> <name> from <src-ws> <dest-ws> [--runtime-map <src=dst,...>]
|
|
42
|
+
const args = process.argv.slice(2);
|
|
43
|
+
const get = (flag) => { const i = args.indexOf(flag); return i !== -1 ? args[i + 1] : null; };
|
|
44
|
+
|
|
45
|
+
// Positional: type name from srcWs destWs
|
|
46
|
+
const [type, name, _from, srcWsName, destWsName] = args;
|
|
47
|
+
const rawMap = get("--runtime-map");
|
|
48
|
+
|
|
49
|
+
if (!type || !name || _from !== "from" || !srcWsName || !destWsName) {
|
|
50
|
+
console.error("Usage: multica-sync.mjs <type> <name> from <src-ws> <dest-ws> [--runtime-map <src=dst,...>]");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
requireAuth(realExec);
|
|
55
|
+
const runtimeMap = parseRuntimeMap(rawMap);
|
|
56
|
+
const tmpDir = nodeFs.mkdtempSync(path.join(os.tmpdir(), "multica-sync-"));
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const result = sync({ exec: realExec, type, name, srcWsName, destWsName, tmpDir, runtimeMap, fs: nodeFs });
|
|
60
|
+
console.log(JSON.stringify(result, null, 2));
|
|
61
|
+
} finally {
|
|
62
|
+
nodeFs.rmSync(tmpDir, { recursive: true, force: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (import.meta.url === `file://${process.argv[1]}`) main();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: export
|
|
3
|
+
description: Use when the user wants to export Multica skills, agents, or squads to a local folder for backup, version control, or cross-workspace migration.
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# export
|
|
8
|
+
|
|
9
|
+
Export a Multica resource (skill, agent, or squad) to a local bundle directory.
|
|
10
|
+
|
|
11
|
+
## Step 1 — Verify authentication
|
|
12
|
+
|
|
13
|
+
Run the export script; it calls `multica auth status` internally and exits with an error message if unauthenticated:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
node plugins/multica-tool/scripts/multica-export.mjs --help 2>&1 || true
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If `multica login` is required, surface that message verbatim and stop.
|
|
20
|
+
|
|
21
|
+
## Step 2 — Determine scope and resource ID
|
|
22
|
+
|
|
23
|
+
If the user named a specific resource and type (`skill`, `agent`, or `squad`), use those directly.
|
|
24
|
+
|
|
25
|
+
Otherwise, list available resources for the chosen type and present a pick list:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
multica <type> list --output json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Ask the user to select a resource by name. Resolve its `id` from the list output.
|
|
32
|
+
|
|
33
|
+
## Step 3 — Determine output directory
|
|
34
|
+
|
|
35
|
+
If the user specified an output directory, use it. Otherwise default to:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
./multica-export-<slug>-<type>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
where `<slug>` is a lowercased, hyphenated form of the resource name.
|
|
42
|
+
|
|
43
|
+
## Step 4 — Run the export
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
node plugins/multica-tool/scripts/multica-export.mjs \
|
|
47
|
+
--scope <type> \
|
|
48
|
+
--id <id> \
|
|
49
|
+
--out <dir> \
|
|
50
|
+
[--workspace <workspace-name>]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The script writes `manifest.json`, skill SKILL.md files, agent JSON files, and squad JSON files into `<dir>`.
|
|
54
|
+
|
|
55
|
+
## Step 5 — Report results
|
|
56
|
+
|
|
57
|
+
Parse the JSON output from the script and report:
|
|
58
|
+
|
|
59
|
+
- Directory written to.
|
|
60
|
+
- Count of skills, agents, and squads exported.
|
|
61
|
+
- If `warnings` is non-empty, surface every agent name verbatim with this message: "WARNING: the following agents had custom environment variables or MCP config that were NOT exported — re-add secrets manually after import: `<agent-name>`."
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: import
|
|
3
|
+
description: Use when the user wants to import a Multica export bundle into a target workspace, mapping source runtimes to target runtimes before writing any resources.
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# import
|
|
8
|
+
|
|
9
|
+
Import a local Multica bundle (produced by the export skill) into a target workspace.
|
|
10
|
+
|
|
11
|
+
## Step 1 — Confirm the target workspace
|
|
12
|
+
|
|
13
|
+
Ask the user to confirm the name of the target workspace if not already stated. You will need the exact workspace name as registered in Multica.
|
|
14
|
+
|
|
15
|
+
## Step 2 — Plan pass: read the bundle and collect unmapped runtimes
|
|
16
|
+
|
|
17
|
+
Read the manifest to discover which source runtimes are referenced:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cat <folder>/manifest.json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Collect each distinct `sourceRuntimeId` from the `agents` array.
|
|
24
|
+
|
|
25
|
+
List runtimes available in the target workspace:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
multica runtime list --output json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For each distinct `sourceRuntimeId`, ask the user to pick a matching target runtime by name or ID. Build a mapping in the form `srcId=dstId`. If any source runtime has no mapping selected, abort and explain which IDs remain unmapped — do not write any resources.
|
|
32
|
+
|
|
33
|
+
## Step 3 — Run the import
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
node plugins/multica-tool/scripts/multica-import.mjs \
|
|
37
|
+
--dir <folder> \
|
|
38
|
+
--workspace <workspace-name> \
|
|
39
|
+
--runtime-map <srcId1=dstId1,srcId2=dstId2,...>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Step 4 — Report results
|
|
43
|
+
|
|
44
|
+
Parse the JSON output and report:
|
|
45
|
+
|
|
46
|
+
- Created and updated counts for skills, agents, and squads.
|
|
47
|
+
- Name-to-ID maps for skills and agents (`skillIdMap`, `agentIdMap`).
|
|
48
|
+
- Squad ID if a squad was imported.
|
|
49
|
+
- If `secretsReminder` is non-empty, surface every agent name verbatim with: "WARNING: the following agents had custom environment variables or MCP config that were NOT exported — re-add secrets manually in the Multica UI: `<agent-name>`."
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sync
|
|
3
|
+
description: Use when the user wants to sync a Multica skill, agent, or squad from one workspace to another in a single operation.
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# sync
|
|
8
|
+
|
|
9
|
+
Copy a Multica resource from a source workspace to a destination workspace.
|
|
10
|
+
|
|
11
|
+
## Step 1 — Parse the sync request
|
|
12
|
+
|
|
13
|
+
Expect the user's request in the form:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
sync <type> <name> from <src-ws> to <dest-ws>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Where `<type>` is `skill`, `agent`, or `squad`; `<name>` is the resource name; `<src-ws>` and `<dest-ws>` are workspace names registered in Multica.
|
|
20
|
+
|
|
21
|
+
## Step 2 — Build the runtime map
|
|
22
|
+
|
|
23
|
+
List runtimes available in the destination workspace:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
multica runtime list --output json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Using the source workspace, fetch the resource to discover which `sourceRuntimeId` values are referenced (for agents and squads). For each distinct `sourceRuntimeId`, ask the user to select a matching target runtime by name or ID. Build a mapping in the form `srcId=dstId`. If any source runtime has no mapping, abort before running the sync.
|
|
30
|
+
|
|
31
|
+
For skills (which have no runtime dependency), an empty runtime map is acceptable.
|
|
32
|
+
|
|
33
|
+
## Step 3 — Run the sync
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
node plugins/multica-tool/scripts/multica-sync.mjs \
|
|
37
|
+
<type> <name> from <src-ws> <dest-ws> \
|
|
38
|
+
[--runtime-map <srcId1=dstId1,srcId2=dstId2,...>]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The script exports to a temporary directory, imports into the destination workspace, then cleans up the temporary files automatically.
|
|
42
|
+
|
|
43
|
+
## Step 4 — Report results
|
|
44
|
+
|
|
45
|
+
Parse the JSON output and report:
|
|
46
|
+
|
|
47
|
+
- Created and updated counts for skills, agents, and squads.
|
|
48
|
+
- Name-to-ID maps (`skillIdMap`, `agentIdMap`).
|
|
49
|
+
- Squad ID if a squad was synced.
|
|
50
|
+
- If `secretsReminder` is non-empty, surface every agent name verbatim with: "WARNING: the following agents had custom environment variables or MCP config that were NOT exported — re-add secrets manually in the Multica UI: `<agent-name>`."
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plugin-validator",
|
|
3
3
|
"displayName": "Plugin Validator",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.32",
|
|
5
5
|
"description": "Orchestrated validator for Claude Code plugins — validates skills, agents, commands, and hooks across every plugin under plugins/**.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Steven Hoang"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "team-share",
|
|
3
3
|
"displayName": "Team Share",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.32",
|
|
5
5
|
"description": "Onboard your team with an interactive setup menu: install CodeGraph, build the Understand-Anything knowledge graph, and share Claude Code settings — run any combination, all idempotent.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Steven Hoang"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: codegraph-setup
|
|
3
|
-
description: Install the CodeGraph CLI, wire it to
|
|
3
|
+
description: Install the CodeGraph CLI, wire it to the local project via MCP (codegraph install --target=auto --location=local), and initialise the current project (codegraph init). Works on macOS, Linux, and Windows (Git Bash / PowerShell). Idempotent — skips install if codegraph is already in PATH.
|
|
4
4
|
allowed-tools: Bash
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -54,15 +54,15 @@ fi
|
|
|
54
54
|
|
|
55
55
|
Note: on Windows with Git Bash, `uname -s` returns `MINGW64_NT-*` or similar, which falls through to the `*)` case and attempts PowerShell. This is correct behaviour.
|
|
56
56
|
|
|
57
|
-
## Step 3 — Wire to
|
|
57
|
+
## Step 3 — Wire to your AI tool
|
|
58
58
|
|
|
59
|
-
Register the CodeGraph MCP server
|
|
59
|
+
Register the CodeGraph MCP server for this project (auto-detects AI tool; config written to project-local settings):
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
codegraph install
|
|
62
|
+
codegraph install --target=auto --location=local
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
This makes CodeGraph's context tools available inside
|
|
65
|
+
This makes CodeGraph's context tools available inside your AI tool's sessions.
|
|
66
66
|
|
|
67
67
|
## Step 4 — Initialise the project
|
|
68
68
|
|