@shrkcrft/generator 0.1.0-alpha.24 → 0.1.0-alpha.26
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/saved-plan.d.ts +28 -2
- package/dist/saved-plan.d.ts.map +1 -1
- package/dist/saved-plan.js +20 -0
- package/package.json +5 -5
package/dist/saved-plan.d.ts
CHANGED
|
@@ -12,6 +12,24 @@ export interface ISavedPlanExpectedChange {
|
|
|
12
12
|
type: string;
|
|
13
13
|
relativePath: string;
|
|
14
14
|
sizeBytes: number;
|
|
15
|
+
/**
|
|
16
|
+
* SHA-256 hex digest of the exact rendered body that `gen --print` shows.
|
|
17
|
+
* Always emitted by `buildSavedPlan`; may be absent on legacy plans written
|
|
18
|
+
* before body/digest persistence. The plan is the review/apply artifact, so
|
|
19
|
+
* this digest lets a later review or apply verify — WITHOUT re-rendering —
|
|
20
|
+
* that the live content still matches what was previewed. Covered by the
|
|
21
|
+
* HMAC signature (canonical JSON includes the whole `expectedChanges`).
|
|
22
|
+
*/
|
|
23
|
+
sha256?: string;
|
|
24
|
+
/**
|
|
25
|
+
* The exact rendered file body that would be written — byte-identical to
|
|
26
|
+
* what `gen --print` / `--show-content` displays. Embedded so the saved
|
|
27
|
+
* plan carries enough to be reviewed for correctness, diffed against HEAD,
|
|
28
|
+
* and re-applied deterministically instead of storing only a byte count.
|
|
29
|
+
* Always emitted by `buildSavedPlan`; may be absent on legacy plans. Covered
|
|
30
|
+
* by the HMAC signature.
|
|
31
|
+
*/
|
|
32
|
+
body?: string;
|
|
15
33
|
/**
|
|
16
34
|
* v2-only — the operation intent that produced this change. Present iff
|
|
17
35
|
* the schema is `sharkcraft.plan/v2`. Tampering with this field invalidates
|
|
@@ -87,12 +105,20 @@ export interface BuildSavedPlanInput {
|
|
|
87
105
|
* resulting plan is tagged `sharkcraft.plan/v2`; otherwise v1.
|
|
88
106
|
*/
|
|
89
107
|
export declare function buildSavedPlan(input: BuildSavedPlanInput): ISavedPlan;
|
|
108
|
+
/** SHA-256 hex digest of a rendered file body (UTF-8). */
|
|
109
|
+
export declare function sha256Hex(body: string): string;
|
|
90
110
|
export declare function savePlanToFile(plan: ISavedPlan, filePath: string): Result<void, AppError>;
|
|
91
111
|
export declare function readPlanFromFile(filePath: string): Result<ISavedPlan, AppError>;
|
|
92
112
|
export interface IPlanDiff {
|
|
93
113
|
relativePath: string;
|
|
94
|
-
/**
|
|
95
|
-
|
|
114
|
+
/**
|
|
115
|
+
* "added" | "removed" | "type-changed" | "size-changed" |
|
|
116
|
+
* "operation-changed" | "content-changed". `content-changed` fires when the
|
|
117
|
+
* live body's digest differs from the saved `sha256` even though the byte
|
|
118
|
+
* count matches — a same-size content edit that a size check alone would
|
|
119
|
+
* miss.
|
|
120
|
+
*/
|
|
121
|
+
kind: 'added' | 'removed' | 'type-changed' | 'size-changed' | 'operation-changed' | 'content-changed';
|
|
96
122
|
detail?: string;
|
|
97
123
|
}
|
|
98
124
|
/**
|
package/dist/saved-plan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"saved-plan.d.ts","sourceRoot":"","sources":["../src/saved-plan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"saved-plan.d.ts","sourceRoot":"","sources":["../src/saved-plan.ts"],"names":[],"mappings":"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"}
|
package/dist/saved-plan.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname } from 'node:path';
|
|
3
3
|
import { mkdirSync } from 'node:fs';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
4
5
|
import { AppErrorImpl, ERROR_CODES, err, ok } from '@shrkcrft/core';
|
|
5
6
|
/** v1 schema marker — kept for legacy CREATE-only plans. */
|
|
6
7
|
export const SAVED_PLAN_SCHEMA_V1 = 'sharkcraft.plan/v1';
|
|
@@ -20,6 +21,11 @@ export function buildSavedPlan(input) {
|
|
|
20
21
|
type: String(c.type),
|
|
21
22
|
relativePath: c.relativePath,
|
|
22
23
|
sizeBytes: c.sizeBytes,
|
|
24
|
+
// Persist the exact rendered body (what `--print` shows) plus its
|
|
25
|
+
// digest, so the saved plan IS the reviewable / re-appliable artifact
|
|
26
|
+
// rather than a bare byte count. Both are covered by the HMAC signature.
|
|
27
|
+
sha256: sha256Hex(c.contents),
|
|
28
|
+
body: c.contents,
|
|
23
29
|
};
|
|
24
30
|
if (c.operation !== undefined)
|
|
25
31
|
entry.operation = c.operation;
|
|
@@ -41,6 +47,10 @@ export function buildSavedPlan(input) {
|
|
|
41
47
|
out.folderOps = [...input.folderOps];
|
|
42
48
|
return out;
|
|
43
49
|
}
|
|
50
|
+
/** SHA-256 hex digest of a rendered file body (UTF-8). */
|
|
51
|
+
export function sha256Hex(body) {
|
|
52
|
+
return createHash('sha256').update(body, 'utf8').digest('hex');
|
|
53
|
+
}
|
|
44
54
|
export function savePlanToFile(plan, filePath) {
|
|
45
55
|
try {
|
|
46
56
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
@@ -202,6 +212,16 @@ export function diffPlanChanges(saved, fresh) {
|
|
|
202
212
|
detail: `${expected.sizeBytes}B → ${actual.sizeBytes}B`,
|
|
203
213
|
});
|
|
204
214
|
}
|
|
215
|
+
else if (expected.sha256 !== undefined &&
|
|
216
|
+
sha256Hex(actual.contents) !== expected.sha256) {
|
|
217
|
+
// Same byte count, different bytes: only the persisted digest catches
|
|
218
|
+
// this. Legacy plans without `sha256` skip the check (size-only).
|
|
219
|
+
out.push({
|
|
220
|
+
relativePath: expected.relativePath,
|
|
221
|
+
kind: 'content-changed',
|
|
222
|
+
detail: 'body digest mismatch (same size, different content)',
|
|
223
|
+
});
|
|
224
|
+
}
|
|
205
225
|
}
|
|
206
226
|
for (const [key, actual] of freshByKey) {
|
|
207
227
|
if (!expectedByKey.has(key)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/generator",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.26",
|
|
4
4
|
"description": "SharkCraft plan-first generator: GenerationPlan, FileChange, dry-run, safe writes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
47
|
-
"@shrkcrft/templates": "^0.1.0-alpha.
|
|
48
|
-
"@shrkcrft/rules": "^0.1.0-alpha.
|
|
49
|
-
"@shrkcrft/paths": "^0.1.0-alpha.
|
|
46
|
+
"@shrkcrft/core": "^0.1.0-alpha.26",
|
|
47
|
+
"@shrkcrft/templates": "^0.1.0-alpha.26",
|
|
48
|
+
"@shrkcrft/rules": "^0.1.0-alpha.26",
|
|
49
|
+
"@shrkcrft/paths": "^0.1.0-alpha.26"
|
|
50
50
|
},
|
|
51
51
|
"publishConfig": {
|
|
52
52
|
"access": "public"
|