@hi-man/himan 0.1.0 → 0.2.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.
@@ -0,0 +1,93 @@
1
+ import { HimanError, errorCodes } from "../utils/errors.js";
2
+ import { getSupportedAgentNames, normalizeAgent } from "../utils/agent-configs.js";
3
+ import { runAction } from "./shared.js";
4
+ export function registerAgentCommands(command, services) {
5
+ command
6
+ .command("list")
7
+ .option("--json", "output json format")
8
+ .description("List supported agents")
9
+ .action(async (options) => {
10
+ await runAction(async () => {
11
+ const agents = getSupportedAgentNames();
12
+ if (options.json) {
13
+ process.stdout.write(`${JSON.stringify(agents, null, 2)}\n`);
14
+ return;
15
+ }
16
+ for (const agent of agents) {
17
+ process.stdout.write(`- ${agent}\n`);
18
+ }
19
+ });
20
+ });
21
+ command
22
+ .command("use")
23
+ .argument("<agent_list>", "agent list, comma separated")
24
+ .option("--global", "save as global default")
25
+ .option("--project", "save as current project default")
26
+ .option("--json", "output json format")
27
+ .description("Set default agents globally or for current project")
28
+ .action(async (agentList, options) => {
29
+ await runAction(async () => {
30
+ const scope = parseScope(options);
31
+ const result = await services.setAgents(parseAgents(agentList), scope, process.cwd());
32
+ if (options.json) {
33
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
34
+ return;
35
+ }
36
+ process.stdout.write(`Using agents (${result.scope}): ${result.agents.join(", ")}\n`);
37
+ });
38
+ });
39
+ command
40
+ .command("current")
41
+ .option("--json", "output json format")
42
+ .description("Show configured and effective default agents")
43
+ .action(async (options) => {
44
+ await runAction(async () => {
45
+ const settings = await services.getAgentSettings(process.cwd());
46
+ if (options.json) {
47
+ process.stdout.write(`${JSON.stringify(settings, null, 2)}\n`);
48
+ return;
49
+ }
50
+ process.stdout.write(`effective: ${settings.effective.join(", ")}\n`);
51
+ process.stdout.write(`project: ${(settings.project ?? []).join(", ") || "-"}\n`);
52
+ process.stdout.write(`global: ${(settings.global ?? []).join(", ") || "-"}\n`);
53
+ });
54
+ });
55
+ command
56
+ .command("clear")
57
+ .option("--global", "clear global default agents")
58
+ .option("--project", "clear current project default agents")
59
+ .option("--json", "output json format")
60
+ .description("Clear configured default agents")
61
+ .action(async (options) => {
62
+ await runAction(async () => {
63
+ const result = await services.clearAgents(parseScope(options), process.cwd());
64
+ if (options.json) {
65
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
66
+ return;
67
+ }
68
+ process.stdout.write(`Cleared agents (${result.scope}).\n`);
69
+ });
70
+ });
71
+ }
72
+ function parseScope(options) {
73
+ if (options.global && options.project) {
74
+ throw new HimanError(errorCodes.CLI_USAGE, "Use only one of --global or --project.");
75
+ }
76
+ return options.global ? "global" : "project";
77
+ }
78
+ function parseAgents(input) {
79
+ const agents = input
80
+ .split(",")
81
+ .map((item) => item.trim())
82
+ .filter(Boolean);
83
+ if (agents.length === 0) {
84
+ throw new HimanError(errorCodes.INVALID_INPUT, "Agent list cannot be empty.");
85
+ }
86
+ const supported = getSupportedAgentNames();
87
+ for (const agent of agents) {
88
+ if (!normalizeAgent(agent)) {
89
+ throw new HimanError(errorCodes.INVALID_INPUT, `Unsupported agent: ${agent}. Supported agents: ${supported.join(", ")}`);
90
+ }
91
+ }
92
+ return agents;
93
+ }
@@ -0,0 +1,72 @@
1
+ import { ServiceFactory } from "../services/index.js";
2
+ import { registerAgentCommands } from "./agent-commands.js";
3
+ import { registerProjectCommands } from "./project-commands.js";
4
+ import { registerResourceCommands } from "./resource-commands.js";
5
+ import { registerInitCommand, registerSourceCommands } from "./source-commands.js";
6
+ import { createBaseProgram } from "./shared.js";
7
+ export function buildCli() {
8
+ const program = createBaseProgram("himan", "Prompt and agent asset management CLI");
9
+ const services = new ServiceFactory();
10
+ appendCommandGroupsHelp(program);
11
+ registerInitCommand(program, services);
12
+ const sourceCmd = program.command("source").description("Manage source repositories");
13
+ registerSourceCommands(sourceCmd, services, { includeInit: true });
14
+ const resourceCmd = program
15
+ .command("resource")
16
+ .description("Manage resources from current default source");
17
+ registerResourceCommands(resourceCmd, services);
18
+ const projectCmd = program
19
+ .command("project")
20
+ .description("Manage installed resources in current project");
21
+ registerProjectCommands(projectCmd, services);
22
+ const agentCmd = program
23
+ .command("agent")
24
+ .description("Manage default agent configuration");
25
+ registerAgentCommands(agentCmd, services);
26
+ // Backward compatible top-level resource lifecycle commands.
27
+ registerResourceCommands(program, services);
28
+ registerProjectCommands(program, services);
29
+ return program;
30
+ }
31
+ export function buildSourceCli() {
32
+ const program = createBaseProgram("himan-source", "Source repository management CLI");
33
+ const services = new ServiceFactory();
34
+ registerSourceCommands(program, services, { includeInit: true });
35
+ return program;
36
+ }
37
+ export function buildResourceCli() {
38
+ const program = createBaseProgram("himan-resource", "Resource lifecycle management CLI");
39
+ const services = new ServiceFactory();
40
+ registerResourceCommands(program, services);
41
+ const agentCmd = program
42
+ .command("agent")
43
+ .description("Manage default agent configuration");
44
+ registerAgentCommands(agentCmd, services);
45
+ // Backward compatible: keep project lifecycle commands in himan-resource.
46
+ registerProjectCommands(program, services);
47
+ return program;
48
+ }
49
+ export function buildProjectCli() {
50
+ const program = createBaseProgram("himan-project", "Project lifecycle management CLI");
51
+ const services = new ServiceFactory();
52
+ const agentCmd = program
53
+ .command("agent")
54
+ .description("Manage default agent configuration");
55
+ registerAgentCommands(agentCmd, services);
56
+ registerProjectCommands(program, services);
57
+ return program;
58
+ }
59
+ function appendCommandGroupsHelp(program) {
60
+ program.addHelpText("after", `
61
+ Command groups:
62
+ source Data source management (git now, registry reserved)
63
+ init, source init, source add, source use, source list
64
+ resource Source resource discovery and metadata
65
+ list, history, create, resource list, resource history, resource create
66
+ project Resource usage lifecycle in current project
67
+ install, dev, uninstall, publish,
68
+ project install, project dev, project uninstall, project publish
69
+ agent Default agent configuration
70
+ agent list, agent use, agent current, agent clear
71
+ `);
72
+ }
package/dist/cli/index.js CHANGED
@@ -1,318 +1,3 @@
1
- import { Command, CommanderError } from "commander";
2
- import { ServiceFactory } from "../services/index.js";
3
- import { errorCodes, HimanError } from "../utils/errors.js";
4
- import { PACKAGE_VERSION } from "../version.js";
5
- export function buildCli() {
6
- const program = new Command();
7
- const services = new ServiceFactory();
8
- program.exitOverride();
9
- program.configureOutput({
10
- writeOut: (str) => {
11
- process.stdout.write(str);
12
- },
13
- writeErr: () => {
14
- // Parse/usage errors are unified by writeCliError().
15
- },
16
- });
17
- program
18
- .name("himan")
19
- .description("Prompt and agent asset management CLI")
20
- .version(PACKAGE_VERSION);
21
- appendCommandGroupsHelp(program);
22
- program
23
- .command("init")
24
- .argument("<git_repo>", "Git repository URL")
25
- .action(async (gitRepo) => {
26
- await runAction(async () => {
27
- const result = await services.initSource("git", gitRepo);
28
- process.stdout.write(`Initialized ${result.sourceType} source: ${result.repo}\n`);
29
- });
30
- });
31
- const sourceCmd = program.command("source").description("Manage source repositories");
32
- sourceCmd
33
- .command("add")
34
- .argument("<name>", "source name (kebab-case)")
35
- .argument("<git_repo>", "Git repository URL")
36
- .description("Add a named git source")
37
- .action(async (name, gitRepo) => {
38
- await runAction(async () => {
39
- const result = await services.addSource(name, "git", gitRepo);
40
- process.stdout.write(`Added source ${result.name}: ${result.type}${result.repo ? ` ${result.repo}` : ""}\n`);
41
- });
42
- });
43
- sourceCmd
44
- .command("use")
45
- .argument("<name>", "source name")
46
- .description("Switch default source")
47
- .action(async (name) => {
48
- await runAction(async () => {
49
- const result = await services.useSource(name);
50
- process.stdout.write(`Using source: ${result.name}\n`);
51
- });
52
- });
53
- sourceCmd
54
- .command("list")
55
- .option("--json", "output json format")
56
- .description("List configured sources and current default")
57
- .action(async (options) => {
58
- await runAction(async () => {
59
- const sources = await services.listSources();
60
- if (options.json) {
61
- process.stdout.write(`${JSON.stringify(sources, null, 2)}\n`);
62
- return;
63
- }
64
- if (sources.length === 0) {
65
- process.stdout.write("No sources configured.\n");
66
- return;
67
- }
68
- for (const source of sources) {
69
- process.stdout.write(`- ${source.name}${source.isDefault ? " (default)" : ""}: ${source.type}${source.repo ? ` ${source.repo}` : ""}\n`);
70
- }
71
- });
72
- });
73
- program
74
- .command("list")
75
- .argument("[type]", "resource type", "rule")
76
- .option("--json", "output json format")
77
- .description("List resources from current default source")
78
- .action(async (type, options) => {
79
- await runAction(async () => {
80
- const resourceType = ensureResourceType(type);
81
- const resources = await services.list(resourceType);
82
- if (options.json) {
83
- process.stdout.write(`${JSON.stringify(resources, null, 2)}\n`);
84
- return;
85
- }
86
- if (resources.length === 0) {
87
- process.stdout.write("No resources found.\n");
88
- return;
89
- }
90
- for (const resource of resources) {
91
- process.stdout.write(`- ${resource.type}/${resource.name}${resource.description ? `: ${resource.description}` : ""}\n`);
92
- }
93
- });
94
- });
95
- program
96
- .command("history")
97
- .argument("<type>", "resource type")
98
- .argument("<name>", "resource name")
99
- .option("--json", "output json format")
100
- .description("Show resource history")
101
- .action(async (type, name, options) => {
102
- await runAction(async () => {
103
- const resourceType = ensureResourceType(type);
104
- const versions = await services.history(resourceType, name);
105
- if (options.json) {
106
- process.stdout.write(`${JSON.stringify(versions, null, 2)}\n`);
107
- return;
108
- }
109
- if (versions.length === 0) {
110
- process.stdout.write(`No history found for ${resourceType}/${name}.\n`);
111
- return;
112
- }
113
- for (const version of versions) {
114
- process.stdout.write(`- ${version.raw}\n`);
115
- }
116
- });
117
- });
118
- program
119
- .command("install")
120
- .argument("[type]", "resource type")
121
- .argument("[name[@version]]", "resource name with optional @version")
122
- .description("Install resource, or install from himan.lock")
123
- .action(async (type, nameVersion) => {
124
- await runAction(async () => {
125
- if (!type && !nameVersion) {
126
- const results = await services.installFromLock(process.cwd());
127
- if (results.length === 0) {
128
- process.stdout.write("No resources in lock file.\n");
129
- return;
130
- }
131
- for (const item of results) {
132
- process.stdout.write(`Installed ${item.type}/${item.name}@${item.version}\n`);
133
- }
134
- return;
135
- }
136
- if (!type || !nameVersion) {
137
- throw new Error("Install usage:\n"
138
- + " - himan install # install from himan.lock\n"
139
- + " - himan install <type> <name[@version]> # install single resource");
140
- }
141
- const resourceType = ensureResourceType(type);
142
- const { name, version } = parseNameVersion(nameVersion);
143
- const result = await services.install(resourceType, name, version, process.cwd());
144
- process.stdout.write(`Installed ${result.type}/${result.name}@${result.version}\n`);
145
- });
146
- });
147
- program
148
- .command("dev")
149
- .argument("<type>", "resource type")
150
- .argument("<name>", "resource name")
151
- .description("Switch resource to development mode")
152
- .action(async (type, name) => {
153
- await runAction(async () => {
154
- const resourceType = ensureResourceType(type);
155
- const result = await services.dev(resourceType, name, process.cwd());
156
- process.stdout.write(`Switched ${result.type}/${result.name} to dev mode: ${result.devPath}\n`);
157
- });
158
- });
159
- program
160
- .command("uninstall")
161
- .argument("<type>", "resource type")
162
- .argument("<name>", "resource name")
163
- .description("Uninstall resource from project and lock")
164
- .action(async (type, name) => {
165
- await runAction(async () => {
166
- const resourceType = ensureResourceType(type);
167
- const result = await services.uninstall(resourceType, name, process.cwd());
168
- process.stdout.write(`Uninstalled ${result.type}/${result.name}\n`);
169
- });
170
- });
171
- program
172
- .command("publish")
173
- .argument("<type>", "resource type")
174
- .argument("<name>", "resource name")
175
- .option("--patch", "patch release")
176
- .option("--minor", "minor release")
177
- .option("--major", "major release")
178
- .description("Publish resource (default: --patch)")
179
- .action(async (type, name, options) => {
180
- await runAction(async () => {
181
- const resourceType = ensureResourceType(type);
182
- const releaseType = resolveReleaseType(options);
183
- const result = await services.publish(resourceType, name, releaseType, process.cwd());
184
- process.stdout.write(`Published ${result.type}/${result.name}@${result.version}\n`);
185
- });
186
- });
187
- program
188
- .command("create")
189
- .argument("<type>", "resource type")
190
- .argument("<name>", "resource name")
191
- .option("--description <text>", "resource description")
192
- .option("--target <list>", "targets list, comma separated")
193
- .option("--entry <file>", "entry file name")
194
- .option("--template <name>", "template name", "basic")
195
- .option("--force", "overwrite existing resource")
196
- .option("--dry-run", "show files without writing")
197
- .option("--json", "output json format")
198
- .description("Create resource scaffold")
199
- .action(async (type, name, options) => {
200
- await runAction(async () => {
201
- const resourceType = ensureCreateResourceType(type);
202
- const result = await services.create(resourceType, name, {
203
- description: options.description,
204
- targets: parseTargets(options.target),
205
- entry: options.entry,
206
- template: options.template,
207
- force: options.force,
208
- dryRun: options.dryRun,
209
- });
210
- if (options.json) {
211
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
212
- return;
213
- }
214
- process.stdout.write(`Created ${result.type}/${result.name} at ${result.resourceDir}${result.dryRun ? " (dry-run)" : ""}\n`);
215
- });
216
- });
217
- return program;
218
- }
219
- function ensureResourceType(type) {
220
- if (type !== "rule" && type !== "command" && type !== "skill") {
221
- throw new Error(`Unsupported resource type: ${type}`);
222
- }
223
- return type;
224
- }
225
- function parseNameVersion(input) {
226
- const idx = input.lastIndexOf("@");
227
- if (idx <= 0)
228
- return { name: input };
229
- return { name: input.slice(0, idx), version: input.slice(idx + 1) };
230
- }
231
- async function runAction(action) {
232
- try {
233
- await action();
234
- }
235
- catch (error) {
236
- writeCliError(error);
237
- process.exitCode = 1;
238
- }
239
- }
240
- export function writeCliError(error) {
241
- const payload = toCliErrorPayload(error);
242
- if (shouldOutputJsonError()) {
243
- process.stderr.write(`${JSON.stringify(payload, null, 2)}\n`);
244
- return;
245
- }
246
- process.stderr.write(`[${payload.error.code}] ${payload.error.message}\n`);
247
- }
248
- function toCliErrorPayload(error) {
249
- if (error instanceof CommanderError) {
250
- return {
251
- ok: false,
252
- error: {
253
- code: errorCodes.CLI_USAGE,
254
- message: error.message,
255
- details: {
256
- commanderCode: error.code,
257
- exitCode: error.exitCode,
258
- },
259
- },
260
- };
261
- }
262
- if (error instanceof HimanError) {
263
- return {
264
- ok: false,
265
- error: {
266
- code: error.code,
267
- message: error.message,
268
- details: error.details,
269
- },
270
- };
271
- }
272
- return {
273
- ok: false,
274
- error: {
275
- code: "E_UNKNOWN",
276
- message: error instanceof Error ? error.message : String(error),
277
- },
278
- };
279
- }
280
- function shouldOutputJsonError() {
281
- return process.argv.includes("--json");
282
- }
283
- function appendCommandGroupsHelp(program) {
284
- program.addHelpText("after", `
285
- Command groups:
286
- source Data source management (git now, registry reserved)
287
- init, source add, source use, source list
288
- resource Source resource discovery and metadata
289
- list, history, create
290
- project Resource usage lifecycle in current project
291
- install, dev, uninstall, publish
292
- `);
293
- }
294
- function resolveReleaseType(options) {
295
- const selected = [
296
- options.patch ? "patch" : undefined,
297
- options.minor ? "minor" : undefined,
298
- options.major ? "major" : undefined,
299
- ].filter(Boolean);
300
- if (selected.length > 1) {
301
- throw new Error("Use only one of --patch, --minor or --major.");
302
- }
303
- return selected[0] ?? "patch";
304
- }
305
- function ensureCreateResourceType(type) {
306
- if (type !== "rule" && type !== "command" && type !== "skill") {
307
- throw new Error(`Unsupported resource type: ${type}`);
308
- }
309
- return type;
310
- }
311
- function parseTargets(input) {
312
- if (!input)
313
- return undefined;
314
- return input
315
- .split(",")
316
- .map((item) => item.trim())
317
- .filter(Boolean);
318
- }
1
+ export { buildCli, buildProjectCli, buildResourceCli, buildSourceCli } from "./builders.js";
2
+ export { registerAgentCommands } from "./agent-commands.js";
3
+ export { writeCliError } from "./shared.js";
@@ -0,0 +1,127 @@
1
+ import { HimanError, errorCodes } from "../utils/errors.js";
2
+ import { getSupportedAgentNames, normalizeAgent } from "../utils/agent-configs.js";
3
+ import { runAction } from "./shared.js";
4
+ export function registerProjectCommands(command, services) {
5
+ command
6
+ .command("install")
7
+ .argument("[type]", "resource type")
8
+ .argument("[name[@version]]", "resource name with optional @version")
9
+ .option("--agent <list>", "install target agents, comma separated")
10
+ .option("--mode <mode>", "install mode: link or copy")
11
+ .description("Install resource, or install from himan.lock")
12
+ .action(async (type, nameVersion, options) => {
13
+ await runAction(async () => {
14
+ const agents = parseAgents(options.agent);
15
+ const mode = parseInstallMode(options.mode);
16
+ if (!type && !nameVersion) {
17
+ const results = await services.installFromLock(process.cwd(), agents, mode);
18
+ if (results.length === 0) {
19
+ process.stdout.write("No resources in lock file.\n");
20
+ return;
21
+ }
22
+ for (const item of results) {
23
+ process.stdout.write(`Installed ${item.type}/${item.name}@${item.version}\n`);
24
+ }
25
+ return;
26
+ }
27
+ if (!type || !nameVersion) {
28
+ throw new HimanError(errorCodes.CLI_USAGE, "Install usage:\n"
29
+ + " - himan install # install from himan.lock\n"
30
+ + " - himan install <type> <name[@version]> [--mode link|copy] # install single resource");
31
+ }
32
+ const resourceType = ensureResourceType(type);
33
+ const { name, version } = parseNameVersion(nameVersion);
34
+ const result = await services.install(resourceType, name, version, process.cwd(), agents, mode);
35
+ process.stdout.write(`Installed ${result.type}/${result.name}@${result.version}\n`);
36
+ });
37
+ });
38
+ command
39
+ .command("dev")
40
+ .argument("<type>", "resource type")
41
+ .argument("<name>", "resource name")
42
+ .description("Switch resource to development mode")
43
+ .action(async (type, name) => {
44
+ await runAction(async () => {
45
+ const resourceType = ensureResourceType(type);
46
+ const result = await services.dev(resourceType, name, process.cwd());
47
+ process.stdout.write(`Switched ${result.type}/${result.name} to dev mode: ${result.devPath}\n`);
48
+ });
49
+ });
50
+ command
51
+ .command("uninstall")
52
+ .argument("<type>", "resource type")
53
+ .argument("<name>", "resource name")
54
+ .description("Uninstall resource from project and lock")
55
+ .action(async (type, name) => {
56
+ await runAction(async () => {
57
+ const resourceType = ensureResourceType(type);
58
+ const result = await services.uninstall(resourceType, name, process.cwd());
59
+ process.stdout.write(`Uninstalled ${result.type}/${result.name}\n`);
60
+ });
61
+ });
62
+ command
63
+ .command("publish")
64
+ .argument("<type>", "resource type")
65
+ .argument("<name>", "resource name")
66
+ .option("--patch", "patch release")
67
+ .option("--minor", "minor release")
68
+ .option("--major", "major release")
69
+ .description("Publish resource (default: --patch)")
70
+ .action(async (type, name, options) => {
71
+ await runAction(async () => {
72
+ const resourceType = ensureResourceType(type);
73
+ const releaseType = resolveReleaseType(options);
74
+ const result = await services.publish(resourceType, name, releaseType, process.cwd());
75
+ process.stdout.write(`Published ${result.type}/${result.name}@${result.version}\n`);
76
+ });
77
+ });
78
+ }
79
+ function ensureResourceType(type) {
80
+ if (type !== "rule" && type !== "command" && type !== "skill") {
81
+ throw new HimanError(errorCodes.UNSUPPORTED_RESOURCE_TYPE, `Unsupported resource type: ${type}`);
82
+ }
83
+ return type;
84
+ }
85
+ function parseNameVersion(input) {
86
+ const idx = input.lastIndexOf("@");
87
+ if (idx <= 0)
88
+ return { name: input };
89
+ return { name: input.slice(0, idx), version: input.slice(idx + 1) };
90
+ }
91
+ function resolveReleaseType(options) {
92
+ const selected = [
93
+ options.patch ? "patch" : undefined,
94
+ options.minor ? "minor" : undefined,
95
+ options.major ? "major" : undefined,
96
+ ].filter(Boolean);
97
+ if (selected.length > 1) {
98
+ throw new HimanError(errorCodes.CLI_USAGE, "Use only one of --patch, --minor or --major.");
99
+ }
100
+ return selected[0] ?? "patch";
101
+ }
102
+ function parseInstallMode(input) {
103
+ if (!input)
104
+ return undefined;
105
+ const normalized = input.trim().toLowerCase();
106
+ if (normalized === "link" || normalized === "copy") {
107
+ return normalized;
108
+ }
109
+ throw new HimanError(errorCodes.INVALID_INPUT, `Unsupported install mode: ${input}. Supported modes: link, copy`);
110
+ }
111
+ function parseAgents(input) {
112
+ if (!input)
113
+ return undefined;
114
+ const agents = input
115
+ .split(",")
116
+ .map((item) => item.trim())
117
+ .filter(Boolean);
118
+ if (agents.length === 0)
119
+ return undefined;
120
+ const supported = getSupportedAgentNames();
121
+ for (const agent of agents) {
122
+ if (!normalizeAgent(agent)) {
123
+ throw new HimanError(errorCodes.INVALID_INPUT, `Unsupported agent: ${agent}. Supported agents: ${supported.join(", ")}`);
124
+ }
125
+ }
126
+ return agents;
127
+ }