@hi-man/himan 0.3.3 → 0.3.4
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 +6 -0
- package/README.md +1 -1
- package/dist/adapters/source/git-source-adapter.js +72 -0
- package/docs/error-codes.md +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,10 +6,16 @@ The format is based on Keep a Changelog, and this project follows semver for the
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.4] - 2026-05-11
|
|
10
|
+
|
|
9
11
|
### Changed
|
|
10
12
|
|
|
11
13
|
- Changed project guidance to require changelog updates for user-visible CLI behavior changes.
|
|
12
14
|
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Fixed `himan publish` so publishing stops with `E_PUBLISH_NO_CHANGES` when the resource content matches the latest published version.
|
|
18
|
+
|
|
13
19
|
## [0.3.3] - 2026-05-11
|
|
14
20
|
|
|
15
21
|
### Added
|
package/README.md
CHANGED
|
@@ -167,7 +167,7 @@ your-himan-source/
|
|
|
167
167
|
说明:资源与项目相关命令统一使用 `--agent` 指定目标 Agent。
|
|
168
168
|
若未显式传 `--agent`,`create` / `install` 会使用当前项目默认 agent、全局默认 agent、资源 metadata 或内置默认 `cursor` 中最合适的一项;`dev` 会优先使用 lock 中记录的 agent。`install --global` 会优先复用当前项目 lock 里该资源的 agent,未命中时再使用默认 install 解析顺序,但目标根目录是用户 home 下对应 agent 目录。
|
|
169
169
|
|
|
170
|
-
`publish` 优先使用项目里 `.himan/dev` 对应目录,否则用源仓库里对应目录。若资源目录包含 `himan.yaml`,发布前会校验元数据与入口文件;若没有 `himan.yaml`,则按默认入口推断最小元数据并发布,不会强制创建 `himan.yaml
|
|
170
|
+
`publish` 优先使用项目里 `.himan/dev` 对应目录,否则用源仓库里对应目录。若资源目录包含 `himan.yaml`,发布前会校验元数据与入口文件;若没有 `himan.yaml`,则按默认入口推断最小元数据并发布,不会强制创建 `himan.yaml`。若待发布资源内容与最新已发布版本一致,则以 `E_PUBLISH_NO_CHANGES` 终止发布。发布需要可推送的 Git 权限。发布 commit 会包含资源目录以及自动维护的 source 根目录 `README.md` / `CHANGELOG.md`。发布成功后会从新版本 store 以 `copy` 模式重新安装到项目目标、更新 lock,并删除对应 `.himan/dev/<type>/<name>` 开发目录。
|
|
171
171
|
|
|
172
172
|
`--json` 模式下,失败时会输出机器可读错误 JSON(`stderr`)。错误码定义见 [docs/error-codes.md](./docs/error-codes.md)。
|
|
173
173
|
|
|
@@ -4,6 +4,7 @@ import semver from "semver";
|
|
|
4
4
|
import { HimanError, errorCodes } from "../../utils/errors.js";
|
|
5
5
|
import { promises as fs } from "node:fs";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
|
+
import os from "node:os";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
import YAML from "yaml";
|
|
9
10
|
import { IndexCacheStore } from "../../state/index-cache-store.js";
|
|
@@ -52,6 +53,7 @@ export class GitSourceAdapter {
|
|
|
52
53
|
const repoDir = this.getRepoDir();
|
|
53
54
|
const targetDir = path.join(repoDir, `${type}s`, name);
|
|
54
55
|
const metadataResult = await this.validatePublishResource(type, name, sourceDir);
|
|
56
|
+
await this.ensurePublishHasContentChanges(type, name, sourceDir);
|
|
55
57
|
const sameDir = await this.isSameDirectory(sourceDir, targetDir);
|
|
56
58
|
if (!sameDir) {
|
|
57
59
|
await fs.rm(targetDir, { recursive: true, force: true });
|
|
@@ -261,6 +263,76 @@ export class GitSourceAdapter {
|
|
|
261
263
|
metadata.agents = agents;
|
|
262
264
|
return metadata;
|
|
263
265
|
}
|
|
266
|
+
async ensurePublishHasContentChanges(type, name, sourceDir) {
|
|
267
|
+
const latest = (await this.history(type, name))[0];
|
|
268
|
+
if (!latest)
|
|
269
|
+
return;
|
|
270
|
+
const previousDir = await fs.mkdtemp(path.join(os.tmpdir(), "himan-publish-"));
|
|
271
|
+
try {
|
|
272
|
+
await this.repoManager.archiveResource(this.getRepoDir(), latest.raw, `${type}s/${name}`, previousDir);
|
|
273
|
+
const [nextSnapshot, previousSnapshot] = await Promise.all([
|
|
274
|
+
this.readComparableResourceSnapshot(sourceDir),
|
|
275
|
+
this.readComparableResourceSnapshot(previousDir),
|
|
276
|
+
]);
|
|
277
|
+
if (this.resourceSnapshotsEqual(nextSnapshot, previousSnapshot)) {
|
|
278
|
+
throw new HimanError(errorCodes.PUBLISH_NO_CHANGES, `No changes to publish for ${type}/${name}.`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
await fs.rm(previousDir, { recursive: true, force: true });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async readComparableResourceSnapshot(resourceDir) {
|
|
286
|
+
const files = await this.listResourceFiles(resourceDir);
|
|
287
|
+
const snapshot = new Map();
|
|
288
|
+
for (const file of files) {
|
|
289
|
+
const relative = this.toPosixPath(path.relative(resourceDir, file));
|
|
290
|
+
const content = await fs.readFile(file, "utf8");
|
|
291
|
+
snapshot.set(relative, relative === "himan.yaml"
|
|
292
|
+
? this.normalizeComparableResourceMetadata(content)
|
|
293
|
+
: content);
|
|
294
|
+
}
|
|
295
|
+
return snapshot;
|
|
296
|
+
}
|
|
297
|
+
async listResourceFiles(resourceDir) {
|
|
298
|
+
const result = [];
|
|
299
|
+
const entries = await fs.readdir(resourceDir, { withFileTypes: true });
|
|
300
|
+
for (const entry of entries) {
|
|
301
|
+
const fullPath = path.join(resourceDir, entry.name);
|
|
302
|
+
if (entry.isDirectory()) {
|
|
303
|
+
result.push(...(await this.listResourceFiles(fullPath)));
|
|
304
|
+
}
|
|
305
|
+
else if (entry.isFile()) {
|
|
306
|
+
result.push(fullPath);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return result.sort((a, b) => a.localeCompare(b));
|
|
310
|
+
}
|
|
311
|
+
normalizeComparableResourceMetadata(content) {
|
|
312
|
+
try {
|
|
313
|
+
const parsed = YAML.parse(content);
|
|
314
|
+
if (!this.isRecord(parsed))
|
|
315
|
+
return content;
|
|
316
|
+
const normalized = { ...parsed };
|
|
317
|
+
delete normalized.version;
|
|
318
|
+
return YAML.stringify(normalized);
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
return content;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
resourceSnapshotsEqual(a, b) {
|
|
325
|
+
if (a.size !== b.size)
|
|
326
|
+
return false;
|
|
327
|
+
for (const [file, content] of a) {
|
|
328
|
+
if (b.get(file) !== content)
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
toPosixPath(filePath) {
|
|
334
|
+
return filePath.split(path.sep).join("/");
|
|
335
|
+
}
|
|
264
336
|
invalidResourceMetadata(type, name, message, details) {
|
|
265
337
|
return new HimanError(errorCodes.INVALID_RESOURCE_METADATA, `Invalid metadata for ${type}/${name}: ${message}`, details);
|
|
266
338
|
}
|
package/docs/error-codes.md
CHANGED
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
### `E_PUBLISH_NO_CHANGES`
|
|
117
117
|
|
|
118
118
|
- **含义**:发布时没有可提交的资源变更。
|
|
119
|
-
-
|
|
119
|
+
- **常见触发**:重复发布与最新已发布版本内容一致的资源目录;`himan.yaml` 中仅版本字段不同也会视为无内容变化。
|
|
120
120
|
- **建议处理**:确认资源内容或元数据已经变更,再重新执行 `publish`。
|
|
121
121
|
|
|
122
122
|
### `E_UNSUPPORTED_RESOURCE_TYPE`
|