mdkg 0.1.1 → 0.1.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 +104 -0
- package/README.md +124 -18
- package/dist/cli.js +567 -15
- package/dist/commands/archive.js +486 -0
- package/dist/commands/bundle.js +743 -0
- package/dist/commands/bundle_import.js +255 -0
- package/dist/commands/capability.js +162 -0
- package/dist/commands/checkpoint.js +31 -5
- package/dist/commands/doctor.js +269 -9
- package/dist/commands/format.js +38 -9
- package/dist/commands/index.js +12 -12
- package/dist/commands/init.js +194 -63
- package/dist/commands/init_manifest.js +19 -6
- package/dist/commands/list.js +5 -2
- package/dist/commands/new.js +36 -7
- package/dist/commands/next.js +7 -0
- package/dist/commands/node_card.js +4 -1
- package/dist/commands/pack.js +62 -2
- package/dist/commands/query_output.js +1 -0
- package/dist/commands/search.js +5 -2
- package/dist/commands/show.js +7 -14
- package/dist/commands/skill_mirror.js +22 -0
- package/dist/commands/task.js +23 -6
- package/dist/commands/upgrade.js +24 -1
- package/dist/commands/validate.js +20 -1
- package/dist/commands/work.js +397 -0
- package/dist/commands/workspace.js +12 -2
- package/dist/core/config.js +115 -1
- package/dist/graph/agent_file_types.js +78 -5
- package/dist/graph/archive_file.js +125 -0
- package/dist/graph/archive_integrity.js +66 -0
- package/dist/graph/bundle_imports.js +418 -0
- package/dist/graph/capabilities_index_cache.js +103 -0
- package/dist/graph/capabilities_indexer.js +231 -0
- package/dist/graph/frontmatter.js +19 -0
- package/dist/graph/index_cache.js +23 -6
- package/dist/graph/indexer.js +4 -1
- package/dist/graph/node.js +23 -4
- package/dist/graph/node_body.js +37 -0
- package/dist/graph/reindex.js +46 -0
- package/dist/graph/skills_index_cache.js +2 -2
- package/dist/graph/skills_indexer.js +8 -3
- package/dist/graph/sqlite_index.js +293 -0
- package/dist/graph/validate_graph.js +83 -7
- package/dist/graph/visibility.js +214 -0
- package/dist/graph/workspace_files.js +22 -0
- package/dist/init/AGENT_START.md +24 -0
- package/dist/init/CLI_COMMAND_MATRIX.md +61 -3
- package/dist/init/README.md +70 -4
- package/dist/init/config.json +18 -2
- package/dist/init/core/guide.md +6 -2
- package/dist/init/core/rule-1-mdkg-conventions.md +2 -1
- package/dist/init/core/rule-3-cli-contract.md +72 -4
- package/dist/init/core/rule-4-repo-safety-and-ignores.md +47 -11
- package/dist/init/core/rule-5-release-and-versioning.md +4 -3
- package/dist/init/core/rule-6-templates-and-schemas.md +7 -0
- package/dist/init/init-manifest.json +21 -16
- package/dist/init/skills/default/build-pack-and-execute-task/SKILL.md +2 -1
- package/dist/init/skills/default/verify-close-and-checkpoint/SKILL.md +26 -0
- package/dist/init/templates/default/archive.md +33 -0
- package/dist/init/templates/default/receipt.md +15 -1
- package/dist/init/templates/default/work.md +6 -1
- package/dist/init/templates/default/work_order.md +15 -1
- package/dist/pack/export_md.js +3 -0
- package/dist/pack/export_xml.js +3 -0
- package/dist/pack/order.js +1 -0
- package/dist/pack/pack.js +3 -13
- package/dist/util/argparse.js +30 -0
- package/dist/util/atomic.js +44 -0
- package/dist/util/lock.js +72 -0
- package/dist/util/refs.js +40 -0
- package/dist/util/zip.js +153 -0
- package/package.json +14 -5
|
@@ -10,6 +10,7 @@ exports.validateAgentFrontmatter = validateAgentFrontmatter;
|
|
|
10
10
|
exports.extractAgentAttributes = extractAgentAttributes;
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const id_1 = require("../util/id");
|
|
13
|
+
const refs_1 = require("../util/refs");
|
|
13
14
|
exports.AGENT_FILE_TYPES = [
|
|
14
15
|
"spec",
|
|
15
16
|
"work",
|
|
@@ -67,6 +68,10 @@ exports.AGENT_ATTRIBUTE_KEY_ORDER = {
|
|
|
67
68
|
"requester",
|
|
68
69
|
"order_status",
|
|
69
70
|
"request_ref",
|
|
71
|
+
"input_refs",
|
|
72
|
+
"requested_outputs",
|
|
73
|
+
"constraint_refs",
|
|
74
|
+
"artifact_policy",
|
|
70
75
|
],
|
|
71
76
|
receipt: [
|
|
72
77
|
"version",
|
|
@@ -74,6 +79,10 @@ exports.AGENT_ATTRIBUTE_KEY_ORDER = {
|
|
|
74
79
|
"receipt_status",
|
|
75
80
|
"outcome",
|
|
76
81
|
"cost_ref",
|
|
82
|
+
"proof_refs",
|
|
83
|
+
"attestation_refs",
|
|
84
|
+
"input_hashes",
|
|
85
|
+
"output_hashes",
|
|
77
86
|
],
|
|
78
87
|
feedback: [
|
|
79
88
|
"version",
|
|
@@ -135,8 +144,13 @@ const ORDER_STATUS_VALUES = new Set([
|
|
|
135
144
|
"cancelled",
|
|
136
145
|
"failed",
|
|
137
146
|
]);
|
|
138
|
-
const RECEIPT_STATUS_VALUES = new Set(["recorded", "verified", "rejected"]);
|
|
147
|
+
const RECEIPT_STATUS_VALUES = new Set(["recorded", "verified", "rejected", "superseded"]);
|
|
139
148
|
const OUTCOME_VALUES = new Set(["success", "partial", "failure"]);
|
|
149
|
+
const ARTIFACT_POLICY_VALUES = new Set([
|
|
150
|
+
"commit_sidecar_and_zip",
|
|
151
|
+
"external_only",
|
|
152
|
+
"local_only",
|
|
153
|
+
]);
|
|
140
154
|
const SENTIMENT_VALUES = new Set(["positive", "neutral", "negative", "mixed"]);
|
|
141
155
|
const FEEDBACK_STATUS_VALUES = new Set(["new", "triaged", "accepted", "rejected"]);
|
|
142
156
|
const DISPUTE_STATUS_VALUES = new Set(["open", "investigating", "resolved", "rejected"]);
|
|
@@ -190,6 +204,23 @@ function optionalString(frontmatter, key, filePath) {
|
|
|
190
204
|
}
|
|
191
205
|
return value;
|
|
192
206
|
}
|
|
207
|
+
function expectRefString(frontmatter, key, filePath) {
|
|
208
|
+
const value = frontmatter[key];
|
|
209
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
210
|
+
throw formatError(filePath, `${key} is required and must be a non-empty string`);
|
|
211
|
+
}
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
function optionalRefString(frontmatter, key, filePath) {
|
|
215
|
+
const value = frontmatter[key];
|
|
216
|
+
if (value === undefined) {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
220
|
+
throw formatError(filePath, `${key} must be a non-empty string`);
|
|
221
|
+
}
|
|
222
|
+
return value;
|
|
223
|
+
}
|
|
193
224
|
function expectBoolean(frontmatter, key, filePath) {
|
|
194
225
|
const value = frontmatter[key];
|
|
195
226
|
if (typeof value !== "boolean") {
|
|
@@ -254,6 +285,31 @@ function validatePortableRefs(values, key, filePath) {
|
|
|
254
285
|
}
|
|
255
286
|
}
|
|
256
287
|
}
|
|
288
|
+
function validatePortableOrUriRefs(values, key, filePath) {
|
|
289
|
+
for (const [index, value] of values.entries()) {
|
|
290
|
+
if (!(0, refs_1.validatePortableOrUriRef)(value)) {
|
|
291
|
+
throw formatError(filePath, `${key}[${index}] must be a portable id or URI ref`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function validatePortableOrUriScalar(value, key, filePath) {
|
|
296
|
+
if (!(0, refs_1.validatePortableOrUriRef)(value)) {
|
|
297
|
+
throw formatError(filePath, `${key} must be a portable id or URI ref`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function validateOptionalFieldDescriptors(values, key, filePath) {
|
|
301
|
+
if (values.length === 0) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
validateFieldDescriptors(values, key, filePath);
|
|
305
|
+
}
|
|
306
|
+
function validateHashRefs(values, key, filePath) {
|
|
307
|
+
for (const [index, value] of values.entries()) {
|
|
308
|
+
if (!(0, refs_1.isSha256Ref)(value)) {
|
|
309
|
+
throw formatError(filePath, `${key}[${index}] must be sha256:<64 lowercase hex chars>`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
257
313
|
function validateRelativeMarkdownPaths(values, key, basename, filePath) {
|
|
258
314
|
for (const [index, value] of values.entries()) {
|
|
259
315
|
if (path_1.default.isAbsolute(value) || value.split(/[\\/]/).includes("..")) {
|
|
@@ -327,11 +383,21 @@ function validateAgentFrontmatter(type, frontmatter, filePath) {
|
|
|
327
383
|
requirePortableId(workId, "work_id", filePath);
|
|
328
384
|
const workVersion = expectString(frontmatter, "work_version", filePath);
|
|
329
385
|
requireSemver(workVersion, "work_version", filePath);
|
|
330
|
-
const requester =
|
|
331
|
-
|
|
386
|
+
const requester = expectRefString(frontmatter, "requester", filePath);
|
|
387
|
+
validatePortableOrUriScalar(requester, "requester", filePath);
|
|
332
388
|
const orderStatus = expectString(frontmatter, "order_status", filePath);
|
|
333
389
|
requireEnum(orderStatus, "order_status", ORDER_STATUS_VALUES, filePath);
|
|
334
|
-
|
|
390
|
+
const requestRef = optionalRefString(frontmatter, "request_ref", filePath);
|
|
391
|
+
if (requestRef) {
|
|
392
|
+
validatePortableOrUriScalar(requestRef, "request_ref", filePath);
|
|
393
|
+
}
|
|
394
|
+
validatePortableOrUriRefs(optionalList(frontmatter, "input_refs", filePath), "input_refs", filePath);
|
|
395
|
+
validateOptionalFieldDescriptors(optionalList(frontmatter, "requested_outputs", filePath), "requested_outputs", filePath);
|
|
396
|
+
validatePortableOrUriRefs(optionalList(frontmatter, "constraint_refs", filePath), "constraint_refs", filePath);
|
|
397
|
+
const artifactPolicy = optionalString(frontmatter, "artifact_policy", filePath);
|
|
398
|
+
if (artifactPolicy) {
|
|
399
|
+
requireEnum(artifactPolicy, "artifact_policy", ARTIFACT_POLICY_VALUES, filePath);
|
|
400
|
+
}
|
|
335
401
|
break;
|
|
336
402
|
}
|
|
337
403
|
case "receipt": {
|
|
@@ -341,7 +407,14 @@ function validateAgentFrontmatter(type, frontmatter, filePath) {
|
|
|
341
407
|
requireEnum(receiptStatus, "receipt_status", RECEIPT_STATUS_VALUES, filePath);
|
|
342
408
|
const outcome = expectString(frontmatter, "outcome", filePath);
|
|
343
409
|
requireEnum(outcome, "outcome", OUTCOME_VALUES, filePath);
|
|
344
|
-
|
|
410
|
+
const costRef = optionalRefString(frontmatter, "cost_ref", filePath);
|
|
411
|
+
if (costRef) {
|
|
412
|
+
validatePortableOrUriScalar(costRef, "cost_ref", filePath);
|
|
413
|
+
}
|
|
414
|
+
validatePortableOrUriRefs(optionalList(frontmatter, "proof_refs", filePath), "proof_refs", filePath);
|
|
415
|
+
validatePortableOrUriRefs(optionalList(frontmatter, "attestation_refs", filePath), "attestation_refs", filePath);
|
|
416
|
+
validateHashRefs(optionalList(frontmatter, "input_hashes", filePath), "input_hashes", filePath);
|
|
417
|
+
validateHashRefs(optionalList(frontmatter, "output_hashes", filePath), "output_hashes", filePath);
|
|
345
418
|
break;
|
|
346
419
|
}
|
|
347
420
|
case "feedback": {
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ARCHIVE_ATTRIBUTE_KEY_ORDER = void 0;
|
|
7
|
+
exports.isArchiveType = isArchiveType;
|
|
8
|
+
exports.validateArchiveFrontmatter = validateArchiveFrontmatter;
|
|
9
|
+
exports.extractArchiveAttributes = extractArchiveAttributes;
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const archive_integrity_1 = require("./archive_integrity");
|
|
12
|
+
const id_1 = require("../util/id");
|
|
13
|
+
exports.ARCHIVE_ATTRIBUTE_KEY_ORDER = [
|
|
14
|
+
"archive_kind",
|
|
15
|
+
"source_path",
|
|
16
|
+
"stored_path",
|
|
17
|
+
"compressed_path",
|
|
18
|
+
"mime_type",
|
|
19
|
+
"byte_size",
|
|
20
|
+
"sha256",
|
|
21
|
+
"compressed_sha256",
|
|
22
|
+
"visibility",
|
|
23
|
+
"provenance",
|
|
24
|
+
"ingest_status",
|
|
25
|
+
];
|
|
26
|
+
const ARCHIVE_KIND_VALUES = new Set(["source", "artifact"]);
|
|
27
|
+
const VISIBILITY_VALUES = new Set(["private", "internal", "public"]);
|
|
28
|
+
const INGEST_STATUS_VALUES = new Set(["pending", "ingested", "compressed", "verified", "failed"]);
|
|
29
|
+
const SHA256_RE = /^sha256:[a-f0-9]{64}$/;
|
|
30
|
+
const MIME_RE = /^[a-z0-9.+-]+\/[a-z0-9.+-]+$/;
|
|
31
|
+
function formatError(filePath, message) {
|
|
32
|
+
return new Error(`${filePath}: ${message}`);
|
|
33
|
+
}
|
|
34
|
+
function expectString(frontmatter, key, filePath) {
|
|
35
|
+
const value = frontmatter[key];
|
|
36
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
37
|
+
throw formatError(filePath, `${key} is required and must be a non-empty string`);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
function requireEnum(value, key, allowed, filePath) {
|
|
42
|
+
if (!allowed.has(value)) {
|
|
43
|
+
throw formatError(filePath, `${key} must be one of ${Array.from(allowed).join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function requireRelativePath(value, key, filePath) {
|
|
47
|
+
if (path_1.default.isAbsolute(value) || value.split(/[\\/]/).includes("..")) {
|
|
48
|
+
throw formatError(filePath, `${key} must be a relative path`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function requireSha256(value, key, filePath) {
|
|
52
|
+
if (!SHA256_RE.test(value)) {
|
|
53
|
+
throw formatError(filePath, `${key} must be sha256:<64 lowercase hex chars>`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function isArchiveType(type) {
|
|
57
|
+
return type === "archive";
|
|
58
|
+
}
|
|
59
|
+
function validateArchiveFrontmatter(type, frontmatter, filePath) {
|
|
60
|
+
if (!isArchiveType(type)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const id = expectString(frontmatter, "id", filePath);
|
|
64
|
+
if (id !== id.toLowerCase() || !(0, id_1.isPortableId)(id) || !id.startsWith("archive.")) {
|
|
65
|
+
throw formatError(filePath, "id must be a lowercase portable archive id like archive.example");
|
|
66
|
+
}
|
|
67
|
+
const archiveKind = expectString(frontmatter, "archive_kind", filePath);
|
|
68
|
+
requireEnum(archiveKind, "archive_kind", ARCHIVE_KIND_VALUES, filePath);
|
|
69
|
+
const sourcePath = expectString(frontmatter, "source_path", filePath);
|
|
70
|
+
if (sourcePath.includes("\0")) {
|
|
71
|
+
throw formatError(filePath, "source_path must not contain NUL bytes");
|
|
72
|
+
}
|
|
73
|
+
if (path_1.default.isAbsolute(sourcePath) || sourcePath.split(/[\\/]/).includes("..")) {
|
|
74
|
+
throw formatError(filePath, "source_path must be repo-relative or external:<label>");
|
|
75
|
+
}
|
|
76
|
+
const storedPath = expectString(frontmatter, "stored_path", filePath);
|
|
77
|
+
requireRelativePath(storedPath, "stored_path", filePath);
|
|
78
|
+
const compressedPath = expectString(frontmatter, "compressed_path", filePath);
|
|
79
|
+
requireRelativePath(compressedPath, "compressed_path", filePath);
|
|
80
|
+
const mimeType = expectString(frontmatter, "mime_type", filePath);
|
|
81
|
+
if (!MIME_RE.test(mimeType)) {
|
|
82
|
+
throw formatError(filePath, "mime_type must look like type/subtype");
|
|
83
|
+
}
|
|
84
|
+
const byteSize = expectString(frontmatter, "byte_size", filePath);
|
|
85
|
+
if (!/^[0-9]+$/.test(byteSize)) {
|
|
86
|
+
throw formatError(filePath, "byte_size must be a non-negative integer string");
|
|
87
|
+
}
|
|
88
|
+
const sourceHash = expectString(frontmatter, "sha256", filePath);
|
|
89
|
+
requireSha256(sourceHash, "sha256", filePath);
|
|
90
|
+
const compressedHash = expectString(frontmatter, "compressed_sha256", filePath);
|
|
91
|
+
requireSha256(compressedHash, "compressed_sha256", filePath);
|
|
92
|
+
const visibility = expectString(frontmatter, "visibility", filePath);
|
|
93
|
+
requireEnum(visibility, "visibility", VISIBILITY_VALUES, filePath);
|
|
94
|
+
const provenance = expectString(frontmatter, "provenance", filePath);
|
|
95
|
+
if (provenance.trim().length === 0) {
|
|
96
|
+
throw formatError(filePath, "provenance must not be empty");
|
|
97
|
+
}
|
|
98
|
+
const ingestStatus = expectString(frontmatter, "ingest_status", filePath);
|
|
99
|
+
requireEnum(ingestStatus, "ingest_status", INGEST_STATUS_VALUES, filePath);
|
|
100
|
+
const sidecarDir = path_1.default.dirname(filePath);
|
|
101
|
+
const checked = (0, archive_integrity_1.checkArchiveIntegrity)({
|
|
102
|
+
root: sidecarDir,
|
|
103
|
+
rawPath: path_1.default.resolve(sidecarDir, storedPath),
|
|
104
|
+
zipPath: path_1.default.resolve(sidecarDir, compressedPath),
|
|
105
|
+
expectedRawHash: sourceHash,
|
|
106
|
+
expectedCompressedHash: compressedHash,
|
|
107
|
+
expectedByteSize: byteSize,
|
|
108
|
+
});
|
|
109
|
+
if (!checked.ok) {
|
|
110
|
+
throw formatError(filePath, checked.errors.join("; "));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function extractArchiveAttributes(type, frontmatter) {
|
|
114
|
+
if (!isArchiveType(type)) {
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
const attributes = {};
|
|
118
|
+
for (const key of exports.ARCHIVE_ATTRIBUTE_KEY_ORDER) {
|
|
119
|
+
const value = frontmatter[key];
|
|
120
|
+
if (value !== undefined) {
|
|
121
|
+
attributes[key] = value;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return attributes;
|
|
125
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.hashArchiveBuffer = hashArchiveBuffer;
|
|
7
|
+
exports.hashArchiveFile = hashArchiveFile;
|
|
8
|
+
exports.checkArchiveIntegrity = checkArchiveIntegrity;
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const zip_1 = require("../util/zip");
|
|
13
|
+
function hashArchiveBuffer(buffer) {
|
|
14
|
+
return `sha256:${crypto_1.default.createHash("sha256").update(buffer).digest("hex")}`;
|
|
15
|
+
}
|
|
16
|
+
function hashArchiveFile(filePath) {
|
|
17
|
+
return hashArchiveBuffer(fs_1.default.readFileSync(filePath));
|
|
18
|
+
}
|
|
19
|
+
function relativeLabel(root, filePath) {
|
|
20
|
+
return path_1.default.relative(root, filePath).split(path_1.default.sep).join("/");
|
|
21
|
+
}
|
|
22
|
+
function checkArchiveIntegrity(options) {
|
|
23
|
+
const result = {
|
|
24
|
+
ok: true,
|
|
25
|
+
raw_present: false,
|
|
26
|
+
compressed_present: false,
|
|
27
|
+
errors: [],
|
|
28
|
+
};
|
|
29
|
+
if (!fs_1.default.existsSync(options.zipPath)) {
|
|
30
|
+
result.errors.push(`compressed cache missing: ${relativeLabel(options.root, options.zipPath)}`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
result.compressed_present = true;
|
|
34
|
+
const actualCompressedHash = hashArchiveFile(options.zipPath);
|
|
35
|
+
if (actualCompressedHash !== options.expectedCompressedHash) {
|
|
36
|
+
result.errors.push(`compressed_sha256 mismatch: ${actualCompressedHash}`);
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const unzipped = (0, zip_1.readSingleFileZip)(fs_1.default.readFileSync(options.zipPath));
|
|
40
|
+
const unzippedHash = hashArchiveBuffer(unzipped.data);
|
|
41
|
+
if (unzippedHash !== options.expectedRawHash) {
|
|
42
|
+
result.errors.push(`zip payload sha256 mismatch: ${unzippedHash}`);
|
|
43
|
+
}
|
|
44
|
+
if (String(unzipped.data.length) !== options.expectedByteSize) {
|
|
45
|
+
result.errors.push(`zip payload byte_size mismatch: ${unzipped.data.length}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
50
|
+
result.errors.push(`zip read failed: ${message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (fs_1.default.existsSync(options.rawPath)) {
|
|
54
|
+
result.raw_present = true;
|
|
55
|
+
const actualRawHash = hashArchiveFile(options.rawPath);
|
|
56
|
+
if (actualRawHash !== options.expectedRawHash) {
|
|
57
|
+
result.errors.push(`raw sha256 mismatch: ${actualRawHash}`);
|
|
58
|
+
}
|
|
59
|
+
const actualByteSize = String(fs_1.default.statSync(options.rawPath).size);
|
|
60
|
+
if (actualByteSize !== options.expectedByteSize) {
|
|
61
|
+
result.errors.push(`raw byte_size mismatch: ${actualByteSize}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
result.ok = result.errors.length === 0;
|
|
65
|
+
return result;
|
|
66
|
+
}
|