@drunkcoding/agents-and-skills 0.0.33 → 0.0.35
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 +5 -5
- package/package.json +1 -1
- package/plugins/html-effectiveness/.claude-plugin/plugin.json +1 -1
- package/plugins/multica-tool/.claude-plugin/plugin.json +1 -1
- package/plugins/multica-tool/scripts/lib.mjs +1 -1
- package/plugins/multica-tool/scripts/multica-export.mjs +20 -9
- package/plugins/multica-tool/scripts/multica-import.mjs +80 -13
- package/plugins/multica-tool/skills/import/SKILL.md +10 -11
- package/plugins/multica-tool/skills/sync/SKILL.md +11 -8
- package/plugins/plugin-validator/.claude-plugin/plugin.json +1 -1
- package/plugins/team-share/.claude-plugin/plugin.json +1 -1
- 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.35",
|
|
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.35",
|
|
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.35",
|
|
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.35",
|
|
61
61
|
"category": "tooling",
|
|
62
62
|
"keywords": [
|
|
63
63
|
"onboarding",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"name": "multica-tool",
|
|
74
74
|
"source": "./plugins/multica-tool",
|
|
75
75
|
"description": "Export, import, and sync Multica skills, agents, and squads between workspaces.",
|
|
76
|
-
"version": "0.0.
|
|
76
|
+
"version": "0.0.35",
|
|
77
77
|
"category": "workflow",
|
|
78
78
|
"keywords": [
|
|
79
79
|
"multica",
|
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.35",
|
|
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"
|
|
@@ -84,7 +84,7 @@ export function getAgent(cli, id) {
|
|
|
84
84
|
|
|
85
85
|
export function getSquad(cli, id) {
|
|
86
86
|
const s = cli.json(["squad", "get", id]);
|
|
87
|
-
return { id: s.id, name: s.name, description: s.description, leaderId: s.leader_id };
|
|
87
|
+
return { id: s.id, name: s.name, description: s.description, instructions: s.instructions, leaderId: s.leader_id };
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export const getSquadMembers = (cli, id) =>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as nodeFs from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { slugify, getSkill, getAgent, getSquad, getSquadMembers, listRuntimes, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
|
|
3
4
|
|
|
4
5
|
const nonEmpty = (v) => v && typeof v === "object" && Object.keys(v).length > 0;
|
|
5
6
|
|
|
@@ -23,8 +24,8 @@ export function buildManifest({ scope, sourceWorkspaceId, skills, agents, squad
|
|
|
23
24
|
scope,
|
|
24
25
|
sourceWorkspaceId,
|
|
25
26
|
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 }] : [],
|
|
27
|
+
agents: [...seenAgents.values()].map((a) => ({ name: a.name, file: `agents/${slugify(a.name)}.json`, sourceRuntimeId: a.sourceRuntimeId, sourceRuntimeProvider: a.sourceRuntimeProvider ?? null, skillNames: a.skillNames, hadSecrets: !!a.hadSecrets })),
|
|
28
|
+
squads: squad ? [{ name: squad.name, file: `squads/${slugify(squad.name)}.json`, description: squad.description ?? "", instructions: squad.instructions ?? "", leaderName: squad.leaderName, members: squad.members }] : [],
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -36,9 +37,10 @@ function collectSkill(cli, id, skills) {
|
|
|
36
37
|
|
|
37
38
|
// Keyed by agent id (so squad leaderId/memberId resolve to names). Stores the
|
|
38
39
|
// normalized agent, its redaction result, and its skill names.
|
|
39
|
-
function collectAgent(cli, id, agentsById, skills) {
|
|
40
|
+
function collectAgent(cli, id, agentsById, skills, providerById) {
|
|
40
41
|
if (agentsById.has(id)) return agentsById.get(id);
|
|
41
42
|
const a = getAgent(cli, id);
|
|
43
|
+
a.sourceRuntimeProvider = providerById.get(a.runtimeId) ?? null;
|
|
42
44
|
const skillNames = a.skills.map((sk) => collectSkill(cli, sk.id, skills));
|
|
43
45
|
const red = redactAgent(a);
|
|
44
46
|
const entry = { raw: a, red, skillNames };
|
|
@@ -50,18 +52,23 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
50
52
|
const skills = new Map(); // name -> normalized skill
|
|
51
53
|
const agentsById = new Map(); // id -> { raw, red, skillNames }
|
|
52
54
|
let squad = null;
|
|
55
|
+
// Lazy + memoized: only fetched when an agent is actually collected (skips
|
|
56
|
+
// the extra CLI call on skill-only exports).
|
|
57
|
+
let providerById = null;
|
|
58
|
+
const getProviderById = () => providerById ??= new Map(listRuntimes(cli).map((r) => [r.id, r.provider]));
|
|
53
59
|
|
|
54
60
|
if (scope === "skill") collectSkill(cli, ids.skillId, skills);
|
|
55
|
-
if (scope === "agent") collectAgent(cli, ids.agentId, agentsById, skills);
|
|
61
|
+
if (scope === "agent") collectAgent(cli, ids.agentId, agentsById, skills, getProviderById());
|
|
56
62
|
if (scope === "squad") {
|
|
57
63
|
const sq = getSquad(cli, ids.squadId);
|
|
58
64
|
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);
|
|
65
|
+
for (const m of members) collectAgent(cli, m.memberId, agentsById, skills, getProviderById());
|
|
66
|
+
if (!agentsById.has(sq.leaderId)) collectAgent(cli, sq.leaderId, agentsById, skills, getProviderById());
|
|
61
67
|
const nameOf = (id) => agentsById.get(id)?.raw.name;
|
|
62
68
|
squad = {
|
|
63
69
|
name: sq.name,
|
|
64
70
|
description: sq.description,
|
|
71
|
+
instructions: sq.instructions,
|
|
65
72
|
leaderName: nameOf(sq.leaderId),
|
|
66
73
|
members: members.map((m) => ({ agentName: nameOf(m.memberId), role: m.role })),
|
|
67
74
|
};
|
|
@@ -70,7 +77,7 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
70
77
|
const manifest = buildManifest({
|
|
71
78
|
scope, sourceWorkspaceId,
|
|
72
79
|
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 })),
|
|
80
|
+
agents: [...agentsById.values()].map((a) => ({ name: a.raw.name, sourceRuntimeId: a.raw.runtimeId, sourceRuntimeProvider: a.raw.sourceRuntimeProvider, skillNames: a.skillNames, hadSecrets: a.red.hadSecrets })),
|
|
74
81
|
squad,
|
|
75
82
|
});
|
|
76
83
|
|
|
@@ -83,7 +90,11 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
83
90
|
fs.mkdirSync(dir, { recursive: true });
|
|
84
91
|
fs.writeFileSync(`${dir}/SKILL.md`, s.content ?? "");
|
|
85
92
|
fs.writeFileSync(`${dir}/config.json`, JSON.stringify(s.config ?? {}, null, 2));
|
|
86
|
-
for (const f of s.files ?? [])
|
|
93
|
+
for (const f of s.files ?? []) {
|
|
94
|
+
const target = `${dir}/${f.path}`;
|
|
95
|
+
fs.mkdirSync(dirname(target), { recursive: true }); // f.path may be nested, e.g. scripts/foo.sh
|
|
96
|
+
fs.writeFileSync(target, f.content ?? "");
|
|
97
|
+
}
|
|
87
98
|
}
|
|
88
99
|
// Index agent entries by name for the manifest writing loop.
|
|
89
100
|
const agentByName = new Map([...agentsById.values()].map((a) => [a.raw.name, a]));
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import * as nodeFs from "node:fs";
|
|
2
|
-
import { listSkills, listAgents, listSquads, findByName, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
|
|
2
|
+
import { listSkills, listAgents, listSquads, listRuntimes, getSquadMembers, findByName, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
|
|
3
|
+
|
|
4
|
+
// Relative paths of every file under root (recursing into subdirs like scripts/).
|
|
5
|
+
function walkSkillFiles(fs, root, rel = "") {
|
|
6
|
+
const out = [];
|
|
7
|
+
for (const ent of fs.readdirSync(rel ? `${root}/${rel}` : root, { withFileTypes: true })) {
|
|
8
|
+
const r = rel ? `${rel}/${ent.name}` : ent.name;
|
|
9
|
+
if (ent.isDirectory()) out.push(...walkSkillFiles(fs, root, r));
|
|
10
|
+
else out.push(r);
|
|
11
|
+
}
|
|
12
|
+
return out;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Pull `description:` out of a SKILL.md YAML frontmatter block.
|
|
16
|
+
// ponytail: single-line values only (the skill frontmatter convention); folded/multi-line YAML not handled.
|
|
17
|
+
function frontmatterDescription(text) {
|
|
18
|
+
const block = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
|
|
19
|
+
if (!block) return "";
|
|
20
|
+
const line = block[1].split(/\r?\n/).find((l) => /^description\s*:/.test(l));
|
|
21
|
+
return line ? line.replace(/^description\s*:/, "").trim().replace(/^["']|["']$/g, "") : "";
|
|
22
|
+
}
|
|
3
23
|
|
|
4
24
|
export function importSkills({ cli, manifest, dir, fs = nodeFs }) {
|
|
5
25
|
const idMap = new Map();
|
|
@@ -12,19 +32,24 @@ export function importSkills({ cli, manifest, dir, fs = nodeFs }) {
|
|
|
12
32
|
const configPath = `${sdir}/config.json`;
|
|
13
33
|
const config = fs.existsSync(configPath) ? fs.readFileSync(configPath, "utf8") : "{}";
|
|
14
34
|
const match = findByName(existing, s.name);
|
|
35
|
+
// Fall back to the SKILL.md frontmatter description when the manifest carries none.
|
|
36
|
+
const fmDesc = frontmatterDescription(fs.readFileSync(contentPath, "utf8"));
|
|
15
37
|
let id;
|
|
16
38
|
if (match) {
|
|
17
|
-
|
|
39
|
+
// Only fill description when the existing skill has none — don't clobber a set one.
|
|
40
|
+
const desc = !match.description && fmDesc ? ["--description", fmDesc] : [];
|
|
41
|
+
cli.run(["skill", "update", match.id, "--content-file", contentPath, "--config", config, ...desc]);
|
|
18
42
|
id = match.id; updated++;
|
|
19
43
|
} else {
|
|
20
|
-
const
|
|
44
|
+
const desc = fmDesc ? ["--description", fmDesc] : [];
|
|
45
|
+
const out = cli.run(["skill", "create", "--name", s.name, "--content-file", contentPath, "--config", config, ...desc]);
|
|
21
46
|
id = JSON.parse(out).id; created++;
|
|
22
47
|
}
|
|
23
48
|
idMap.set(s.name, id);
|
|
24
|
-
// upsert extra files (everything except SKILL.md and config.json)
|
|
25
|
-
for (const
|
|
26
|
-
if (
|
|
27
|
-
cli.run(["skill", "files", "upsert", id, "--path",
|
|
49
|
+
// upsert extra files (everything except SKILL.md and config.json), by relative path
|
|
50
|
+
for (const rel of walkSkillFiles(fs, sdir)) {
|
|
51
|
+
if (rel === "SKILL.md" || rel === "config.json") continue;
|
|
52
|
+
cli.run(["skill", "files", "upsert", id, "--path", rel, "--content-file", `${sdir}/${rel}`]);
|
|
28
53
|
}
|
|
29
54
|
}
|
|
30
55
|
return { idMap, created, updated };
|
|
@@ -70,16 +95,21 @@ export function importSquad({ cli, squad, agentIdMap }) {
|
|
|
70
95
|
const leaderId = agentIdMap.get(squad.leaderName);
|
|
71
96
|
const match = findByName(existing, squad.name);
|
|
72
97
|
let id, created = 0, updated = 0;
|
|
98
|
+
const instr = squad.instructions ? ["--instructions", squad.instructions] : [];
|
|
73
99
|
if (match) {
|
|
74
|
-
cli.run(["squad", "update", match.id, "--leader", leaderId, "--description", squad.description ?? ""]);
|
|
100
|
+
cli.run(["squad", "update", match.id, "--leader", leaderId, "--description", squad.description ?? "", ...instr]);
|
|
75
101
|
id = match.id; updated++;
|
|
76
102
|
} else {
|
|
77
|
-
const out = cli.run(["squad", "create", "--name", squad.name, "--leader", leaderId, "--description", squad.description ?? ""]);
|
|
103
|
+
const out = cli.run(["squad", "create", "--name", squad.name, "--leader", leaderId, "--description", squad.description ?? "", ...instr]);
|
|
78
104
|
id = JSON.parse(out).id; created++;
|
|
79
105
|
}
|
|
106
|
+
// Add non-leader members, skipping any already present so re-runs are idempotent.
|
|
107
|
+
const present = new Set(getSquadMembers(cli, id).map((m) => m.memberId));
|
|
80
108
|
for (const m of squad.members) {
|
|
81
109
|
if (m.agentName === squad.leaderName) continue;
|
|
82
|
-
|
|
110
|
+
const memberId = agentIdMap.get(m.agentName);
|
|
111
|
+
if (present.has(memberId)) continue;
|
|
112
|
+
cli.run(["squad", "member", "add", id, "--member-id", memberId, "--role", m.role, "--type", "agent"]);
|
|
83
113
|
}
|
|
84
114
|
return { newId: id, created, updated };
|
|
85
115
|
}
|
|
@@ -88,13 +118,50 @@ export function collectSourceRuntimes(manifest) {
|
|
|
88
118
|
return [...new Set((manifest.agents ?? []).map((a) => a.sourceRuntimeId).filter(Boolean))];
|
|
89
119
|
}
|
|
90
120
|
|
|
121
|
+
// sourceRuntimeId -> provider (e.g. "claude", "opencode"), from whichever agent recorded it.
|
|
122
|
+
function collectRuntimeProviders(manifest) {
|
|
123
|
+
const map = new Map();
|
|
124
|
+
for (const a of manifest.agents ?? []) {
|
|
125
|
+
if (a.sourceRuntimeId && a.sourceRuntimeProvider && !map.has(a.sourceRuntimeId)) {
|
|
126
|
+
map.set(a.sourceRuntimeId, a.sourceRuntimeProvider);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return map;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Starts from the explicit --runtime-map (always wins), then auto-resolves any
|
|
133
|
+
// remaining source runtime by provider — only when exactly one destination
|
|
134
|
+
// runtime shares that provider. Ambiguous (0 or 2+ matches) stays unresolved.
|
|
135
|
+
export function resolveRuntimeMap({ cli, manifest, runtimeMap }) {
|
|
136
|
+
const effective = new Map(runtimeMap);
|
|
137
|
+
const missing = collectSourceRuntimes(manifest).filter((r) => !effective.has(r));
|
|
138
|
+
if (!missing.length) return { effective, unresolved: [] };
|
|
139
|
+
|
|
140
|
+
const providers = collectRuntimeProviders(manifest);
|
|
141
|
+
const resolvable = missing.filter((r) => providers.has(r));
|
|
142
|
+
const destRuntimes = resolvable.length ? listRuntimes(cli) : [];
|
|
143
|
+
const unresolved = [];
|
|
144
|
+
for (const srcId of missing) {
|
|
145
|
+
const provider = providers.get(srcId);
|
|
146
|
+
const matches = provider ? destRuntimes.filter((r) => r.provider === provider) : [];
|
|
147
|
+
if (matches.length === 1) effective.set(srcId, matches[0].id);
|
|
148
|
+
else unresolved.push({ srcId, provider, matchCount: matches.length });
|
|
149
|
+
}
|
|
150
|
+
return { effective, unresolved };
|
|
151
|
+
}
|
|
152
|
+
|
|
91
153
|
export function importBundle({ cli, dir, runtimeMap, fs = nodeFs }) {
|
|
92
154
|
const manifest = JSON.parse(fs.readFileSync(`${dir}/manifest.json`, "utf8"));
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
155
|
+
const { effective, unresolved } = resolveRuntimeMap({ cli, manifest, runtimeMap });
|
|
156
|
+
if (unresolved.length) {
|
|
157
|
+
const detail = unresolved.map(({ srcId, provider, matchCount }) => provider
|
|
158
|
+
? `${srcId} (provider "${provider}": ${matchCount} matching runtimes in destination, expected exactly 1)`
|
|
159
|
+
: `${srcId} (no provider recorded)`).join(", ");
|
|
160
|
+
throw new Error(`Unmapped runtimes: ${detail} — pass --runtime-map, aborting before any write`);
|
|
161
|
+
}
|
|
95
162
|
|
|
96
163
|
const skillRes = importSkills({ cli, manifest, dir, fs });
|
|
97
|
-
const agentRes = importAgents({ cli, manifest, dir, skillIdMap: skillRes.idMap, runtimeMap, fs });
|
|
164
|
+
const agentRes = importAgents({ cli, manifest, dir, skillIdMap: skillRes.idMap, runtimeMap: effective, fs });
|
|
98
165
|
let squadRes = { newId: null, created: 0, updated: 0 };
|
|
99
166
|
if (manifest.squads?.length) squadRes = importSquad({ cli, squad: manifest.squads[0], agentIdMap: agentRes.idMap });
|
|
100
167
|
|
|
@@ -12,25 +12,24 @@ Import a local Multica bundle (produced by the export skill) into a target works
|
|
|
12
12
|
|
|
13
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
14
|
|
|
15
|
-
## Step 2 —
|
|
15
|
+
## Step 2 — Run the import (auto-mapping first)
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Each exported agent record carries its source runtime's `provider` (e.g. `claude`, `opencode`) alongside its ID. The import script auto-maps a source runtime to the target workspace's runtime when there is **exactly one** runtime of that provider there — no manual mapping needed in the common case. Try the import without `--runtime-map` first:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
20
|
+
node "${CLAUDE_PLUGIN_ROOT}/scripts/multica-import.mjs" \
|
|
21
|
+
--dir <folder> \
|
|
22
|
+
--workspace <workspace-name>
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
List runtimes available in the target workspace:
|
|
25
|
+
If it aborts with `Unmapped runtimes: ...` (0 or 2+ runtimes share that provider in the target workspace, or the bundle predates provider capture), resolve manually:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
|
|
28
|
+
cat <folder>/manifest.json # note each distinct sourceRuntimeId
|
|
29
|
+
multica runtime list --output json # list target workspace runtimes
|
|
29
30
|
```
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
## Step 3 — Run the import
|
|
32
|
+
Ask the user to pick a matching target runtime by name or ID for each unmapped `sourceRuntimeId`, then re-run with an explicit map (explicit entries always take precedence over auto-mapping):
|
|
34
33
|
|
|
35
34
|
```bash
|
|
36
35
|
node "${CLAUDE_PLUGIN_ROOT}/scripts/multica-import.mjs" \
|
|
@@ -39,7 +38,7 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/multica-import.mjs" \
|
|
|
39
38
|
--runtime-map <srcId1=dstId1,srcId2=dstId2,...>
|
|
40
39
|
```
|
|
41
40
|
|
|
42
|
-
## Step
|
|
41
|
+
## Step 3 — Report results
|
|
43
42
|
|
|
44
43
|
Parse the JSON output and report:
|
|
45
44
|
|
|
@@ -18,29 +18,32 @@ sync <type> <name> from <src-ws> to <dest-ws>
|
|
|
18
18
|
|
|
19
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
20
|
|
|
21
|
-
## Step 2 —
|
|
21
|
+
## Step 2 — Run the sync (auto-mapping first)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
For agents and squads, each exported agent record carries its source runtime's `provider` (e.g. `claude`, `opencode`) alongside its ID. The sync script auto-maps a source runtime to the destination workspace's runtime when there is **exactly one** runtime of that provider there — no manual mapping needed in the common case. For skills (which have no runtime dependency), an empty runtime map is always acceptable. Try the sync without `--runtime-map` first:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
multica
|
|
26
|
+
node "${CLAUDE_PLUGIN_ROOT}/scripts/multica-sync.mjs" \
|
|
27
|
+
<type> <name> from <src-ws> <dest-ws>
|
|
27
28
|
```
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
If it aborts with `Unmapped runtimes: ...` (0 or 2+ runtimes share that provider in the destination workspace), resolve manually:
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
```bash
|
|
33
|
+
multica runtime list --workspace-id <dest-ws-id> --output json # list destination workspace runtimes
|
|
34
|
+
```
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
Ask the user to select a matching target runtime by name or ID for each unmapped `sourceRuntimeId`, then re-run with an explicit map (explicit entries always take precedence over auto-mapping):
|
|
34
37
|
|
|
35
38
|
```bash
|
|
36
39
|
node "${CLAUDE_PLUGIN_ROOT}/scripts/multica-sync.mjs" \
|
|
37
40
|
<type> <name> from <src-ws> <dest-ws> \
|
|
38
|
-
|
|
41
|
+
--runtime-map <srcId1=dstId1,srcId2=dstId2,...>
|
|
39
42
|
```
|
|
40
43
|
|
|
41
44
|
The script exports to a temporary directory, imports into the destination workspace, then cleans up the temporary files automatically.
|
|
42
45
|
|
|
43
|
-
## Step
|
|
46
|
+
## Step 3 — Report results
|
|
44
47
|
|
|
45
48
|
Parse the JSON output and report:
|
|
46
49
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plugin-validator",
|
|
3
3
|
"displayName": "Plugin Validator",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.35",
|
|
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.35",
|
|
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"
|