@drunkcoding/agents-and-skills 0.0.34 → 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.
@@ -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.34",
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.34",
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.34",
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.34",
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.34",
76
+ "version": "0.0.35",
77
77
  "category": "workflow",
78
78
  "keywords": [
79
79
  "multica",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drunkcoding/agents-and-skills",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
4
4
  "description": "Personal collection of Claude Code skills and agents, installable via `npx skills`.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "html-effectiveness",
3
3
  "displayName": "HTML Effectiveness Reports",
4
- "version": "0.0.34",
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"
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "multica-tool",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
4
4
  "description": "Export, import, and sync Multica skills, agents, and squads between workspaces via the multica CLI."
5
5
  }
@@ -1,6 +1,6 @@
1
1
  import * as nodeFs from "node:fs";
2
2
  import { dirname } from "node:path";
3
- import { slugify, getSkill, getAgent, getSquad, getSquadMembers, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
3
+ import { slugify, getSkill, getAgent, getSquad, getSquadMembers, listRuntimes, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
4
4
 
5
5
  const nonEmpty = (v) => v && typeof v === "object" && Object.keys(v).length > 0;
6
6
 
@@ -24,7 +24,7 @@ export function buildManifest({ scope, sourceWorkspaceId, skills, agents, squad
24
24
  scope,
25
25
  sourceWorkspaceId,
26
26
  skills: [...seenSkills.values()].map((s) => ({ name: s.name, dir: `skills/${slugify(s.name)}`, sourceId: s.sourceId })),
27
- agents: [...seenAgents.values()].map((a) => ({ name: a.name, file: `agents/${slugify(a.name)}.json`, sourceRuntimeId: a.sourceRuntimeId, skillNames: a.skillNames, hadSecrets: !!a.hadSecrets })),
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
28
  squads: squad ? [{ name: squad.name, file: `squads/${slugify(squad.name)}.json`, description: squad.description ?? "", instructions: squad.instructions ?? "", leaderName: squad.leaderName, members: squad.members }] : [],
29
29
  };
30
30
  }
@@ -37,9 +37,10 @@ function collectSkill(cli, id, skills) {
37
37
 
38
38
  // Keyed by agent id (so squad leaderId/memberId resolve to names). Stores the
39
39
  // normalized agent, its redaction result, and its skill names.
40
- function collectAgent(cli, id, agentsById, skills) {
40
+ function collectAgent(cli, id, agentsById, skills, providerById) {
41
41
  if (agentsById.has(id)) return agentsById.get(id);
42
42
  const a = getAgent(cli, id);
43
+ a.sourceRuntimeProvider = providerById.get(a.runtimeId) ?? null;
43
44
  const skillNames = a.skills.map((sk) => collectSkill(cli, sk.id, skills));
44
45
  const red = redactAgent(a);
45
46
  const entry = { raw: a, red, skillNames };
@@ -51,14 +52,18 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
51
52
  const skills = new Map(); // name -> normalized skill
52
53
  const agentsById = new Map(); // id -> { raw, red, skillNames }
53
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]));
54
59
 
55
60
  if (scope === "skill") collectSkill(cli, ids.skillId, skills);
56
- if (scope === "agent") collectAgent(cli, ids.agentId, agentsById, skills);
61
+ if (scope === "agent") collectAgent(cli, ids.agentId, agentsById, skills, getProviderById());
57
62
  if (scope === "squad") {
58
63
  const sq = getSquad(cli, ids.squadId);
59
64
  const members = getSquadMembers(cli, ids.squadId).filter((m) => m.memberType === "agent");
60
- for (const m of members) collectAgent(cli, m.memberId, agentsById, skills);
61
- 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());
62
67
  const nameOf = (id) => agentsById.get(id)?.raw.name;
63
68
  squad = {
64
69
  name: sq.name,
@@ -72,7 +77,7 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
72
77
  const manifest = buildManifest({
73
78
  scope, sourceWorkspaceId,
74
79
  skills: [...skills.values()].map((s) => ({ name: s.name, sourceId: s.id })),
75
- 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 })),
76
81
  squad,
77
82
  });
78
83
 
@@ -1,5 +1,5 @@
1
1
  import * as nodeFs from "node:fs";
2
- import { listSkills, listAgents, listSquads, getSquadMembers, findByName, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
2
+ import { listSkills, listAgents, listSquads, listRuntimes, getSquadMembers, findByName, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
3
3
 
4
4
  // Relative paths of every file under root (recursing into subdirs like scripts/).
5
5
  function walkSkillFiles(fs, root, rel = "") {
@@ -118,13 +118,50 @@ export function collectSourceRuntimes(manifest) {
118
118
  return [...new Set((manifest.agents ?? []).map((a) => a.sourceRuntimeId).filter(Boolean))];
119
119
  }
120
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
+
121
153
  export function importBundle({ cli, dir, runtimeMap, fs = nodeFs }) {
122
154
  const manifest = JSON.parse(fs.readFileSync(`${dir}/manifest.json`, "utf8"));
123
- const missing = collectSourceRuntimes(manifest).filter((r) => !runtimeMap.has(r));
124
- if (missing.length) throw new Error(`Unmapped runtimes: ${missing.join(", ")} — aborting before any write`);
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
+ }
125
162
 
126
163
  const skillRes = importSkills({ cli, manifest, dir, fs });
127
- const agentRes = importAgents({ cli, manifest, dir, skillIdMap: skillRes.idMap, runtimeMap, fs });
164
+ const agentRes = importAgents({ cli, manifest, dir, skillIdMap: skillRes.idMap, runtimeMap: effective, fs });
128
165
  let squadRes = { newId: null, created: 0, updated: 0 };
129
166
  if (manifest.squads?.length) squadRes = importSquad({ cli, squad: manifest.squads[0], agentIdMap: agentRes.idMap });
130
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 — Plan pass: read the bundle and collect unmapped runtimes
15
+ ## Step 2 — Run the import (auto-mapping first)
16
16
 
17
- Read the manifest to discover which source runtimes are referenced:
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
- cat <folder>/manifest.json
20
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/multica-import.mjs" \
21
+ --dir <folder> \
22
+ --workspace <workspace-name>
21
23
  ```
22
24
 
23
- Collect each distinct `sourceRuntimeId` from the `agents` array.
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
- multica runtime list --output json
28
+ cat <folder>/manifest.json # note each distinct sourceRuntimeId
29
+ multica runtime list --output json # list target workspace runtimes
29
30
  ```
30
31
 
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
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 4 — Report results
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 — Build the runtime map
21
+ ## Step 2 — Run the sync (auto-mapping first)
22
22
 
23
- List runtimes available in the destination workspace:
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 runtime list --output json
26
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/multica-sync.mjs" \
27
+ <type> <name> from <src-ws> <dest-ws>
27
28
  ```
28
29
 
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
+ If it aborts with `Unmapped runtimes: ...` (0 or 2+ runtimes share that provider in the destination workspace), resolve manually:
30
31
 
31
- For skills (which have no runtime dependency), an empty runtime map is acceptable.
32
+ ```bash
33
+ multica runtime list --workspace-id <dest-ws-id> --output json # list destination workspace runtimes
34
+ ```
32
35
 
33
- ## Step 3 Run the sync
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
- [--runtime-map <srcId1=dstId1,srcId2=dstId2,...>]
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 4 — Report results
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.34",
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.34",
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"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tech-graph",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
4
4
  "description": "Step-by-step wizard for generating technical diagrams as SVG+PNG.",
5
5
  "author": {
6
6
  "name": "steven"