@rbbtsn0w/adg 0.1.0-alpha.1 → 0.1.0-beta.2

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.
Files changed (110) hide show
  1. package/dist/bin/adg.js +703 -0
  2. package/dist/src/adapters/anthropic.js +54 -0
  3. package/dist/src/adapters/index.js +10 -0
  4. package/dist/src/adapters/openai.js +30 -0
  5. package/dist/src/adapters/reverse.js +53 -0
  6. package/dist/src/agents/claude.js +118 -0
  7. package/dist/src/agents/codex.js +61 -0
  8. package/{src/agents/index.ts → dist/src/agents/index.js} +6 -8
  9. package/dist/src/agents/registry.js +24 -0
  10. package/dist/src/agents/types.js +1 -0
  11. package/dist/src/commands/adapt.js +26 -0
  12. package/dist/src/commands/import.js +51 -0
  13. package/dist/src/commands/init.js +104 -0
  14. package/dist/src/commands/install.js +257 -0
  15. package/dist/src/commands/link.js +34 -0
  16. package/dist/src/commands/list.js +19 -0
  17. package/dist/src/commands/marketplace.js +124 -0
  18. package/dist/src/commands/migrate.js +60 -0
  19. package/dist/src/commands/multiselect-skills.js +103 -0
  20. package/dist/src/commands/remove.js +102 -0
  21. package/dist/src/commands/select-agents.js +40 -0
  22. package/dist/src/commands/select-components.js +61 -0
  23. package/dist/src/commands/select-plugins.js +25 -0
  24. package/dist/src/commands/select-scope.js +20 -0
  25. package/dist/src/commands/update.js +50 -0
  26. package/dist/src/commands/validate.js +50 -0
  27. package/dist/src/components.js +90 -0
  28. package/dist/src/deps.js +46 -0
  29. package/dist/src/fsutil.js +32 -0
  30. package/dist/src/hash.js +51 -0
  31. package/dist/src/lock.js +51 -0
  32. package/dist/src/manifest.js +110 -0
  33. package/dist/src/marketplace.js +39 -0
  34. package/{src/package.ts → dist/src/package.js} +37 -42
  35. package/{src/paths.ts → dist/src/paths.js} +54 -60
  36. package/dist/src/semver.js +55 -0
  37. package/dist/src/skills.js +79 -0
  38. package/dist/src/sources.js +122 -0
  39. package/dist/src/types.js +19 -0
  40. package/dist/vendor/skills/package.json +143 -0
  41. package/dist/vendor/skills/src/add.js +1663 -0
  42. package/dist/vendor/skills/src/agents.js +729 -0
  43. package/dist/vendor/skills/src/blob.js +436 -0
  44. package/dist/vendor/skills/src/cli.js +340 -0
  45. package/dist/vendor/skills/src/constants.js +3 -0
  46. package/dist/vendor/skills/src/detect-agent.js +56 -0
  47. package/dist/vendor/skills/src/find.js +294 -0
  48. package/dist/vendor/skills/src/frontmatter.js +13 -0
  49. package/dist/vendor/skills/src/git-tree.js +32 -0
  50. package/dist/vendor/skills/src/git.js +235 -0
  51. package/dist/vendor/skills/src/install.js +75 -0
  52. package/dist/vendor/skills/src/installer.js +924 -0
  53. package/dist/vendor/skills/src/list.js +201 -0
  54. package/dist/vendor/skills/src/local-lock.js +109 -0
  55. package/dist/vendor/skills/src/plugin-manifest.js +152 -0
  56. package/dist/vendor/skills/src/prompts/search-multiselect.js +312 -0
  57. package/dist/vendor/skills/src/providers/index.js +4 -0
  58. package/dist/vendor/skills/src/providers/registry.js +42 -0
  59. package/dist/vendor/skills/src/providers/types.js +1 -0
  60. package/dist/vendor/skills/src/providers/wellknown.js +625 -0
  61. package/dist/vendor/skills/src/remove.js +263 -0
  62. package/dist/vendor/skills/src/sanitize.js +57 -0
  63. package/dist/vendor/skills/src/self-cli.js +15 -0
  64. package/dist/vendor/skills/src/skill-lock.js +237 -0
  65. package/dist/vendor/skills/src/skills.js +264 -0
  66. package/dist/vendor/skills/src/source-parser.js +367 -0
  67. package/dist/vendor/skills/src/sync.js +404 -0
  68. package/dist/vendor/skills/src/telemetry.js +101 -0
  69. package/dist/vendor/skills/src/test-utils.js +59 -0
  70. package/dist/vendor/skills/src/types.js +1 -0
  71. package/dist/vendor/skills/src/update-source.js +76 -0
  72. package/dist/vendor/skills/src/update.js +590 -0
  73. package/dist/vendor/skills/src/use.js +505 -0
  74. package/package.json +15 -7
  75. package/bin/adg.ts +0 -758
  76. package/src/adapters/anthropic.ts +0 -54
  77. package/src/adapters/index.ts +0 -24
  78. package/src/adapters/openai.ts +0 -37
  79. package/src/adapters/reverse.ts +0 -60
  80. package/src/agents/claude.ts +0 -124
  81. package/src/agents/codex.ts +0 -67
  82. package/src/agents/registry.ts +0 -30
  83. package/src/agents/types.ts +0 -47
  84. package/src/commands/adapt.ts +0 -36
  85. package/src/commands/import.ts +0 -69
  86. package/src/commands/init.ts +0 -146
  87. package/src/commands/install.ts +0 -411
  88. package/src/commands/link.ts +0 -61
  89. package/src/commands/list.ts +0 -28
  90. package/src/commands/marketplace.ts +0 -198
  91. package/src/commands/migrate.ts +0 -84
  92. package/src/commands/multiselect-skills.ts +0 -137
  93. package/src/commands/remove.ts +0 -136
  94. package/src/commands/select-agents.ts +0 -45
  95. package/src/commands/select-components.ts +0 -66
  96. package/src/commands/select-plugins.ts +0 -28
  97. package/src/commands/select-scope.ts +0 -21
  98. package/src/commands/update.ts +0 -85
  99. package/src/commands/validate.ts +0 -57
  100. package/src/components.ts +0 -90
  101. package/src/deps.ts +0 -64
  102. package/src/fsutil.ts +0 -38
  103. package/src/hash.ts +0 -61
  104. package/src/lock.ts +0 -57
  105. package/src/manifest.ts +0 -113
  106. package/src/marketplace.ts +0 -41
  107. package/src/semver.ts +0 -67
  108. package/src/skills.ts +0 -88
  109. package/src/sources.ts +0 -159
  110. package/src/types.ts +0 -140
