@agents-inc/cli 0.45.0 → 0.46.0
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/CHANGELOG.md +14 -0
- package/dist/{chunk-NTPHCNJO.js → chunk-3WKFSTG6.js} +2 -2
- package/dist/{chunk-ELRGSZHZ.js → chunk-4C7PDDLY.js} +5 -5
- package/dist/{chunk-HKRLWERR.js → chunk-5M6JI76P.js} +2 -2
- package/dist/{chunk-473YHDYQ.js → chunk-5QRJUBK7.js} +131 -45
- package/dist/chunk-5QRJUBK7.js.map +1 -0
- package/dist/{chunk-KVHLKPYB.js → chunk-72GS6PIH.js} +7 -7
- package/dist/{chunk-FVN5PFFY.js → chunk-74HSA7C4.js} +3 -1
- package/dist/chunk-74HSA7C4.js.map +1 -0
- package/dist/chunk-7LDSHHKN.js +132 -0
- package/dist/chunk-7LDSHHKN.js.map +1 -0
- package/dist/{chunk-F3O5YHSI.js → chunk-C7BO2ASM.js} +2 -2
- package/dist/{chunk-ABE55TEU.js → chunk-CD64ZNYI.js} +2 -2
- package/dist/chunk-CDGHSTB6.js +69 -0
- package/dist/chunk-CDGHSTB6.js.map +1 -0
- package/dist/{chunk-Q5BSIARS.js → chunk-CTQHZELA.js} +15 -15
- package/dist/chunk-CTQHZELA.js.map +1 -0
- package/dist/{chunk-OALQWRLG.js → chunk-D7JTL3DJ.js} +2 -2
- package/dist/{chunk-KWWLPPHF.js → chunk-DO5OZHSS.js} +2 -2
- package/dist/{chunk-DAVOSI4M.js → chunk-FKBCYT7B.js} +5 -5
- package/dist/{chunk-VTDEENSP.js → chunk-FUEZQ2H6.js} +5 -5
- package/dist/{chunk-VTDEENSP.js.map → chunk-FUEZQ2H6.js.map} +1 -1
- package/dist/{chunk-V43QDMYQ.js → chunk-G2WNOT3R.js} +2 -2
- package/dist/{chunk-M3AGB4TR.js → chunk-GVLYNP2I.js} +4 -4
- package/dist/{chunk-WWSKP5SR.js → chunk-HM3DHMW7.js} +70 -24
- package/dist/chunk-HM3DHMW7.js.map +1 -0
- package/dist/{chunk-ENWMWIHP.js → chunk-I26YP2Q3.js} +5 -12
- package/dist/chunk-I26YP2Q3.js.map +1 -0
- package/dist/{chunk-KZNPPUQG.js → chunk-J64CA4V6.js} +5 -3
- package/dist/chunk-J64CA4V6.js.map +1 -0
- package/dist/{chunk-YQFU2KZ5.js → chunk-KWQ2BQXF.js} +3 -3
- package/dist/{chunk-SRFNNOLC.js → chunk-LFZXMQOH.js} +2 -2
- package/dist/{chunk-ARET3NYO.js → chunk-NMXNHRAK.js} +3 -3
- package/dist/{chunk-GUIRWCKI.js → chunk-ODQ2BKWU.js} +3 -3
- package/dist/{chunk-SYGEV3KV.js → chunk-PZLUO4OY.js} +4 -4
- package/dist/{chunk-CLHBKFHU.js → chunk-QBUOZVNZ.js} +2 -2
- package/dist/{chunk-ZECXM7LP.js → chunk-RT6IBH37.js} +3524 -3502
- package/dist/chunk-RT6IBH37.js.map +1 -0
- package/dist/{chunk-YRVTXSXP.js → chunk-RWR56UVK.js} +3 -18
- package/dist/chunk-RWR56UVK.js.map +1 -0
- package/dist/{chunk-OLZBZAW4.js → chunk-SGXUMZWL.js} +2 -2
- package/dist/{chunk-3S4GIO4B.js → chunk-TOWP4T5L.js} +2 -2
- package/dist/{chunk-FYNMNY4P.js → chunk-UK3AMBR7.js} +17 -11
- package/dist/chunk-UK3AMBR7.js.map +1 -0
- package/dist/{chunk-M2XPTQDT.js → chunk-VH3PI43B.js} +4 -4
- package/dist/{chunk-3JRWNWBF.js → chunk-XE6RTHUD.js} +2 -3
- package/dist/{chunk-3JRWNWBF.js.map → chunk-XE6RTHUD.js.map} +1 -1
- package/dist/{chunk-KCYNTAAF.js → chunk-YT7UHV67.js} +8 -8
- package/dist/{chunk-SBWMSNS2.js → chunk-YVMYQSED.js} +2 -2
- package/dist/commands/build/marketplace.js +12 -126
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +5 -5
- package/dist/commands/build/stack.js +5 -5
- package/dist/commands/compile.js +6 -6
- package/dist/commands/config/get.js +4 -4
- package/dist/commands/config/index.js +5 -5
- package/dist/commands/config/path.js +4 -4
- package/dist/commands/config/set-project.js +4 -4
- package/dist/commands/config/show.js +5 -5
- package/dist/commands/config/unset-project.js +4 -4
- package/dist/commands/diff.js +4 -4
- package/dist/commands/doctor.js +4 -4
- package/dist/commands/edit.js +29 -29
- package/dist/commands/eject.js +19 -23
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +5 -5
- package/dist/commands/info.js +5 -5
- package/dist/commands/init.js +30 -29
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +4 -4
- package/dist/commands/new/agent.js +52 -38
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/marketplace.js +252 -0
- package/dist/commands/new/marketplace.js.map +1 -0
- package/dist/commands/new/skill.js +30 -14
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +4 -4
- package/dist/commands/search.js +7 -7
- package/dist/commands/uninstall.js +6 -6
- package/dist/commands/update.js +6 -6
- package/dist/commands/validate.js +5 -5
- package/dist/components/skill-search/skill-search.js +3 -3
- package/dist/components/wizard/category-grid.js +2 -2
- package/dist/components/wizard/category-grid.test.js +2 -2
- package/dist/components/wizard/checkbox-grid.js +3 -3
- package/dist/components/wizard/checkbox-grid.test.js +3 -3
- package/dist/components/wizard/domain-selection.js +9 -8
- package/dist/components/wizard/help-modal.js +2 -2
- package/dist/components/wizard/menu-item.js +1 -1
- package/dist/components/wizard/search-modal.js +2 -2
- package/dist/components/wizard/search-modal.test.js +2 -2
- package/dist/components/wizard/section-progress.js +2 -2
- package/dist/components/wizard/section-progress.test.js +2 -2
- package/dist/components/wizard/selection-card.js +2 -2
- package/dist/components/wizard/source-grid.js +3 -3
- package/dist/components/wizard/source-grid.test.js +3 -3
- package/dist/components/wizard/stack-selection.js +8 -9
- package/dist/components/wizard/step-agents.js +8 -7
- package/dist/components/wizard/step-agents.test.js +25 -20
- package/dist/components/wizard/step-agents.test.js.map +1 -1
- package/dist/components/wizard/step-build.js +8 -8
- package/dist/components/wizard/step-build.test.js +10 -10
- package/dist/components/wizard/step-confirm.js +4 -4
- package/dist/components/wizard/step-confirm.test.js +8 -8
- package/dist/components/wizard/step-refine.js +2 -2
- package/dist/components/wizard/step-refine.test.js +2 -2
- package/dist/components/wizard/step-settings.js +5 -5
- package/dist/components/wizard/step-settings.test.js +8 -8
- package/dist/components/wizard/step-sources.js +10 -10
- package/dist/components/wizard/step-sources.test.js +11 -11
- package/dist/components/wizard/step-stack.js +12 -12
- package/dist/components/wizard/step-stack.test.js +27 -15
- package/dist/components/wizard/step-stack.test.js.map +1 -1
- package/dist/components/wizard/view-title.js +2 -2
- package/dist/components/wizard/wizard-layout.js +8 -8
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard-tabs.test.js +2 -2
- package/dist/components/wizard/wizard.js +25 -25
- package/dist/hooks/init.js +3 -5
- package/dist/hooks/init.js.map +1 -1
- package/dist/{source-manager-HXFXBZJU.js → source-manager-6QZ2GDUA.js} +4 -4
- package/dist/stores/wizard-store.js +5 -5
- package/dist/stores/wizard-store.test.js +6 -6
- package/package.json +1 -1
- package/src/schemas/agent.schema.json +3 -0
- package/src/schemas/metadata.schema.json +4 -41
- package/src/schemas/project-config.schema.json +8 -4
- package/src/schemas/skills-matrix.schema.json +11 -298
- package/src/schemas/stacks.schema.json +2 -4
- package/dist/chunk-473YHDYQ.js.map +0 -1
- package/dist/chunk-5BDYODWP.js +0 -45
- package/dist/chunk-5BDYODWP.js.map +0 -1
- package/dist/chunk-ENWMWIHP.js.map +0 -1
- package/dist/chunk-FVN5PFFY.js.map +0 -1
- package/dist/chunk-FYNMNY4P.js.map +0 -1
- package/dist/chunk-KZNPPUQG.js.map +0 -1
- package/dist/chunk-Q5BSIARS.js.map +0 -1
- package/dist/chunk-WWSKP5SR.js.map +0 -1
- package/dist/chunk-YRVTXSXP.js.map +0 -1
- package/dist/chunk-ZECXM7LP.js.map +0 -1
- package/dist/cli/defaults/agent-mappings.yaml +0 -215
- /package/dist/{chunk-NTPHCNJO.js.map → chunk-3WKFSTG6.js.map} +0 -0
- /package/dist/{chunk-ELRGSZHZ.js.map → chunk-4C7PDDLY.js.map} +0 -0
- /package/dist/{chunk-HKRLWERR.js.map → chunk-5M6JI76P.js.map} +0 -0
- /package/dist/{chunk-KVHLKPYB.js.map → chunk-72GS6PIH.js.map} +0 -0
- /package/dist/{chunk-F3O5YHSI.js.map → chunk-C7BO2ASM.js.map} +0 -0
- /package/dist/{chunk-ABE55TEU.js.map → chunk-CD64ZNYI.js.map} +0 -0
- /package/dist/{chunk-OALQWRLG.js.map → chunk-D7JTL3DJ.js.map} +0 -0
- /package/dist/{chunk-KWWLPPHF.js.map → chunk-DO5OZHSS.js.map} +0 -0
- /package/dist/{chunk-DAVOSI4M.js.map → chunk-FKBCYT7B.js.map} +0 -0
- /package/dist/{chunk-V43QDMYQ.js.map → chunk-G2WNOT3R.js.map} +0 -0
- /package/dist/{chunk-M3AGB4TR.js.map → chunk-GVLYNP2I.js.map} +0 -0
- /package/dist/{chunk-YQFU2KZ5.js.map → chunk-KWQ2BQXF.js.map} +0 -0
- /package/dist/{chunk-SRFNNOLC.js.map → chunk-LFZXMQOH.js.map} +0 -0
- /package/dist/{chunk-ARET3NYO.js.map → chunk-NMXNHRAK.js.map} +0 -0
- /package/dist/{chunk-GUIRWCKI.js.map → chunk-ODQ2BKWU.js.map} +0 -0
- /package/dist/{chunk-SYGEV3KV.js.map → chunk-PZLUO4OY.js.map} +0 -0
- /package/dist/{chunk-CLHBKFHU.js.map → chunk-QBUOZVNZ.js.map} +0 -0
- /package/dist/{chunk-OLZBZAW4.js.map → chunk-SGXUMZWL.js.map} +0 -0
- /package/dist/{chunk-3S4GIO4B.js.map → chunk-TOWP4T5L.js.map} +0 -0
- /package/dist/{chunk-M2XPTQDT.js.map → chunk-VH3PI43B.js.map} +0 -0
- /package/dist/{chunk-KCYNTAAF.js.map → chunk-YT7UHV67.js.map} +0 -0
- /package/dist/{chunk-SBWMSNS2.js.map → chunk-YVMYQSED.js.map} +0 -0
- /package/dist/{source-manager-HXFXBZJU.js.map → source-manager-6QZ2GDUA.js.map} +0 -0
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getAgentDefinitions
|
|
4
|
+
} from "../../chunk-PZLUO4OY.js";
|
|
2
5
|
import {
|
|
3
6
|
isClaudeCLIAvailable
|
|
4
|
-
} from "../../chunk-
|
|
7
|
+
} from "../../chunk-QBUOZVNZ.js";
|
|
5
8
|
import {
|
|
6
9
|
BaseCommand,
|
|
7
10
|
EXIT_CODES
|
|
8
|
-
} from "../../chunk-
|
|
11
|
+
} from "../../chunk-LFZXMQOH.js";
|
|
9
12
|
import {
|
|
10
|
-
fetchFromSource,
|
|
11
13
|
resolveSource
|
|
12
|
-
} from "../../chunk-
|
|
14
|
+
} from "../../chunk-RT6IBH37.js";
|
|
13
15
|
import "../../chunk-T4EXUIBY.js";
|
|
14
16
|
import {
|
|
15
17
|
fileExists,
|
|
16
18
|
readFile
|
|
17
|
-
} from "../../chunk-
|
|
19
|
+
} from "../../chunk-5QRJUBK7.js";
|
|
18
20
|
import {
|
|
19
21
|
CLAUDE_DIR,
|
|
20
22
|
CLI_COLORS
|
|
21
|
-
} from "../../chunk-
|
|
23
|
+
} from "../../chunk-74HSA7C4.js";
|
|
22
24
|
import {
|
|
23
25
|
init_esm_shims
|
|
24
26
|
} from "../../chunk-DHET7RCE.js";
|
|
@@ -30,16 +32,17 @@ import { Args, Flags } from "@oclif/core";
|
|
|
30
32
|
import { TextInput } from "@inkjs/ui";
|
|
31
33
|
import { spawn } from "child_process";
|
|
32
34
|
import matter from "gray-matter";
|
|
33
|
-
import { render, Box, Text, useInput } from "ink";
|
|
35
|
+
import { render, Box, Text, useApp, useInput } from "ink";
|
|
34
36
|
import path from "path";
|
|
35
37
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
36
38
|
var META_AGENT_NAME = "agent-summoner";
|
|
37
|
-
var AGENTS_SUBDIR = ".claude/agents";
|
|
38
39
|
var PurposeInput = ({ onSubmit, onCancel }) => {
|
|
40
|
+
const { exit } = useApp();
|
|
39
41
|
const [error, setError] = useState(null);
|
|
40
42
|
useInput((_input, key) => {
|
|
41
43
|
if (key.escape) {
|
|
42
44
|
onCancel();
|
|
45
|
+
exit();
|
|
43
46
|
}
|
|
44
47
|
});
|
|
45
48
|
const handleSubmit = (value) => {
|
|
@@ -49,6 +52,7 @@ var PurposeInput = ({ onSubmit, onCancel }) => {
|
|
|
49
52
|
return;
|
|
50
53
|
}
|
|
51
54
|
onSubmit(trimmed);
|
|
55
|
+
exit();
|
|
52
56
|
};
|
|
53
57
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
54
58
|
/* @__PURE__ */ jsx(Text, { bold: true, children: "Create New Agent" }),
|
|
@@ -59,31 +63,41 @@ var PurposeInput = ({ onSubmit, onCancel }) => {
|
|
|
59
63
|
error && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: CLI_COLORS.ERROR, children: error }) })
|
|
60
64
|
] });
|
|
61
65
|
};
|
|
62
|
-
|
|
63
|
-
const result = await fetchFromSource(source, {
|
|
64
|
-
forceRefresh,
|
|
65
|
-
subdir: AGENTS_SUBDIR
|
|
66
|
-
});
|
|
67
|
-
const agentPath = path.join(result.path, `${META_AGENT_NAME}.md`);
|
|
68
|
-
if (!await fileExists(agentPath)) {
|
|
69
|
-
throw new Error(
|
|
70
|
-
`Meta-agent not found: ${META_AGENT_NAME}.md
|
|
71
|
-
|
|
72
|
-
Expected at: ${agentPath}
|
|
73
|
-
The source repository may not contain the agent-summoner agent.`
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
const content = await readFile(agentPath);
|
|
66
|
+
function parseCompiledAgent(content) {
|
|
77
67
|
const { data: frontmatter, content: body } = matter(content);
|
|
78
|
-
const
|
|
79
|
-
const tools = fm.tools ? fm.tools.split(",").map((t) => t.trim()) : void 0;
|
|
68
|
+
const tools = typeof frontmatter.tools === "string" ? frontmatter.tools.split(",").map((t) => t.trim()) : frontmatter.tools;
|
|
80
69
|
return {
|
|
81
|
-
description:
|
|
82
|
-
prompt: body,
|
|
83
|
-
model:
|
|
70
|
+
description: frontmatter.description || "Creates new agents",
|
|
71
|
+
prompt: body.trim(),
|
|
72
|
+
model: frontmatter.model,
|
|
84
73
|
tools
|
|
85
74
|
};
|
|
86
75
|
}
|
|
76
|
+
async function loadMetaAgent(projectDir, source, forceRefresh) {
|
|
77
|
+
const compiledFileName = `${META_AGENT_NAME}.md`;
|
|
78
|
+
const localAgentPath = path.join(projectDir, CLAUDE_DIR, "agents", compiledFileName);
|
|
79
|
+
if (await fileExists(localAgentPath)) {
|
|
80
|
+
return parseCompiledAgent(await readFile(localAgentPath));
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const agentPaths = await getAgentDefinitions(source, { forceRefresh, projectDir });
|
|
84
|
+
const remoteAgentPath = path.join(
|
|
85
|
+
agentPaths.sourcePath,
|
|
86
|
+
CLAUDE_DIR,
|
|
87
|
+
"agents",
|
|
88
|
+
compiledFileName
|
|
89
|
+
);
|
|
90
|
+
if (await fileExists(remoteAgentPath)) {
|
|
91
|
+
return parseCompiledAgent(await readFile(remoteAgentPath));
|
|
92
|
+
}
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Agent '${META_AGENT_NAME}' not found.
|
|
97
|
+
|
|
98
|
+
Run 'compile' first to generate agents.`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
87
101
|
function buildAgentPrompt(agentName, purpose, outputDir) {
|
|
88
102
|
return `Create a new Claude Code agent named "${agentName}" in the directory "${outputDir}".
|
|
89
103
|
|
|
@@ -96,6 +110,7 @@ Requirements:
|
|
|
96
110
|
4. Create workflow.md with the agent's operational process
|
|
97
111
|
5. Optionally create examples.md if relevant examples would help
|
|
98
112
|
6. Optionally create critical-requirements.md for important rules
|
|
113
|
+
7. Include \`custom: true\` in the agent.yaml configuration
|
|
99
114
|
|
|
100
115
|
Follow the existing agent patterns in the codebase. Keep the agent focused and practical.`;
|
|
101
116
|
}
|
|
@@ -116,8 +131,7 @@ async function invokeMetaAgent(agentDef, prompt, nonInteractive) {
|
|
|
116
131
|
}
|
|
117
132
|
return new Promise((resolve, reject) => {
|
|
118
133
|
const child = spawn("claude", args, {
|
|
119
|
-
stdio: "inherit"
|
|
120
|
-
shell: true
|
|
134
|
+
stdio: "inherit"
|
|
121
135
|
});
|
|
122
136
|
child.on("error", (error) => {
|
|
123
137
|
reject(new Error(`Failed to spawn claude CLI: ${error.message}`));
|
|
@@ -147,15 +161,15 @@ var NewAgent = class _NewAgent extends BaseCommand {
|
|
|
147
161
|
description: "Purpose/description of the agent",
|
|
148
162
|
required: false
|
|
149
163
|
}),
|
|
150
|
-
refresh: Flags.boolean({
|
|
151
|
-
char: "r",
|
|
152
|
-
description: "Force refresh remote source",
|
|
153
|
-
default: false
|
|
154
|
-
}),
|
|
155
164
|
"non-interactive": Flags.boolean({
|
|
156
165
|
char: "n",
|
|
157
166
|
description: "Run in non-interactive mode",
|
|
158
167
|
default: false
|
|
168
|
+
}),
|
|
169
|
+
refresh: Flags.boolean({
|
|
170
|
+
char: "r",
|
|
171
|
+
description: "Force refresh remote source",
|
|
172
|
+
default: false
|
|
159
173
|
})
|
|
160
174
|
};
|
|
161
175
|
async run() {
|
|
@@ -168,8 +182,6 @@ var NewAgent = class _NewAgent extends BaseCommand {
|
|
|
168
182
|
{ exit: EXIT_CODES.ERROR }
|
|
169
183
|
);
|
|
170
184
|
}
|
|
171
|
-
const sourceConfig = await resolveSource(flags.source, projectDir);
|
|
172
|
-
const source = sourceConfig.source;
|
|
173
185
|
let purpose = flags.purpose;
|
|
174
186
|
if (!purpose) {
|
|
175
187
|
let inputResult = null;
|
|
@@ -202,7 +214,8 @@ var NewAgent = class _NewAgent extends BaseCommand {
|
|
|
202
214
|
this.log("");
|
|
203
215
|
this.log("Fetching agent-summoner from source...");
|
|
204
216
|
try {
|
|
205
|
-
const
|
|
217
|
+
const sourceConfig = await resolveSource(flags.source, projectDir);
|
|
218
|
+
const agentDef = await loadMetaAgent(projectDir, sourceConfig.source, flags.refresh);
|
|
206
219
|
this.log("Meta-agent loaded");
|
|
207
220
|
this.log("");
|
|
208
221
|
const agentPrompt = buildAgentPrompt(args.name, purpose, outputDir);
|
|
@@ -219,6 +232,7 @@ var NewAgent = class _NewAgent extends BaseCommand {
|
|
|
219
232
|
}
|
|
220
233
|
};
|
|
221
234
|
export {
|
|
235
|
+
buildAgentPrompt,
|
|
222
236
|
NewAgent as default
|
|
223
237
|
};
|
|
224
238
|
//# sourceMappingURL=agent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/new/agent.tsx"],"sourcesContent":["import React, { useState } from \"react\";\n\nimport { Args, Flags } from \"@oclif/core\";\nimport { TextInput } from \"@inkjs/ui\";\nimport { spawn } from \"child_process\";\nimport matter from \"gray-matter\";\nimport { render, Box, Text, useInput } from \"ink\";\nimport path from \"path\";\n\nimport { BaseCommand } from \"../../base-command.js\";\nimport { CLAUDE_DIR, CLI_COLORS } from \"../../consts.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { resolveSource } from \"../../lib/configuration/index.js\";\nimport { fetchFromSource } from \"../../lib/loading/index.js\";\nimport { isClaudeCLIAvailable } from \"../../utils/exec.js\";\nimport { fileExists, readFile } from \"../../utils/fs.js\";\n\nconst META_AGENT_NAME = \"agent-summoner\";\nconst AGENTS_SUBDIR = \".claude/agents\";\n\ntype NewAgentInput = {\n description: string;\n prompt: string;\n model?: string;\n tools?: string[];\n};\n\ntype AgentSourceFrontmatter = {\n name: string;\n description: string;\n tools?: string;\n model?: string;\n permissionMode?: string;\n};\n\ntype PurposeInputProps = {\n onSubmit: (purpose: string) => void;\n onCancel: () => void;\n};\n\nconst PurposeInput: React.FC<PurposeInputProps> = ({ onSubmit, onCancel }) => {\n const [error, setError] = useState<string | null>(null);\n\n useInput((_input, key) => {\n if (key.escape) {\n onCancel();\n }\n });\n\n const handleSubmit = (value: string) => {\n const trimmed = value.trim();\n if (!trimmed) {\n setError(\"Purpose is required\");\n return;\n }\n onSubmit(trimmed);\n };\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>Create New Agent</Text>\n <Text>What should this agent do?</Text>\n <Text dimColor>e.g., Manages database migrations with rollback support</Text>\n <Text> </Text>\n <TextInput placeholder=\"Enter agent purpose...\" onSubmit={handleSubmit} />\n {error && (\n <Box marginTop={1}>\n <Text color={CLI_COLORS.ERROR}>{error}</Text>\n </Box>\n )}\n </Box>\n );\n};\n\nasync function fetchMetaAgent(source: string, forceRefresh: boolean): Promise<NewAgentInput> {\n const result = await fetchFromSource(source, {\n forceRefresh,\n subdir: AGENTS_SUBDIR,\n });\n\n const agentPath = path.join(result.path, `${META_AGENT_NAME}.md`);\n\n if (!(await fileExists(agentPath))) {\n throw new Error(\n `Meta-agent not found: ${META_AGENT_NAME}.md\\n\\n` +\n `Expected at: ${agentPath}\\n` +\n `The source repository may not contain the agent-summoner agent.`,\n );\n }\n\n const content = await readFile(agentPath);\n\n const { data: frontmatter, content: body } = matter(content);\n const fm = frontmatter as AgentSourceFrontmatter;\n\n const tools = fm.tools ? fm.tools.split(\",\").map((t: string) => t.trim()) : undefined;\n\n return {\n description: fm.description || \"Creates new agents\",\n prompt: body,\n model: fm.model,\n tools,\n };\n}\n\nfunction buildAgentPrompt(agentName: string, purpose: string, outputDir: string): string {\n return `Create a new Claude Code agent named \"${agentName}\" in the directory \"${outputDir}\".\n\nAgent Purpose: ${purpose}\n\nRequirements:\n1. Create the agent directory structure at ${outputDir}/${agentName}/\n2. Create agent.yaml with appropriate configuration\n3. Create intro.md with the agent's role and context\n4. Create workflow.md with the agent's operational process\n5. Optionally create examples.md if relevant examples would help\n6. Optionally create critical-requirements.md for important rules\n\nFollow the existing agent patterns in the codebase. Keep the agent focused and practical.`;\n}\n\nasync function invokeMetaAgent(\n agentDef: NewAgentInput,\n prompt: string,\n nonInteractive: boolean,\n): Promise<void> {\n const agentsJson = JSON.stringify({\n [META_AGENT_NAME]: {\n description: agentDef.description,\n prompt: agentDef.prompt,\n model: agentDef.model,\n tools: agentDef.tools,\n },\n });\n\n const args = [\"--agents\", agentsJson, \"--agent\", META_AGENT_NAME];\n\n if (nonInteractive) {\n args.push(\"-p\", prompt);\n } else {\n args.push(\"--prompt\", prompt);\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn(\"claude\", args, {\n stdio: \"inherit\",\n shell: true,\n });\n\n child.on(\"error\", (error) => {\n reject(new Error(`Failed to spawn claude CLI: ${error.message}`));\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Claude CLI exited with code ${code}`));\n }\n });\n });\n}\n\nexport default class NewAgent extends BaseCommand {\n static summary = \"Create a new custom agent using AI generation\";\n static description =\n \"Uses the agent-summoner meta-agent to scaffold a new agent with proper structure and documentation.\";\n\n static args = {\n name: Args.string({\n description: \"Name of the agent to create\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n purpose: Flags.string({\n char: \"p\",\n description: \"Purpose/description of the agent\",\n required: false,\n }),\n refresh: Flags.boolean({\n char: \"r\",\n description: \"Force refresh remote source\",\n default: false,\n }),\n \"non-interactive\": Flags.boolean({\n char: \"n\",\n description: \"Run in non-interactive mode\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(NewAgent);\n const projectDir = process.cwd();\n\n const cliAvailable = await isClaudeCLIAvailable();\n if (!cliAvailable) {\n this.error(\n \"Claude CLI not found. Please install it first:\\n\" +\n \" npm install -g @anthropic-ai/claude-code\",\n { exit: EXIT_CODES.ERROR },\n );\n }\n\n const sourceConfig = await resolveSource(flags.source, projectDir);\n const source = sourceConfig.source;\n\n let purpose = flags.purpose;\n\n if (!purpose) {\n let inputResult: string | null = null;\n let cancelled = false;\n\n const { waitUntilExit } = render(\n <PurposeInput\n onSubmit={(value) => {\n inputResult = value;\n }}\n onCancel={() => {\n cancelled = true;\n }}\n />,\n );\n\n await waitUntilExit();\n\n if (cancelled || !inputResult) {\n this.log(\"Cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n\n purpose = inputResult;\n }\n\n const outputDir = path.join(projectDir, CLAUDE_DIR, \"agents\", \"_custom\");\n\n this.log(\"\");\n this.log(`Agent name: ${args.name}`);\n this.log(`Purpose: ${purpose}`);\n this.log(`Output: ${outputDir}`);\n this.log(\"\");\n\n this.log(\"Fetching agent-summoner from source...\");\n\n try {\n const agentDef = await fetchMetaAgent(source, flags.refresh);\n this.log(\"Meta-agent loaded\");\n this.log(\"\");\n\n const agentPrompt = buildAgentPrompt(args.name, purpose, outputDir);\n\n this.log(\"Invoking agent-summoner to create your agent...\");\n this.log(\"─\".repeat(60));\n this.log(\"\");\n\n await invokeMetaAgent(agentDef, agentPrompt, flags[\"non-interactive\"]);\n\n this.log(\"\");\n this.log(\"─\".repeat(60));\n this.logSuccess(\"Agent creation complete!\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/new/agent.tsx"],"sourcesContent":["import React, { useState } from \"react\";\n\nimport { Args, Flags } from \"@oclif/core\";\nimport { TextInput } from \"@inkjs/ui\";\nimport { spawn } from \"child_process\";\nimport matter from \"gray-matter\";\nimport { render, Box, Text, useApp, useInput } from \"ink\";\nimport path from \"path\";\n\nimport { BaseCommand } from \"../../base-command.js\";\nimport { CLAUDE_DIR, CLI_COLORS } from \"../../consts.js\";\nimport { getAgentDefinitions } from \"../../lib/agents/index.js\";\nimport { resolveSource } from \"../../lib/configuration/index.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { isClaudeCLIAvailable } from \"../../utils/exec.js\";\nimport { fileExists, readFile } from \"../../utils/fs.js\";\n\nconst META_AGENT_NAME = \"agent-summoner\";\n\ntype NewAgentInput = {\n description: string;\n prompt: string;\n model?: string;\n tools?: string[];\n};\n\ntype PurposeInputProps = {\n onSubmit: (purpose: string) => void;\n onCancel: () => void;\n};\n\nconst PurposeInput: React.FC<PurposeInputProps> = ({ onSubmit, onCancel }) => {\n const { exit } = useApp();\n const [error, setError] = useState<string | null>(null);\n\n useInput((_input, key) => {\n if (key.escape) {\n onCancel();\n exit();\n }\n });\n\n const handleSubmit = (value: string) => {\n const trimmed = value.trim();\n if (!trimmed) {\n setError(\"Purpose is required\");\n return;\n }\n onSubmit(trimmed);\n exit();\n };\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>Create New Agent</Text>\n <Text>What should this agent do?</Text>\n <Text dimColor>e.g., Manages database migrations with rollback support</Text>\n <Text> </Text>\n <TextInput placeholder=\"Enter agent purpose...\" onSubmit={handleSubmit} />\n {error && (\n <Box marginTop={1}>\n <Text color={CLI_COLORS.ERROR}>{error}</Text>\n </Box>\n )}\n </Box>\n );\n};\n\nfunction parseCompiledAgent(content: string): NewAgentInput {\n const { data: frontmatter, content: body } = matter(content);\n const tools =\n typeof frontmatter.tools === \"string\"\n ? frontmatter.tools.split(\",\").map((t: string) => t.trim())\n : frontmatter.tools;\n\n return {\n description: frontmatter.description || \"Creates new agents\",\n prompt: body.trim(),\n model: frontmatter.model,\n tools,\n };\n}\n\nasync function loadMetaAgent(\n projectDir: string,\n source: string,\n forceRefresh: boolean,\n): Promise<NewAgentInput> {\n const compiledFileName = `${META_AGENT_NAME}.md`;\n\n // Check for compiled agent in the current project\n const localAgentPath = path.join(projectDir, CLAUDE_DIR, \"agents\", compiledFileName);\n if (await fileExists(localAgentPath)) {\n return parseCompiledAgent(await readFile(localAgentPath));\n }\n\n // Fall back to remote source (may not have agents)\n try {\n const agentPaths = await getAgentDefinitions(source, { forceRefresh, projectDir });\n const remoteAgentPath = path.join(\n agentPaths.sourcePath,\n CLAUDE_DIR,\n \"agents\",\n compiledFileName,\n );\n if (await fileExists(remoteAgentPath)) {\n return parseCompiledAgent(await readFile(remoteAgentPath));\n }\n } catch {\n // Source does not contain agents — fall through to error\n }\n\n throw new Error(\n `Agent '${META_AGENT_NAME}' not found.\\n\\n` + `Run 'compile' first to generate agents.`,\n );\n}\n\nexport function buildAgentPrompt(agentName: string, purpose: string, outputDir: string): string {\n return `Create a new Claude Code agent named \"${agentName}\" in the directory \"${outputDir}\".\n\nAgent Purpose: ${purpose}\n\nRequirements:\n1. Create the agent directory structure at ${outputDir}/${agentName}/\n2. Create agent.yaml with appropriate configuration\n3. Create intro.md with the agent's role and context\n4. Create workflow.md with the agent's operational process\n5. Optionally create examples.md if relevant examples would help\n6. Optionally create critical-requirements.md for important rules\n7. Include \\`custom: true\\` in the agent.yaml configuration\n\nFollow the existing agent patterns in the codebase. Keep the agent focused and practical.`;\n}\n\nasync function invokeMetaAgent(\n agentDef: NewAgentInput,\n prompt: string,\n nonInteractive: boolean,\n): Promise<void> {\n const agentsJson = JSON.stringify({\n [META_AGENT_NAME]: {\n description: agentDef.description,\n prompt: agentDef.prompt,\n model: agentDef.model,\n tools: agentDef.tools,\n },\n });\n\n const args = [\"--agents\", agentsJson, \"--agent\", META_AGENT_NAME];\n\n if (nonInteractive) {\n args.push(\"-p\", prompt);\n } else {\n args.push(\"--prompt\", prompt);\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn(\"claude\", args, {\n stdio: \"inherit\",\n });\n\n child.on(\"error\", (error) => {\n reject(new Error(`Failed to spawn claude CLI: ${error.message}`));\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Claude CLI exited with code ${code}`));\n }\n });\n });\n}\n\nexport default class NewAgent extends BaseCommand {\n static summary = \"Create a new custom agent using AI generation\";\n static description =\n \"Uses the agent-summoner meta-agent to scaffold a new agent with proper structure and documentation.\";\n\n static args = {\n name: Args.string({\n description: \"Name of the agent to create\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n purpose: Flags.string({\n char: \"p\",\n description: \"Purpose/description of the agent\",\n required: false,\n }),\n \"non-interactive\": Flags.boolean({\n char: \"n\",\n description: \"Run in non-interactive mode\",\n default: false,\n }),\n refresh: Flags.boolean({\n char: \"r\",\n description: \"Force refresh remote source\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(NewAgent);\n const projectDir = process.cwd();\n\n const cliAvailable = await isClaudeCLIAvailable();\n if (!cliAvailable) {\n this.error(\n \"Claude CLI not found. Please install it first:\\n\" +\n \" npm install -g @anthropic-ai/claude-code\",\n { exit: EXIT_CODES.ERROR },\n );\n }\n\n let purpose = flags.purpose;\n\n if (!purpose) {\n let inputResult: string | null = null;\n let cancelled = false;\n\n const { waitUntilExit } = render(\n <PurposeInput\n onSubmit={(value) => {\n inputResult = value;\n }}\n onCancel={() => {\n cancelled = true;\n }}\n />,\n );\n\n await waitUntilExit();\n\n if (cancelled || !inputResult) {\n this.log(\"Cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n\n purpose = inputResult;\n }\n\n const outputDir = path.join(projectDir, CLAUDE_DIR, \"agents\", \"_custom\");\n\n this.log(\"\");\n this.log(`Agent name: ${args.name}`);\n this.log(`Purpose: ${purpose}`);\n this.log(`Output: ${outputDir}`);\n this.log(\"\");\n\n this.log(\"Fetching agent-summoner from source...\");\n\n try {\n const sourceConfig = await resolveSource(flags.source, projectDir);\n const agentDef = await loadMetaAgent(projectDir, sourceConfig.source, flags.refresh);\n this.log(\"Meta-agent loaded\");\n this.log(\"\");\n\n const agentPrompt = buildAgentPrompt(args.name, purpose, outputDir);\n\n this.log(\"Invoking agent-summoner to create your agent...\");\n this.log(\"─\".repeat(60));\n this.log(\"\");\n\n await invokeMetaAgent(agentDef, agentPrompt, flags[\"non-interactive\"]);\n\n this.log(\"\");\n this.log(\"─\".repeat(60));\n this.logSuccess(\"Agent creation complete!\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
generateMarketplace,
|
|
4
|
+
writeMarketplace
|
|
5
|
+
} from "../../chunk-7LDSHHKN.js";
|
|
6
|
+
import {
|
|
7
|
+
BaseCommand,
|
|
8
|
+
EXIT_CODES
|
|
9
|
+
} from "../../chunk-LFZXMQOH.js";
|
|
10
|
+
import {
|
|
11
|
+
compileAllSkillPlugins
|
|
12
|
+
} from "../../chunk-RT6IBH37.js";
|
|
13
|
+
import "../../chunk-T4EXUIBY.js";
|
|
14
|
+
import {
|
|
15
|
+
directoryExists,
|
|
16
|
+
ensureDir,
|
|
17
|
+
getErrorMessage,
|
|
18
|
+
writeFile
|
|
19
|
+
} from "../../chunk-5QRJUBK7.js";
|
|
20
|
+
import {
|
|
21
|
+
CLI_BIN_NAME,
|
|
22
|
+
KEBAB_CASE_PATTERN,
|
|
23
|
+
PLUGIN_MANIFEST_DIR,
|
|
24
|
+
SKILLS_DIR_PATH,
|
|
25
|
+
STACKS_FILE_PATH,
|
|
26
|
+
STANDARD_FILES
|
|
27
|
+
} from "../../chunk-74HSA7C4.js";
|
|
28
|
+
import {
|
|
29
|
+
init_esm_shims
|
|
30
|
+
} from "../../chunk-DHET7RCE.js";
|
|
31
|
+
|
|
32
|
+
// src/cli/commands/new/marketplace.ts
|
|
33
|
+
init_esm_shims();
|
|
34
|
+
import { Args, Flags } from "@oclif/core";
|
|
35
|
+
import path from "path";
|
|
36
|
+
function validateMarketplaceName(name) {
|
|
37
|
+
if (!name || name.trim() === "") {
|
|
38
|
+
return "Marketplace name is required";
|
|
39
|
+
}
|
|
40
|
+
if (!KEBAB_CASE_PATTERN.test(name)) {
|
|
41
|
+
return "Marketplace name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)";
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function generateStacksYaml(name) {
|
|
46
|
+
return `# Stack definitions for ${name}
|
|
47
|
+
|
|
48
|
+
stacks:
|
|
49
|
+
- id: dummy-stack
|
|
50
|
+
name: Dummy Stack
|
|
51
|
+
description: Default stack for ${name}
|
|
52
|
+
agents:
|
|
53
|
+
web-developer:
|
|
54
|
+
dummy-category: dummy-skill
|
|
55
|
+
philosophy: Ship fast, iterate faster
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
function generateReadme(name) {
|
|
59
|
+
return `# ${name}
|
|
60
|
+
|
|
61
|
+
Private marketplace for custom skills and stacks.
|
|
62
|
+
|
|
63
|
+
## Directory Structure
|
|
64
|
+
|
|
65
|
+
\`\`\`
|
|
66
|
+
${STACKS_FILE_PATH} # Stack definitions (agent groupings with skill mappings)
|
|
67
|
+
${SKILLS_DIR_PATH}/ # Custom skill definitions
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
## Creating Skills
|
|
71
|
+
|
|
72
|
+
\`\`\`bash
|
|
73
|
+
${CLI_BIN_NAME} new skill <name> --category <category-name>
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
76
|
+
Each skill lives in \`${SKILLS_DIR_PATH}/<skill-name>/\` with:
|
|
77
|
+
- \`${STANDARD_FILES.SKILL_MD}\` -- Skill content (what the skill teaches)
|
|
78
|
+
- \`${STANDARD_FILES.METADATA_YAML}\` -- Skill metadata (category, author, description, custom: true)
|
|
79
|
+
|
|
80
|
+
## Using This Marketplace
|
|
81
|
+
|
|
82
|
+
Point the CLI at this marketplace as a source:
|
|
83
|
+
|
|
84
|
+
\`\`\`bash
|
|
85
|
+
# Local development
|
|
86
|
+
${CLI_BIN_NAME} init --source /path/to/${name}
|
|
87
|
+
|
|
88
|
+
# From a git repository
|
|
89
|
+
${CLI_BIN_NAME} init --source github:your-org/${name}
|
|
90
|
+
\`\`\`
|
|
91
|
+
|
|
92
|
+
## How It Works
|
|
93
|
+
|
|
94
|
+
The CLI auto-discovers skills from the \`${SKILLS_DIR_PATH}/\` directory
|
|
95
|
+
and stacks from \`${STACKS_FILE_PATH}\`.
|
|
96
|
+
Custom categories are discovered from skill \`${STANDARD_FILES.METADATA_YAML}\` files with \`custom: true\`.
|
|
97
|
+
Custom skills appear alongside built-in ones in the wizard. No manual registration needed.
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
var NewMarketplace = class _NewMarketplace extends BaseCommand {
|
|
101
|
+
static summary = "Scaffold a new private marketplace project";
|
|
102
|
+
static description = "Create a new private marketplace directory with the required structure for custom skills and stacks.";
|
|
103
|
+
static examples = [
|
|
104
|
+
{
|
|
105
|
+
description: "Create a new marketplace",
|
|
106
|
+
command: "<%= config.bin %> <%= command.id %> acme-skills"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
description: "Initialize the current directory as a marketplace",
|
|
110
|
+
command: "<%= config.bin %> <%= command.id %> ."
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
description: "Create in a specific location",
|
|
114
|
+
command: "<%= config.bin %> <%= command.id %> acme-skills --output ~/projects"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
description: "Overwrite an existing directory",
|
|
118
|
+
command: "<%= config.bin %> <%= command.id %> acme-skills --force"
|
|
119
|
+
}
|
|
120
|
+
];
|
|
121
|
+
static args = {
|
|
122
|
+
name: Args.string({
|
|
123
|
+
description: 'Name of the marketplace directory (kebab-case), or "." to use the current directory',
|
|
124
|
+
required: true
|
|
125
|
+
})
|
|
126
|
+
};
|
|
127
|
+
static flags = {
|
|
128
|
+
...BaseCommand.baseFlags,
|
|
129
|
+
force: Flags.boolean({
|
|
130
|
+
char: "f",
|
|
131
|
+
description: "Overwrite existing directory",
|
|
132
|
+
default: false
|
|
133
|
+
}),
|
|
134
|
+
output: Flags.string({
|
|
135
|
+
char: "o",
|
|
136
|
+
description: "Parent directory to create the marketplace in (default: current directory)"
|
|
137
|
+
})
|
|
138
|
+
};
|
|
139
|
+
async run() {
|
|
140
|
+
const { args, flags } = await this.parse(_NewMarketplace);
|
|
141
|
+
this.log("");
|
|
142
|
+
this.log("Create New Marketplace");
|
|
143
|
+
this.log("");
|
|
144
|
+
const parentDir = flags.output ? path.resolve(flags.output) : process.cwd();
|
|
145
|
+
const useCurrentDir = args.name === ".";
|
|
146
|
+
const marketplaceName = useCurrentDir ? path.basename(parentDir) : args.name;
|
|
147
|
+
const marketplaceDir = useCurrentDir ? parentDir : path.join(parentDir, args.name);
|
|
148
|
+
const validationError = validateMarketplaceName(marketplaceName);
|
|
149
|
+
if (validationError) {
|
|
150
|
+
if (useCurrentDir) {
|
|
151
|
+
this.error(
|
|
152
|
+
`Current directory name '${marketplaceName}' is not valid kebab-case. Rename it or pass an explicit name.`,
|
|
153
|
+
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
this.error(validationError, { exit: EXIT_CODES.INVALID_ARGS });
|
|
157
|
+
}
|
|
158
|
+
if (!useCurrentDir && await directoryExists(marketplaceDir)) {
|
|
159
|
+
if (!flags.force) {
|
|
160
|
+
this.error(`Directory already exists: ${marketplaceDir}
|
|
161
|
+
Use --force to overwrite.`, {
|
|
162
|
+
exit: EXIT_CODES.ERROR
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
this.warn(`Overwriting existing directory at ${marketplaceDir}`);
|
|
166
|
+
}
|
|
167
|
+
this.log(`Marketplace: ${marketplaceName}`);
|
|
168
|
+
this.log(`Directory: ${marketplaceDir}`);
|
|
169
|
+
this.log("");
|
|
170
|
+
const skillName = "dummy-skill";
|
|
171
|
+
const skillPath = path.join(SKILLS_DIR_PATH, skillName);
|
|
172
|
+
if (flags["dry-run"]) {
|
|
173
|
+
this.log("[DRY RUN] Would create marketplace structure:");
|
|
174
|
+
this.log(` ${STACKS_FILE_PATH}`);
|
|
175
|
+
this.log(` ${skillPath}/${STANDARD_FILES.SKILL_MD}`);
|
|
176
|
+
this.log(` ${skillPath}/${STANDARD_FILES.METADATA_YAML}`);
|
|
177
|
+
this.log(" README.md");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.log("Creating marketplace structure...");
|
|
181
|
+
try {
|
|
182
|
+
const stacksContent = generateStacksYaml(marketplaceName);
|
|
183
|
+
const stacksPath = path.join(marketplaceDir, STACKS_FILE_PATH);
|
|
184
|
+
await ensureDir(path.dirname(stacksPath));
|
|
185
|
+
await writeFile(stacksPath, stacksContent);
|
|
186
|
+
const skillsDir = path.join(marketplaceDir, SKILLS_DIR_PATH);
|
|
187
|
+
const skillArgs = [skillName, "--output", skillsDir];
|
|
188
|
+
if (flags.force) skillArgs.push("--force");
|
|
189
|
+
await this.config.runCommand("new:skill", skillArgs);
|
|
190
|
+
const readmeContent = generateReadme(marketplaceName);
|
|
191
|
+
const readmePath = path.join(marketplaceDir, "README.md");
|
|
192
|
+
await writeFile(readmePath, readmeContent);
|
|
193
|
+
this.log("");
|
|
194
|
+
this.logSuccess(`Created ${STACKS_FILE_PATH}`);
|
|
195
|
+
this.logSuccess("Created README.md");
|
|
196
|
+
this.log("");
|
|
197
|
+
await this.buildMarketplace(marketplaceDir, marketplaceName);
|
|
198
|
+
this.log("Marketplace created successfully!");
|
|
199
|
+
this.log("");
|
|
200
|
+
this.log("Next steps:");
|
|
201
|
+
if (!useCurrentDir) {
|
|
202
|
+
this.log(` 1. cd ${marketplaceName}`);
|
|
203
|
+
}
|
|
204
|
+
this.log(
|
|
205
|
+
` ${useCurrentDir ? "1" : "2"}. ${CLI_BIN_NAME} new skill <name> --category <category-name>`
|
|
206
|
+
);
|
|
207
|
+
this.log(` ${useCurrentDir ? "2" : "3"}. Push to a git repository`);
|
|
208
|
+
this.log(
|
|
209
|
+
` ${useCurrentDir ? "3" : "4"}. ${CLI_BIN_NAME} init --source github:your-org/${marketplaceName}`
|
|
210
|
+
);
|
|
211
|
+
this.log("");
|
|
212
|
+
} catch (error) {
|
|
213
|
+
this.handleError(error);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async buildMarketplace(marketplaceDir, marketplaceName) {
|
|
217
|
+
const skillsDir = path.resolve(marketplaceDir, SKILLS_DIR_PATH);
|
|
218
|
+
const pluginsOutputDir = path.resolve(marketplaceDir, "dist/plugins");
|
|
219
|
+
const marketplaceOutputPath = path.resolve(
|
|
220
|
+
marketplaceDir,
|
|
221
|
+
PLUGIN_MANIFEST_DIR,
|
|
222
|
+
"marketplace.json"
|
|
223
|
+
);
|
|
224
|
+
try {
|
|
225
|
+
this.log("Building plugins...");
|
|
226
|
+
const results = await compileAllSkillPlugins(skillsDir, pluginsOutputDir);
|
|
227
|
+
this.logSuccess(`Built ${results.length} skill plugins.`);
|
|
228
|
+
this.log("Generating marketplace.json...");
|
|
229
|
+
const marketplace = await generateMarketplace(pluginsOutputDir, {
|
|
230
|
+
name: marketplaceName,
|
|
231
|
+
ownerName: marketplaceName,
|
|
232
|
+
pluginRoot: "./dist/plugins"
|
|
233
|
+
});
|
|
234
|
+
await writeMarketplace(marketplaceOutputPath, marketplace);
|
|
235
|
+
this.logSuccess(
|
|
236
|
+
`Generated ${PLUGIN_MANIFEST_DIR}/marketplace.json with ${marketplace.plugins.length} plugins.`
|
|
237
|
+
);
|
|
238
|
+
} catch (error) {
|
|
239
|
+
this.warn(`Build step failed: ${getErrorMessage(error)}`);
|
|
240
|
+
this.warn(
|
|
241
|
+
"The scaffold is still valid. Run 'build plugins' and 'build marketplace' manually."
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
export {
|
|
247
|
+
NewMarketplace as default,
|
|
248
|
+
generateReadme,
|
|
249
|
+
generateStacksYaml,
|
|
250
|
+
validateMarketplaceName
|
|
251
|
+
};
|
|
252
|
+
//# sourceMappingURL=marketplace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/new/marketplace.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { BaseCommand } from \"../../base-command.js\";\nimport { writeFile, directoryExists, ensureDir } from \"../../utils/fs.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport {\n CLI_BIN_NAME,\n KEBAB_CASE_PATTERN,\n PLUGIN_MANIFEST_DIR,\n SKILLS_DIR_PATH,\n STACKS_FILE_PATH,\n STANDARD_FILES,\n} from \"../../consts.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { compileAllSkillPlugins } from \"../../lib/skills/skill-plugin-compiler.js\";\nimport { generateMarketplace, writeMarketplace } from \"../../lib/marketplace-generator.js\";\n\nexport function validateMarketplaceName(name: string): string | null {\n if (!name || name.trim() === \"\") {\n return \"Marketplace name is required\";\n }\n\n if (!KEBAB_CASE_PATTERN.test(name)) {\n return \"Marketplace name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)\";\n }\n\n return null;\n}\n\nexport function generateStacksYaml(name: string): string {\n return `# Stack definitions for ${name}\n\nstacks:\n - id: dummy-stack\n name: Dummy Stack\n description: Default stack for ${name}\n agents:\n web-developer:\n dummy-category: dummy-skill\n philosophy: Ship fast, iterate faster\n`;\n}\n\nexport function generateReadme(name: string): string {\n return `# ${name}\n\nPrivate marketplace for custom skills and stacks.\n\n## Directory Structure\n\n\\`\\`\\`\n${STACKS_FILE_PATH} # Stack definitions (agent groupings with skill mappings)\n${SKILLS_DIR_PATH}/ # Custom skill definitions\n\\`\\`\\`\n\n## Creating Skills\n\n\\`\\`\\`bash\n${CLI_BIN_NAME} new skill <name> --category <category-name>\n\\`\\`\\`\n\nEach skill lives in \\`${SKILLS_DIR_PATH}/<skill-name>/\\` with:\n- \\`${STANDARD_FILES.SKILL_MD}\\` -- Skill content (what the skill teaches)\n- \\`${STANDARD_FILES.METADATA_YAML}\\` -- Skill metadata (category, author, description, custom: true)\n\n## Using This Marketplace\n\nPoint the CLI at this marketplace as a source:\n\n\\`\\`\\`bash\n# Local development\n${CLI_BIN_NAME} init --source /path/to/${name}\n\n# From a git repository\n${CLI_BIN_NAME} init --source github:your-org/${name}\n\\`\\`\\`\n\n## How It Works\n\nThe CLI auto-discovers skills from the \\`${SKILLS_DIR_PATH}/\\` directory\nand stacks from \\`${STACKS_FILE_PATH}\\`.\nCustom categories are discovered from skill \\`${STANDARD_FILES.METADATA_YAML}\\` files with \\`custom: true\\`.\nCustom skills appear alongside built-in ones in the wizard. No manual registration needed.\n`;\n}\n\nexport default class NewMarketplace extends BaseCommand {\n static summary = \"Scaffold a new private marketplace project\";\n static description =\n \"Create a new private marketplace directory with the required structure \" +\n \"for custom skills and stacks.\";\n\n static examples = [\n {\n description: \"Create a new marketplace\",\n command: \"<%= config.bin %> <%= command.id %> acme-skills\",\n },\n {\n description: \"Initialize the current directory as a marketplace\",\n command: \"<%= config.bin %> <%= command.id %> .\",\n },\n {\n description: \"Create in a specific location\",\n command: \"<%= config.bin %> <%= command.id %> acme-skills --output ~/projects\",\n },\n {\n description: \"Overwrite an existing directory\",\n command: \"<%= config.bin %> <%= command.id %> acme-skills --force\",\n },\n ];\n\n static args = {\n name: Args.string({\n description:\n 'Name of the marketplace directory (kebab-case), or \".\" to use the current directory',\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing directory\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Parent directory to create the marketplace in (default: current directory)\",\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(NewMarketplace);\n\n this.log(\"\");\n this.log(\"Create New Marketplace\");\n this.log(\"\");\n\n const parentDir = flags.output ? path.resolve(flags.output) : process.cwd();\n const useCurrentDir = args.name === \".\";\n\n const marketplaceName = useCurrentDir ? path.basename(parentDir) : args.name;\n const marketplaceDir = useCurrentDir ? parentDir : path.join(parentDir, args.name);\n\n const validationError = validateMarketplaceName(marketplaceName);\n if (validationError) {\n if (useCurrentDir) {\n this.error(\n `Current directory name '${marketplaceName}' is not valid kebab-case. Rename it or pass an explicit name.`,\n { exit: EXIT_CODES.INVALID_ARGS },\n );\n }\n this.error(validationError, { exit: EXIT_CODES.INVALID_ARGS });\n }\n\n // Skip existing directory check when using \".\" (the directory obviously exists)\n if (!useCurrentDir && (await directoryExists(marketplaceDir))) {\n if (!flags.force) {\n this.error(`Directory already exists: ${marketplaceDir}\\nUse --force to overwrite.`, {\n exit: EXIT_CODES.ERROR,\n });\n }\n this.warn(`Overwriting existing directory at ${marketplaceDir}`);\n }\n\n this.log(`Marketplace: ${marketplaceName}`);\n this.log(`Directory: ${marketplaceDir}`);\n this.log(\"\");\n\n const skillName = \"dummy-skill\";\n const skillPath = path.join(SKILLS_DIR_PATH, skillName);\n\n if (flags[\"dry-run\"]) {\n this.log(\"[DRY RUN] Would create marketplace structure:\");\n this.log(` ${STACKS_FILE_PATH}`);\n this.log(` ${skillPath}/${STANDARD_FILES.SKILL_MD}`);\n this.log(` ${skillPath}/${STANDARD_FILES.METADATA_YAML}`);\n this.log(\" README.md\");\n return;\n }\n\n this.log(\"Creating marketplace structure...\");\n\n try {\n // Create config/stacks.yaml\n const stacksContent = generateStacksYaml(marketplaceName);\n const stacksPath = path.join(marketplaceDir, STACKS_FILE_PATH);\n await ensureDir(path.dirname(stacksPath));\n await writeFile(stacksPath, stacksContent);\n\n // Delegate skill creation to the new:skill command\n const skillsDir = path.join(marketplaceDir, SKILLS_DIR_PATH);\n\n const skillArgs = [skillName, \"--output\", skillsDir];\n if (flags.force) skillArgs.push(\"--force\");\n await this.config.runCommand(\"new:skill\", skillArgs);\n\n // Create README.md\n const readmeContent = generateReadme(marketplaceName);\n const readmePath = path.join(marketplaceDir, \"README.md\");\n await writeFile(readmePath, readmeContent);\n\n this.log(\"\");\n this.logSuccess(`Created ${STACKS_FILE_PATH}`);\n this.logSuccess(\"Created README.md\");\n this.log(\"\");\n\n // Build plugins and marketplace.json so the marketplace is immediately valid\n await this.buildMarketplace(marketplaceDir, marketplaceName);\n\n this.log(\"Marketplace created successfully!\");\n this.log(\"\");\n this.log(\"Next steps:\");\n if (!useCurrentDir) {\n this.log(` 1. cd ${marketplaceName}`);\n }\n this.log(\n ` ${useCurrentDir ? \"1\" : \"2\"}. ${CLI_BIN_NAME} new skill <name> --category <category-name>`,\n );\n this.log(` ${useCurrentDir ? \"2\" : \"3\"}. Push to a git repository`);\n this.log(\n ` ${useCurrentDir ? \"3\" : \"4\"}. ${CLI_BIN_NAME} init --source github:your-org/${marketplaceName}`,\n );\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async buildMarketplace(marketplaceDir: string, marketplaceName: string): Promise<void> {\n const skillsDir = path.resolve(marketplaceDir, SKILLS_DIR_PATH);\n const pluginsOutputDir = path.resolve(marketplaceDir, \"dist/plugins\");\n const marketplaceOutputPath = path.resolve(\n marketplaceDir,\n PLUGIN_MANIFEST_DIR,\n \"marketplace.json\",\n );\n\n try {\n this.log(\"Building plugins...\");\n const results = await compileAllSkillPlugins(skillsDir, pluginsOutputDir);\n this.logSuccess(`Built ${results.length} skill plugins.`);\n\n this.log(\"Generating marketplace.json...\");\n const marketplace = await generateMarketplace(pluginsOutputDir, {\n name: marketplaceName,\n ownerName: marketplaceName,\n pluginRoot: \"./dist/plugins\",\n });\n await writeMarketplace(marketplaceOutputPath, marketplace);\n this.logSuccess(\n `Generated ${PLUGIN_MANIFEST_DIR}/marketplace.json with ${marketplace.plugins.length} plugins.`,\n );\n } catch (error) {\n this.warn(`Build step failed: ${getErrorMessage(error)}`);\n this.warn(\n \"The scaffold is still valid. Run 'build plugins' and 'build marketplace' manually.\",\n );\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAS,MAAM,aAAa;AAC5B,OAAO,UAAU;AAgBV,SAAS,wBAAwB,MAA6B;AACnE,MAAI,CAAC,QAAQ,KAAK,KAAK,MAAM,IAAI;AAC/B,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,mBAAmB,KAAK,IAAI,GAAG;AAClC,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,mBAAmB,MAAsB;AACvD,SAAO,2BAA2B,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,qCAKH,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAMzC;AAEO,SAAS,eAAe,MAAsB;AACnD,SAAO,KAAK,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,gBAAgB;AAAA,EAChB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMf,YAAY;AAAA;AAAA;AAAA,wBAGU,eAAe;AAAA,MACjC,eAAe,QAAQ;AAAA,MACvB,eAAe,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhC,YAAY,2BAA2B,IAAI;AAAA;AAAA;AAAA,EAG3C,YAAY,kCAAkC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,2CAKT,eAAe;AAAA,oBACtC,gBAAgB;AAAA,gDACY,eAAe,aAAa;AAAA;AAAA;AAG5E;AAEA,IAAqB,iBAArB,MAAqB,wBAAuB,YAAY;AAAA,EACtD,OAAO,UAAU;AAAA,EACjB,OAAO,cACL;AAAA,EAGF,OAAO,WAAW;AAAA,IAChB;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,OAAO,OAAO;AAAA,IACZ,MAAM,KAAK,OAAO;AAAA,MAChB,aACE;AAAA,MACF,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,QAAQ;AAAA,IACb,GAAG,YAAY;AAAA,IACf,OAAO,MAAM,QAAQ;AAAA,MACnB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,QAAQ,MAAM,OAAO;AAAA,MACnB,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,MAAM,eAAc;AAEvD,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,wBAAwB;AACjC,SAAK,IAAI,EAAE;AAEX,UAAM,YAAY,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,IAAI,QAAQ,IAAI;AAC1E,UAAM,gBAAgB,KAAK,SAAS;AAEpC,UAAM,kBAAkB,gBAAgB,KAAK,SAAS,SAAS,IAAI,KAAK;AACxE,UAAM,iBAAiB,gBAAgB,YAAY,KAAK,KAAK,WAAW,KAAK,IAAI;AAEjF,UAAM,kBAAkB,wBAAwB,eAAe;AAC/D,QAAI,iBAAiB;AACnB,UAAI,eAAe;AACjB,aAAK;AAAA,UACH,2BAA2B,eAAe;AAAA,UAC1C,EAAE,MAAM,WAAW,aAAa;AAAA,QAClC;AAAA,MACF;AACA,WAAK,MAAM,iBAAiB,EAAE,MAAM,WAAW,aAAa,CAAC;AAAA,IAC/D;AAGA,QAAI,CAAC,iBAAkB,MAAM,gBAAgB,cAAc,GAAI;AAC7D,UAAI,CAAC,MAAM,OAAO;AAChB,aAAK,MAAM,6BAA6B,cAAc;AAAA,4BAA+B;AAAA,UACnF,MAAM,WAAW;AAAA,QACnB,CAAC;AAAA,MACH;AACA,WAAK,KAAK,qCAAqC,cAAc,EAAE;AAAA,IACjE;AAEA,SAAK,IAAI,gBAAgB,eAAe,EAAE;AAC1C,SAAK,IAAI,cAAc,cAAc,EAAE;AACvC,SAAK,IAAI,EAAE;AAEX,UAAM,YAAY;AAClB,UAAM,YAAY,KAAK,KAAK,iBAAiB,SAAS;AAEtD,QAAI,MAAM,SAAS,GAAG;AACpB,WAAK,IAAI,+CAA+C;AACxD,WAAK,IAAI,KAAK,gBAAgB,EAAE;AAChC,WAAK,IAAI,KAAK,SAAS,IAAI,eAAe,QAAQ,EAAE;AACpD,WAAK,IAAI,KAAK,SAAS,IAAI,eAAe,aAAa,EAAE;AACzD,WAAK,IAAI,aAAa;AACtB;AAAA,IACF;AAEA,SAAK,IAAI,mCAAmC;AAE5C,QAAI;AAEF,YAAM,gBAAgB,mBAAmB,eAAe;AACxD,YAAM,aAAa,KAAK,KAAK,gBAAgB,gBAAgB;AAC7D,YAAM,UAAU,KAAK,QAAQ,UAAU,CAAC;AACxC,YAAM,UAAU,YAAY,aAAa;AAGzC,YAAM,YAAY,KAAK,KAAK,gBAAgB,eAAe;AAE3D,YAAM,YAAY,CAAC,WAAW,YAAY,SAAS;AACnD,UAAI,MAAM,MAAO,WAAU,KAAK,SAAS;AACzC,YAAM,KAAK,OAAO,WAAW,aAAa,SAAS;AAGnD,YAAM,gBAAgB,eAAe,eAAe;AACpD,YAAM,aAAa,KAAK,KAAK,gBAAgB,WAAW;AACxD,YAAM,UAAU,YAAY,aAAa;AAEzC,WAAK,IAAI,EAAE;AACX,WAAK,WAAW,WAAW,gBAAgB,EAAE;AAC7C,WAAK,WAAW,mBAAmB;AACnC,WAAK,IAAI,EAAE;AAGX,YAAM,KAAK,iBAAiB,gBAAgB,eAAe;AAE3D,WAAK,IAAI,mCAAmC;AAC5C,WAAK,IAAI,EAAE;AACX,WAAK,IAAI,aAAa;AACtB,UAAI,CAAC,eAAe;AAClB,aAAK,IAAI,WAAW,eAAe,EAAE;AAAA,MACvC;AACA,WAAK;AAAA,QACH,KAAK,gBAAgB,MAAM,GAAG,KAAK,YAAY;AAAA,MACjD;AACA,WAAK,IAAI,KAAK,gBAAgB,MAAM,GAAG,4BAA4B;AACnE,WAAK;AAAA,QACH,KAAK,gBAAgB,MAAM,GAAG,KAAK,YAAY,kCAAkC,eAAe;AAAA,MAClG;AACA,WAAK,IAAI,EAAE;AAAA,IACb,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,gBAAwB,iBAAwC;AAC7F,UAAM,YAAY,KAAK,QAAQ,gBAAgB,eAAe;AAC9D,UAAM,mBAAmB,KAAK,QAAQ,gBAAgB,cAAc;AACpE,UAAM,wBAAwB,KAAK;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI;AACF,WAAK,IAAI,qBAAqB;AAC9B,YAAM,UAAU,MAAM,uBAAuB,WAAW,gBAAgB;AACxE,WAAK,WAAW,SAAS,QAAQ,MAAM,iBAAiB;AAExD,WAAK,IAAI,gCAAgC;AACzC,YAAM,cAAc,MAAM,oBAAoB,kBAAkB;AAAA,QAC9D,MAAM;AAAA,QACN,WAAW;AAAA,QACX,YAAY;AAAA,MACd,CAAC;AACD,YAAM,iBAAiB,uBAAuB,WAAW;AACzD,WAAK;AAAA,QACH,aAAa,mBAAmB,0BAA0B,YAAY,QAAQ,MAAM;AAAA,MACtF;AAAA,IACF,SAAS,OAAO;AACd,WAAK,KAAK,sBAAsB,gBAAgB,KAAK,CAAC,EAAE;AACxD,WAAK;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -2,23 +2,25 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BaseCommand,
|
|
4
4
|
EXIT_CODES
|
|
5
|
-
} from "../../chunk-
|
|
5
|
+
} from "../../chunk-LFZXMQOH.js";
|
|
6
6
|
import {
|
|
7
7
|
LOCAL_DEFAULTS,
|
|
8
8
|
resolveAuthor
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-RT6IBH37.js";
|
|
10
10
|
import "../../chunk-T4EXUIBY.js";
|
|
11
11
|
import {
|
|
12
12
|
directoryExists,
|
|
13
|
+
fileExists,
|
|
13
14
|
writeFile
|
|
14
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-5QRJUBK7.js";
|
|
15
16
|
import {
|
|
16
17
|
CLI_BIN_NAME,
|
|
18
|
+
KEBAB_CASE_PATTERN,
|
|
17
19
|
LOCAL_SKILLS_PATH,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} from "../../chunk-
|
|
20
|
+
PLUGIN_MANIFEST_DIR,
|
|
21
|
+
SKILLS_DIR_PATH,
|
|
22
|
+
STANDARD_FILES
|
|
23
|
+
} from "../../chunk-74HSA7C4.js";
|
|
22
24
|
import {
|
|
23
25
|
init_esm_shims
|
|
24
26
|
} from "../../chunk-DHET7RCE.js";
|
|
@@ -27,7 +29,6 @@ import {
|
|
|
27
29
|
init_esm_shims();
|
|
28
30
|
import { Args, Flags } from "@oclif/core";
|
|
29
31
|
import path from "path";
|
|
30
|
-
var KEBAB_CASE_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
31
32
|
function validateSkillName(name) {
|
|
32
33
|
if (!name || name.trim() === "") {
|
|
33
34
|
return "Skill name is required";
|
|
@@ -40,11 +41,10 @@ function validateSkillName(name) {
|
|
|
40
41
|
function toTitleCase(kebabCase) {
|
|
41
42
|
return kebabCase.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
42
43
|
}
|
|
43
|
-
function generateSkillMd(name
|
|
44
|
+
function generateSkillMd(name) {
|
|
44
45
|
const titleName = toTitleCase(name);
|
|
45
|
-
const skillId = `${name} (${author})`;
|
|
46
46
|
return `---
|
|
47
|
-
name: ${
|
|
47
|
+
name: ${name}
|
|
48
48
|
description: Brief description of this skill
|
|
49
49
|
---
|
|
50
50
|
|
|
@@ -97,7 +97,7 @@ Add your patterns here.
|
|
|
97
97
|
}
|
|
98
98
|
function generateMetadataYaml(name, author, category) {
|
|
99
99
|
const titleName = toTitleCase(name);
|
|
100
|
-
return
|
|
100
|
+
return `custom: true
|
|
101
101
|
category: ${category}
|
|
102
102
|
categoryExclusive: false
|
|
103
103
|
author: "${author}"
|
|
@@ -134,6 +134,10 @@ var NewSkill = class _NewSkill extends BaseCommand {
|
|
|
134
134
|
char: "f",
|
|
135
135
|
description: "Overwrite existing skill directory",
|
|
136
136
|
default: false
|
|
137
|
+
}),
|
|
138
|
+
output: Flags.string({
|
|
139
|
+
char: "o",
|
|
140
|
+
description: "Output directory for the skill (overrides marketplace detection)"
|
|
137
141
|
})
|
|
138
142
|
};
|
|
139
143
|
async run() {
|
|
@@ -151,7 +155,19 @@ var NewSkill = class _NewSkill extends BaseCommand {
|
|
|
151
155
|
author = await resolveAuthor(projectDir) || LOCAL_DEFAULTS.AUTHOR;
|
|
152
156
|
}
|
|
153
157
|
const category = flags.category;
|
|
154
|
-
|
|
158
|
+
let skillsBasePath;
|
|
159
|
+
if (flags.output) {
|
|
160
|
+
skillsBasePath = path.resolve(flags.output);
|
|
161
|
+
} else {
|
|
162
|
+
const marketplacePath = path.join(projectDir, PLUGIN_MANIFEST_DIR, "marketplace.json");
|
|
163
|
+
if (await fileExists(marketplacePath)) {
|
|
164
|
+
this.log(`Detected marketplace context, creating skill in ${SKILLS_DIR_PATH}/`);
|
|
165
|
+
skillsBasePath = path.join(projectDir, SKILLS_DIR_PATH);
|
|
166
|
+
} else {
|
|
167
|
+
skillsBasePath = path.join(projectDir, LOCAL_SKILLS_PATH);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const skillDir = path.join(skillsBasePath, args.name);
|
|
155
171
|
if (await directoryExists(skillDir)) {
|
|
156
172
|
if (!flags.force) {
|
|
157
173
|
this.error(`Skill directory already exists: ${skillDir}
|
|
@@ -172,7 +188,7 @@ Use --force to overwrite.`, {
|
|
|
172
188
|
}
|
|
173
189
|
this.log("Creating skill files...");
|
|
174
190
|
try {
|
|
175
|
-
const skillMdContent = generateSkillMd(args.name
|
|
191
|
+
const skillMdContent = generateSkillMd(args.name);
|
|
176
192
|
const metadataContent = generateMetadataYaml(args.name, author, category);
|
|
177
193
|
const skillMdPath = path.join(skillDir, STANDARD_FILES.SKILL_MD);
|
|
178
194
|
const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);
|