@drunkcoding/agents-and-skills 0.0.45 → 0.0.46
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 +2 -47
- package/README.md +3 -6
- package/package.json +4 -1
- package/plugins/multica-tool/.claude-plugin/plugin.json +1 -1
- package/plugins/multica-tool/scripts/lib.mjs +53 -4
- package/plugins/multica-tool/scripts/multica-export.mjs +135 -32
- package/plugins/multica-tool/scripts/multica-import.mjs +192 -17
- package/plugins/multica-tool/skills/export/SKILL.md +84 -14
- package/plugins/multica-tool/skills/import/SKILL.md +22 -7
- package/plugins/multica-tool/skills/sync/SKILL.md +1 -1
- package/plugins/plugin-validator/.claude-plugin/plugin.json +1 -1
- package/plugins/html-effectiveness/.claude-plugin/plugin.json +0 -17
- package/plugins/html-effectiveness/README.md +0 -28
- package/plugins/html-effectiveness/agents/report-builder.md +0 -66
- package/plugins/html-effectiveness/assets/base.css +0 -51
- package/plugins/html-effectiveness/assets/base.js +0 -11
- package/plugins/html-effectiveness/assets/charts.js +0 -1
- package/plugins/html-effectiveness/assets/components.css +0 -10
- package/plugins/html-effectiveness/commands/html-report.md +0 -13
- package/plugins/html-effectiveness/docs/template-gallery.md +0 -28
- package/plugins/html-effectiveness/package.json +0 -6
- package/plugins/html-effectiveness/scripts/_tmp.js +0 -37
- package/plugins/html-effectiveness/scripts/catalog.js +0 -47
- package/plugins/html-effectiveness/scripts/extract.js +0 -104
- package/plugins/html-effectiveness/scripts/mustache.js +0 -90
- package/plugins/html-effectiveness/scripts/render.js +0 -176
- package/plugins/html-effectiveness/skills/html-effectiveness/SKILL.md +0 -94
- package/plugins/html-effectiveness/templates/01-exploration-code-approaches.html.tmpl +0 -400
- package/plugins/html-effectiveness/templates/02-exploration-visual-designs.html.tmpl +0 -456
- package/plugins/html-effectiveness/templates/03-code-review-pr.html.tmpl +0 -581
- package/plugins/html-effectiveness/templates/04-code-understanding.html.tmpl +0 -443
- package/plugins/html-effectiveness/templates/05-design-system.html.tmpl +0 -578
- package/plugins/html-effectiveness/templates/06-component-variants.html.tmpl +0 -557
- package/plugins/html-effectiveness/templates/07-prototype-animation.html.tmpl +0 -417
- package/plugins/html-effectiveness/templates/08-prototype-interaction.html.tmpl +0 -363
- package/plugins/html-effectiveness/templates/09-slide-deck.html.tmpl +0 -535
- package/plugins/html-effectiveness/templates/10-svg-illustrations.html.tmpl +0 -444
- package/plugins/html-effectiveness/templates/11-status-report.html.tmpl +0 -152
- package/plugins/html-effectiveness/templates/12-incident-report.html.tmpl +0 -547
- package/plugins/html-effectiveness/templates/13-flowchart-diagram.html.tmpl +0 -361
- package/plugins/html-effectiveness/templates/14-research-feature-explainer.html.tmpl +0 -348
- package/plugins/html-effectiveness/templates/15-research-concept-explainer.html.tmpl +0 -334
- package/plugins/html-effectiveness/templates/16-implementation-plan.html.tmpl +0 -657
- package/plugins/html-effectiveness/templates/17-pr-writeup.html.tmpl +0 -553
- package/plugins/html-effectiveness/templates/18-editor-triage-board.html.tmpl +0 -541
- package/plugins/html-effectiveness/templates/19-editor-feature-flags.html.tmpl +0 -627
- package/plugins/html-effectiveness/templates/20-editor-prompt-tuner.html.tmpl +0 -687
- package/plugins/html-effectiveness/templates/manifest.json +0 -441
- package/plugins/team-share/.claude-plugin/plugin.json +0 -18
- package/plugins/team-share/README.md +0 -46
- package/plugins/team-share/agents/team-share.md +0 -53
- package/plugins/team-share/commands/team-share.md +0 -4
- package/plugins/team-share/skills/claude-config/SKILL.md +0 -143
- package/plugins/team-share/skills/codegraph-setup/SKILL.md +0 -81
- package/plugins/team-share/skills/understand-setup/SKILL.md +0 -115
- package/plugins/tech-graph/.claude-plugin/plugin.json +0 -17
- package/plugins/tech-graph/README.md +0 -66
- package/plugins/tech-graph/agents/tech-graph.md +0 -97
- package/plugins/tech-graph/commands/tech-graph.md +0 -13
- package/plugins/tech-graph/scripts/check-deps.sh +0 -55
- package/plugins/tech-graph/skills/tech-graph/LICENSE +0 -21
- package/plugins/tech-graph/skills/tech-graph/README.md +0 -555
- package/plugins/tech-graph/skills/tech-graph/README.zh.md +0 -514
- package/plugins/tech-graph/skills/tech-graph/SKILL.md +0 -263
- package/plugins/tech-graph/skills/tech-graph/agents/openai.yaml +0 -4
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style1-flat.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style2-dark.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style3-blueprint.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style4-notion.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style5-glass.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style6-claude.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style7-openai.png +0 -0
- package/plugins/tech-graph/skills/tech-graph/fixtures/agent-memory-types-style4.json +0 -181
- package/plugins/tech-graph/skills/tech-graph/fixtures/api-flow-style7.json +0 -40
- package/plugins/tech-graph/skills/tech-graph/fixtures/mem0-style1.json +0 -297
- package/plugins/tech-graph/skills/tech-graph/fixtures/microservices-style3.json +0 -64
- package/plugins/tech-graph/skills/tech-graph/fixtures/multi-agent-style5.json +0 -45
- package/plugins/tech-graph/skills/tech-graph/fixtures/system-architecture-style6.json +0 -48
- package/plugins/tech-graph/skills/tech-graph/fixtures/tool-call-style2.json +0 -182
- package/plugins/tech-graph/skills/tech-graph/package.json +0 -42
- package/plugins/tech-graph/skills/tech-graph/references/diagram-types.md +0 -171
- package/plugins/tech-graph/skills/tech-graph/references/icons.md +0 -406
- package/plugins/tech-graph/skills/tech-graph/references/style-1-flat-icon.md +0 -108
- package/plugins/tech-graph/skills/tech-graph/references/style-2-dark-terminal.md +0 -107
- package/plugins/tech-graph/skills/tech-graph/references/style-3-blueprint.md +0 -113
- package/plugins/tech-graph/skills/tech-graph/references/style-4-notion-clean.md +0 -95
- package/plugins/tech-graph/skills/tech-graph/references/style-5-glassmorphism.md +0 -125
- package/plugins/tech-graph/skills/tech-graph/references/style-6-claude-official.md +0 -209
- package/plugins/tech-graph/skills/tech-graph/references/style-7-openai.md +0 -215
- package/plugins/tech-graph/skills/tech-graph/references/style-diagram-matrix.md +0 -135
- package/plugins/tech-graph/skills/tech-graph/references/svg-layout-best-practices.md +0 -100
- package/plugins/tech-graph/skills/tech-graph/references/svg-to-png.md +0 -115
- package/plugins/tech-graph/skills/tech-graph/scripts/README.md +0 -269
- package/plugins/tech-graph/skills/tech-graph/scripts/generate-diagram.sh +0 -181
- package/plugins/tech-graph/skills/tech-graph/scripts/generate-from-template.py +0 -1587
- package/plugins/tech-graph/skills/tech-graph/scripts/test-all-styles.sh +0 -143
- package/plugins/tech-graph/skills/tech-graph/scripts/validate-svg.sh +0 -306
- package/plugins/tech-graph/skills/tech-graph/templates/agent-architecture.svg +0 -28
- package/plugins/tech-graph/skills/tech-graph/templates/architecture.svg +0 -23
- package/plugins/tech-graph/skills/tech-graph/templates/comparison-matrix.svg +0 -14
- package/plugins/tech-graph/skills/tech-graph/templates/data-flow.svg +0 -28
- package/plugins/tech-graph/skills/tech-graph/templates/er-diagram.svg +0 -21
- package/plugins/tech-graph/skills/tech-graph/templates/flowchart.svg +0 -21
- package/plugins/tech-graph/skills/tech-graph/templates/sequence.svg +0 -20
- package/plugins/tech-graph/skills/tech-graph/templates/state-machine.svg +0 -20
- package/plugins/tech-graph/skills/tech-graph/templates/timeline.svg +0 -19
- package/plugins/tech-graph/skills/tech-graph/templates/use-case.svg +0 -21
|
@@ -8,40 +8,11 @@
|
|
|
8
8
|
"description": "Personal agents and skills marketplace"
|
|
9
9
|
},
|
|
10
10
|
"plugins": [
|
|
11
|
-
{
|
|
12
|
-
"name": "tech-graph",
|
|
13
|
-
"source": "./plugins/tech-graph",
|
|
14
|
-
"description": "6-step wizard for technical diagrams (SVG/PNG) via fireworks-tech-graph",
|
|
15
|
-
"version": "0.0.45",
|
|
16
|
-
"category": "diagram",
|
|
17
|
-
"keywords": [
|
|
18
|
-
"diagram",
|
|
19
|
-
"svg",
|
|
20
|
-
"architecture",
|
|
21
|
-
"uml",
|
|
22
|
-
"flowchart"
|
|
23
|
-
]
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"name": "html-effectiveness",
|
|
27
|
-
"source": "./plugins/html-effectiveness",
|
|
28
|
-
"description": "Generate self-contained interactive HTML reports from 20 upstream templates via a conversational agent.",
|
|
29
|
-
"version": "0.0.45",
|
|
30
|
-
"category": "reports",
|
|
31
|
-
"keywords": [
|
|
32
|
-
"html",
|
|
33
|
-
"report",
|
|
34
|
-
"status",
|
|
35
|
-
"incident",
|
|
36
|
-
"slide-deck",
|
|
37
|
-
"decision-matrix"
|
|
38
|
-
]
|
|
39
|
-
},
|
|
40
11
|
{
|
|
41
12
|
"name": "plugin-validator",
|
|
42
13
|
"source": "./plugins/plugin-validator",
|
|
43
14
|
"description": "Orchestrated validator for Claude Code plugins — validates skills, agents, commands, and hooks across every plugin under plugins/**.",
|
|
44
|
-
"version": "0.0.
|
|
15
|
+
"version": "0.0.46",
|
|
45
16
|
"category": "tooling",
|
|
46
17
|
"keywords": [
|
|
47
18
|
"validation",
|
|
@@ -53,27 +24,11 @@
|
|
|
53
24
|
"hooks"
|
|
54
25
|
]
|
|
55
26
|
},
|
|
56
|
-
{
|
|
57
|
-
"name": "team-share",
|
|
58
|
-
"source": "./plugins/team-share",
|
|
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.45",
|
|
61
|
-
"category": "tooling",
|
|
62
|
-
"keywords": [
|
|
63
|
-
"onboarding",
|
|
64
|
-
"team",
|
|
65
|
-
"claude",
|
|
66
|
-
"settings",
|
|
67
|
-
"codegraph",
|
|
68
|
-
"understand-anything",
|
|
69
|
-
"git-lfs"
|
|
70
|
-
]
|
|
71
|
-
},
|
|
72
27
|
{
|
|
73
28
|
"name": "multica-tool",
|
|
74
29
|
"source": "./plugins/multica-tool",
|
|
75
30
|
"description": "Export, import, and sync Multica skills, agents, and squads between workspaces.",
|
|
76
|
-
"version": "0.0.
|
|
31
|
+
"version": "0.0.46",
|
|
77
32
|
"category": "workflow",
|
|
78
33
|
"keywords": [
|
|
79
34
|
"multica",
|
package/README.md
CHANGED
|
@@ -8,11 +8,8 @@ Published on npm as [`@drunkcoding/agents-and-skills`](https://www.npmjs.com/pac
|
|
|
8
8
|
|
|
9
9
|
| Plugin | Description |
|
|
10
10
|
|--------|-------------|
|
|
11
|
-
| [`tech-graph`](plugins/tech-graph) | 6-step wizard for technical diagrams (SVG + PNG). |
|
|
12
|
-
| [`html-effectiveness`](plugins/html-effectiveness) | Conversational agent that generates self-contained interactive HTML reports from 20 templates. |
|
|
13
11
|
| [`team-superpower`](plugins/team-superpower) | Shape-adaptive engineering team running the Superpowers skill chain — up to 8 roles (designer, planner, software-architect, security-engineer, backend-developer, frontend-developer, qa-engineer, reviewer); spawns 7 or 8 depending on stack (`full-stack` / `be-only` / `fe-only`) declared in `CLAUDE.md`. Test/build commands, contract publish + sync, security checklist, and CI gate before merge are all driven by the project's `CLAUDE.md` `team-superpower` block. |
|
|
14
12
|
| [`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
|
-
| [`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
13
|
| [`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
14
|
| [`multica-tool`](plugins/multica-tool) | Export, import, and sync Multica skills, agents, and squads between workspaces. |
|
|
18
15
|
|
|
@@ -52,8 +49,8 @@ Add the marketplace once:
|
|
|
52
49
|
Then install any plugin individually:
|
|
53
50
|
|
|
54
51
|
```text
|
|
55
|
-
/plugin install
|
|
56
|
-
/plugin install
|
|
52
|
+
/plugin install plugin-validator@drunkcoding
|
|
53
|
+
/plugin install multica-tool@drunkcoding --scope local
|
|
57
54
|
```
|
|
58
55
|
|
|
59
56
|
Reload after install:
|
|
@@ -69,7 +66,7 @@ Only the plugin you install loads; others stay dormant.
|
|
|
69
66
|
Install into a project's `.claude/` instead of your user profile:
|
|
70
67
|
|
|
71
68
|
```text
|
|
72
|
-
/plugin install
|
|
69
|
+
/plugin install plugin-validator@drunkcoding --scope project
|
|
73
70
|
```
|
|
74
71
|
|
|
75
72
|
#### Manage installed plugins
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drunkcoding/agents-and-skills",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.46",
|
|
4
4
|
"description": "Personal collection of Claude Code skills and agents, installable via `npx skills`.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
"README.md",
|
|
27
27
|
"LICENSE"
|
|
28
28
|
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build:opencode": "node plugins/multica-tool/scripts/build-dist.mjs"
|
|
31
|
+
},
|
|
29
32
|
"private": false,
|
|
30
33
|
"publishConfig": {
|
|
31
34
|
"access": "public"
|
|
@@ -59,6 +59,21 @@ export const listAgentsIncludingArchived = (cli) => cli.json(["agent", "list", "
|
|
|
59
59
|
export const listSquads = (cli) => cli.json(["squad", "list"]);
|
|
60
60
|
export const listWorkspaceMembers = (cli) => cli.json(["workspace", "member", "list"]);
|
|
61
61
|
|
|
62
|
+
// --- Workspace MCP server library ------------------------------------------
|
|
63
|
+
// `workspace mcp list` returns only id/name/transport — the server entry JSON
|
|
64
|
+
// (command/args/env, and any token inside it) is write-only: `workspace mcp
|
|
65
|
+
// add/update` take it, nothing reads it back. So the library travels as a
|
|
66
|
+
// NAME + TRANSPORT roster only, and import reports each entry as needing its
|
|
67
|
+
// config re-entered by hand rather than pretending it round-trips.
|
|
68
|
+
export const listWorkspaceMcpServers = (cli) =>
|
|
69
|
+
(cli.json(["workspace", "mcp", "list"]) ?? []).map((s) => ({ id: s.id, name: s.name, transport: s.transport }));
|
|
70
|
+
|
|
71
|
+
// Which workspace MCP servers an agent uses, and whether each is on. Keyed by
|
|
72
|
+
// NAME (the server id is re-minted per workspace); `agent mcp add/enable/disable`
|
|
73
|
+
// take a server id, which import resolves from the destination library by name.
|
|
74
|
+
export const listAgentMcpServers = (cli, agentId) =>
|
|
75
|
+
(cli.json(["agent", "mcp", "list", agentId]) ?? []).map((s) => ({ name: s.name, enabled: !!s.enabled }));
|
|
76
|
+
|
|
62
77
|
// Get-wrappers: the ONLY place that knows the raw CLI field names — an
|
|
63
78
|
// explicit allow-list, so unexpected/internal CLI fields never leak into a
|
|
64
79
|
// bundle. Field names mirror the CLI's own snake_case; nothing is renamed.
|
|
@@ -137,16 +152,19 @@ export const listAutopilots = (cli) => cli.json(["autopilot", "list"]).autopilot
|
|
|
137
152
|
|
|
138
153
|
// `autopilot get` wraps the record as {autopilot, collaborators, triggers} — only
|
|
139
154
|
// autopilot + triggers are portable; collaborators/can_write/can_manage_access are
|
|
140
|
-
// caller-relative and never bundled. `priority` is
|
|
141
|
-
//
|
|
142
|
-
//
|
|
155
|
+
// caller-relative and never bundled. `priority` is deliberately absent: the API
|
|
156
|
+
// never returns it on read, and as of multica 0.4.36 `autopilot create`/`update`
|
|
157
|
+
// no longer accept `--priority` either — so it can be neither captured nor
|
|
158
|
+
// restored. Import reports every autopilot under `priorityNotCaptured`.
|
|
143
159
|
export function getAutopilot(cli, id) {
|
|
144
160
|
const r = cli.json(["autopilot", "get", id]);
|
|
145
161
|
const a = r.autopilot;
|
|
146
162
|
return {
|
|
147
163
|
id: a.id, title: a.title, description: a.description ?? "",
|
|
164
|
+
// Source status (active|paused). Import never auto-activates — it is captured
|
|
165
|
+
// so the operator can be told which autopilots were live at the source.
|
|
166
|
+
status: a.status ?? null,
|
|
148
167
|
execution_mode: a.execution_mode, issue_title_template: a.issue_title_template ?? null,
|
|
149
|
-
priority: a.priority ?? null,
|
|
150
168
|
project_id: a.project_id ?? null,
|
|
151
169
|
assignee_id: a.assignee_id, assignee_type: a.assignee_type,
|
|
152
170
|
subscribers: (a.subscribers ?? []).map((s) => ({ user_id: s.user_id, user_type: s.user_type })),
|
|
@@ -156,3 +174,34 @@ export function getAutopilot(cli, id) {
|
|
|
156
174
|
})),
|
|
157
175
|
};
|
|
158
176
|
}
|
|
177
|
+
|
|
178
|
+
// --- Workspace-scoped issue taxonomy (multica 0.4.36) -----------------------
|
|
179
|
+
// Labels and custom properties are defined per WORKSPACE, not per project — the
|
|
180
|
+
// CLI has no project-scoped variant of either. They are bundled with project
|
|
181
|
+
// exports (and `all`) so a migrated project lands somewhere its issues can
|
|
182
|
+
// actually be labelled and filled in.
|
|
183
|
+
|
|
184
|
+
// `id` is kept: `label update` addresses a label by id only.
|
|
185
|
+
// `resource_type`/`usage_count`/timestamps are server-owned with no CLI setter.
|
|
186
|
+
// `description` IS captured, but `label create`/`update` expose no
|
|
187
|
+
// `--description` flag — import reports it as unrestorable rather than dropping
|
|
188
|
+
// it silently.
|
|
189
|
+
export const listLabels = (cli) =>
|
|
190
|
+
(cli.json(["label", "list"]) ?? []).map((l) => ({
|
|
191
|
+
id: l.id, name: l.name, color: l.color, description: l.description ?? "",
|
|
192
|
+
}));
|
|
193
|
+
|
|
194
|
+
// Archived definitions included so an archived property round-trips as archived
|
|
195
|
+
// instead of silently reappearing in every picker at the destination.
|
|
196
|
+
// No `id`: `property get/update/archive/unarchive` all accept `<id-or-name>`,
|
|
197
|
+
// and names are what issue values reference, so name is the portable key.
|
|
198
|
+
// `position`/`usage_count` are server-assigned and have no CLI setter.
|
|
199
|
+
export const listProperties = (cli) =>
|
|
200
|
+
(cli.json(["property", "list", "--include-archived"]) ?? []).map((p) => ({
|
|
201
|
+
name: p.name, type: p.type, description: p.description ?? "", icon: p.icon ?? "",
|
|
202
|
+
archived: !!p.archived,
|
|
203
|
+
// Only select/multi_select carry options; every other type reports null.
|
|
204
|
+
// Option ids are re-minted at the destination — `property update` re-matches
|
|
205
|
+
// existing options BY NAME, so name+color is the whole portable payload.
|
|
206
|
+
options: (p.config?.options ?? []).map((o) => ({ name: o.name, color: o.color ?? null })),
|
|
207
|
+
}));
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import * as nodeFs from "node:fs";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
|
-
import { slugify, getSkill, getAgent, getAgentCustomEnv, getSquad, getSquadMembers, listRuntimes, listSkills, listAgents, listAgentsIncludingArchived, listSquads, listProjects, getProject, getProjectResources, listWorkspaceMembers, getAutopilot, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
|
|
4
|
+
import { slugify, getSkill, getAgent, getAgentCustomEnv, getSquad, getSquadMembers, listRuntimes, listSkills, listAgents, listAgentsIncludingArchived, listSquads, listProjects, getProject, getProjectResources, listWorkspaceMembers, listAutopilots, getAutopilot, listLabels, listProperties, listWorkspaceMcpServers, listAgentMcpServers, makeCli, realExec, requireAuth, resolveWorkspaceId } from "./lib.mjs";
|
|
5
|
+
|
|
6
|
+
// Export levels for a WHOLE-WORKSPACE export, lowest tier first. A level pulls
|
|
7
|
+
// in its own tier plus every tier below it, so `project` is the full workspace
|
|
8
|
+
// and `skill` is skills alone. Single-resource exports (`--scope <type> --id`)
|
|
9
|
+
// ignore this and always bundle what that one resource needs.
|
|
10
|
+
export const LEVELS = ["skill", "agent", "squad", "project"];
|
|
11
|
+
export const levelRank = (level) => LEVELS.indexOf(level);
|
|
12
|
+
export const levelAtLeast = (level, tier) => levelRank(level) >= levelRank(tier);
|
|
5
13
|
|
|
6
14
|
const nonEmpty = (v) => v && typeof v === "object" && Object.keys(v).length > 0;
|
|
7
15
|
|
|
@@ -70,7 +78,7 @@ export function redactAgent(a) {
|
|
|
70
78
|
};
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
export function buildManifest({ scope, sourceWorkspaceId, skills, agents, squads, projects, autopilots }) {
|
|
81
|
+
export function buildManifest({ scope, level, sourceWorkspaceId, skills, agents, squads, projects, autopilots, labels, properties, mcpServers }) {
|
|
74
82
|
const seenSkills = new Map();
|
|
75
83
|
for (const s of skills) if (!seenSkills.has(s.name)) seenSkills.set(s.name, s);
|
|
76
84
|
const seenAgents = new Map();
|
|
@@ -80,6 +88,8 @@ export function buildManifest({ scope, sourceWorkspaceId, skills, agents, squads
|
|
|
80
88
|
return {
|
|
81
89
|
version: "1",
|
|
82
90
|
scope,
|
|
91
|
+
// null for a single-resource export; the requested tier for a workspace export.
|
|
92
|
+
level: level ?? null,
|
|
83
93
|
source_workspace_id: sourceWorkspaceId,
|
|
84
94
|
skills: [...seenSkills.values()].map((s) => ({ name: s.name, dir: `skills/${slugify(s.name)}`, source_id: s.source_id })),
|
|
85
95
|
agents: [...seenAgents.values()].map((a) => ({ name: a.name, file: `agents/${slugify(a.name)}.json`, source_id: a.source_id, source_runtime_id: a.source_runtime_id, source_runtime_provider: a.source_runtime_provider ?? null, skill_names: a.skill_names, had_secrets: !!a.had_secrets })),
|
|
@@ -101,6 +111,30 @@ export function buildManifest({ scope, sourceWorkspaceId, skills, agents, squads
|
|
|
101
111
|
assignee_type: ap.assignee_type, assignee_name: ap.assignee_name,
|
|
102
112
|
project_title: ap.project_title, had_webhook_trigger: ap.had_webhook_trigger,
|
|
103
113
|
})),
|
|
114
|
+
// Labels, properties and the workspace MCP roster are workspace-wide sets
|
|
115
|
+
// with no per-resource file to point at, so each gets its own flat folder
|
|
116
|
+
// (labels/, properties/, mcp/) and the manifest carries only a pointer plus
|
|
117
|
+
// a count. Import reads the pointer, falling back to a legacy bundle's
|
|
118
|
+
// inline array. `id` is dropped from labels: both labels and properties are
|
|
119
|
+
// matched by NAME at the destination.
|
|
120
|
+
labels_file: (labels ?? []).length ? "labels/labels.json" : null,
|
|
121
|
+
labels_count: (labels ?? []).length,
|
|
122
|
+
properties_file: (properties ?? []).length ? "properties/properties.json" : null,
|
|
123
|
+
properties_count: (properties ?? []).length,
|
|
124
|
+
mcp_servers_file: (mcpServers ?? []).length ? "mcp/servers.json" : null,
|
|
125
|
+
mcp_servers_count: (mcpServers ?? []).length,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// The payloads written to labels/, properties/ and mcp/. Kept next to
|
|
130
|
+
// buildManifest so the manifest pointers and the files they name can't drift.
|
|
131
|
+
export function buildTaxonomyFiles({ labels, properties, mcpServers }) {
|
|
132
|
+
return {
|
|
133
|
+
"labels/labels.json": (labels ?? []).map(({ id, ...rest }) => rest),
|
|
134
|
+
"properties/properties.json": properties ?? [],
|
|
135
|
+
// The server entry JSON is not readable via the CLI — only name/transport
|
|
136
|
+
// travel, so import re-creates the roster as a to-do list, not a copy.
|
|
137
|
+
"mcp/servers.json": (mcpServers ?? []).map(({ id, ...rest }) => rest),
|
|
104
138
|
};
|
|
105
139
|
}
|
|
106
140
|
|
|
@@ -130,6 +164,13 @@ function collectAgent(cli, id, agentsById, skills, providerById) {
|
|
|
130
164
|
a.custom_env_fetch_failed = true; // e.g. insufficient permission — non-fatal, warned via hadSecrets
|
|
131
165
|
}
|
|
132
166
|
}
|
|
167
|
+
// Workspace MCP servers assigned to this agent (name + enabled). Separate from
|
|
168
|
+
// `mcp_config`, which is the agent's own inline server JSON.
|
|
169
|
+
try {
|
|
170
|
+
a.mcp_servers = listAgentMcpServers(cli, id);
|
|
171
|
+
} catch {
|
|
172
|
+
a.mcp_servers = []; // e.g. insufficient permission — non-fatal
|
|
173
|
+
}
|
|
133
174
|
const skill_names = a.skills.map((sk) => collectSkill(cli, sk.id, skills));
|
|
134
175
|
const red = redactAgent(a);
|
|
135
176
|
const entry = { raw: a, red, skill_names };
|
|
@@ -137,7 +178,7 @@ function collectAgent(cli, id, agentsById, skills, providerById) {
|
|
|
137
178
|
return entry;
|
|
138
179
|
}
|
|
139
180
|
|
|
140
|
-
export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs = nodeFs, download = fetchBinary }) {
|
|
181
|
+
export function exportResource({ cli, scope, level, ids, outDir, sourceWorkspaceId, fs = nodeFs, download = fetchBinary }) {
|
|
141
182
|
const skills = new Map(); // name -> normalized skill
|
|
142
183
|
const agentsById = new Map(); // id -> { raw, red, skill_names }
|
|
143
184
|
const squads = [];
|
|
@@ -184,6 +225,12 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
184
225
|
};
|
|
185
226
|
}
|
|
186
227
|
|
|
228
|
+
// A squad can be reached twice in one export (listed at level `squad`, then
|
|
229
|
+
// again as an autopilot's assignee) — keep exactly one copy, by name.
|
|
230
|
+
function pushSquad(built) {
|
|
231
|
+
if (built && !squads.some((s) => s.name === built.name)) squads.push(built);
|
|
232
|
+
}
|
|
233
|
+
|
|
187
234
|
// Collect a project's portable metadata + its lead agent (bundled, like a
|
|
188
235
|
// squad leader) and github_repo/other resources. An archived lead is dropped
|
|
189
236
|
// (project still exports, just with no lead set) — unlike a squad, a project
|
|
@@ -208,19 +255,26 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
208
255
|
};
|
|
209
256
|
}
|
|
210
257
|
|
|
211
|
-
// Collect a single autopilot
|
|
212
|
-
//
|
|
258
|
+
// Collect a single autopilot. Its assignee is BUNDLED (like a squad leader or a
|
|
259
|
+
// project lead) so the bundle is self-contained — import resolves the assignee
|
|
260
|
+
// by name, which only works if that agent/squad travels with it or already
|
|
261
|
+
// exists at the destination.
|
|
213
262
|
// Webhook trigger secrets (url/token) are never read into the bundle — only
|
|
214
263
|
// kind/label/enabled, matching the existing agent MCP/env redaction pattern.
|
|
215
264
|
function collectOneAutopilot(autopilotId) {
|
|
216
265
|
const ap = getAutopilot(cli, autopilotId);
|
|
217
266
|
let assignee_name = null;
|
|
218
267
|
if (ap.assignee_type === "agent") {
|
|
219
|
-
|
|
220
|
-
|
|
268
|
+
try {
|
|
269
|
+
const entry = collectAgent(cli, ap.assignee_id, agentsById, skills, getProviderById());
|
|
270
|
+
if (entry.archived) recordArchivedSkip(entry.name, "autopilot assignee", ap.title);
|
|
271
|
+
else assignee_name = entry.raw.name;
|
|
272
|
+
} catch { assignee_name = null; }
|
|
221
273
|
} else if (ap.assignee_type === "squad") {
|
|
222
|
-
|
|
223
|
-
|
|
274
|
+
try {
|
|
275
|
+
const built = collectOneSquad(ap.assignee_id);
|
|
276
|
+
if (built) { pushSquad(built); assignee_name = built.name; }
|
|
277
|
+
} catch { assignee_name = null; }
|
|
224
278
|
}
|
|
225
279
|
let project_title = null;
|
|
226
280
|
if (ap.project_id) {
|
|
@@ -233,6 +287,7 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
233
287
|
}
|
|
234
288
|
return {
|
|
235
289
|
title: ap.title, source_id: ap.id, description: ap.description,
|
|
290
|
+
status: ap.status,
|
|
236
291
|
execution_mode: ap.execution_mode, issue_title_template: ap.issue_title_template,
|
|
237
292
|
priority: ap.priority, project_title, assignee_type: ap.assignee_type, assignee_name,
|
|
238
293
|
subscriber_names, had_webhook_trigger: ap.triggers.some((t) => t.kind === "webhook"),
|
|
@@ -242,33 +297,51 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
242
297
|
};
|
|
243
298
|
}
|
|
244
299
|
|
|
300
|
+
// Labels, custom properties and the workspace MCP roster are workspace-wide,
|
|
301
|
+
// not per-project — three cheap list calls, bundled only where issue-bearing
|
|
302
|
+
// work travels: a single `project` export, or a workspace export at level
|
|
303
|
+
// `project`. Never for a lone skill/agent/squad/autopilot.
|
|
304
|
+
const wantsTaxonomy = scope === "project" || (scope === "workspace" && levelAtLeast(level, "project"));
|
|
305
|
+
const labels = wantsTaxonomy ? listLabels(cli) : [];
|
|
306
|
+
const properties = wantsTaxonomy ? listProperties(cli) : [];
|
|
307
|
+
const mcpServers = wantsTaxonomy ? listWorkspaceMcpServers(cli) : [];
|
|
308
|
+
|
|
245
309
|
if (scope === "skill") collectSkill(cli, ids.skillId, skills);
|
|
246
310
|
else if (scope === "agent") {
|
|
247
311
|
const entry = collectAgent(cli, ids.agentId, agentsById, skills, getProviderById());
|
|
248
312
|
if (entry.archived) throw new Error(`Cannot export agent "${entry.name}": it is archived`);
|
|
249
313
|
}
|
|
250
|
-
else if (scope === "squad")
|
|
314
|
+
else if (scope === "squad") pushSquad(collectOneSquad(ids.squadId));
|
|
251
315
|
else if (scope === "project") projects.push(collectProject(ids.projectId));
|
|
252
|
-
else if (scope === "projects") for (const p of listProjects(cli)) projects.push(collectProject(p.id));
|
|
253
316
|
else if (scope === "autopilot") autopilots.push(collectOneAutopilot(ids.autopilotId));
|
|
254
|
-
else if (scope === "
|
|
317
|
+
else if (scope === "workspace") {
|
|
318
|
+
// Tiers are cumulative: every level bundles skills; `agent` and up add every
|
|
319
|
+
// agent; `squad` and up add every squad; `project` adds projects + autopilots
|
|
320
|
+
// (plus the taxonomy above).
|
|
255
321
|
for (const s of listSkills(cli)) collectSkill(cli, s.id, skills);
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
322
|
+
if (levelAtLeast(level, "agent")) {
|
|
323
|
+
for (const a of listAgents(cli)) collectAgent(cli, a.id, agentsById, skills, getProviderById());
|
|
324
|
+
// listAgents() above already excludes archived agents server-side — surface
|
|
325
|
+
// that exclusion in the report too, not just the squad/project paths.
|
|
326
|
+
for (const a of listAgentsIncludingArchived(cli)) {
|
|
327
|
+
if (a.archived_at) recordArchivedSkip(a.name, "workspace listing");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (levelAtLeast(level, "squad")) {
|
|
331
|
+
for (const sq of listSquads(cli)) pushSquad(collectOneSquad(sq.id));
|
|
332
|
+
}
|
|
333
|
+
if (levelAtLeast(level, "project")) {
|
|
334
|
+
for (const p of listProjects(cli)) projects.push(collectProject(p.id));
|
|
335
|
+
for (const ap of listAutopilots(cli)) autopilots.push(collectOneAutopilot(ap.id));
|
|
263
336
|
}
|
|
264
337
|
}
|
|
265
338
|
|
|
266
339
|
// Orphan-skill cleanup: drop skills that no exported agent references via its
|
|
267
|
-
// skill_names.
|
|
268
|
-
//
|
|
269
|
-
//
|
|
340
|
+
// skill_names. Skipped for `scope: skill` (its one skill IS the target, not an
|
|
341
|
+
// orphan) and for a workspace export at level `skill`, where the skills tier is
|
|
342
|
+
// itself what was asked for.
|
|
270
343
|
const pruned_skills = [];
|
|
271
|
-
if (scope !== "skill") {
|
|
344
|
+
if (scope !== "skill" && !(scope === "workspace" && level === "skill")) {
|
|
272
345
|
const referenced = new Set();
|
|
273
346
|
for (const a of agentsById.values()) for (const n of a.skill_names) referenced.add(n);
|
|
274
347
|
for (const name of [...skills.keys()]) {
|
|
@@ -277,12 +350,15 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
277
350
|
}
|
|
278
351
|
|
|
279
352
|
const manifest = buildManifest({
|
|
280
|
-
scope, sourceWorkspaceId,
|
|
353
|
+
scope, level, sourceWorkspaceId,
|
|
281
354
|
skills: [...skills.values()].map((s) => ({ name: s.name, source_id: s.id })),
|
|
282
355
|
agents: [...agentsById.values()].map((a) => ({ name: a.raw.name, source_id: a.raw.id, source_runtime_id: a.raw.runtime_id, source_runtime_provider: a.raw.source_runtime_provider, skill_names: a.skill_names, had_secrets: a.red.hadSecrets })),
|
|
283
356
|
squads,
|
|
284
357
|
projects,
|
|
285
358
|
autopilots,
|
|
359
|
+
labels,
|
|
360
|
+
properties,
|
|
361
|
+
mcpServers,
|
|
286
362
|
});
|
|
287
363
|
|
|
288
364
|
const warnings = [];
|
|
@@ -348,10 +424,28 @@ export function exportResource({ cli, scope, ids, outDir, sourceWorkspaceId, fs
|
|
|
348
424
|
writeSidecar(fs, outDir, entry.file, ".description.md", desc, record, "description_file");
|
|
349
425
|
fs.writeFileSync(`${outDir}/${entry.file}`, JSON.stringify(record, null, 2));
|
|
350
426
|
}
|
|
427
|
+
// labels/, properties/, mcp/ — one flat folder per object type, matching the
|
|
428
|
+
// per-type folders written above. Only written when the manifest points at them.
|
|
429
|
+
const taxonomyFiles = buildTaxonomyFiles({ labels, properties, mcpServers });
|
|
430
|
+
for (const rel of [manifest.labels_file, manifest.properties_file, manifest.mcp_servers_file]) {
|
|
431
|
+
if (!rel) continue;
|
|
432
|
+
fs.mkdirSync(`${outDir}/${dirname(rel)}`, { recursive: true });
|
|
433
|
+
fs.writeFileSync(`${outDir}/${rel}`, JSON.stringify(taxonomyFiles[rel], null, 2));
|
|
434
|
+
}
|
|
351
435
|
fs.writeFileSync(`${outDir}/manifest.json`, JSON.stringify(manifest, null, 2));
|
|
352
436
|
return {
|
|
353
437
|
manifest, warnings, pruned_skills, archivedAgentsSkipped,
|
|
438
|
+
// Autopilots that were live at the source. Import always lands them paused,
|
|
439
|
+
// so activation is a deliberate manual step at the destination.
|
|
440
|
+
autopilotsActiveAtSource: autopilots.filter((a) => a.status === "active").map((a) => a.title),
|
|
441
|
+
// Only name/transport are readable via `workspace mcp list` — the server
|
|
442
|
+
// entry JSON (and any token in it) must be re-entered at the destination.
|
|
443
|
+
mcpServerConfigsNotPortable: mcpServers.map((m) => m.name),
|
|
354
444
|
autopilotWebhookTriggers: autopilots.filter((a) => a.had_webhook_trigger).map((a) => a.title),
|
|
445
|
+
// Captured in the bundle for review, but `label create`/`update` have no
|
|
446
|
+
// --description flag — flagged at export time so the gap is known before the
|
|
447
|
+
// migration, not discovered at the far end.
|
|
448
|
+
labelDescriptionsNotPortable: labels.filter((l) => l.description).map((l) => l.name),
|
|
355
449
|
};
|
|
356
450
|
}
|
|
357
451
|
|
|
@@ -359,14 +453,24 @@ function main() {
|
|
|
359
453
|
const args = process.argv.slice(2);
|
|
360
454
|
const get = (flag) => { const i = args.indexOf(flag); return i !== -1 ? args[i + 1] : null; };
|
|
361
455
|
|
|
362
|
-
const
|
|
456
|
+
const rawScope = get("--scope");
|
|
457
|
+
const rawLevel = get("--level");
|
|
363
458
|
const id = get("--id");
|
|
364
459
|
const out = get("--out");
|
|
365
460
|
const workspace = get("--workspace"); // optional: source workspace name
|
|
366
461
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
462
|
+
const USAGE = "Usage: multica-export.mjs --out <dir> [--level skill|agent|squad|project] [--workspace <name>]\n" +
|
|
463
|
+
" or: multica-export.mjs --scope <skill|agent|squad|project|autopilot> --id <id> --out <dir> [--workspace <name>]\n" +
|
|
464
|
+
" --level exports the WHOLE workspace down to that tier (default: squad); --scope exports one named resource.";
|
|
465
|
+
|
|
466
|
+
// No --scope means a whole-workspace export driven by --level (default squad).
|
|
467
|
+
const scope = rawScope ?? "workspace";
|
|
468
|
+
const level = scope === "workspace" ? (rawLevel ?? "squad") : null;
|
|
469
|
+
|
|
470
|
+
if (rawScope && rawLevel) { console.error("--scope and --level are mutually exclusive.\n" + USAGE); process.exit(1); }
|
|
471
|
+
if (!out || (scope !== "workspace" && !id)) { console.error(USAGE); process.exit(1); }
|
|
472
|
+
if (scope === "workspace" && !LEVELS.includes(level)) {
|
|
473
|
+
console.error(`Unknown level "${level}" — use ${LEVELS.join("|")}`); process.exit(1);
|
|
370
474
|
}
|
|
371
475
|
|
|
372
476
|
requireAuth(realExec);
|
|
@@ -381,12 +485,11 @@ function main() {
|
|
|
381
485
|
else if (scope === "agent") ids.agentId = id;
|
|
382
486
|
else if (scope === "squad") ids.squadId = id;
|
|
383
487
|
else if (scope === "project") ids.projectId = id;
|
|
384
|
-
else if (scope === "projects") { /* all projects — no id */ }
|
|
385
488
|
else if (scope === "autopilot") ids.autopilotId = id;
|
|
386
|
-
else if (scope === "
|
|
387
|
-
else { console.error(`Unknown scope "${scope}" — use skill|agent|squad|project|
|
|
489
|
+
else if (scope === "workspace") { /* whole workspace — no id */ }
|
|
490
|
+
else { console.error(`Unknown scope "${scope}" — use skill|agent|squad|project|autopilot`); process.exit(1); }
|
|
388
491
|
|
|
389
|
-
const result = exportResource({ cli, scope, ids, outDir: out, sourceWorkspaceId, fs: nodeFs });
|
|
492
|
+
const result = exportResource({ cli, scope, level, ids, outDir: out, sourceWorkspaceId, fs: nodeFs });
|
|
390
493
|
console.log(JSON.stringify(result, null, 2));
|
|
391
494
|
}
|
|
392
495
|
|