@hi-man/himan 0.3.2 → 0.3.3
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 +15 -0
- package/README.md +4 -3
- package/dist/cli/builders.js +6 -5
- package/dist/cli/installed-resource-list.js +46 -0
- package/dist/cli/project-commands.js +31 -1
- package/dist/cli/resource-commands.js +93 -10
- package/dist/services/index.js +22 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,21 @@ The format is based on Keep a Changelog, and this project follows semver for the
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Changed project guidance to require changelog updates for user-visible CLI behavior changes.
|
|
12
|
+
|
|
13
|
+
## [0.3.3] - 2026-05-11
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Added `himan project list` and `himan list --installed` to show resources recorded in the current project's `himan.lock`.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Changed `himan list` without a resource type to group all source resources by `rule`, `command`, and `skill`.
|
|
22
|
+
- Added `himan list --brief` to hide resource descriptions in concise list output.
|
|
23
|
+
|
|
9
24
|
## [0.3.2] - 2026-05-08
|
|
10
25
|
|
|
11
26
|
### Added
|
package/README.md
CHANGED
|
@@ -133,7 +133,7 @@ your-himan-source/
|
|
|
133
133
|
|
|
134
134
|
| 命令 | 说明 |
|
|
135
135
|
| -------------------------------- | ----------------------------------------------------------------------------------- |
|
|
136
|
-
| `list [type] [--agent a,b] [--json]` |
|
|
136
|
+
| `list [type] [--agent a,b] [--brief] [--installed] [--json]` | 默认列出当前 default source 的资源;未传 `type` 时按 `rule`/`command`/`skill` 分组展示全部资源;可按 agent 过滤;默认显示描述,`--brief` 可隐藏描述;`--installed` 改为查看当前项目 `himan.lock` 中的已安装资源 |
|
|
137
137
|
| `history <type> <name> [--json]` | 按 tag 查看版本历史 |
|
|
138
138
|
| `create <type> <name>` | 脚手架;常用选项:`--description`、`--agent a,b`、`--dry-run`、`--force`、`--json` |
|
|
139
139
|
|
|
@@ -141,6 +141,7 @@ your-himan-source/
|
|
|
141
141
|
|
|
142
142
|
| 命令 | 说明 |
|
|
143
143
|
| --------------------------------- | --------------------------------------------------------- |
|
|
144
|
+
| `list [type] [--agent a,b] [--json]` | 查看当前项目 `himan.lock` 中记录的已安装资源;未传 `type` 时按 `rule`/`command`/`skill` 分组展示 |
|
|
144
145
|
| `install [type] [name[@version]] [--global] [--agent a,b] [--mode link\|copy]` | 有参数时从当前 default source 安装指定资源;**无参数**时按 `himan.lock` 记录的 source 批量安装;加 `--global` 时安装到用户级 agent 目录且不写项目 lock;可覆盖安装目标 agent 或安装模式 |
|
|
145
146
|
| `dev <type> <name>` | 切换到开发态,并按安装模式将项目目标指向或复制自 `.himan/dev/...` |
|
|
146
147
|
| `uninstall <type> <name>` | 从项目移除安装目标,并同步删除 `himan.lock` 条目 |
|
|
@@ -159,8 +160,8 @@ your-himan-source/
|
|
|
159
160
|
|
|
160
161
|
- `himan resource list|history|create ...`
|
|
161
162
|
- `himan-resource list|history|create ...`(兼容保留:也可执行 install/dev/uninstall/publish)
|
|
162
|
-
- `himan project install|dev|uninstall|publish ...`
|
|
163
|
-
- `himan-project install|dev|uninstall|publish ...`
|
|
163
|
+
- `himan project list|install|dev|uninstall|publish ...`
|
|
164
|
+
- `himan-project list|install|dev|uninstall|publish ...`
|
|
164
165
|
- `himan agent list|use|current|clear ...`
|
|
165
166
|
|
|
166
167
|
说明:资源与项目相关命令统一使用 `--agent` 指定目标 Agent。
|
package/dist/cli/builders.js
CHANGED
|
@@ -25,7 +25,7 @@ export function buildCli() {
|
|
|
25
25
|
registerAgentCommands(agentCmd, services);
|
|
26
26
|
// Backward compatible top-level resource lifecycle commands.
|
|
27
27
|
registerResourceCommands(program, services);
|
|
28
|
-
registerProjectCommands(program, services);
|
|
28
|
+
registerProjectCommands(program, services, { includeList: false });
|
|
29
29
|
return program;
|
|
30
30
|
}
|
|
31
31
|
export function buildSourceCli() {
|
|
@@ -43,7 +43,7 @@ export function buildResourceCli() {
|
|
|
43
43
|
.description("Manage default agent configuration");
|
|
44
44
|
registerAgentCommands(agentCmd, services);
|
|
45
45
|
// Backward compatible: keep project lifecycle commands in himan-resource.
|
|
46
|
-
registerProjectCommands(program, services);
|
|
46
|
+
registerProjectCommands(program, services, { includeList: false });
|
|
47
47
|
return program;
|
|
48
48
|
}
|
|
49
49
|
export function buildProjectCli() {
|
|
@@ -62,10 +62,11 @@ Command groups:
|
|
|
62
62
|
source Data source management (git now, registry reserved)
|
|
63
63
|
init, source init, source add, source use, source list, source init-docs
|
|
64
64
|
resource Source resource discovery and metadata
|
|
65
|
-
list,
|
|
65
|
+
list, list --installed, history, create,
|
|
66
|
+
resource list, resource history, resource create
|
|
66
67
|
project Resource usage lifecycle in current project or user-level agent dirs
|
|
67
|
-
install, dev, uninstall, publish,
|
|
68
|
-
project install, project dev, project uninstall, project publish
|
|
68
|
+
list, install, dev, uninstall, publish,
|
|
69
|
+
project list, project install, project dev, project uninstall, project publish
|
|
69
70
|
agent Default agent configuration
|
|
70
71
|
agent list, agent use, agent current, agent clear
|
|
71
72
|
`);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const RESOURCE_TYPES = ["rule", "command", "skill"];
|
|
2
|
+
export async function listInstalledResourceGroups(services, projectDir, agents) {
|
|
3
|
+
const resources = await services.listInstalled(projectDir, undefined, agents);
|
|
4
|
+
return groupInstalledResources(resources);
|
|
5
|
+
}
|
|
6
|
+
export function groupInstalledResources(resources) {
|
|
7
|
+
return {
|
|
8
|
+
rule: resources.filter((resource) => resource.type === "rule"),
|
|
9
|
+
command: resources.filter((resource) => resource.type === "command"),
|
|
10
|
+
skill: resources.filter((resource) => resource.type === "skill"),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function writeInstalledResourceGroups(groups) {
|
|
14
|
+
const hasResources = RESOURCE_TYPES.some((type) => groups[type].length > 0);
|
|
15
|
+
if (!hasResources) {
|
|
16
|
+
process.stdout.write("No installed resources found.\n");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
for (const type of RESOURCE_TYPES) {
|
|
20
|
+
const resources = groups[type];
|
|
21
|
+
if (resources.length === 0)
|
|
22
|
+
continue;
|
|
23
|
+
process.stdout.write(`${formatGroupTitle(type)}:\n`);
|
|
24
|
+
writeInstalledResources(resources);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function writeInstalledResources(resources) {
|
|
28
|
+
if (resources.length === 0) {
|
|
29
|
+
process.stdout.write("No installed resources found.\n");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
for (const resource of resources) {
|
|
33
|
+
process.stdout.write(`- ${formatInstalledResource(resource)}\n`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function formatInstalledResource(resource) {
|
|
37
|
+
const agents = resource.agents.length > 0 ? ` [${resource.agents.join(", ")}]` : "";
|
|
38
|
+
return `${resource.type}/${resource.name}@${resource.version}${agents} (${resource.mode})`;
|
|
39
|
+
}
|
|
40
|
+
function formatGroupTitle(type) {
|
|
41
|
+
if (type === "rule")
|
|
42
|
+
return "Rules";
|
|
43
|
+
if (type === "command")
|
|
44
|
+
return "Commands";
|
|
45
|
+
return "Skills";
|
|
46
|
+
}
|
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
import { HimanError, errorCodes } from "../utils/errors.js";
|
|
2
2
|
import { getSupportedAgentNames, normalizeAgent } from "../utils/agent-configs.js";
|
|
3
|
+
import { listInstalledResourceGroups, writeInstalledResourceGroups, writeInstalledResources, } from "./installed-resource-list.js";
|
|
3
4
|
import { runAction } from "./shared.js";
|
|
4
|
-
export function registerProjectCommands(command, services) {
|
|
5
|
+
export function registerProjectCommands(command, services, options = {}) {
|
|
6
|
+
if (options.includeList !== false) {
|
|
7
|
+
command
|
|
8
|
+
.command("list")
|
|
9
|
+
.argument("[type]", "resource type")
|
|
10
|
+
.option("--agent <list>", "agent list filter, comma separated")
|
|
11
|
+
.option("--json", "output json format")
|
|
12
|
+
.description("List resources installed in current project")
|
|
13
|
+
.action(async (type, commandOptions) => {
|
|
14
|
+
await runAction(async () => {
|
|
15
|
+
const agents = parseAgents(commandOptions.agent);
|
|
16
|
+
if (!type) {
|
|
17
|
+
const groups = await listInstalledResourceGroups(services, process.cwd(), agents);
|
|
18
|
+
if (commandOptions.json) {
|
|
19
|
+
process.stdout.write(`${JSON.stringify(groups, null, 2)}\n`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
writeInstalledResourceGroups(groups);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const resourceType = ensureResourceType(type);
|
|
26
|
+
const resources = await services.listInstalled(process.cwd(), resourceType, agents);
|
|
27
|
+
if (commandOptions.json) {
|
|
28
|
+
process.stdout.write(`${JSON.stringify(resources, null, 2)}\n`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
writeInstalledResources(resources);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
5
35
|
command
|
|
6
36
|
.command("install")
|
|
7
37
|
.argument("[type]", "resource type")
|
|
@@ -1,28 +1,41 @@
|
|
|
1
1
|
import { HimanError, errorCodes } from "../utils/errors.js";
|
|
2
2
|
import { getSupportedAgentNames, normalizeAgent } from "../utils/agent-configs.js";
|
|
3
|
+
import { listInstalledResourceGroups, writeInstalledResourceGroups, writeInstalledResources, } from "./installed-resource-list.js";
|
|
3
4
|
import { runAction } from "./shared.js";
|
|
5
|
+
const RESOURCE_TYPES = ["rule", "command", "skill"];
|
|
4
6
|
export function registerResourceCommands(command, services) {
|
|
5
7
|
command
|
|
6
8
|
.command("list")
|
|
7
|
-
.argument("[type]", "resource type"
|
|
9
|
+
.argument("[type]", "resource type")
|
|
8
10
|
.option("--agent <list>", "agent list filter, comma separated")
|
|
11
|
+
.option("--brief", "hide resource descriptions")
|
|
12
|
+
.option("--installed", "list resources installed in current project")
|
|
9
13
|
.option("--json", "output json format")
|
|
10
|
-
.description("List resources from current default source")
|
|
14
|
+
.description("List resources from current default source or project installs")
|
|
11
15
|
.action(async (type, options) => {
|
|
12
16
|
await runAction(async () => {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
if (options.
|
|
16
|
-
|
|
17
|
+
const agents = parseAgents(options.agent);
|
|
18
|
+
const showDescription = !options.brief;
|
|
19
|
+
if (options.installed) {
|
|
20
|
+
await writeInstalledList(services, type, agents, Boolean(options.json));
|
|
17
21
|
return;
|
|
18
22
|
}
|
|
19
|
-
if (
|
|
20
|
-
|
|
23
|
+
if (!type) {
|
|
24
|
+
const groups = await listGroupedResources(services, agents);
|
|
25
|
+
if (options.json) {
|
|
26
|
+
process.stdout.write(`${JSON.stringify(formatResourceGroups(groups, showDescription), null, 2)}\n`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
writeGroupedResources(groups, showDescription);
|
|
21
30
|
return;
|
|
22
31
|
}
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
const resourceType = ensureResourceType(type);
|
|
33
|
+
const resources = await services.list(resourceType, agents);
|
|
34
|
+
if (options.json) {
|
|
35
|
+
process.stdout.write(`${JSON.stringify(formatResources(resources, showDescription), null, 2)}\n`);
|
|
36
|
+
return;
|
|
25
37
|
}
|
|
38
|
+
writeResourceList(resources, showDescription);
|
|
26
39
|
});
|
|
27
40
|
});
|
|
28
41
|
command
|
|
@@ -79,12 +92,82 @@ export function registerResourceCommands(command, services) {
|
|
|
79
92
|
});
|
|
80
93
|
});
|
|
81
94
|
}
|
|
95
|
+
async function writeInstalledList(services, type, agents, json) {
|
|
96
|
+
if (!type) {
|
|
97
|
+
const groups = await listInstalledResourceGroups(services, process.cwd(), agents);
|
|
98
|
+
if (json) {
|
|
99
|
+
process.stdout.write(`${JSON.stringify(groups, null, 2)}\n`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
writeInstalledResourceGroups(groups);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const resourceType = ensureResourceType(type);
|
|
106
|
+
const resources = await services.listInstalled(process.cwd(), resourceType, agents);
|
|
107
|
+
if (json) {
|
|
108
|
+
process.stdout.write(`${JSON.stringify(resources, null, 2)}\n`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
writeInstalledResources(resources);
|
|
112
|
+
}
|
|
82
113
|
function ensureResourceType(type) {
|
|
83
114
|
if (type !== "rule" && type !== "command" && type !== "skill") {
|
|
84
115
|
throw new HimanError(errorCodes.UNSUPPORTED_RESOURCE_TYPE, `Unsupported resource type: ${type}`);
|
|
85
116
|
}
|
|
86
117
|
return type;
|
|
87
118
|
}
|
|
119
|
+
async function listGroupedResources(services, agents) {
|
|
120
|
+
return {
|
|
121
|
+
rule: await services.list("rule", agents),
|
|
122
|
+
command: await services.list("command", agents),
|
|
123
|
+
skill: await services.list("skill", agents),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function formatResourceGroups(groups, showDescription) {
|
|
127
|
+
return {
|
|
128
|
+
rule: formatResources(groups.rule, showDescription),
|
|
129
|
+
command: formatResources(groups.command, showDescription),
|
|
130
|
+
skill: formatResources(groups.skill, showDescription),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function formatResources(resources, showDescription) {
|
|
134
|
+
if (showDescription)
|
|
135
|
+
return resources;
|
|
136
|
+
return resources.map((resource) => {
|
|
137
|
+
const { description: _description, ...withoutDescription } = resource;
|
|
138
|
+
return withoutDescription;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function writeGroupedResources(groups, showDescription) {
|
|
142
|
+
const hasResources = RESOURCE_TYPES.some((type) => groups[type].length > 0);
|
|
143
|
+
if (!hasResources) {
|
|
144
|
+
process.stdout.write("No resources found.\n");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
for (const type of RESOURCE_TYPES) {
|
|
148
|
+
const resources = groups[type];
|
|
149
|
+
if (resources.length === 0)
|
|
150
|
+
continue;
|
|
151
|
+
process.stdout.write(`${formatGroupTitle(type)}:\n`);
|
|
152
|
+
writeResourceList(resources, showDescription);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function writeResourceList(resources, showDescription) {
|
|
156
|
+
if (resources.length === 0) {
|
|
157
|
+
process.stdout.write("No resources found.\n");
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
for (const resource of resources) {
|
|
161
|
+
process.stdout.write(`- ${resource.type}/${resource.name}${showDescription && resource.description ? `: ${resource.description}` : ""}\n`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function formatGroupTitle(type) {
|
|
165
|
+
if (type === "rule")
|
|
166
|
+
return "Rules";
|
|
167
|
+
if (type === "command")
|
|
168
|
+
return "Commands";
|
|
169
|
+
return "Skills";
|
|
170
|
+
}
|
|
88
171
|
function parseAgents(input) {
|
|
89
172
|
if (!input)
|
|
90
173
|
return undefined;
|
package/dist/services/index.js
CHANGED
|
@@ -157,6 +157,28 @@ export class ServiceFactory {
|
|
|
157
157
|
const selected = normalizeAgents(agents);
|
|
158
158
|
return resources.filter((resource) => normalizeAgents(resource.agents).some((agent) => selected.includes(agent)));
|
|
159
159
|
}
|
|
160
|
+
async listInstalled(projectDir, type, agents) {
|
|
161
|
+
const { lock, state } = await this.lockStore.loadWithState(projectDir);
|
|
162
|
+
if (state === "invalid") {
|
|
163
|
+
throw new HimanError(errorCodes.LOCK_INVALID, `Lock file is invalid: ${this.lockStore.getLockPath(projectDir)}`);
|
|
164
|
+
}
|
|
165
|
+
if (state === "missing" || !lock) {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
const selectedAgents = agents?.length ? normalizeAgents(agents) : undefined;
|
|
169
|
+
return lock.resources
|
|
170
|
+
.filter((resource) => !type || resource.type === type)
|
|
171
|
+
.map((resource) => ({
|
|
172
|
+
type: resource.type,
|
|
173
|
+
name: resource.name,
|
|
174
|
+
version: resource.version,
|
|
175
|
+
agents: normalizeAgents(resource.agents),
|
|
176
|
+
mode: this.resolveInstallMode(resource.mode),
|
|
177
|
+
updatedAt: resource.updatedAt,
|
|
178
|
+
}))
|
|
179
|
+
.filter((resource) => !selectedAgents ||
|
|
180
|
+
resource.agents.some((agent) => selectedAgents.includes(agent)));
|
|
181
|
+
}
|
|
160
182
|
async history(type, name) {
|
|
161
183
|
const source = await this.loadSourceFromConfig();
|
|
162
184
|
return source.history(type, name);
|