@hi-man/himan 0.1.0 → 0.2.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/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
+ }
@@ -0,0 +1,104 @@
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 registerResourceCommands(command, services) {
5
+ command
6
+ .command("list")
7
+ .argument("[type]", "resource type", "rule")
8
+ .option("--agent <list>", "agent list filter, comma separated")
9
+ .option("--json", "output json format")
10
+ .description("List resources from current default source")
11
+ .action(async (type, options) => {
12
+ await runAction(async () => {
13
+ const resourceType = ensureResourceType(type);
14
+ const resources = await services.list(resourceType, parseAgents(options.agent));
15
+ if (options.json) {
16
+ process.stdout.write(`${JSON.stringify(resources, null, 2)}\n`);
17
+ return;
18
+ }
19
+ if (resources.length === 0) {
20
+ process.stdout.write("No resources found.\n");
21
+ return;
22
+ }
23
+ for (const resource of resources) {
24
+ process.stdout.write(`- ${resource.type}/${resource.name}${resource.description ? `: ${resource.description}` : ""}\n`);
25
+ }
26
+ });
27
+ });
28
+ command
29
+ .command("history")
30
+ .argument("<type>", "resource type")
31
+ .argument("<name>", "resource name")
32
+ .option("--json", "output json format")
33
+ .description("Show resource history")
34
+ .action(async (type, name, options) => {
35
+ await runAction(async () => {
36
+ const resourceType = ensureResourceType(type);
37
+ const versions = await services.history(resourceType, name);
38
+ if (options.json) {
39
+ process.stdout.write(`${JSON.stringify(versions, null, 2)}\n`);
40
+ return;
41
+ }
42
+ if (versions.length === 0) {
43
+ process.stdout.write(`No history found for ${resourceType}/${name}.\n`);
44
+ return;
45
+ }
46
+ for (const version of versions) {
47
+ process.stdout.write(`- ${version.raw}\n`);
48
+ }
49
+ });
50
+ });
51
+ command
52
+ .command("create")
53
+ .argument("<type>", "resource type")
54
+ .argument("<name>", "resource name")
55
+ .option("--description <text>", "resource description")
56
+ .option("--agent <list>", "agent list, comma separated")
57
+ .option("--entry <file>", "entry file name")
58
+ .option("--template <name>", "template name", "basic")
59
+ .option("--force", "overwrite existing resource")
60
+ .option("--dry-run", "show files without writing")
61
+ .option("--json", "output json format")
62
+ .description("Create resource scaffold")
63
+ .action(async (type, name, options) => {
64
+ await runAction(async () => {
65
+ const resourceType = ensureResourceType(type);
66
+ const result = await services.create(resourceType, name, {
67
+ description: options.description,
68
+ agents: parseAgents(options.agent),
69
+ entry: options.entry,
70
+ template: options.template,
71
+ force: options.force,
72
+ dryRun: options.dryRun,
73
+ }, process.cwd());
74
+ if (options.json) {
75
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
76
+ return;
77
+ }
78
+ process.stdout.write(`Created ${result.type}/${result.name} at ${result.resourceDir}${result.dryRun ? " (dry-run)" : ""}\n`);
79
+ });
80
+ });
81
+ }
82
+ function ensureResourceType(type) {
83
+ if (type !== "rule" && type !== "command" && type !== "skill") {
84
+ throw new HimanError(errorCodes.UNSUPPORTED_RESOURCE_TYPE, `Unsupported resource type: ${type}`);
85
+ }
86
+ return type;
87
+ }
88
+ function parseAgents(input) {
89
+ if (!input)
90
+ return undefined;
91
+ const agents = input
92
+ .split(",")
93
+ .map((item) => item.trim())
94
+ .filter(Boolean);
95
+ if (agents.length === 0)
96
+ return undefined;
97
+ const supported = getSupportedAgentNames();
98
+ for (const agent of agents) {
99
+ if (!normalizeAgent(agent)) {
100
+ throw new HimanError(errorCodes.INVALID_INPUT, `Unsupported agent: ${agent}. Supported agents: ${supported.join(", ")}`);
101
+ }
102
+ }
103
+ return agents;
104
+ }
@@ -0,0 +1,69 @@
1
+ import { Command, CommanderError } from "commander";
2
+ import { errorCodes, HimanError } from "../utils/errors.js";
3
+ import { PACKAGE_VERSION } from "../utils/version.js";
4
+ export function createBaseProgram(name, description) {
5
+ const program = new Command();
6
+ program.exitOverride();
7
+ program.configureOutput({
8
+ writeOut: (str) => {
9
+ process.stdout.write(str);
10
+ },
11
+ writeErr: () => {
12
+ // Parse/usage errors are unified by writeCliError().
13
+ },
14
+ });
15
+ program.name(name).description(description).version(PACKAGE_VERSION);
16
+ return program;
17
+ }
18
+ export async function runAction(action) {
19
+ try {
20
+ await action();
21
+ }
22
+ catch (error) {
23
+ writeCliError(error);
24
+ process.exitCode = 1;
25
+ }
26
+ }
27
+ export function writeCliError(error) {
28
+ const payload = toCliErrorPayload(error);
29
+ if (shouldOutputJsonError()) {
30
+ process.stderr.write(`${JSON.stringify(payload, null, 2)}\n`);
31
+ return;
32
+ }
33
+ process.stderr.write(`[${payload.error.code}] ${payload.error.message}\n`);
34
+ }
35
+ function toCliErrorPayload(error) {
36
+ if (error instanceof CommanderError) {
37
+ return {
38
+ ok: false,
39
+ error: {
40
+ code: errorCodes.CLI_USAGE,
41
+ message: error.message,
42
+ details: {
43
+ commanderCode: error.code,
44
+ exitCode: error.exitCode,
45
+ },
46
+ },
47
+ };
48
+ }
49
+ if (error instanceof HimanError) {
50
+ return {
51
+ ok: false,
52
+ error: {
53
+ code: error.code,
54
+ message: error.message,
55
+ details: error.details,
56
+ },
57
+ };
58
+ }
59
+ return {
60
+ ok: false,
61
+ error: {
62
+ code: "E_UNKNOWN",
63
+ message: error instanceof Error ? error.message : String(error),
64
+ },
65
+ };
66
+ }
67
+ function shouldOutputJsonError() {
68
+ return process.argv.includes("--json");
69
+ }
@@ -0,0 +1,58 @@
1
+ import { runAction } from "./shared.js";
2
+ export function registerInitCommand(command, services) {
3
+ command
4
+ .command("init")
5
+ .argument("<git_repo>", "Git repository URL")
6
+ .action(async (gitRepo) => {
7
+ await runAction(async () => {
8
+ const result = await services.initSource("git", gitRepo);
9
+ process.stdout.write(`Initialized ${result.sourceType} source: ${result.repo}\n`);
10
+ });
11
+ });
12
+ }
13
+ export function registerSourceCommands(command, services, options) {
14
+ if (options?.includeInit) {
15
+ registerInitCommand(command, services);
16
+ }
17
+ command
18
+ .command("add")
19
+ .argument("<name>", "source name (kebab-case)")
20
+ .argument("<git_repo>", "Git repository URL")
21
+ .description("Add a named git source")
22
+ .action(async (name, gitRepo) => {
23
+ await runAction(async () => {
24
+ const result = await services.addSource(name, "git", gitRepo);
25
+ process.stdout.write(`Added source ${result.name}: ${result.type}${result.repo ? ` ${result.repo}` : ""}\n`);
26
+ });
27
+ });
28
+ command
29
+ .command("use")
30
+ .argument("<name>", "source name")
31
+ .description("Switch default source")
32
+ .action(async (name) => {
33
+ await runAction(async () => {
34
+ const result = await services.useSource(name);
35
+ process.stdout.write(`Using source: ${result.name}\n`);
36
+ });
37
+ });
38
+ command
39
+ .command("list")
40
+ .option("--json", "output json format")
41
+ .description("List configured sources and current default")
42
+ .action(async (options) => {
43
+ await runAction(async () => {
44
+ const sources = await services.listSources();
45
+ if (options.json) {
46
+ process.stdout.write(`${JSON.stringify(sources, null, 2)}\n`);
47
+ return;
48
+ }
49
+ if (sources.length === 0) {
50
+ process.stdout.write("No sources configured.\n");
51
+ return;
52
+ }
53
+ for (const source of sources) {
54
+ process.stdout.write(`- ${source.name}${source.isDefault ? " (default)" : ""}: ${source.type}${source.repo ? ` ${source.repo}` : ""}\n`);
55
+ }
56
+ });
57
+ });
58
+ }