@hi-man/himan 0.4.0 → 0.5.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.
@@ -10,18 +10,30 @@ export function registerResourceCommands(command, services) {
10
10
  .option("--agent <list>", "agent list filter, comma separated")
11
11
  .option("--brief", "hide resource descriptions")
12
12
  .option("--installed", "list resources installed in current project")
13
+ .option("--archived", "list archived resources only")
14
+ .option("--include-archived", "include archived resources in source list")
13
15
  .option("--json", "output json format")
14
16
  .description("List resources from current default source or project installs")
15
17
  .action(async (type, options) => {
16
18
  await runAction(async () => {
17
19
  const agents = parseAgents(options.agent);
18
20
  const showDescription = !options.brief;
21
+ if (options.installed && (options.archived || options.includeArchived)) {
22
+ throw new HimanError(errorCodes.CLI_USAGE, "--archived and --include-archived only apply to source resource lists.");
23
+ }
24
+ if (options.archived && options.includeArchived) {
25
+ throw new HimanError(errorCodes.CLI_USAGE, "Use only one of --archived or --include-archived.");
26
+ }
27
+ const listOptions = {
28
+ archived: Boolean(options.archived),
29
+ includeArchived: Boolean(options.includeArchived),
30
+ };
19
31
  if (options.installed) {
20
32
  await writeInstalledList(services, type, agents, Boolean(options.json));
21
33
  return;
22
34
  }
23
35
  if (!type) {
24
- const groups = await listGroupedResources(services, agents);
36
+ const groups = await listGroupedResources(services, agents, listOptions);
25
37
  if (options.json) {
26
38
  process.stdout.write(`${JSON.stringify(formatResourceGroups(groups, showDescription), null, 2)}\n`);
27
39
  return;
@@ -30,7 +42,7 @@ export function registerResourceCommands(command, services) {
30
42
  return;
31
43
  }
32
44
  const resourceType = ensureResourceType(type);
33
- const resources = await services.list(resourceType, agents);
45
+ const resources = await services.list(resourceType, agents, listOptions);
34
46
  if (options.json) {
35
47
  process.stdout.write(`${JSON.stringify(formatResources(resources, showDescription), null, 2)}\n`);
36
48
  return;
@@ -91,6 +103,48 @@ export function registerResourceCommands(command, services) {
91
103
  process.stdout.write(`Created ${result.type}/${result.name} at ${result.resourceDir}${result.dryRun ? " (dry-run)" : ""}\n`);
92
104
  });
93
105
  });
106
+ command
107
+ .command("archive")
108
+ .argument("<type>", "resource type")
109
+ .argument("<name>", "resource name")
110
+ .option("--reason <text>", "archive reason")
111
+ .option("--dry-run", "show archive result without writing")
112
+ .option("--json", "output json format")
113
+ .description("Archive resource in current default source")
114
+ .action(async (type, name, options) => {
115
+ await runAction(async () => {
116
+ const resourceType = ensureResourceType(type);
117
+ const result = await services.archive(resourceType, name, {
118
+ reason: options.reason,
119
+ dryRun: options.dryRun,
120
+ });
121
+ if (options.json) {
122
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
123
+ return;
124
+ }
125
+ process.stdout.write(`Archived ${result.type}/${result.name}${result.dryRun ? " (dry-run)" : ""}\n`);
126
+ });
127
+ });
128
+ command
129
+ .command("restore")
130
+ .argument("<type>", "resource type")
131
+ .argument("<name>", "resource name")
132
+ .option("--dry-run", "show restore result without writing")
133
+ .option("--json", "output json format")
134
+ .description("Restore archived resource into current default source")
135
+ .action(async (type, name, options) => {
136
+ await runAction(async () => {
137
+ const resourceType = ensureResourceType(type);
138
+ const result = await services.restore(resourceType, name, {
139
+ dryRun: options.dryRun,
140
+ });
141
+ if (options.json) {
142
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
143
+ return;
144
+ }
145
+ process.stdout.write(`Restored ${result.type}/${result.name}${result.dryRun ? " (dry-run)" : ""}\n`);
146
+ });
147
+ });
94
148
  command
95
149
  .command("rename")
96
150
  .argument("<type>", "resource type")
@@ -139,11 +193,11 @@ function ensureResourceType(type) {
139
193
  }
140
194
  return type;
141
195
  }
142
- async function listGroupedResources(services, agents) {
196
+ async function listGroupedResources(services, agents, options = {}) {
143
197
  return {
144
- rule: await services.list("rule", agents),
145
- command: await services.list("command", agents),
146
- skill: await services.list("skill", agents),
198
+ rule: await services.list("rule", agents, options),
199
+ command: await services.list("command", agents, options),
200
+ skill: await services.list("skill", agents, options),
147
201
  };
148
202
  }
149
203
  function formatResourceGroups(groups, showDescription) {
@@ -181,7 +235,8 @@ function writeResourceList(resources, showDescription) {
181
235
  return;
182
236
  }
183
237
  for (const resource of resources) {
184
- process.stdout.write(`- ${resource.type}/${resource.name}${showDescription && resource.description ? `: ${resource.description}` : ""}\n`);
238
+ const archived = resource.archived ? " [archived]" : "";
239
+ process.stdout.write(`- ${resource.type}/${resource.name}${archived}${showDescription && resource.description ? `: ${resource.description}` : ""}\n`);
185
240
  }
186
241
  }
187
242
  function formatGroupTitle(type) {
@@ -1,12 +1,41 @@
1
+ import { getSupportedAgentNames, normalizeAgent } from "../utils/agent-configs.js";
2
+ import { HimanError, errorCodes } from "../utils/errors.js";
1
3
  import { runAction } from "./shared.js";
2
4
  export function registerInitCommand(command, services) {
3
5
  command
4
6
  .command("init")
5
7
  .argument("<git_repo>", "Git repository URL")
6
- .action(async (gitRepo) => {
8
+ .option("--agent <list>", "set current project default agents, comma separated")
9
+ .option("--install <refs>", "install resource refs after init, comma separated: rule/name[@version]")
10
+ .option("--mode <mode>", "install mode for --install: link or copy")
11
+ .option("--json", "output json format")
12
+ .action(async (gitRepo, options) => {
7
13
  await runAction(async () => {
8
- const result = await services.initSource("git", gitRepo);
9
- process.stdout.write(`Initialized ${result.sourceType} source: ${result.repo}\n`);
14
+ const agents = parseAgents(options.agent);
15
+ const installRefs = parseInstallRefs(options.install);
16
+ const mode = parseInstallMode(options.mode);
17
+ if (mode && installRefs.length === 0) {
18
+ throw new HimanError(errorCodes.CLI_USAGE, "Use --mode only with --install.");
19
+ }
20
+ const source = await services.initSource("git", gitRepo);
21
+ const agentResult = agents?.length
22
+ ? await services.setAgents(agents, "project", process.cwd())
23
+ : undefined;
24
+ const installed = [];
25
+ for (const ref of installRefs) {
26
+ installed.push(await services.install(ref.type, ref.name, ref.version, process.cwd(), agents, mode));
27
+ }
28
+ if (options.json) {
29
+ process.stdout.write(`${JSON.stringify({ source, agents: agentResult, installed }, null, 2)}\n`);
30
+ return;
31
+ }
32
+ process.stdout.write(`Initialized ${source.sourceType} source: ${source.repo}\n`);
33
+ if (agentResult) {
34
+ process.stdout.write(`Using agents (${agentResult.scope}): ${agentResult.agents.join(", ")}\n`);
35
+ }
36
+ for (const item of installed) {
37
+ process.stdout.write(`Installed ${item.type}/${item.name}@${item.version}\n`);
38
+ }
10
39
  });
11
40
  });
12
41
  }
@@ -158,3 +187,67 @@ export function registerSourceCommands(command, services, options) {
158
187
  });
159
188
  });
160
189
  }
190
+ function ensureResourceType(type) {
191
+ if (type !== "rule" && type !== "command" && type !== "skill") {
192
+ throw new HimanError(errorCodes.UNSUPPORTED_RESOURCE_TYPE, `Unsupported resource type: ${type}`);
193
+ }
194
+ return type;
195
+ }
196
+ function parseInstallRefs(input) {
197
+ if (!input)
198
+ return [];
199
+ const refs = input
200
+ .split(",")
201
+ .map((item) => item.trim())
202
+ .filter(Boolean);
203
+ if (refs.length === 0) {
204
+ throw new HimanError(errorCodes.INVALID_INPUT, "Install list cannot be empty.");
205
+ }
206
+ return refs.map((ref) => {
207
+ const parts = ref.split("/");
208
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
209
+ throw new HimanError(errorCodes.INVALID_INPUT, `Invalid install ref: ${ref}. Use type/name[@version].`);
210
+ }
211
+ const { name, version } = parseNameVersion(parts[1]);
212
+ if (!name) {
213
+ throw new HimanError(errorCodes.INVALID_INPUT, `Invalid install ref: ${ref}. Use type/name[@version].`);
214
+ }
215
+ return {
216
+ type: ensureResourceType(parts[0]),
217
+ name,
218
+ version,
219
+ };
220
+ });
221
+ }
222
+ function parseNameVersion(input) {
223
+ const idx = input.lastIndexOf("@");
224
+ if (idx <= 0)
225
+ return { name: input };
226
+ return { name: input.slice(0, idx), version: input.slice(idx + 1) };
227
+ }
228
+ function parseInstallMode(input) {
229
+ if (!input)
230
+ return undefined;
231
+ const normalized = input.trim().toLowerCase();
232
+ if (normalized === "link" || normalized === "copy") {
233
+ return normalized;
234
+ }
235
+ throw new HimanError(errorCodes.INVALID_INPUT, `Unsupported install mode: ${input}. Supported modes: link, copy`);
236
+ }
237
+ function parseAgents(input) {
238
+ if (!input)
239
+ return undefined;
240
+ const agents = input
241
+ .split(",")
242
+ .map((item) => item.trim())
243
+ .filter(Boolean);
244
+ if (agents.length === 0)
245
+ return undefined;
246
+ const supported = getSupportedAgentNames();
247
+ for (const agent of agents) {
248
+ if (!normalizeAgent(agent)) {
249
+ throw new HimanError(errorCodes.INVALID_INPUT, `Unsupported agent: ${agent}. Supported agents: ${supported.join(", ")}`);
250
+ }
251
+ }
252
+ return agents;
253
+ }
@@ -0,0 +1 @@
1
+ export {};