@@ -1,54 +0,0 @@
1
- import { join } from "node:path";
2
- import type { AdgManifest, PluginSelection } from "../types.ts";
3
- import { resolveSkills } from "../skills.ts";
4
- import { isExposed } from "../components.ts";
5
- import type { AdapterResult } from "./index.ts";
6
-
7
- /**
8
- * Generate a Claude (.claude-plugin/plugin.json) manifest from an ADG manifest.
9
- *
10
- * Maps the universal fields onto Claude's plugin shape. When `strict` is false,
11
- * skills are listed explicitly so a skill-bundle marketplace entry can be built.
12
- * An optional `selection` narrows what is exposed (partial install): categories
13
- * outside it are dropped and skills are pinned to an explicit subset list.
14
- */
15
- export function toAnthropicManifest(
16
- pluginDir: string,
17
- manifest: AdgManifest,
18
- selection?: PluginSelection,
19
- ): AdapterResult {
20
- const out: Record<string, unknown> = {
21
- name: manifest.name,
22
- version: manifest.version,
23
- description: manifest.description,
24
- };
25
-
26
- if (manifest.author) out.author = manifest.author;
27
- if (manifest.homepage) out.homepage = manifest.homepage;
28
- if (manifest.license) out.license = manifest.license;
29
- if (manifest.category) out.category = manifest.category;
30
- if (manifest.commands && isExposed(selection, "commands")) out.commands = manifest.commands;
31
- if (manifest.agents && isExposed(selection, "agents")) out.agents = manifest.agents;
32
- if (manifest.hooks && isExposed(selection, "hooks")) out.hooks = manifest.hooks;
33
- if (manifest.mcp && isExposed(selection, "mcp")) out.mcp = manifest.mcp;
34
-
35
- if (selection) {
36
- // Partial install: always an explicit (possibly empty) skill list.
37
- out.strict = false;
38
- const names = isExposed(selection, "skills")
39
- ? selection.skills ?? resolveSkills(pluginDir, manifest)
40
- : [];
41
- out.skills = names.map((name) => `./skills/${name}`);
42
- } else {
43
- const strict = manifest.strict !== false;
44
- if (strict && manifest.skills !== undefined) {
45
- out.skills = manifest.skills;
46
- } else {
47
- // skill-bundle form: explicit list, strict:false
48
- out.strict = false;
49
- out.skills = resolveSkills(pluginDir, manifest).map((name) => `./skills/${name}`);
50
- }
51
- }
52
-
53
- return { defaultPath: join(".claude-plugin", "plugin.json"), manifest: out };
54
- }
@@ -1,24 +0,0 @@
1
- import type { AdgManifest, PluginSelection } from "../types.ts";
2
- import { toAnthropicManifest } from "./anthropic.ts";
3
- import { toCodexManifest } from "./openai.ts";
4
-
5
- export interface AdapterResult {
6
- /** Default manifest path relative to the plugin directory. */
7
- defaultPath: string;
8
- /** The generated runtime-specific manifest object. */
9
- manifest: Record<string, unknown>;
10
- }
11
-
12
- export type AdapterFn = (pluginDir: string, manifest: AdgManifest, selection?: PluginSelection) => AdapterResult;
13
-
14
- export const ADAPTERS: Record<string, AdapterFn> = {
15
- claude: toAnthropicManifest,
16
- anthropic: toAnthropicManifest,
17
- codex: toCodexManifest,
18
- openai: toCodexManifest,
19
- };
20
-
21
- export const ADAPTER_TARGETS = ["claude", "codex"] as const;
22
- export type AdapterTarget = (typeof ADAPTER_TARGETS)[number];
23
-
24
- export { toAnthropicManifest, toCodexManifest };
@@ -1,37 +0,0 @@
1
- import { join } from "node:path";
2
- import type { AdgManifest, PluginSelection } from "../types.ts";
3
- import { resolveSkills } from "../skills.ts";
4
- import { isExposed } from "../components.ts";
5
- import type { AdapterResult } from "./index.ts";
6
-
7
- /**
8
- * Generate a Codex (.codex-plugin/plugin.json) manifest from an ADG manifest.
9
- *
10
- * Codex's minimal manifest requires name, version, description and skills. The
11
- * skills field is emitted as an explicit array of skill identifiers. An optional
12
- * `selection` narrows the exposed skills (Codex only consumes skills).
13
- */
14
- export function toCodexManifest(
15
- pluginDir: string,
16
- manifest: AdgManifest,
17
- selection?: PluginSelection,
18
- ): AdapterResult {
19
- const skills = !selection
20
- ? resolveSkills(pluginDir, manifest)
21
- : isExposed(selection, "skills")
22
- ? selection.skills ?? resolveSkills(pluginDir, manifest)
23
- : [];
24
-
25
- const out: Record<string, unknown> = {
26
- name: manifest.name,
27
- version: manifest.version,
28
- description: manifest.description,
29
- skills,
30
- };
31
-
32
- if (manifest.author) out.author = manifest.author;
33
- if (manifest.homepage) out.homepage = manifest.homepage;
34
- if (manifest.license) out.license = manifest.license;
35
-
36
- return { defaultPath: join(".codex-plugin", "plugin.json"), manifest: out };
37
- }
@@ -1,60 +0,0 @@
1
- import { ADG_SCHEMA_VERSION, type AdgManifest } from "../types.ts";
2
- import { validateManifest } from "../manifest.ts";
3
-
4
- export type NativeKind = "anthropic" | "openai";
5
-
6
- /**
7
- * Reverse-adapt a runtime-native manifest (.claude-plugin/plugin.json or
8
- * .codex-plugin/plugin.json) into a canonical ADG manifest. This is the inverse
9
- * of the forward adapters and is used when importing existing plugins.
10
- *
11
- * Missing `version` falls back to 0.0.0 (callers may override with a git SHA);
12
- * skills normalize to the manifest's array/string or the default ./skills/.
13
- */
14
- export function fromNativeManifest(raw: unknown, _kind: NativeKind): AdgManifest {
15
- if (typeof raw !== "object" || raw === null) {
16
- throw new Error("native manifest must be a JSON object");
17
- }
18
- const n = raw as Record<string, unknown>;
19
- if (typeof n.name !== "string") throw new Error("native manifest missing string `name`");
20
-
21
- const manifest: AdgManifest = {
22
- schemaVersion: ADG_SCHEMA_VERSION,
23
- name: n.name,
24
- version: typeof n.version === "string" ? n.version : "0.0.0",
25
- description: typeof n.description === "string" && n.description ? n.description : `${n.name} plugin.`,
26
- };
27
-
28
- const out = manifest as unknown as Record<string, unknown>;
29
- copyIfString(n, out, "license");
30
- copyIfString(n, out, "category");
31
- copyIfString(n, out, "homepage");
32
- copyIfString(n, out, "commands");
33
- copyIfString(n, out, "agents");
34
- copyIfString(n, out, "hooks");
35
- copyIfString(n, out, "mcp");
36
-
37
- if (typeof n.author === "object" && n.author !== null) {
38
- manifest.author = n.author as AdgManifest["author"];
39
- } else if (typeof n.author === "string") {
40
- manifest.author = { name: n.author };
41
- }
42
-
43
- if (typeof n.skills === "string" || isStringArray(n.skills)) {
44
- manifest.skills = n.skills as string | string[];
45
- } else {
46
- manifest.skills = "./skills/";
47
- }
48
-
49
- manifest.strict = typeof n.strict === "boolean" ? n.strict : true;
50
-
51
- return validateManifest(manifest);
52
- }
53
-
54
- function copyIfString(src: Record<string, unknown>, dst: Record<string, unknown>, key: string): void {
55
- if (typeof src[key] === "string") dst[key] = src[key];
56
- }
57
-
58
- function isStringArray(v: unknown): v is string[] {
59
- return Array.isArray(v) && v.every((x) => typeof x === "string");
60
- }
@@ -1,124 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { join, relative } from "node:path";
5
- import { writeJson } from "../fsutil.ts";
6
- import { readManifest } from "../manifest.ts";
7
- import { installedPluginDir, lockPath } from "../paths.ts";
8
- import { readLock } from "../lock.ts";
9
- import type { Agent, AgentContext, AgentSyncResult } from "./types.ts";
10
-
11
- /**
12
- * Claude Code agent.
13
- *
14
- * Claude consumes plugins through its own marketplace system, so we emit a
15
- * Claude-shaped catalog at `<pluginsDir>/.claude-plugin/marketplace.json` and
16
- * drive everything through the `claude plugin` CLI (which owns ~/.claude across
17
- * versions) rather than hand-editing Claude's internal state.
18
- */
19
-
20
- const MARKETPLACE = "adg";
21
-
22
- function toPosix(p: string): string {
23
- return p.split("\\").join("/");
24
- }
25
-
26
- function claudeHome(env: NodeJS.ProcessEnv): string {
27
- return env.CLAUDE_CONFIG_DIR?.trim() || join(homedir(), ".claude");
28
- }
29
-
30
- function available(): boolean {
31
- return spawnSync("claude", ["plugin", "--help"], { stdio: "ignore" }).status === 0;
32
- }
33
-
34
- function run(args: string[]): { ok: boolean; out: string } {
35
- const r = spawnSync("claude", args, { encoding: "utf8" });
36
- return { ok: r.status === 0, out: `${r.stdout ?? ""}${r.stderr ?? ""}` };
37
- }
38
-
39
- /**
40
- * Write a Claude marketplace catalog listing every installed plugin, each
41
- * `source` pointing at its on-disk directory (relative to the catalog).
42
- */
43
- export function writeClaudeCatalog(pluginsDir: string, name: string = MARKETPLACE): { file: string; name: string } {
44
- const lock = readLock(lockPath(pluginsDir));
45
- const plugins: Record<string, unknown>[] = [];
46
-
47
- for (const [pname, entry] of Object.entries(lock.plugins)) {
48
- const dir = installedPluginDir(pluginsDir, pname, entry.origin);
49
- let description = "";
50
- let author: unknown;
51
- let category: string | undefined;
52
- try {
53
- const m = readManifest(dir);
54
- description = m.description;
55
- author = m.author;
56
- category = m.category;
57
- } catch {
58
- // no manifest on disk — list it minimally so the catalog stays complete
59
- }
60
- const rel = toPosix(relative(pluginsDir, dir)) || pname;
61
- plugins.push({
62
- name: pname,
63
- description,
64
- source: `./${rel}`,
65
- ...(author ? { author } : {}),
66
- ...(category ? { category } : {}),
67
- });
68
- }
69
-
70
- const catalog = {
71
- $schema: "https://anthropic.com/claude-code/marketplace.schema.json",
72
- name,
73
- description: "ADG-managed plugins",
74
- owner: { name: "ADG" },
75
- plugins,
76
- };
77
- const file = join(pluginsDir, ".claude-plugin", "marketplace.json");
78
- writeJson(file, catalog);
79
- return { file, name };
80
- }
81
-
82
- /** Register the ADG store as a Claude marketplace (add, or update if present). */
83
- function syncMarketplace(pluginsDir: string): void {
84
- const list = run(["plugin", "marketplace", "list"]);
85
- if (list.ok && list.out.includes(MARKETPLACE)) run(["plugin", "marketplace", "update", MARKETPLACE]);
86
- else run(["plugin", "marketplace", "add", pluginsDir]);
87
- }
88
-
89
- export const claudeAgent: Agent = {
90
- id: "claude",
91
- displayName: "Claude Code",
92
- adaptTarget: "claude",
93
- detect: (env = process.env) => existsSync(claudeHome(env)),
94
- available,
95
-
96
- activate(ctx: AgentContext): AgentSyncResult {
97
- if (!available()) return { agent: "claude", affected: [], skipped: true };
98
- writeClaudeCatalog(ctx.pluginsDir);
99
- syncMarketplace(ctx.pluginsDir);
100
- const affected: string[] = [];
101
- for (const p of ctx.plugins) {
102
- if (run(["plugin", "install", `${p}@${MARKETPLACE}`, "--scope", ctx.scope]).ok) affected.push(p);
103
- }
104
- return { agent: "claude", affected, skipped: false };
105
- },
106
-
107
- deactivate(ctx: AgentContext): AgentSyncResult {
108
- if (!available()) return { agent: "claude", affected: [], skipped: true };
109
- const affected: string[] = [];
110
- for (const p of ctx.plugins) {
111
- if (run(["plugin", "uninstall", p, "--scope", ctx.scope]).ok) affected.push(p);
112
- }
113
- return { agent: "claude", affected, skipped: false };
114
- },
115
-
116
- refresh(ctx: AgentContext): AgentSyncResult {
117
- if (!available()) return { agent: "claude", affected: [], skipped: true };
118
- // Claude caches a copy on install and won't re-pull from a local marketplace,
119
- // so uninstall (keeping data) then re-install to force a fresh copy.
120
- for (const p of ctx.plugins) run(["plugin", "uninstall", p, "--scope", ctx.scope, "--keep-data"]);
121
- const act = claudeAgent.activate(ctx);
122
- return { agent: "claude", affected: act.affected, skipped: act.skipped };
123
- },
124
- };
@@ -1,67 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { join } from "node:path";
5
- import { marketplacePath } from "../paths.ts";
6
- import { readMarketplace } from "../marketplace.ts";
7
- import type { Agent, AgentContext, AgentSyncResult } from "./types.ts";
8
-
9
- /**
10
- * Codex agent.
11
- *
12
- * Codex natively discovers the `.agents/plugins/marketplace.json` ADG writes, so
13
- * plugins show up as *available* — but aren't usable until installed with
14
- * `codex plugin add`. We drive that via the `codex` CLI (which owns ~/.codex).
15
- */
16
-
17
- function codexHome(env: NodeJS.ProcessEnv): string {
18
- return env.CODEX_HOME?.trim() || join(homedir(), ".codex");
19
- }
20
-
21
- function available(): boolean {
22
- return spawnSync("codex", ["plugin", "--help"], { stdio: "ignore" }).status === 0;
23
- }
24
-
25
- function run(args: string[]): { ok: boolean; out: string } {
26
- const r = spawnSync("codex", args, { encoding: "utf8" });
27
- return { ok: r.status === 0, out: `${r.stdout ?? ""}${r.stderr ?? ""}` };
28
- }
29
-
30
- /** The marketplace name Codex sees, read from the generated marketplace.json. */
31
- function marketplaceName(pluginsDir: string): string {
32
- return readMarketplace(marketplacePath(pluginsDir), "").name;
33
- }
34
-
35
- export const codexAgent: Agent = {
36
- id: "codex",
37
- displayName: "Codex",
38
- adaptTarget: "codex",
39
- detect: (env = process.env) => existsSync(codexHome(env)) || existsSync("/etc/codex"),
40
- available,
41
-
42
- activate(ctx: AgentContext): AgentSyncResult {
43
- const mp = marketplaceName(ctx.pluginsDir);
44
- if (!available()) return { agent: "codex", affected: [], skipped: true };
45
- const affected: string[] = [];
46
- for (const p of ctx.plugins) {
47
- if (run(["plugin", "add", `${p}@${mp}`]).ok) affected.push(p);
48
- }
49
- return { agent: "codex", affected, skipped: false };
50
- },
51
-
52
- deactivate(ctx: AgentContext): AgentSyncResult {
53
- const mp = marketplaceName(ctx.pluginsDir);
54
- if (!available()) return { agent: "codex", affected: [], skipped: true };
55
- const affected: string[] = [];
56
- for (const p of ctx.plugins) {
57
- if (run(["plugin", "remove", `${p}@${mp}`]).ok) affected.push(p);
58
- }
59
- return { agent: "codex", affected, skipped: false };
60
- },
61
-
62
- // `codex plugin add` is idempotent and re-copies into the cache, so re-adding
63
- // is the refresh.
64
- refresh(ctx: AgentContext): AgentSyncResult {
65
- return codexAgent.activate(ctx);
66
- },
67
- };
@@ -1,30 +0,0 @@
1
- import type { Agent, AgentId } from "./types.ts";
2
-
3
- /**
4
- * The agent registry — the "factory": construction/lookup only. Orchestration
5
- * (looping, dependency order, store writes) stays in the command layer.
6
- */
7
- const REGISTRY = new Map<AgentId, Agent>();
8
-
9
- export function registerAgent(agent: Agent): void {
10
- REGISTRY.set(agent.id, agent);
11
- }
12
-
13
- export function getAgent(id: AgentId): Agent | undefined {
14
- return REGISTRY.get(id);
15
- }
16
-
17
- export function allAgents(): Agent[] {
18
- return [...REGISTRY.values()];
19
- }
20
-
21
- /** Agents that appear installed on this machine. */
22
- export function detectedAgents(env?: NodeJS.ProcessEnv): Agent[] {
23
- return allAgents().filter((a) => a.detect(env));
24
- }
25
-
26
- /** Agents matching the given ids, or every registered agent when none are given. */
27
- export function resolveAgents(targets?: readonly AgentId[]): Agent[] {
28
- if (!targets) return allAgents();
29
- return targets.map((t) => getAgent(t)).filter((a): a is Agent => a !== undefined);
30
- }
@@ -1,47 +0,0 @@
1
- import type { AdapterTarget } from "../adapters/index.ts";
2
-
3
- /** Identifier for an agent ADG can install plugins into ("claude", "codex", or a third-party id). */
4
- export type AgentId = string;
5
-
6
- /** Install scope within an agent. Codex is global-only and ignores it. */
7
- export type AgentScope = "user" | "project";
8
-
9
- /** What an agent operation acts on. Agents derive their own specifics (marketplace name, …). */
10
- export interface AgentContext {
11
- pluginsDir: string;
12
- plugins: string[];
13
- scope: AgentScope;
14
- }
15
-
16
- /** Outcome of one agent lifecycle call. */
17
- export interface AgentSyncResult {
18
- agent: AgentId;
19
- /** Plugins enabled / disabled / refreshed. */
20
- affected: string[];
21
- /** True when the agent's CLI wasn't present, so the op was skipped (never a hard failure). */
22
- skipped: boolean;
23
- }
24
-
25
- /**
26
- * The runtime-integration contract every agent implements. The pure manifest
27
- * transform stays in `src/adapters` and is *composed* via `adaptTarget` — agents
28
- * own only the side-effectful lifecycle (detect / available / activate / …).
29
- *
30
- * Adding an agent (including third-party) = implement this + `registerAgent()`.
31
- */
32
- export interface Agent {
33
- id: AgentId;
34
- displayName: string;
35
- /** Manifest format to generate for this agent (keys into `ADAPTERS`). */
36
- adaptTarget: AdapterTarget;
37
- /** Whether the agent appears installed on this machine (config dir present). */
38
- detect(env?: NodeJS.ProcessEnv): boolean;
39
- /** Whether the agent's CLI is usable. */
40
- available(): boolean;
41
- /** Enable/install the plugins in the agent. */
42
- activate(ctx: AgentContext): AgentSyncResult;
43
- /** Uninstall the plugins from the agent. */
44
- deactivate(ctx: AgentContext): AgentSyncResult;
45
- /** Refresh the agent's cached copy after the store changed. */
46
- refresh(ctx: AgentContext): AgentSyncResult;
47
- }
@@ -1,36 +0,0 @@
1
- import { join } from "node:path";
2
- import { ADAPTERS, type AdapterTarget } from "../adapters/index.ts";
3
- import { readManifest } from "../manifest.ts";
4
- import { writeJson } from "../fsutil.ts";
5
- import type { PluginSelection } from "../types.ts";
6
-
7
- export interface AdaptResult {
8
- target: string;
9
- file: string;
10
- }
11
-
12
- /**
13
- * Generate runtime-specific manifests for the given targets from a plugin's
14
- * .agents/.plugin.json. The output path honors the manifest's `adapters`
15
- * mapping when present, otherwise falls back to the adapter's default path.
16
- * An optional `selection` narrows what the generated manifests expose.
17
- */
18
- export function adaptPlugin(pluginDir: string, targets: AdapterTarget[], selection?: PluginSelection): AdaptResult[] {
19
- const manifest = readManifest(pluginDir);
20
- const results: AdaptResult[] = [];
21
-
22
- for (const target of targets) {
23
- const adapter = ADAPTERS[target];
24
- if (!adapter) throw new Error(`unknown adapter target: ${target}`);
25
- const { defaultPath, manifest: out } = adapter(pluginDir, manifest, selection);
26
-
27
- // Output paths are ADG-internal conventions, not producer-configurable: each
28
- // runtime mandates its own (.claude-plugin/ , .codex-plugin/).
29
- const file = join(pluginDir, defaultPath);
30
-
31
- writeJson(file, out);
32
- results.push({ target, file });
33
- }
34
-
35
- return results;
36
- }
@@ -1,69 +0,0 @@
1
- import { cpSync, existsSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join, resolve } from "node:path";
4
- import { ADG_MANIFEST_PATH } from "../manifest.ts";
5
- import { writeJson, writeText } from "../fsutil.ts";
6
- import { installPlugin, type InstallResult } from "./install.ts";
7
- import { ADG_SCHEMA_VERSION, type AdgManifest } from "../types.ts";
8
-
9
- export interface ImportSkillsOptions {
10
- /** Directory holding flat <name>/SKILL.md skill folders. */
11
- skillsDir: string;
12
- /** Name of the synthesized plugin. */
13
- as: string;
14
- /** Only include skills whose folder name starts with this prefix. */
15
- prefix?: string;
16
- pluginsDir: string;
17
- version?: string;
18
- description?: string;
19
- marketplaceName?: string;
20
- now?: string;
21
- }
22
-
23
- /**
24
- * Wrap a flat directory of `<name>/SKILL.md` skills into a single ADG plugin and
25
- * install it. Skill folders are copied verbatim under the new plugin's skills/.
26
- */
27
- export function importSkills(opts: ImportSkillsOptions): InstallResult {
28
- const src = resolve(opts.skillsDir);
29
- const names = readdirSync(src, { withFileTypes: true })
30
- .filter((e) => e.isDirectory() && existsSync(join(src, e.name, "SKILL.md")))
31
- .map((e) => e.name)
32
- .filter((name) => !opts.prefix || name.startsWith(opts.prefix))
33
- .sort();
34
-
35
- if (names.length === 0) {
36
- throw new Error(`no SKILL.md skills found in ${src}${opts.prefix ? ` with prefix "${opts.prefix}"` : ""}`);
37
- }
38
-
39
- const staging = mkdtempSync(join(tmpdir(), "adg-skills-"));
40
- try {
41
- const manifest: AdgManifest = {
42
- schemaVersion: ADG_SCHEMA_VERSION,
43
- name: opts.as,
44
- version: opts.version ?? "0.1.0",
45
- description: opts.description ?? `Imported skills bundle (${names.length}).`,
46
- skills: "./skills/",
47
- strict: false,
48
- };
49
- writeJson(join(staging, ADG_MANIFEST_PATH), manifest);
50
- for (const name of names) {
51
- copySkill(join(src, name), join(staging, "skills", name));
52
- }
53
- writeText(join(staging, "README.md"), `# ${opts.as}\n\n${manifest.description}\n`);
54
-
55
- return installPlugin({
56
- source: staging,
57
- pluginsDir: opts.pluginsDir,
58
- origin: { type: "local", path: `./${opts.as}` },
59
- marketplaceName: opts.marketplaceName,
60
- now: opts.now,
61
- });
62
- } finally {
63
- rmSync(staging, { recursive: true, force: true });
64
- }
65
- }
66
-
67
- function copySkill(from: string, to: string): void {
68
- cpSync(from, to, { recursive: true });
69
- }